diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll b/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll index fddf1bbb5fab..25b2b0c76d3a 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll @@ -246,17 +246,35 @@ private class SummarizedCallableWithCallback extends SummarizedCallable::Range { private class FlowSourceFromModel extends FlowSource::Range { private string path; + private string output_; + private string kind_; + private Provenance provenance_; + private QlBuiltins::ExtensionId madId; FlowSourceFromModel() { - sourceModel(path, _, _, _, _) and - this.getCanonicalPath() = path + exists(string output, string kind, Function f, Provenance p | + sourceModel(path, output, kind, p, madId) and + f.getCanonicalPath() = path + | + output_ = output and + kind_ = kind and + ( + this = f and + provenance_ = p + or + this.implements(f) and + not this.getCanonicalPath() = path and + this.getCanonicalPath().matches("<_ as %") and + provenance_ = "hq-generated" + ) + ) } override predicate isSource(string output, string kind, Provenance provenance, string model) { - exists(QlBuiltins::ExtensionId madId | - sourceModel(path, output, kind, provenance, madId) and - model = "MaD:" + madId.toString() - ) and + output = output_ and + kind = kind_ and + provenance = provenance_ and + model = "MaD:" + madId.toString() and // Only apply generated models when no neutral model exists // (the shared code only applies neutral models to summaries at present) not ( @@ -268,17 +286,35 @@ private class FlowSourceFromModel extends FlowSource::Range { private class FlowSinkFromModel extends FlowSink::Range { private string path; + private string input_; + private string kind_; + private Provenance provenance_; + private QlBuiltins::ExtensionId madId; FlowSinkFromModel() { - sinkModel(path, _, _, _, _) and - this.getCanonicalPath() = path + exists(string input, string kind, Function f, Provenance p | + sinkModel(path, input, kind, p, madId) and + f.getCanonicalPath() = path + | + input_ = input and + kind_ = kind and + ( + this = f and + provenance_ = p + or + this.implements(f) and + not this.getCanonicalPath() = path and + this.getCanonicalPath().matches("<_ as %") and + provenance_ = "hq-generated" + ) + ) } override predicate isSink(string input, string kind, Provenance provenance, string model) { - exists(QlBuiltins::ExtensionId madId | - sinkModel(path, input, kind, provenance, madId) and - model = "MaD:" + madId.toString() - ) and + input = input_ and + kind = kind_ and + provenance = provenance_ and + model = "MaD:" + madId.toString() and // Only apply generated models when no neutral model exists // (the shared code only applies neutral models to summaries at present) not ( @@ -290,35 +326,74 @@ private class FlowSinkFromModel extends FlowSink::Range { private class FlowBarrierFromModel extends FlowBarrier::Range { private string path; + private string output_; + private string kind_; + private Provenance provenance_; + private QlBuiltins::ExtensionId madId; FlowBarrierFromModel() { - barrierModel(path, _, _, _, _) and - this.getCanonicalPath() = path + exists(string output, string kind, Function f, Provenance p | + barrierModel(path, output, kind, p, madId) and + f.getCanonicalPath() = path + | + output_ = output and + kind_ = kind and + ( + this = f and + provenance_ = p + or + this.implements(f) and + not this.getCanonicalPath() = path and + this.getCanonicalPath().matches("<_ as %") and + provenance_ = "hq-generated" + ) + ) } override predicate isBarrier(string output, string kind, Provenance provenance, string model) { - exists(QlBuiltins::ExtensionId madId | - barrierModel(path, output, kind, provenance, madId) and - model = "MaD:" + madId.toString() - ) + output = output_ and + kind = kind_ and + provenance = provenance_ and + model = "MaD:" + madId.toString() } } private class FlowBarrierGuardFromModel extends FlowBarrierGuard::Range { private string path; + private string input_; + private string acceptingValue_; + private string kind_; + private Provenance provenance_; + private QlBuiltins::ExtensionId madId; FlowBarrierGuardFromModel() { - barrierGuardModel(path, _, _, _, _, _) and - this.getCanonicalPath() = path + exists(string input, string acceptingValue, string kind, Function f, Provenance p | + barrierGuardModel(path, input, acceptingValue, kind, p, madId) and + f.getCanonicalPath() = path + | + input_ = input and + acceptingValue_ = acceptingValue and + kind_ = kind and + ( + this = f and + provenance_ = p + or + this.implements(f) and + not this.getCanonicalPath() = path and + this.getCanonicalPath().matches("<_ as %") and + provenance_ = "hq-generated" + ) + ) } override predicate isBarrierGuard( string input, string acceptingValue, string kind, Provenance provenance, string model ) { - exists(QlBuiltins::ExtensionId madId | - barrierGuardModel(path, input, acceptingValue, kind, provenance, madId) and - model = "MaD:" + madId.toString() - ) + input = input_ and + acceptingValue = acceptingValue_ and + kind = kind_ and + provenance = provenance_ and + model = "MaD:" + madId.toString() } } diff --git a/rust/ql/lib/codeql/rust/frameworks/stdlib/alloc.model.yml b/rust/ql/lib/codeql/rust/frameworks/stdlib/alloc.model.yml index 7b97fdb1c4c9..d82db307a4fc 100644 --- a/rust/ql/lib/codeql/rust/frameworks/stdlib/alloc.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/stdlib/alloc.model.yml @@ -15,6 +15,7 @@ extensions: - ["alloc::alloc::realloc", "Argument[2]", "alloc-size", "manual"] - ["core::alloc::global::GlobalAlloc::alloc", "Argument[0]", "alloc-layout", "manual"] - ["core::alloc::global::GlobalAlloc::alloc_zeroed", "Argument[0]", "alloc-layout", "manual"] + - ["core::alloc::global::GlobalAlloc::realloc", "Argument[2]", "alloc-size", "manual"] - ["core::alloc::Allocator::allocate", "Argument[0]", "alloc-layout", "manual"] - ["core::alloc::Allocator::allocate_zeroed", "Argument[0]", "alloc-layout", "manual"] - ["core::alloc::Allocator::grow", "Argument[2]", "alloc-layout", "manual"] diff --git a/rust/ql/test/library-tests/dataflow/barrier/inline-flow.ext.yml b/rust/ql/test/library-tests/dataflow/barrier/inline-flow.ext.yml index 58e55a040d21..f0d120c5d907 100644 --- a/rust/ql/test/library-tests/dataflow/barrier/inline-flow.ext.yml +++ b/rust/ql/test/library-tests/dataflow/barrier/inline-flow.ext.yml @@ -4,8 +4,10 @@ extensions: extensible: barrierModel data: - ["main::sanitize", "ReturnValue", "test-barrier", "manual"] + - ["main::MyTraitBarrier::sanitize_trait", "ReturnValue", "test-barrier", "manual"] - addsTo: pack: codeql/rust-all extensible: barrierGuardModel data: - ["main::verify_safe", "Argument[0]", "true", "test-barrier", "manual"] + - ["main::MyTraitBarrier::verify_safe_trait", "Argument[0]", "true", "test-barrier", "manual"] diff --git a/rust/ql/test/library-tests/dataflow/barrier/main.rs b/rust/ql/test/library-tests/dataflow/barrier/main.rs index 268a8673bc9b..9ed6181b6f8a 100644 --- a/rust/ql/test/library-tests/dataflow/barrier/main.rs +++ b/rust/ql/test/library-tests/dataflow/barrier/main.rs @@ -46,3 +46,31 @@ fn with_barrier_guard() { sink(s); } } + +trait MyTraitBarrier { + fn sanitize_trait(s: &str) -> &str; + fn verify_safe_trait(s: &str) -> bool; +} + +impl MyTraitBarrier for T { + fn sanitize_trait(s: &str) -> &str { + sanitize(s) + } + + fn verify_safe_trait(s: &str) -> bool { + verify_safe(s) + } +} + +fn with_trait_barrier() { + let s = source(1); + let s = <()>::sanitize_trait(s); + sink(s); +} + +fn with_trait_barrier_guard() { + let s = source(1); + if <()>::verify_safe_trait(s) { + sink(s); + } +}