-
Notifications
You must be signed in to change notification settings - Fork 2k
Rust: Query for dereferencing an invalid pointer #19080
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
Merged
Merged
Changes from 14 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
19f009a
Rust: Add tests for various kinds of dangling pointers.
geoffw0 a139b37
Rust: Split lang-core.model.yml into lang-core and lang-alloc.
geoffw0 dcd016f
Rust: Initial version of the query.
geoffw0 c2ee421
Rust: Add more models.
geoffw0 be6d0d1
Rust: Work around data flow source issue.
geoffw0 7ceb764
Rust: Improve the source to account for conversions.
geoffw0 671f7df
Rust: Query metadata.
geoffw0 019fcbf
Rust: Add qhelp examples, and add them as tests.
geoffw0 7ecba71
Rust: Add .qhelp.
geoffw0 5831c44
Rust: Add test cases for another situation I came across.
geoffw0 5e18e1b
Rust: Autofix and US spelling.
geoffw0 c6c4e3c
Rust: Add another reference.
geoffw0 98690f9
Rust: Incidental changes to other .expected files.
geoffw0 91d273a
Rust: I think these generated models are correct. Accept them.
geoffw0 f582054
Rust: Refactor the tests that have multiple control flow paths.
geoffw0 b7044bd
Rust: Add a test of repeat sinks.
geoffw0 e4cadf0
Rust: Don't report excessive results for the same source.
geoffw0 363128f
Apply suggestions from code review
geoffw0 82068a2
Rust: Further rephrasing.
geoffw0 56f330d
Merge branch 'main' into deallocation
geoffw0 0a04191
Rust: Effect of merging main (duplicate results).
geoffw0 c84e2cd
Rust: Reduce the workaround (fixes duplicate results).
geoffw0 d1a0237
Rust: Correct a few details in the test.
geoffw0 8598d61
Rust: Add a test case involving a Drop method.
geoffw0 4e496fe
Rust: Lets just not model 'drop' incorrectly, for now.
geoffw0 9ae271a
Rust: Fix incidentally affected test merge conflict.
geoffw0 ce7a0fd
Rust: Test for sinks inside sources.
geoffw0 ed14b37
Merge branch 'main' into deallocation
geoffw0 4a76b5b
Rust: Accept consistency check failures.
geoffw0 1d7dac4
Rust: switch the query to taint flow so that we get taint through con…
geoffw0 c737ee9
Rust: Accept another consistency check failure.
geoffw0 8b23945
Merge branch 'main' into deallocation
geoffw0 24a4aad
Rust: Accept consistency check fixes following merge with main.
geoffw0 d47e925
Rust: Delete empty .expected files.
geoffw0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| extensions: | ||
| - addsTo: | ||
| pack: codeql/rust-all | ||
| extensible: sourceModel | ||
| data: | ||
| # Alloc | ||
| - ["repo:https://github.com/rust-lang/libc:libc", "::free", "Argument[0]", "pointer-invalidate", "manual"] |
17 changes: 17 additions & 0 deletions
17
rust/ql/lib/codeql/rust/frameworks/stdlib/lang-alloc.model.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| extensions: | ||
| - addsTo: | ||
| pack: codeql/rust-all | ||
| extensible: summaryModel | ||
| data: | ||
| # Fmt | ||
| - ["lang:alloc", "crate::fmt::format", "Argument[0]", "ReturnValue", "taint", "manual"] | ||
| # String | ||
| - ["lang:alloc", "<crate::string::String>::as_str", "Argument[self]", "ReturnValue", "taint", "manual"] | ||
| - ["lang:alloc", "<crate::string::String>::as_bytes", "Argument[self]", "ReturnValue", "taint", "manual"] | ||
| - ["lang:alloc", "<_ as crate::string::ToString>::to_string", "Argument[self]", "ReturnValue", "taint", "manual"] | ||
| - addsTo: | ||
| pack: codeql/rust-all | ||
| extensible: sourceModel | ||
| data: | ||
| # Alloc | ||
| - ["lang:alloc", "crate::alloc::dealloc", "Argument[0]", "pointer-invalidate", "manual"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
73 changes: 73 additions & 0 deletions
73
rust/ql/lib/codeql/rust/security/AccessInvalidPointerExtensions.qll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| /** | ||
| * Provides classes and predicates for reasoning about accesses to invalid | ||
| * pointers. | ||
| */ | ||
|
|
||
| import rust | ||
| private import codeql.rust.dataflow.DataFlow | ||
| private import codeql.rust.dataflow.FlowSource | ||
| private import codeql.rust.dataflow.FlowSink | ||
| private import codeql.rust.Concepts | ||
| private import codeql.rust.dataflow.internal.Node | ||
|
|
||
| /** | ||
| * Provides default sources, sinks and barriers for detecting accesses to | ||
| * invalid pointers, as well as extension points for adding your own. | ||
| */ | ||
| module AccessInvalidPointer { | ||
| /** | ||
| * A data flow source for invalid pointer accesses, that is, an operation | ||
| * where a pointer becomes invalid. | ||
| */ | ||
| abstract class Source extends DataFlow::Node { } | ||
|
|
||
| /** | ||
| * A data flow sink for invalid pointer accesses, that is, a pointer | ||
| * dereference. | ||
| */ | ||
| abstract class Sink extends QuerySink::Range { | ||
| override string getSinkType() { result = "AccessInvalidPointer" } | ||
| } | ||
|
|
||
| /** | ||
| * A barrier for invalid pointer accesses. | ||
| */ | ||
| abstract class Barrier extends DataFlow::Node { } | ||
|
|
||
| /** | ||
| * A pointer invalidation from model data. | ||
| */ | ||
| private class ModelsAsDataSource extends Source { | ||
| ModelsAsDataSource() { sourceNode(this, "pointer-invalidate") } | ||
| } | ||
|
|
||
| /** | ||
| * A pointer invalidation from an argument of a modeled call (this is a workaround). | ||
| */ | ||
| private class ModelsAsDataArgumentSource extends Source { | ||
| ModelsAsDataArgumentSource() { | ||
| exists(DataFlow::Node n, CallExpr ce, Expr arg | | ||
| sourceNode(n, "pointer-invalidate") and | ||
| n.(FlowSummaryNode).getSourceElement() = ce.getFunction() and | ||
| arg = ce.getArgList().getAnArg() and | ||
| this.asExpr().getExpr().getParentNode*() = arg | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * A pointer access using the unary `*` operator. | ||
| */ | ||
| private class DereferenceSink extends Sink { | ||
| DereferenceSink() { | ||
| exists(PrefixExpr p | p.getOperatorName() = "*" and p.getExpr() = this.asExpr().getExpr()) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * A pointer access from model data. | ||
| */ | ||
| private class ModelsAsDataSink extends Sink { | ||
| ModelsAsDataSink() { sinkNode(this, "pointer-access") } | ||
| } | ||
| } | ||
49 changes: 49 additions & 0 deletions
49
rust/ql/src/queries/security/CWE-825/AccessInvalidPointer.qhelp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
| <overview> | ||
|
|
||
| <p> | ||
| Dereferencing an invalid or dangling pointer is undefined behavior. Memory may be corrupted | ||
geoffw0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| causing the program to crash or behave incorrectly, in some cases exposing the program to | ||
| potential attacks. | ||
| </p> | ||
|
|
||
| </overview> | ||
| <recommendation> | ||
|
|
||
| <p> | ||
| When dereferencing a pointer in <code>unsafe</code> code, take care that the pointer is valid and | ||
| points to the intended data. Code may need to be rearranged or additional checks added to ensure | ||
| safety in all circumstances. If possible, rewrite the code using safe Rust types to avoid this | ||
| class of problems altogether. | ||
geoffw0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| </p> | ||
|
|
||
| </recommendation> | ||
| <example> | ||
|
|
||
| <p> | ||
| In the following example, <code>std::ptr::drop_in_place</code> is used to execute the destructor | ||
| of an object. However, a pointer to that object is dereferenced later in the program, causing | ||
| undefined behavior: | ||
| </p> | ||
|
|
||
| <sample src="AccessInvalidPointerBad.rs" /> | ||
|
|
||
| <p> | ||
| In this case undefined behavior can be avoided by rearranging the code so that the dereference | ||
geoffw0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| comes before the call to <code>std::ptr::drop_in_place</code>: | ||
| </p> | ||
|
|
||
| <sample src="AccessInvalidPointerGood.rs" /> | ||
|
|
||
| </example> | ||
| <references> | ||
|
|
||
| <li>Rust Documentation: <a href="https://doc.rust-lang.org/reference/behavior-considered-undefined.html#dangling-pointers">Behavior considered undefined >> Dangling pointers</a>.</li> | ||
| <li>Rust Documentation: <a href="https://doc.rust-lang.org/std/ptr/index.html#safety">Module ptr - Safety</a>.</li> | ||
| <li>Massachusetts Institute of Technology: <a href="https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/second-edition/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer">Unsafe Rust - Dereferencing a Raw Pointer</a>.</li> | ||
|
|
||
| </references> | ||
| </qhelp> | ||
36 changes: 36 additions & 0 deletions
36
rust/ql/src/queries/security/CWE-825/AccessInvalidPointer.ql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| /** | ||
| * @name Access of invalid pointer | ||
| * @description Dereferencing an invalid or dangling pointer is undefined behavior and may cause memory corruption. | ||
geoffw0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * @kind path-problem | ||
| * @problem.severity error | ||
| * @security-severity 7.5 | ||
| * @precision high | ||
| * @id rust/access-invalid-pointer | ||
| * @tags reliability | ||
| * security | ||
| * external/cwe/cwe-476 | ||
| * external/cwe/cwe-825 | ||
| */ | ||
|
|
||
| import rust | ||
| import codeql.rust.dataflow.DataFlow | ||
| import codeql.rust.security.AccessInvalidPointerExtensions | ||
| import AccessInvalidPointerFlow::PathGraph | ||
|
|
||
| /** | ||
| * A data flow configuration for accesses to invalid pointers. | ||
| */ | ||
| module AccessInvalidPointerConfig implements DataFlow::ConfigSig { | ||
| predicate isSource(DataFlow::Node node) { node instanceof AccessInvalidPointer::Source } | ||
|
|
||
| predicate isSink(DataFlow::Node node) { node instanceof AccessInvalidPointer::Sink } | ||
|
|
||
| predicate isBarrier(DataFlow::Node barrier) { barrier instanceof AccessInvalidPointer::Barrier } | ||
| } | ||
|
|
||
| module AccessInvalidPointerFlow = DataFlow::Global<AccessInvalidPointerConfig>; | ||
|
|
||
| from AccessInvalidPointerFlow::PathNode sourceNode, AccessInvalidPointerFlow::PathNode sinkNode | ||
| where AccessInvalidPointerFlow::flowPath(sourceNode, sinkNode) | ||
| select sinkNode.getNode(), sourceNode, sinkNode, | ||
| "This operation dereferences a pointer that may be $@.", sourceNode.getNode(), "invalid" | ||
10 changes: 10 additions & 0 deletions
10
rust/ql/src/queries/security/CWE-825/AccessInvalidPointerBad.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
|
|
||
| unsafe { | ||
| std::ptr::drop_in_place(ptr); // executes the destructor of `*ptr` | ||
| } | ||
|
|
||
| // ... | ||
|
|
||
| unsafe { | ||
| do_something(&*ptr); // BAD: dereferences `ptr` | ||
| } |
10 changes: 10 additions & 0 deletions
10
rust/ql/src/queries/security/CWE-825/AccessInvalidPointerGood.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
|
|
||
| unsafe { | ||
| do_something(&*ptr); // GOOD: dereferences `ptr` while it is still valid | ||
| } | ||
|
|
||
| // ... | ||
|
|
||
| { | ||
| std::ptr::drop_in_place(ptr); // executes the destructor of `*ptr` | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.