-
Notifications
You must be signed in to change notification settings - Fork 2.1k
unified: Add taint reach stats #22692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -109,6 +109,32 @@ module CallGraphStats implements EntityStatsSig { | |||||||||||||
|
|
||||||||||||||
| module CallGraphStatsReport = EntityReportStats<CallGraphStats>; | ||||||||||||||
|
|
||||||||||||||
| module TaintReach { | ||||||||||||||
| private class Candidate extends DataFlow::Node { | ||||||||||||||
| Candidate() { exists(this.asExpr()) } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| module TaintReachConfig implements DataFlow::ConfigSig { | ||||||||||||||
| predicate isSource(DataFlow::Node node) { Models::isSource(node, _) } | ||||||||||||||
|
|
||||||||||||||
| predicate isSink(DataFlow::Node node) { node instanceof Candidate } | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might work for now, but I would expect performance to eventually be horrendous to the point of breaking dca. If you were to try this on e.g. Java or C# then I'd be fairly certain that it just wouldn't work. We could perhaps draw the numbers from an early data flow stage - that would be a coarse over-approximation, but could guard against severe performance degradation.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's somewhat alleviated by the use of But it would be great we could get the data flow library to report a better version of taint reach.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
See below for a stage-2-representation. I don't think it's possible in general, otherwise we could calculate taint up front and share it across queries instead of having individual configurations.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd expect stage 3 and beyond to be infeasible for a large chunk of repos. And given that I expect the trouble to begin already there, the improvement of using
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huh, I just tested on a couple of Java repos and I must admit that this was surprisingly more feasible than I had imagined. It won't work for customer dbs, but I'll concede that it indeed might work on dca.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can actually calculate stage 4 on a very large Java db (but stage 5 failed).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess that's perhaps somewhat explainable - stage 4 limits the access path representation to the (precise) head, so type pruning likely prevents cartesian blowups in many places. In any case, that's probably enough of my hypothetical rambling - let's go with what we have if it works, and then we can always limit it to e.g. stage 4 if necessary. |
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| module TaintReachFlow = TaintTracking::Global<TaintReachConfig>; | ||||||||||||||
|
|
||||||||||||||
| DataFlow::Node taintedNode() { TaintReachFlow::flowTo(result) } | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possibly something like this:
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| int numberOfTaintedNodes() { result = count(taintedNode()) } | ||||||||||||||
|
|
||||||||||||||
| int numberOfCandidates() { result = count(Candidate c) } | ||||||||||||||
|
|
||||||||||||||
| int perMillionNodes() { | ||||||||||||||
| result = (numberOfTaintedNodes() * 1000000) / numberOfCandidates() | ||||||||||||||
| or | ||||||||||||||
| numberOfCandidates() = 0 and result = 0 | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Gets summary statistics about taint. | ||||||||||||||
| */ | ||||||||||||||
|
|
@@ -123,11 +149,11 @@ predicate taintStats(string key, int value) { | |||||||||||||
| or | ||||||||||||||
| key = "Taint edges - number of edges" and none() | ||||||||||||||
| or | ||||||||||||||
| key = "Taint reach - nodes tainted" and none() | ||||||||||||||
| key = "Taint reach - nodes tainted" and value = TaintReach::numberOfTaintedNodes() | ||||||||||||||
| or | ||||||||||||||
| key = "Taint reach - total non-summary nodes" and none() | ||||||||||||||
| or | ||||||||||||||
| key = "Taint reach - per million nodes" and none() | ||||||||||||||
| key = "Taint reach - per million nodes" and value = TaintReach::perMillionNodes() | ||||||||||||||
| or | ||||||||||||||
| key = "Taint sinks - query sinks" and value = count(DataFlow::Node n | Models::isSink(n, _)) | ||||||||||||||
| or | ||||||||||||||
|
|
||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have written
any()here as well I think. But if there's a reason you restricted candidate nodes to those corresponding with expressions, I think it's fine and we still have a useful metric.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We avoid counting synthetic nodes, so we don't move the goal posts whenever synthetic nodes are added/removed. E.g. something like the introduction of use-use flow can add a large number of synthetic nodes, but then you can't compare the taint reach numbers across that change.
IMO Rust should should also stop measuring synthetic nodes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, then I agree with you, that has been a problem with the rust taint reach statistic.
👍