From 68a4ea3be06f87366e80cd250d9b60dfc3eb8f5d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:02:52 +0000 Subject: [PATCH 1/9] Rust: New query rust/ctor-initialization (placeholder). undo --- .../security/CWE-696/BadCtorInitialization.ql | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql diff --git a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql new file mode 100644 index 000000000000..9d6fa7351e77 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql @@ -0,0 +1,16 @@ +/** + * @name Bad 'ctor' initialization + * @description TODO + * @kind path-problem + * @problem.severity error + * @ security-severity TODO + * @ precision TODO + * @id rust/ctor-initialization + * @tags security + * external/cwe/cwe-696 + * external/cwe/cwe-665 + */ + +import rust + +select 0 From 9ead2dc03c5d8914f5d654ad511990c7ae076120 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:12:09 +0000 Subject: [PATCH 2/9] Rust: Add a query test. --- .../CWE-696/BadCTorInitialization.expected | 1 + .../CWE-696/BadCTorInitialization.qlref | 2 + .../query-tests/security/CWE-696/options.yml | 3 + .../test/query-tests/security/CWE-696/test.rs | 144 ++++++++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected create mode 100644 rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.qlref create mode 100644 rust/ql/test/query-tests/security/CWE-696/options.yml create mode 100644 rust/ql/test/query-tests/security/CWE-696/test.rs diff --git a/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected new file mode 100644 index 000000000000..f082a67fcf66 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected @@ -0,0 +1 @@ +| 0 | diff --git a/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.qlref b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.qlref new file mode 100644 index 000000000000..2b71705c98b8 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.qlref @@ -0,0 +1,2 @@ +query: queries/security/CWE-696/BadCtorInitialization.ql +postprocess: utils/InlineExpectationsTestQuery.ql diff --git a/rust/ql/test/query-tests/security/CWE-696/options.yml b/rust/ql/test/query-tests/security/CWE-696/options.yml new file mode 100644 index 000000000000..1f1a13e589ea --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-696/options.yml @@ -0,0 +1,3 @@ +qltest_cargo_check: true +qltest_dependencies: + - ctor = { version = "0.2.9" } diff --git a/rust/ql/test/query-tests/security/CWE-696/test.rs b/rust/ql/test/query-tests/security/CWE-696/test.rs new file mode 100644 index 000000000000..9fb90a018e6b --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-696/test.rs @@ -0,0 +1,144 @@ + +// --- attribute variants --- + +use std::io::Write; + +fn harmless1_1() { + // ... +} + +#[ctor::ctor] +fn harmless1_2() { + // ... +} + +#[ctor::dtor] +fn harmless1_3() { + // ... +} + +fn harmless1_4() { + _ = std::io::stdout().write(b"Hello, world!"); +} + +#[rustfmt::skip] +fn harmless1_5() { + _ = std::io::stdout().write(b"Hello, world!"); +} + +#[ctor::ctor] +fn bad1_1() { // $ MISSING: Alert[rust/ctor-initialization] + _ = std::io::stdout().write(b"Hello, world!"); +} + +#[ctor::dtor] +fn bad1_2() { // $ MISSING: Alert[rust/ctor-initialization] + _ = std::io::stdout().write(b"Hello, world!"); +} + +#[rustfmt::skip] +#[ctor::dtor] +#[rustfmt::skip] +fn bad1_3() { // $ MISSING: Alert[rust/ctor-initialization] + _ = std::io::stdout().write(b"Hello, world!"); +} + +// --- code variants --- + +use ctor::ctor; +use std::io::*; + +#[ctor] +fn bad2_1() { // $ MISSING: Alert[rust/ctor-initialization] + _ = stdout().write(b"Hello, world!"); +} + +#[ctor] +fn bad2_2() { // $ MISSING: Alert[rust/ctor-initialization] + _ = stderr().write_all(b"Hello, world!"); +} + +#[ctor] +fn bad2_3() { // $ MISSING: Alert[rust/ctor-initialization] + println!("Hello, world!"); +} + +#[ctor] +fn bad2_4() { // $ MISSING: Alert[rust/ctor-initialization] + let mut buff = String::new(); + _ = std::io::stdin().read_line(&mut buff); +} + +use std::fs; + +#[ctor] +fn bad2_5() { // $ MISSING: Alert[rust/ctor-initialization] + let _buff = fs::File::create("hello.txt").unwrap(); +} + +#[ctor] +fn bad2_6() { // $ MISSING: Alert[rust/ctor-initialization] + let _t = std::time::Instant::now(); +} + +use std::time::Duration; + +const DURATION2_7: Duration = Duration::new(1, 0); + +#[ctor] +fn bad2_7() { // $ MISSING: Alert[rust/ctor-initialization] + std::thread::sleep(DURATION2_7); +} + +use std::process; + +#[ctor] +fn bad2_8() { // $ MISSING: Alert[rust/ctor-initialization] + process::exit(1234); +} + +// --- transitive cases --- + +fn call_target3_1() { + _ = stderr().write_all(b"Hello, world!"); +} + +#[ctor] +fn bad3_1() { // $ MISSING: Alert[rust/ctor-initialization] + call_target3_1(); +} + +fn call_target3_2() { + for _x in 0..10 { + // ... + } +} + +#[ctor] +fn harmless3_2() { + call_target3_2(); +} + +#[ctor] +fn bad3_3() { // $ MISSING: Alert[rust/ctor-initialization] + call_target3_1(); + call_target3_2(); +} + +#[ctor] +fn bad3_4() { // $ MISSING: Alert[rust/ctor-initialization] + bad3_3(); +} + +// --- macros --- + +macro_rules! macro4_1 { + () => { + _ = std::io::stdout().write(b"Hello, world!"); + }; +} + +#[ctor] +fn bad4_1() { // $ MISSING: Alert[rust/ctor-initialization] + macro4_1!(); +} From 88fc7be0a233f8fa26bd13b2c22de6f6ca0e234c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 21 Nov 2024 22:37:41 +0000 Subject: [PATCH 3/9] Rust: Implement the query. --- .../security/CWE-696/BadCtorInitialization.ql | 24 ++++++++++++++++++- .../CWE-696/BadCTorInitialization.expected | 11 ++++++++- .../test/query-tests/security/CWE-696/test.rs | 20 ++++++++-------- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql index 9d6fa7351e77..5999ac0e02ec 100644 --- a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql +++ b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql @@ -13,4 +13,26 @@ import rust -select 0 +/** + * A `#[ctor]` or `#[dtor]` attribute. + */ +class CtorAttr extends Attr { + CtorAttr() { this.getMeta().getPath().getPart().getNameRef().getText() = ["ctor", "dtor"] } +} + +/** + * A call into the Rust standard library. + */ +class StdCall extends Expr { + StdCall() { + this.(CallExpr).getExpr().(PathExpr).getPath().getResolvedCrateOrigin() = "lang:std" or + this.(MethodCallExpr).getResolvedCrateOrigin() = "lang:std" + } +} + +from CtorAttr ctor, Function f, StdCall call +where + f.getAnAttr() = ctor and + call.getEnclosingCallable() = f +select f.getName(), "This function has the $@ attribute but calls $@ in the standard library.", + ctor, ctor.toString(), call, call.toString() diff --git a/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected index f082a67fcf66..36ab89a79bf4 100644 --- a/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected +++ b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected @@ -1 +1,10 @@ -| 0 | +| test.rs:30:4:30:9 | bad1_1 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:29:1:29:13 | Attr | Attr | test.rs:31:9:31:25 | ...::stdout(...) | ...::stdout(...) | +| test.rs:35:4:35:9 | bad1_2 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:34:1:34:13 | Attr | Attr | test.rs:36:9:36:25 | ...::stdout(...) | ...::stdout(...) | +| test.rs:42:4:42:9 | bad1_3 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:40:1:40:13 | Attr | Attr | test.rs:43:9:43:25 | ...::stdout(...) | ...::stdout(...) | +| test.rs:52:4:52:9 | bad2_1 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:51:1:51:7 | Attr | Attr | test.rs:53:9:53:16 | stdout(...) | stdout(...) | +| test.rs:57:4:57:9 | bad2_2 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:56:1:56:7 | Attr | Attr | test.rs:58:9:58:16 | stderr(...) | stderr(...) | +| test.rs:62:4:62:9 | bad2_3 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:61:1:61:7 | Attr | Attr | test.rs:63:14:63:28 | ...::_print(...) | ...::_print(...) | +| test.rs:67:4:67:9 | bad2_4 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:66:1:66:7 | Attr | Attr | test.rs:69:9:69:24 | ...::stdin(...) | ...::stdin(...) | +| test.rs:89:4:89:9 | bad2_7 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:88:1:88:7 | Attr | Attr | test.rs:90:5:90:35 | ...::sleep(...) | ...::sleep(...) | +| test.rs:96:4:96:9 | bad2_8 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:95:1:95:7 | Attr | Attr | test.rs:97:5:97:23 | ...::exit(...) | ...::exit(...) | +| test.rs:142:4:142:9 | bad4_1 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:141:1:141:7 | Attr | Attr | test.rs:143:5:143:15 | ...::stdout(...) | ...::stdout(...) | diff --git a/rust/ql/test/query-tests/security/CWE-696/test.rs b/rust/ql/test/query-tests/security/CWE-696/test.rs index 9fb90a018e6b..4041efcae173 100644 --- a/rust/ql/test/query-tests/security/CWE-696/test.rs +++ b/rust/ql/test/query-tests/security/CWE-696/test.rs @@ -27,19 +27,19 @@ fn harmless1_5() { } #[ctor::ctor] -fn bad1_1() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad1_1() { // $ Alert[rust/ctor-initialization] _ = std::io::stdout().write(b"Hello, world!"); } #[ctor::dtor] -fn bad1_2() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad1_2() { // $ Alert[rust/ctor-initialization] _ = std::io::stdout().write(b"Hello, world!"); } #[rustfmt::skip] #[ctor::dtor] #[rustfmt::skip] -fn bad1_3() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad1_3() { // $ Alert[rust/ctor-initialization] _ = std::io::stdout().write(b"Hello, world!"); } @@ -49,22 +49,22 @@ use ctor::ctor; use std::io::*; #[ctor] -fn bad2_1() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad2_1() { // $ Alert[rust/ctor-initialization] _ = stdout().write(b"Hello, world!"); } #[ctor] -fn bad2_2() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad2_2() { // $ Alert[rust/ctor-initialization] _ = stderr().write_all(b"Hello, world!"); } #[ctor] -fn bad2_3() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad2_3() { // $ Alert[rust/ctor-initialization] println!("Hello, world!"); } #[ctor] -fn bad2_4() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad2_4() { // $ Alert[rust/ctor-initialization] let mut buff = String::new(); _ = std::io::stdin().read_line(&mut buff); } @@ -86,14 +86,14 @@ use std::time::Duration; const DURATION2_7: Duration = Duration::new(1, 0); #[ctor] -fn bad2_7() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad2_7() { // $ Alert[rust/ctor-initialization] std::thread::sleep(DURATION2_7); } use std::process; #[ctor] -fn bad2_8() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad2_8() { // $ Alert[rust/ctor-initialization] process::exit(1234); } @@ -139,6 +139,6 @@ macro_rules! macro4_1 { } #[ctor] -fn bad4_1() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad4_1() { // $ Alert[rust/ctor-initialization] macro4_1!(); } From 82f2c6075f30198bc48be6eeac82824717e1d939 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:00:55 +0000 Subject: [PATCH 4/9] Rust: Add qhelp + examples. --- .../CWE-696/BadCtorInitialization.qhelp | 44 +++++++++++++++++++ .../CWE-696/BadCtorInitializationBad.rs | 5 +++ .../CWE-696/BadCtorInitializationGood.rs | 5 +++ 3 files changed, 54 insertions(+) create mode 100644 rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp create mode 100644 rust/ql/src/queries/security/CWE-696/BadCtorInitializationBad.rs create mode 100644 rust/ql/src/queries/security/CWE-696/BadCtorInitializationGood.rs diff --git a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp new file mode 100644 index 000000000000..60f6e3eb45d0 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp @@ -0,0 +1,44 @@ + + + + +

