-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Rust: Lift content reads as taint steps #20879
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
7d47a48
7479309
530a898
a8d580f
22d39b4
5d6e52a
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 |
|---|---|---|
|
|
@@ -7,6 +7,23 @@ private import Node as Node | |
| private import Content | ||
| private import FlowSummaryImpl as FlowSummaryImpl | ||
| private import codeql.rust.internal.CachedStages | ||
| private import codeql.rust.internal.TypeInference as TypeInference | ||
| private import codeql.rust.internal.Type as Type | ||
| private import codeql.rust.frameworks.stdlib.Builtins as Builtins | ||
|
|
||
| /** | ||
| * Holds if the field `field` should, by default, be excluded from taint steps. | ||
| * The syntax used to denote the field is the same as for `Field` in | ||
| * models-as-data. | ||
| */ | ||
| extensible predicate excludeFieldTaintStep(string field); | ||
|
|
||
| private predicate excludedTaintStepContent(Content c) { | ||
| exists(string arg | excludeFieldTaintStep(arg) | | ||
| FlowSummaryImpl::encodeContentStructField(c, arg) or | ||
| FlowSummaryImpl::encodeContentTupleField(c, arg) | ||
| ) | ||
| } | ||
|
|
||
| module RustTaintTracking implements InputSig<Location, RustDataFlow> { | ||
| predicate defaultTaintSanitizer(DataFlow::Node node) { none() } | ||
|
|
@@ -40,11 +57,26 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> { | |
| succ.asExpr() = index | ||
| ) | ||
| or | ||
| // Although data flow through collections and references is modeled using | ||
| // stores/reads, we also allow taint to flow out of a tainted collection | ||
| // or reference. | ||
| // This is needed in order to support taint-tracking configurations where | ||
| // the source is a collection or reference. | ||
| // Read steps give rise to taint steps. This has the effect that if `foo` | ||
| // is tainted and an operation reads from `foo` (e.g., `foo.bar`) then | ||
| // taint is propagated. We limit this to not apply if the type of the | ||
| // operation is a small primitive type as these are often uninteresting | ||
| // (for instance in the case of an injection query). | ||
|
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'm not completely convinced we should apply this limitation here, rather than adding barriers for these types to all injection queries. I haven't seen the kinds of results you're talking about though, other than in the pseudocode example you gave on this PR discussion. Perhaps we could plan to look into this as follow-up, since doing this would mostly add even more flow to what we're already doing here. |
||
| exists(Content c | | ||
| RustDataFlow::readContentStep(pred, c, succ) and | ||
| forex(Type::Type t | t = TypeInference::inferType(succ.asExpr()) | | ||
| not exists(Struct s | s = t.(Type::StructType).getStruct() | | ||
| s instanceof Builtins::NumericType or | ||
| s instanceof Builtins::Bool or | ||
| s instanceof Builtins::Char | ||
| ) | ||
| ) and | ||
|
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. The |
||
| not excludedTaintStepContent(c) and | ||
| not TypeInference::inferType(succ.asExpr()).(Type::EnumType).getEnum().isFieldless() | ||
|
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. You could move this line into the |
||
| ) | ||
| or | ||
| // Let all read steps (including those from flow summaries and those that | ||
| // result in small primitive types) give rise to taint steps. | ||
|
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. You've lost some context from the original comment here, I think. |
||
| exists(SingletonContentSet cs | RustDataFlow::readStep(pred, cs, succ) | | ||
| cs.getContent() instanceof ElementContent | ||
| 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 think we should be slightly more specific about what we mean here, perhaps something like: