- Notifications
You must be signed in to change notification settings - Fork1.9k
TaintTracking::FunctionModel taints not shown by hasFlowPath in custom modelling of API#13415
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Hi, I am trying to model the Go API for Kubernetes/OpenShift controllers/operators. Using The taint tracking logic seem to work fine (on simple examples). However, the flow is not shown by A simple example with Json's Here is my minimal OpenShift sample operator with codeql db:https://github.com/rh-tguittet/sample-openshift-operator The minimal Kubernetes QLL: privateimport gomodule K8sControllerClient{abstractclassRangeextends TaintTracking::FunctionModel,Method{abstractFunctionInputgetAnInput();abstractFunctionOutputgetOutput();overridepredicatehasTaintFlow(FunctionInputinput,FunctionOutputoutput){input=getAnInput()andoutput=getOutput()}}/** * Signature: Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error * https://github.com/kubernetes-sigs/controller-runtime/blob/v0.15.0/pkg/client/interfaces.go#L54 */privateclassKubernetesControllerClientGetFunctionextendsRange{KubernetesControllerClientGetFunction(){this.hasQualifiedName("sigs.k8s.io/controller-runtime/pkg/client.Client","Get")}// Marking this arg as input to avoid having to go deeper (down to the network) in the call stack; because what is behind Get() does not matter in this instanceoverrideFunctionInputgetAnInput(){result.isParameter(1)}overrideFunctionOutputgetOutput(){result.isParameter(2)}}} The minimal codeql query: /** * @kind path-problem */import goimport DataFlowimport PathGraphimport semmle.go.security.CommandInjectionimport kubernetes_controller_clientclassMySourceextendsParameter{MySource(){this.getFunction().getName()="Reconcile"andthis.getType().hasQualifiedName("sigs.k8s.io/controller-runtime/pkg/reconcile","Request")}}classMyConfextends TaintTracking::Configuration{MyConf(){this="MyConf"}overridepredicateisSource(DataFlow::Nodenode){node.asParameter()instanceofMySource}overridepredicateisSink(DataFlow::Nodenode){nodeinstanceof CommandInjection::Sink}}from DataFlow::PathNodesource, DataFlow::PathNodesink,MyConfcfgwherecfg.hasFlowPath(source,sink)selectsink.getNode(),source,sink,"Found path" Any ideas ? P.S.: I would also like to taint onlysome of the Thanks in advance! |
BetaWas this translation helpful?Give feedback.
All reactions
I discussed your first point with some colleagues. It would be nice, but it would be a lot of work. We have added it to our list of issues we may work on in the future.
For your second point, I have madea draft PR which should fix/improve the situation (when combined with#13461). So far I have only tested it on your example, where it does indeed add a path step where you expected it. (There is the same backwards flow immediately afterwards, but it isn't shown in the path summary because it is skipped over). There is more work to be done to make sure this doesn't cause any regressions and works in all situations, but I am hopeful we will be able to get this in and improve path summaries …
Replies: 5 comments 10 replies
-
Hi@rh-tguittet ! 👋🏼 Thank you for posting the question and the accompanying clear description. The CodeQL Go team has reviewed your question and will be posting a response. Since it is close to the end of the day in European time zones (where the team works), you may only receive a response with suggestions / solutions only early next week. I just wanted to acknowledge that your question is being reviewed. |
BetaWas this translation helpful?Give feedback.
All reactions
-
Thank you Sid, I appreciate you notifying me :) |
BetaWas this translation helpful?Give feedback.
All reactions
-
I will look into why nothing appears in this case. I don't think there is any way to force a node to appear in the path explanation, except adding I believe you are getting a different result when you use Using MaD would also solve your second problem. For the output, instead of "Argument[2]" you can write "Argument[2].Field[pkg.classname.fieldname]" to indicate that the taint flows into the |
BetaWas this translation helpful?Give feedback.
All reactions
-
Thanks for your quick answer Owen! Going through Models as Data did show one additional taint step, number 5 in the screen capture, but it isn't on the method call: Here are the changes I made to leverage Models as Data:
dataExtensions: -ext/*.model.yml
extensions: -addsTo:pack:tguittet/kubernetesextensible:summaryModeldata:#- ["sigs.k8s.io/controller-runtime/pkg/client", "Client", True, "Get", "", "", "Argument[1]", "Argument[2].Field[github.com/rh-tguittet/sample-openshift-operator/api/v1.Sample.Annotations]", "taint", "manual"] # annotations only, no results returned#- ["sigs.k8s.io/controller-runtime/pkg/client", "Client", True, "Get", "", "", "Argument[1]", "Argument[2].Field[github.com/rh-tguittet/sample-openshift-operator/api/v1.Sample.Spec]", "taint", "manual"] # spec only, no results returned -["sigs.k8s.io/controller-runtime/pkg/client", "Client", True, "Get", "", "", "Argument[1]", "Argument[2]", "taint", "manual"]# catchall
I couldn't get the |
BetaWas this translation helpful?Give feedback.
All reactions
-
I can explain why the extra step in the path appears to go backwards. It is because the CodeQL library for Go uses "def-use" flow. (all the other languages use "use-use", which wouldn't exhibit this behaviour.) Suppose you have code like this The way the go library has set up data flow is that data flows from the a definition (def) to each use of that value, so in this case from def to use1 and from def to use2. So if we mark use1 of x to be tainted, that taint won't flow to use2. We instead have to mark the def corresponding to use1 as tainted, so that other uses of the value will see that it is tainted. We are aware this is counter-intuitive and there has been discussion about switching to "use-use" flow (though that does have some downsides as well). I will look further into your other questions when I am able to. |
BetaWas this translation helpful?Give feedback.
All reactions
👍 2
-
By the way, we have justswitched to use-use flow, so you shouldn't see backwards steps in paths any more. |
BetaWas this translation helpful?Give feedback.
All reactions
-
I have had an opportunity to look into this more and talk it through with some colleagues. Let me take your questions in turn.
Note that I mentioned overriding
Then I adapted it to use partial flow (I don't think there is any documentation on how to do this yet - I had to use trial-and-error): The results tell me that the taint is flowing to all the right uses of I will update you when I have discovered the cause of the problem. Please let me know if there is a question that I have not addressed. |
BetaWas this translation helpful?Give feedback.
All reactions
-
Many thanks for your work on this and your in-depth explanations Owen! It indeed covers all but one interrogation remains for: So this got me a bit confused. Here's what I am seeing with a minimal However, even when I use MaD for (Apologies if this is similar to the what I described in the other thread.) |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Step 3 in your first image is there because of the |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
-
Got it, thanks. (From a user-perspective it is nonetheless surprising behaviour.) |
BetaWas this translation helpful?Give feedback.
All reactions
-
The reason why the flow doesn't work is that I have also madea PR to address your initial point that when a flow path goes through a function modeled with |
BetaWas this translation helpful?Give feedback.
All reactions
-
Ah, yes, gotcha. Thank your for looking into it and coming up with a solution, much appreciated! -(Would a fuzzy match be considered useful? Having to spell out the full qualified name when only its name is what appears to be really needed isn't super practical. e.g. could For#13461, I understand the def-use logic that makes it look like the flow is going backwards. Frankly, that's not an issue, it's not less clear (some documentation would lift residual fog). What would make it clearer however is having the |
BetaWas this translation helpful?Give feedback.
All reactions
-
I discussed your first point with some colleagues. It would be nice, but it would be a lot of work. We have added it to our list of issues we may work on in the future. For your second point, I have madea draft PR which should fix/improve the situation (when combined with#13461). So far I have only tested it on your example, where it does indeed add a path step where you expected it. (There is the same backwards flow immediately afterwards, but it isn't shown in the path summary because it is skipped over). There is more work to be done to make sure this doesn't cause any regressions and works in all situations, but I am hopeful we will be able to get this in and improve path summaries for CodeQL for Go. |
BetaWas this translation helpful?Give feedback.
All reactions
-
Many thanks Owen for all your work, patience, and thorough replies. I shall keep an eye out for those PRs to land in a release version! From the clone at HEAD + loose patching with the various PR you made, the results I expect are returned and paths are highlighted without obvious gaps. |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1