+Calling functions and methods in the Rust std library from a #[ctor] or #[dtor] function is not safe. This is because the std library only guarantees stability and portability between the beginning and end of main, whereas #[ctor] functions are called before main, and #[dtor] functions are called after it. +

+ +
+ + +

+Do not call any part of the std library from a #[ctor] or #[dtor] function. Instead either: +

+
    +
  • Move the code to a different location, such as inside your program's main function.
  • +
  • Rewrite the code using an alternative library.
  • +
+ +
+ + +

+In the following example, a #[ctor] function uses the println! macro which calls std library functions. This may cause unexpected behaviour at runtime. +

+ + + +

+The issue can be fixed by replacing println! with something that does not rely on the std library. In the fixed code below we use the libc_println! macro from the libc-print library: +

+ + + +
+ + +
  • GitHub: rust-ctor - Warnings.
  • +
  • Rust Programming Language: Crate std - Use before and after main().
  • + +
    +
    diff --git a/rust/ql/src/queries/security/CWE-696/BadCtorInitializationBad.rs b/rust/ql/src/queries/security/CWE-696/BadCtorInitializationBad.rs new file mode 100644 index 000000000000..2a6c60272d5c --- /dev/null +++ b/rust/ql/src/queries/security/CWE-696/BadCtorInitializationBad.rs @@ -0,0 +1,5 @@ + +#[ctor::ctor] +fn bad_example() { + println!("Hello, world!"); // BAD: the println! macro calls std library functions +} diff --git a/rust/ql/src/queries/security/CWE-696/BadCtorInitializationGood.rs b/rust/ql/src/queries/security/CWE-696/BadCtorInitializationGood.rs new file mode 100644 index 000000000000..cbb8bc089a3f --- /dev/null +++ b/rust/ql/src/queries/security/CWE-696/BadCtorInitializationGood.rs @@ -0,0 +1,5 @@ + +#[ctor::ctor] +fn good_example() { + libc_print::libc_println!("Hello, world!"); // GOOD: libc-print does not use the std library +} From be5bd1da0a2a82d91688842920cecf56d244f075 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 25 Nov 2024 14:57:30 +0000 Subject: [PATCH 5/9] Rust: Also add the good example and a couple of other cited good cases to the test. --- .../CWE-696/BadCTorInitialization.expected | 2 +- .../query-tests/security/CWE-696/options.yml | 1 + .../test/query-tests/security/CWE-696/test.rs | 23 +++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected index 36ab89a79bf4..10313da17a6c 100644 --- a/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected +++ b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected @@ -7,4 +7,4 @@ | test.rs:67:4:67:9 | bad2_4 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:66:1:66:7 | Attr | Attr | test.rs:69:9:69:24 | ...::stdin(...) | ...::stdin(...) | | test.rs:89:4:89:9 | bad2_7 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:88:1:88:7 | Attr | Attr | test.rs:90:5:90:35 | ...::sleep(...) | ...::sleep(...) | | test.rs:96:4:96:9 | bad2_8 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:95:1:95:7 | Attr | Attr | test.rs:97:5:97:23 | ...::exit(...) | ...::exit(...) | -| test.rs:142:4:142:9 | bad4_1 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:141:1:141:7 | Attr | Attr | test.rs:143:5:143:15 | ...::stdout(...) | ...::stdout(...) | +| test.rs:165:4:165:9 | bad4_1 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:164:1:164:7 | Attr | Attr | test.rs:166:5:166:15 | ...::stdout(...) | ...::stdout(...) | diff --git a/rust/ql/test/query-tests/security/CWE-696/options.yml b/rust/ql/test/query-tests/security/CWE-696/options.yml index 1f1a13e589ea..cc3dc0f35196 100644 --- a/rust/ql/test/query-tests/security/CWE-696/options.yml +++ b/rust/ql/test/query-tests/security/CWE-696/options.yml @@ -1,3 +1,4 @@ qltest_cargo_check: true qltest_dependencies: - ctor = { version = "0.2.9" } + - libc-print = { version = "0.1.23" } diff --git a/rust/ql/test/query-tests/security/CWE-696/test.rs b/rust/ql/test/query-tests/security/CWE-696/test.rs index 4041efcae173..2510a833b0f6 100644 --- a/rust/ql/test/query-tests/security/CWE-696/test.rs +++ b/rust/ql/test/query-tests/security/CWE-696/test.rs @@ -97,6 +97,29 @@ fn bad2_8() { // $ Alert[rust/ctor-initialization] process::exit(1234); } +#[ctor::ctor] +fn harmless2_9() { + libc_print::libc_println!("Hello, world!"); // does not use the std library +} + +#[ctor::ctor] +fn harmless2_10() { + core::assert!(true); // core library should be OK in this context +} + +extern crate alloc; +use alloc::alloc::{alloc, dealloc, Layout}; + +#[ctor::ctor] +unsafe fn harmless2_11() { + let layout = Layout::new::(); + let ptr = alloc(layout); // alloc library should be OK in this context + + if !ptr.is_null() { + dealloc(ptr, layout); + } +} + // --- transitive cases --- fn call_target3_1() { From 77f51685903a056f2753b61b3fb11f7061fc6f19 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:48:42 +0000 Subject: [PATCH 6/9] Rust: Query metadata and path edges. --- .../security/CWE-696/BadCtorInitialization.ql | 42 ++++++--- .../CWE-696/BadCTorInitialization.expected | 32 ++++--- .../test/query-tests/security/CWE-696/test.rs | 86 +++++++++---------- 3 files changed, 96 insertions(+), 64 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql index 5999ac0e02ec..90a7acc69208 100644 --- a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql +++ b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql @@ -1,12 +1,12 @@ /** * @name Bad 'ctor' initialization - * @description TODO + * @description Calling functions in the Rust std library from a ctor or dtor function is not safe. * @kind path-problem * @problem.severity error - * @ security-severity TODO - * @ precision TODO + * @precision high * @id rust/ctor-initialization - * @tags security + * @tags reliability + * correctness * external/cwe/cwe-696 * external/cwe/cwe-665 */ @@ -17,7 +17,14 @@ import rust * A `#[ctor]` or `#[dtor]` attribute. */ class CtorAttr extends Attr { - CtorAttr() { this.getMeta().getPath().getPart().getNameRef().getText() = ["ctor", "dtor"] } + string whichAttr; + + CtorAttr() { + whichAttr = this.getMeta().getPath().getPart().getNameRef().getText() and + whichAttr = ["ctor", "dtor"] + } + + string getWhichAttr() { result = whichAttr } } /** @@ -30,9 +37,22 @@ class StdCall extends Expr { } } -from CtorAttr ctor, Function f, StdCall call -where - f.getAnAttr() = ctor and - call.getEnclosingCallable() = f -select f.getName(), "This function has the $@ attribute but calls $@ in the standard library.", - ctor, ctor.toString(), call, call.toString() +class PathElement = AstNode; + +query predicate edges(PathElement pred, PathElement succ) { + // starting edge + exists(CtorAttr ctor, Function f, StdCall call | + f.getAnAttr() = ctor and + call.getEnclosingCallable() = f and + pred = ctor and // source + succ = call // sink + ) + // or + // transitive edge + // TODO +} + +from CtorAttr ctor, StdCall call +where edges*(ctor, call) +select call, ctor, call, "Call to $@ in a function with the " + ctor.getWhichAttr() + " attribute.", + call, call.toString() diff --git a/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected index 10313da17a6c..8ad81870e06d 100644 --- a/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected +++ b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected @@ -1,10 +1,22 @@ -| test.rs:30:4:30:9 | bad1_1 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:29:1:29:13 | Attr | Attr | test.rs:31:9:31:25 | ...::stdout(...) | ...::stdout(...) | -| test.rs:35:4:35:9 | bad1_2 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:34:1:34:13 | Attr | Attr | test.rs:36:9:36:25 | ...::stdout(...) | ...::stdout(...) | -| test.rs:42:4:42:9 | bad1_3 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:40:1:40:13 | Attr | Attr | test.rs:43:9:43:25 | ...::stdout(...) | ...::stdout(...) | -| test.rs:52:4:52:9 | bad2_1 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:51:1:51:7 | Attr | Attr | test.rs:53:9:53:16 | stdout(...) | stdout(...) | -| test.rs:57:4:57:9 | bad2_2 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:56:1:56:7 | Attr | Attr | test.rs:58:9:58:16 | stderr(...) | stderr(...) | -| test.rs:62:4:62:9 | bad2_3 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:61:1:61:7 | Attr | Attr | test.rs:63:14:63:28 | ...::_print(...) | ...::_print(...) | -| test.rs:67:4:67:9 | bad2_4 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:66:1:66:7 | Attr | Attr | test.rs:69:9:69:24 | ...::stdin(...) | ...::stdin(...) | -| test.rs:89:4:89:9 | bad2_7 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:88:1:88:7 | Attr | Attr | test.rs:90:5:90:35 | ...::sleep(...) | ...::sleep(...) | -| test.rs:96:4:96:9 | bad2_8 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:95:1:95:7 | Attr | Attr | test.rs:97:5:97:23 | ...::exit(...) | ...::exit(...) | -| test.rs:165:4:165:9 | bad4_1 | This function has the $@ attribute but calls $@ in the standard library. | test.rs:164:1:164:7 | Attr | Attr | test.rs:166:5:166:15 | ...::stdout(...) | ...::stdout(...) | +#select +| test.rs:31:9:31:25 | ...::stdout(...) | test.rs:29:1:29:13 | Attr | test.rs:31:9:31:25 | ...::stdout(...) | Call to $@ in a function with the ctor attribute. | test.rs:31:9:31:25 | ...::stdout(...) | ...::stdout(...) | +| test.rs:36:9:36:25 | ...::stdout(...) | test.rs:34:1:34:13 | Attr | test.rs:36:9:36:25 | ...::stdout(...) | Call to $@ in a function with the dtor attribute. | test.rs:36:9:36:25 | ...::stdout(...) | ...::stdout(...) | +| test.rs:43:9:43:25 | ...::stdout(...) | test.rs:40:1:40:13 | Attr | test.rs:43:9:43:25 | ...::stdout(...) | Call to $@ in a function with the dtor attribute. | test.rs:43:9:43:25 | ...::stdout(...) | ...::stdout(...) | +| test.rs:53:9:53:16 | stdout(...) | test.rs:51:1:51:7 | Attr | test.rs:53:9:53:16 | stdout(...) | Call to $@ in a function with the ctor attribute. | test.rs:53:9:53:16 | stdout(...) | stdout(...) | +| test.rs:58:9:58:16 | stderr(...) | test.rs:56:1:56:7 | Attr | test.rs:58:9:58:16 | stderr(...) | Call to $@ in a function with the ctor attribute. | test.rs:58:9:58:16 | stderr(...) | stderr(...) | +| test.rs:63:14:63:28 | ...::_print(...) | test.rs:61:1:61:7 | Attr | test.rs:63:14:63:28 | ...::_print(...) | Call to $@ in a function with the ctor attribute. | test.rs:63:14:63:28 | ...::_print(...) | ...::_print(...) | +| test.rs:69:9:69:24 | ...::stdin(...) | test.rs:66:1:66:7 | Attr | test.rs:69:9:69:24 | ...::stdin(...) | Call to $@ in a function with the ctor attribute. | test.rs:69:9:69:24 | ...::stdin(...) | ...::stdin(...) | +| test.rs:90:5:90:35 | ...::sleep(...) | test.rs:88:1:88:7 | Attr | test.rs:90:5:90:35 | ...::sleep(...) | Call to $@ in a function with the ctor attribute. | test.rs:90:5:90:35 | ...::sleep(...) | ...::sleep(...) | +| test.rs:97:5:97:23 | ...::exit(...) | test.rs:95:1:95:7 | Attr | test.rs:97:5:97:23 | ...::exit(...) | Call to $@ in a function with the ctor attribute. | test.rs:97:5:97:23 | ...::exit(...) | ...::exit(...) | +| test.rs:166:5:166:15 | ...::stdout(...) | test.rs:164:1:164:7 | Attr | test.rs:166:5:166:15 | ...::stdout(...) | Call to $@ in a function with the ctor attribute. | test.rs:166:5:166:15 | ...::stdout(...) | ...::stdout(...) | +edges +| test.rs:29:1:29:13 | Attr | test.rs:31:9:31:25 | ...::stdout(...) | +| test.rs:34:1:34:13 | Attr | test.rs:36:9:36:25 | ...::stdout(...) | +| test.rs:40:1:40:13 | Attr | test.rs:43:9:43:25 | ...::stdout(...) | +| test.rs:51:1:51:7 | Attr | test.rs:53:9:53:16 | stdout(...) | +| test.rs:56:1:56:7 | Attr | test.rs:58:9:58:16 | stderr(...) | +| test.rs:61:1:61:7 | Attr | test.rs:63:14:63:28 | ...::_print(...) | +| test.rs:66:1:66:7 | Attr | test.rs:69:9:69:24 | ...::stdin(...) | +| test.rs:88:1:88:7 | Attr | test.rs:90:5:90:35 | ...::sleep(...) | +| test.rs:95:1:95:7 | Attr | test.rs:97:5:97:23 | ...::exit(...) | +| test.rs:164:1:164:7 | Attr | test.rs:166:5:166:15 | ...::stdout(...) | diff --git a/rust/ql/test/query-tests/security/CWE-696/test.rs b/rust/ql/test/query-tests/security/CWE-696/test.rs index 2510a833b0f6..87f544be85c1 100644 --- a/rust/ql/test/query-tests/security/CWE-696/test.rs +++ b/rust/ql/test/query-tests/security/CWE-696/test.rs @@ -26,21 +26,21 @@ fn harmless1_5() { _ = std::io::stdout().write(b"Hello, world!"); } -#[ctor::ctor] -fn bad1_1() { // $ Alert[rust/ctor-initialization] - _ = std::io::stdout().write(b"Hello, world!"); +#[ctor::ctor] // $ Source=source1_1 +fn bad1_1() { + _ = std::io::stdout().write(b"Hello, world!"); // $ Alert[rust/ctor-initialization]=source1_1 } -#[ctor::dtor] -fn bad1_2() { // $ Alert[rust/ctor-initialization] - _ = std::io::stdout().write(b"Hello, world!"); +#[ctor::dtor] // $ Source=source1_2 +fn bad1_2() { + _ = std::io::stdout().write(b"Hello, world!"); // $ Alert[rust/ctor-initialization]=source1_2 } #[rustfmt::skip] -#[ctor::dtor] +#[ctor::dtor] // $ Source=source1_3 #[rustfmt::skip] -fn bad1_3() { // $ Alert[rust/ctor-initialization] - _ = std::io::stdout().write(b"Hello, world!"); +fn bad1_3() { + _ = std::io::stdout().write(b"Hello, world!"); // $ Alert[rust/ctor-initialization]=source1_3 } // --- code variants --- @@ -48,53 +48,53 @@ fn bad1_3() { // $ Alert[rust/ctor-initialization] use ctor::ctor; use std::io::*; -#[ctor] -fn bad2_1() { // $ Alert[rust/ctor-initialization] - _ = stdout().write(b"Hello, world!"); +#[ctor] // $ Source=source2_1 +fn bad2_1() { + _ = stdout().write(b"Hello, world!"); // $ Alert[rust/ctor-initialization]=source2_1 } -#[ctor] -fn bad2_2() { // $ Alert[rust/ctor-initialization] - _ = stderr().write_all(b"Hello, world!"); +#[ctor] // $ Source=source2_2 +fn bad2_2() { + _ = stderr().write_all(b"Hello, world!"); // $ Alert[rust/ctor-initialization]=source2_2 } -#[ctor] -fn bad2_3() { // $ Alert[rust/ctor-initialization] - println!("Hello, world!"); +#[ctor] // $ Source=source2_3 +fn bad2_3() { + println!("Hello, world!"); // $ Alert[rust/ctor-initialization]=source2_3 } -#[ctor] -fn bad2_4() { // $ Alert[rust/ctor-initialization] +#[ctor] // $ Source=source2_4 +fn bad2_4() { let mut buff = String::new(); - _ = std::io::stdin().read_line(&mut buff); + _ = std::io::stdin().read_line(&mut buff); // $ Alert[rust/ctor-initialization]=source2_4 } use std::fs; -#[ctor] -fn bad2_5() { // $ MISSING: Alert[rust/ctor-initialization] - let _buff = fs::File::create("hello.txt").unwrap(); +#[ctor] // $ MISSING: Source=source2_5 +fn bad2_5() { + let _buff = fs::File::create("hello.txt").unwrap(); // $ MISSING: Alert[rust/ctor-initialization]=source2_5 } -#[ctor] -fn bad2_6() { // $ MISSING: Alert[rust/ctor-initialization] - let _t = std::time::Instant::now(); +#[ctor] // $ MISSING: Source=source2_6 +fn bad2_6() { + let _t = std::time::Instant::now(); // $ MISSING: Alert[rust/ctor-initialization]=source2_6 } use std::time::Duration; const DURATION2_7: Duration = Duration::new(1, 0); -#[ctor] -fn bad2_7() { // $ Alert[rust/ctor-initialization] - std::thread::sleep(DURATION2_7); +#[ctor] // $ Source=source2_7 +fn bad2_7() { + std::thread::sleep(DURATION2_7); // $ Alert[rust/ctor-initialization]=source2_7 } use std::process; -#[ctor] -fn bad2_8() { // $ Alert[rust/ctor-initialization] - process::exit(1234); +#[ctor] // $ Source=source2_8 +fn bad2_8() { + process::exit(1234); // $ Alert[rust/ctor-initialization]=source2_8 } #[ctor::ctor] @@ -123,11 +123,11 @@ unsafe fn harmless2_11() { // --- transitive cases --- fn call_target3_1() { - _ = stderr().write_all(b"Hello, world!"); + _ = stderr().write_all(b"Hello, world!"); // $ MISSING: Alert=source3_1 Alert=source3_3 Alert=source3_4 } -#[ctor] -fn bad3_1() { // $ MISSING: Alert[rust/ctor-initialization] +#[ctor] // $ MISSING: Source=source3_1 +fn bad3_1() { call_target3_1(); } @@ -137,19 +137,19 @@ fn call_target3_2() { } } -#[ctor] +#[ctor] // $ MISSING: Source=source3_2 fn harmless3_2() { call_target3_2(); } #[ctor] -fn bad3_3() { // $ MISSING: Alert[rust/ctor-initialization] +fn bad3_3() { call_target3_1(); call_target3_2(); } -#[ctor] -fn bad3_4() { // $ MISSING: Alert[rust/ctor-initialization] +#[ctor] // $ MISSING: Source=source3_4 +fn bad3_4() { bad3_3(); } @@ -161,7 +161,7 @@ macro_rules! macro4_1 { }; } -#[ctor] -fn bad4_1() { // $ Alert[rust/ctor-initialization] - macro4_1!(); +#[ctor] // $ Source=source4_1 +fn bad4_1() { + macro4_1!(); // $ Alert[rust/ctor-initialization]=source4_1 } From e8981a505d2fb1db293c801b25cbe80f51271a58 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 25 Nov 2024 20:00:22 +0000 Subject: [PATCH 7/9] Rust: Fix qhelp. --- .../ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp index 60f6e3eb45d0..3a3b2e48c6d0 100644 --- a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp +++ b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp @@ -5,7 +5,7 @@

    -Calling functions and methods in the Rust std library from a #[ctor] or #[dtor] function is not safe. This is because the std library only guarantees stability and portability between the beginning and end of main, whereas #[ctor] functions are called before main, and #[dtor] functions are called after it. +Calling functions and methods in the Rust std library from a #[ctor] or #[dtor] function is not safe. This is because the std library only guarantees stability and portability between the beginning and end of main, whereas #[ctor] functions are called before main, and #[dtor] functions are called after it.

    From e6302cae535e38eaca403a1dc868a968d9393a17 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 25 Nov 2024 20:07:47 +0000 Subject: [PATCH 8/9] Rust: Address CI and ql-for-ql issues. --- .../CWE-696/BadCtorInitialization.qhelp | 2 +- .../security/CWE-696/BadCtorInitialization.ql | 3 +-- .../CWE-696/BadCTorInitialization.expected | 20 +++++++++---------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp index 3a3b2e48c6d0..82683ccfdba4 100644 --- a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp +++ b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.qhelp @@ -12,7 +12,7 @@ Calling functions and methods in the Rust std library from a

    -Do not call any part of the std library from a #[ctor] or #[dtor] function. Instead either: +Do not call any part of the std library from a #[ctor] or #[dtor] function. Instead either:

    • Move the code to a different location, such as inside your program's main function.
    • diff --git a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql index 90a7acc69208..9d9c698db245 100644 --- a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql +++ b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql @@ -54,5 +54,4 @@ query predicate edges(PathElement pred, PathElement succ) { from CtorAttr ctor, StdCall call where edges*(ctor, call) -select call, ctor, call, "Call to $@ in a function with the " + ctor.getWhichAttr() + " attribute.", - call, call.toString() +select call, ctor, call, "Call to " + call.toString() + " in a function with the " + ctor.getWhichAttr() + " attribute." diff --git a/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected index 8ad81870e06d..508a359b0c0b 100644 --- a/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected +++ b/rust/ql/test/query-tests/security/CWE-696/BadCTorInitialization.expected @@ -1,14 +1,14 @@ #select -| test.rs:31:9:31:25 | ...::stdout(...) | test.rs:29:1:29:13 | Attr | test.rs:31:9:31:25 | ...::stdout(...) | Call to $@ in a function with the ctor attribute. | test.rs:31:9:31:25 | ...::stdout(...) | ...::stdout(...) | -| test.rs:36:9:36:25 | ...::stdout(...) | test.rs:34:1:34:13 | Attr | test.rs:36:9:36:25 | ...::stdout(...) | Call to $@ in a function with the dtor attribute. | test.rs:36:9:36:25 | ...::stdout(...) | ...::stdout(...) | -| test.rs:43:9:43:25 | ...::stdout(...) | test.rs:40:1:40:13 | Attr | test.rs:43:9:43:25 | ...::stdout(...) | Call to $@ in a function with the dtor attribute. | test.rs:43:9:43:25 | ...::stdout(...) | ...::stdout(...) | -| test.rs:53:9:53:16 | stdout(...) | test.rs:51:1:51:7 | Attr | test.rs:53:9:53:16 | stdout(...) | Call to $@ in a function with the ctor attribute. | test.rs:53:9:53:16 | stdout(...) | stdout(...) | -| test.rs:58:9:58:16 | stderr(...) | test.rs:56:1:56:7 | Attr | test.rs:58:9:58:16 | stderr(...) | Call to $@ in a function with the ctor attribute. | test.rs:58:9:58:16 | stderr(...) | stderr(...) | -| test.rs:63:14:63:28 | ...::_print(...) | test.rs:61:1:61:7 | Attr | test.rs:63:14:63:28 | ...::_print(...) | Call to $@ in a function with the ctor attribute. | test.rs:63:14:63:28 | ...::_print(...) | ...::_print(...) | -| test.rs:69:9:69:24 | ...::stdin(...) | test.rs:66:1:66:7 | Attr | test.rs:69:9:69:24 | ...::stdin(...) | Call to $@ in a function with the ctor attribute. | test.rs:69:9:69:24 | ...::stdin(...) | ...::stdin(...) | -| test.rs:90:5:90:35 | ...::sleep(...) | test.rs:88:1:88:7 | Attr | test.rs:90:5:90:35 | ...::sleep(...) | Call to $@ in a function with the ctor attribute. | test.rs:90:5:90:35 | ...::sleep(...) | ...::sleep(...) | -| test.rs:97:5:97:23 | ...::exit(...) | test.rs:95:1:95:7 | Attr | test.rs:97:5:97:23 | ...::exit(...) | Call to $@ in a function with the ctor attribute. | test.rs:97:5:97:23 | ...::exit(...) | ...::exit(...) | -| test.rs:166:5:166:15 | ...::stdout(...) | test.rs:164:1:164:7 | Attr | test.rs:166:5:166:15 | ...::stdout(...) | Call to $@ in a function with the ctor attribute. | test.rs:166:5:166:15 | ...::stdout(...) | ...::stdout(...) | +| test.rs:31:9:31:25 | ...::stdout(...) | test.rs:29:1:29:13 | Attr | test.rs:31:9:31:25 | ...::stdout(...) | Call to ...::stdout(...) in a function with the ctor attribute. | +| test.rs:36:9:36:25 | ...::stdout(...) | test.rs:34:1:34:13 | Attr | test.rs:36:9:36:25 | ...::stdout(...) | Call to ...::stdout(...) in a function with the dtor attribute. | +| test.rs:43:9:43:25 | ...::stdout(...) | test.rs:40:1:40:13 | Attr | test.rs:43:9:43:25 | ...::stdout(...) | Call to ...::stdout(...) in a function with the dtor attribute. | +| test.rs:53:9:53:16 | stdout(...) | test.rs:51:1:51:7 | Attr | test.rs:53:9:53:16 | stdout(...) | Call to stdout(...) in a function with the ctor attribute. | +| test.rs:58:9:58:16 | stderr(...) | test.rs:56:1:56:7 | Attr | test.rs:58:9:58:16 | stderr(...) | Call to stderr(...) in a function with the ctor attribute. | +| test.rs:63:14:63:28 | ...::_print(...) | test.rs:61:1:61:7 | Attr | test.rs:63:14:63:28 | ...::_print(...) | Call to ...::_print(...) in a function with the ctor attribute. | +| test.rs:69:9:69:24 | ...::stdin(...) | test.rs:66:1:66:7 | Attr | test.rs:69:9:69:24 | ...::stdin(...) | Call to ...::stdin(...) in a function with the ctor attribute. | +| test.rs:90:5:90:35 | ...::sleep(...) | test.rs:88:1:88:7 | Attr | test.rs:90:5:90:35 | ...::sleep(...) | Call to ...::sleep(...) in a function with the ctor attribute. | +| test.rs:97:5:97:23 | ...::exit(...) | test.rs:95:1:95:7 | Attr | test.rs:97:5:97:23 | ...::exit(...) | Call to ...::exit(...) in a function with the ctor attribute. | +| test.rs:166:5:166:15 | ...::stdout(...) | test.rs:164:1:164:7 | Attr | test.rs:166:5:166:15 | ...::stdout(...) | Call to ...::stdout(...) in a function with the ctor attribute. | edges | test.rs:29:1:29:13 | Attr | test.rs:31:9:31:25 | ...::stdout(...) | | test.rs:34:1:34:13 | Attr | test.rs:36:9:36:25 | ...::stdout(...) | From 28c0e899b7e4ce67e3d1ea7c8ef3e752ba24d5ae Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 25 Nov 2024 20:50:56 +0000 Subject: [PATCH 9/9] Rust: Autoformat. --- rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql index 9d9c698db245..8d434b1f6e4d 100644 --- a/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql +++ b/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql @@ -54,4 +54,5 @@ query predicate edges(PathElement pred, PathElement succ) { from CtorAttr ctor, StdCall call where edges*(ctor, call) -select call, ctor, call, "Call to " + call.toString() + " in a function with the " + ctor.getWhichAttr() + " attribute." +select call, ctor, call, + "Call to " + call.toString() + " in a function with the " + ctor.getWhichAttr() + " attribute."