Skip to content

Commit 77f5168

Browse files
committed
Rust: Query metadata and path edges.
1 parent be5bd1d commit 77f5168

File tree

3 files changed

+96
-64
lines changed

3 files changed

+96
-64
lines changed
Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/**
22
* @name Bad 'ctor' initialization
3-
* @description TODO
3+
* @description Calling functions in the Rust std library from a ctor or dtor function is not safe.
44
* @kind path-problem
55
* @problem.severity error
6-
* @ security-severity TODO
7-
* @ precision TODO
6+
* @precision high
87
* @id rust/ctor-initialization
9-
* @tags security
8+
* @tags reliability
9+
* correctness
1010
* external/cwe/cwe-696
1111
* external/cwe/cwe-665
1212
*/
@@ -17,7 +17,14 @@ import rust
1717
* A `#[ctor]` or `#[dtor]` attribute.
1818
*/
1919
class CtorAttr extends Attr {
20-
CtorAttr() { this.getMeta().getPath().getPart().getNameRef().getText() = ["ctor", "dtor"] }
20+
string whichAttr;
21+
22+
CtorAttr() {
23+
whichAttr = this.getMeta().getPath().getPart().getNameRef().getText() and
24+
whichAttr = ["ctor", "dtor"]
25+
}
26+
27+
string getWhichAttr() { result = whichAttr }
2128
}
2229

2330
/**
@@ -30,9 +37,22 @@ class StdCall extends Expr {
3037
}
3138
}
3239

33-
from CtorAttr ctor, Function f, StdCall call
34-
where
35-
f.getAnAttr() = ctor and
36-
call.getEnclosingCallable() = f
37-
select f.getName(), "This function has the $@ attribute but calls $@ in the standard library.",
38-
ctor, ctor.toString(), call, call.toString()
40+
class PathElement = AstNode;
41+
42+
query predicate edges(PathElement pred, PathElement succ) {
43+
// starting edge
44+
exists(CtorAttr ctor, Function f, StdCall call |
45+
f.getAnAttr() = ctor and
46+
call.getEnclosingCallable() = f and
47+
pred = ctor and // source
48+
succ = call // sink
49+
)
50+
// or
51+
// transitive edge
52+
// TODO
53+
}
54+
55+
from CtorAttr ctor, StdCall call
56+
where edges*(ctor, call)
57+
select call, ctor, call, "Call to $@ in a function with the " + ctor.getWhichAttr() + " attribute.",
58+
call, call.toString()
Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
1-
| 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(...) |
2-
| 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(...) |
3-
| 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(...) |
4-
| 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(...) |
5-
| 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(...) |
6-
| 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(...) |
7-
| 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(...) |
8-
| 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(...) |
9-
| 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(...) |
10-
| 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(...) |
1+
#select
2+
| 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(...) |
3+
| 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(...) |
4+
| 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(...) |
5+
| 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(...) |
6+
| 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(...) |
7+
| 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(...) |
8+
| 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(...) |
9+
| 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(...) |
10+
| 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(...) |
11+
| 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(...) |
12+
edges
13+
| test.rs:29:1:29:13 | Attr | test.rs:31:9:31:25 | ...::stdout(...) |
14+
| test.rs:34:1:34:13 | Attr | test.rs:36:9:36:25 | ...::stdout(...) |
15+
| test.rs:40:1:40:13 | Attr | test.rs:43:9:43:25 | ...::stdout(...) |
16+
| test.rs:51:1:51:7 | Attr | test.rs:53:9:53:16 | stdout(...) |
17+
| test.rs:56:1:56:7 | Attr | test.rs:58:9:58:16 | stderr(...) |
18+
| test.rs:61:1:61:7 | Attr | test.rs:63:14:63:28 | ...::_print(...) |
19+
| test.rs:66:1:66:7 | Attr | test.rs:69:9:69:24 | ...::stdin(...) |
20+
| test.rs:88:1:88:7 | Attr | test.rs:90:5:90:35 | ...::sleep(...) |
21+
| test.rs:95:1:95:7 | Attr | test.rs:97:5:97:23 | ...::exit(...) |
22+
| test.rs:164:1:164:7 | Attr | test.rs:166:5:166:15 | ...::stdout(...) |

rust/ql/test/query-tests/security/CWE-696/test.rs

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,75 +26,75 @@ fn harmless1_5() {
2626
_ = std::io::stdout().write(b"Hello, world!");
2727
}
2828

29-
#[ctor::ctor]
30-
fn bad1_1() { // $ Alert[rust/ctor-initialization]
31-
_ = std::io::stdout().write(b"Hello, world!");
29+
#[ctor::ctor] // $ Source=source1_1
30+
fn bad1_1() {
31+
_ = std::io::stdout().write(b"Hello, world!"); // $ Alert[rust/ctor-initialization]=source1_1
3232
}
3333

34-
#[ctor::dtor]
35-
fn bad1_2() { // $ Alert[rust/ctor-initialization]
36-
_ = std::io::stdout().write(b"Hello, world!");
34+
#[ctor::dtor] // $ Source=source1_2
35+
fn bad1_2() {
36+
_ = std::io::stdout().write(b"Hello, world!"); // $ Alert[rust/ctor-initialization]=source1_2
3737
}
3838

3939
#[rustfmt::skip]
40-
#[ctor::dtor]
40+
#[ctor::dtor] // $ Source=source1_3
4141
#[rustfmt::skip]
42-
fn bad1_3() { // $ Alert[rust/ctor-initialization]
43-
_ = std::io::stdout().write(b"Hello, world!");
42+
fn bad1_3() {
43+
_ = std::io::stdout().write(b"Hello, world!"); // $ Alert[rust/ctor-initialization]=source1_3
4444
}
4545

4646
// --- code variants ---
4747

4848
use ctor::ctor;
4949
use std::io::*;
5050

51-
#[ctor]
52-
fn bad2_1() { // $ Alert[rust/ctor-initialization]
53-
_ = stdout().write(b"Hello, world!");
51+
#[ctor] // $ Source=source2_1
52+
fn bad2_1() {
53+
_ = stdout().write(b"Hello, world!"); // $ Alert[rust/ctor-initialization]=source2_1
5454
}
5555

56-
#[ctor]
57-
fn bad2_2() { // $ Alert[rust/ctor-initialization]
58-
_ = stderr().write_all(b"Hello, world!");
56+
#[ctor] // $ Source=source2_2
57+
fn bad2_2() {
58+
_ = stderr().write_all(b"Hello, world!"); // $ Alert[rust/ctor-initialization]=source2_2
5959
}
6060

61-
#[ctor]
62-
fn bad2_3() { // $ Alert[rust/ctor-initialization]
63-
println!("Hello, world!");
61+
#[ctor] // $ Source=source2_3
62+
fn bad2_3() {
63+
println!("Hello, world!"); // $ Alert[rust/ctor-initialization]=source2_3
6464
}
6565

66-
#[ctor]
67-
fn bad2_4() { // $ Alert[rust/ctor-initialization]
66+
#[ctor] // $ Source=source2_4
67+
fn bad2_4() {
6868
let mut buff = String::new();
69-
_ = std::io::stdin().read_line(&mut buff);
69+
_ = std::io::stdin().read_line(&mut buff); // $ Alert[rust/ctor-initialization]=source2_4
7070
}
7171

7272
use std::fs;
7373

74-
#[ctor]
75-
fn bad2_5() { // $ MISSING: Alert[rust/ctor-initialization]
76-
let _buff = fs::File::create("hello.txt").unwrap();
74+
#[ctor] // $ MISSING: Source=source2_5
75+
fn bad2_5() {
76+
let _buff = fs::File::create("hello.txt").unwrap(); // $ MISSING: Alert[rust/ctor-initialization]=source2_5
7777
}
7878

79-
#[ctor]
80-
fn bad2_6() { // $ MISSING: Alert[rust/ctor-initialization]
81-
let _t = std::time::Instant::now();
79+
#[ctor] // $ MISSING: Source=source2_6
80+
fn bad2_6() {
81+
let _t = std::time::Instant::now(); // $ MISSING: Alert[rust/ctor-initialization]=source2_6
8282
}
8383

8484
use std::time::Duration;
8585

8686
const DURATION2_7: Duration = Duration::new(1, 0);
8787

88-
#[ctor]
89-
fn bad2_7() { // $ Alert[rust/ctor-initialization]
90-
std::thread::sleep(DURATION2_7);
88+
#[ctor] // $ Source=source2_7
89+
fn bad2_7() {
90+
std::thread::sleep(DURATION2_7); // $ Alert[rust/ctor-initialization]=source2_7
9191
}
9292

9393
use std::process;
9494

95-
#[ctor]
96-
fn bad2_8() { // $ Alert[rust/ctor-initialization]
97-
process::exit(1234);
95+
#[ctor] // $ Source=source2_8
96+
fn bad2_8() {
97+
process::exit(1234); // $ Alert[rust/ctor-initialization]=source2_8
9898
}
9999

100100
#[ctor::ctor]
@@ -123,11 +123,11 @@ unsafe fn harmless2_11() {
123123
// --- transitive cases ---
124124

125125
fn call_target3_1() {
126-
_ = stderr().write_all(b"Hello, world!");
126+
_ = stderr().write_all(b"Hello, world!"); // $ MISSING: Alert=source3_1 Alert=source3_3 Alert=source3_4
127127
}
128128

129-
#[ctor]
130-
fn bad3_1() { // $ MISSING: Alert[rust/ctor-initialization]
129+
#[ctor] // $ MISSING: Source=source3_1
130+
fn bad3_1() {
131131
call_target3_1();
132132
}
133133

@@ -137,19 +137,19 @@ fn call_target3_2() {
137137
}
138138
}
139139

140-
#[ctor]
140+
#[ctor] // $ MISSING: Source=source3_2
141141
fn harmless3_2() {
142142
call_target3_2();
143143
}
144144

145145
#[ctor]
146-
fn bad3_3() { // $ MISSING: Alert[rust/ctor-initialization]
146+
fn bad3_3() {
147147
call_target3_1();
148148
call_target3_2();
149149
}
150150

151-
#[ctor]
152-
fn bad3_4() { // $ MISSING: Alert[rust/ctor-initialization]
151+
#[ctor] // $ MISSING: Source=source3_4
152+
fn bad3_4() {
153153
bad3_3();
154154
}
155155

@@ -161,7 +161,7 @@ macro_rules! macro4_1 {
161161
};
162162
}
163163

164-
#[ctor]
165-
fn bad4_1() { // $ Alert[rust/ctor-initialization]
166-
macro4_1!();
164+
#[ctor] // $ Source=source4_1
165+
fn bad4_1() {
166+
macro4_1!(); // $ Alert[rust/ctor-initialization]=source4_1
167167
}

0 commit comments

Comments
 (0)