Skip to content

Commit c34b704

Browse files
committed
file-access-before-action-cpp
1 parent f4ca709 commit c34b704

File tree

4 files changed

+389
-1
lines changed

4 files changed

+389
-1
lines changed
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
id: file-access-before-action-cpp
2+
language: cpp
3+
severity: warning
4+
message: >-
5+
A check is done with `access` and then the file is later used. There is no guarantee that the status of the file has not changed since the call to `access` which may allow attackers to bypass permission checks.
6+
note: >-
7+
[CWE-367]: Time-of-check Time-of-use (TOCTOU) Race Condition
8+
[REFERENCES]
9+
- https://wiki.sei.cmu.edu/confluence/display/c/FIO45-C.+Avoid+TOCTOU+race+conditions+while+accessing+files
10+
11+
utils:
12+
PATTERN_1(identifier):
13+
kind: identifier
14+
regex: ^(fopen|freopen|remove|rename|access|open|stat|lstat|unlink|mkdir|rmdir|chdir)$
15+
all:
16+
- precedes:
17+
kind: argument_list
18+
has:
19+
pattern: $SRC
20+
- inside:
21+
kind: call_expression
22+
not:
23+
inside:
24+
stopBy: end
25+
kind: condition_clause
26+
inside:
27+
stopBy: end
28+
kind: compound_statement
29+
inside:
30+
kind: if_statement
31+
has:
32+
kind: condition_clause
33+
has:
34+
stopBy: end
35+
any:
36+
- kind: binary_expression
37+
has:
38+
stopBy: end
39+
kind: parenthesized_expression
40+
has:
41+
kind: binary_expression
42+
all:
43+
- has:
44+
kind: call_expression
45+
nthChild: 1
46+
all:
47+
- has:
48+
kind: identifier
49+
regex: ^(access|faccessat|faccessat2)$
50+
precedes:
51+
kind: argument_list
52+
all:
53+
- has:
54+
nthChild: 1
55+
pattern: $SRC
56+
- has:
57+
kind: identifier
58+
nthChild: 2
59+
regex: ^(F_OK|R_OK|W_OK|X_OK)$
60+
- has:
61+
kind: number_literal
62+
regex: ^(0)$
63+
follows:
64+
regex: ^==$
65+
- kind: binary_expression
66+
all:
67+
- has:
68+
nthChild: 1
69+
kind: call_expression
70+
all:
71+
- has:
72+
nthChild: 1
73+
kind: identifier
74+
regex: ^(access|faccessat|faccessat2)$
75+
- has:
76+
nthChild: 2
77+
kind: argument_list
78+
all:
79+
- has:
80+
nthChild: 1
81+
pattern: $SRC
82+
- has:
83+
nthChild: 2
84+
kind: identifier
85+
regex: ^(F_OK|R_OK|W_OK|X_OK)$
86+
- has:
87+
nthChild: 2
88+
kind: number_literal
89+
regex: ^(0)$
90+
follows:
91+
regex: ^==$
92+
93+
PATTERN_2(qualified_identifier):
94+
kind: qualified_identifier
95+
any:
96+
- regex: ^(folly::readFile|folly::writeFile|folly::writeFileAtomic|folly::writeFileAtomicNoThrow|folly::File)$
97+
- regex: ^(boost::)?(filesystem::file_size|filesystem::create_directory|filesystem::create_directories|filesystem::remove|filesystem::remove_all|filesystem::rename|filesystem::copy_file|filesystem::copy|filesystem::copy_directory|filesystem::resize_file|filesystem::last_write_time|filesystem::permissions|filesystem::symlink_status|filesystem::create_symlink|filesystem::create_hard_link|filesystem::read_symlink)$
98+
all:
99+
- precedes:
100+
kind: argument_list
101+
has:
102+
pattern: $SRC
103+
- inside:
104+
kind: call_expression
105+
not:
106+
inside:
107+
stopBy: end
108+
kind: condition_clause
109+
inside:
110+
stopBy: end
111+
kind: compound_statement
112+
inside:
113+
kind: if_statement
114+
has:
115+
kind: condition_clause
116+
has:
117+
stopBy: end
118+
any:
119+
- kind: binary_expression
120+
has:
121+
stopBy: end
122+
kind: parenthesized_expression
123+
has:
124+
kind: binary_expression
125+
all:
126+
- has:
127+
kind: call_expression
128+
nthChild: 1
129+
all:
130+
- has:
131+
kind: identifier
132+
regex: ^(access|faccessat|faccessat2)$
133+
precedes:
134+
kind: argument_list
135+
all:
136+
- has:
137+
nthChild: 1
138+
pattern: $SRC
139+
- has:
140+
kind: identifier
141+
nthChild: 2
142+
regex: ^(F_OK|R_OK|W_OK|X_OK)$
143+
- has:
144+
kind: number_literal
145+
regex: ^(0)$
146+
follows:
147+
regex: ^==$
148+
- kind: binary_expression
149+
all:
150+
- has:
151+
nthChild: 1
152+
kind: call_expression
153+
all:
154+
- has:
155+
nthChild: 1
156+
kind: identifier
157+
regex: ^(access|faccessat|faccessat2)$
158+
- has:
159+
nthChild: 2
160+
kind: argument_list
161+
all:
162+
- has:
163+
nthChild: 1
164+
pattern: $SRC
165+
- has:
166+
nthChild: 2
167+
kind: identifier
168+
regex: ^(F_OK|R_OK|W_OK|X_OK)$
169+
- has:
170+
nthChild: 2
171+
kind: number_literal
172+
regex: ^(0)$
173+
follows:
174+
regex: ^==$
175+
176+
identifier_and_qualified_identifier:
177+
any:
178+
- kind: identifier
179+
regex: ^(fopen|freopen|remove|rename|access|open|stat|lstat|unlink|mkdir|rmdir|chdir)$
180+
- kind: qualified_identifier
181+
any:
182+
- regex: ^(folly::readFile|folly::writeFile|folly::writeFileAtomic|folly::writeFileAtomicNoThrow|folly::File)$
183+
- regex: ^(boost::)?(filesystem::file_size|filesystem::create_directory|filesystem::create_directories|filesystem::remove|filesystem::remove_all|filesystem::rename|filesystem::copy_file|filesystem::copy|filesystem::copy_directory|filesystem::resize_file|filesystem::last_write_time|filesystem::permissions|filesystem::symlink_status|filesystem::create_symlink|filesystem::create_hard_link|filesystem::read_symlink)$
184+
185+
PATTERN_3(field_expression):
186+
kind: field_expression
187+
has:
188+
nthChild: 1
189+
stopBy: end
190+
matches: identifier_and_qualified_identifier
191+
all:
192+
- precedes:
193+
kind: argument_list
194+
has:
195+
pattern: $SRC
196+
- inside:
197+
kind: call_expression
198+
not:
199+
inside:
200+
stopBy: end
201+
kind: condition_clause
202+
inside:
203+
stopBy: end
204+
kind: compound_statement
205+
inside:
206+
kind: if_statement
207+
has:
208+
kind: condition_clause
209+
has:
210+
stopBy: end
211+
any:
212+
- kind: binary_expression
213+
has:
214+
stopBy: end
215+
kind: parenthesized_expression
216+
has:
217+
kind: binary_expression
218+
all:
219+
- has:
220+
kind: call_expression
221+
nthChild: 1
222+
all:
223+
- has:
224+
kind: identifier
225+
regex: ^(access|faccessat|faccessat2)$
226+
precedes:
227+
kind: argument_list
228+
all:
229+
- has:
230+
nthChild: 1
231+
pattern: $SRC
232+
- has:
233+
kind: identifier
234+
nthChild: 2
235+
regex: ^(F_OK|R_OK|W_OK|X_OK)$
236+
- has:
237+
kind: number_literal
238+
regex: ^(0)$
239+
follows:
240+
regex: ^==$
241+
- kind: binary_expression
242+
all:
243+
- has:
244+
nthChild: 1
245+
kind: call_expression
246+
all:
247+
- has:
248+
nthChild: 1
249+
kind: identifier
250+
regex: ^(access|faccessat|faccessat2)$
251+
- has:
252+
nthChild: 2
253+
kind: argument_list
254+
all:
255+
- has:
256+
nthChild: 1
257+
pattern: $SRC
258+
- has:
259+
nthChild: 2
260+
kind: identifier
261+
regex: ^(F_OK|R_OK|W_OK|X_OK)$
262+
- has:
263+
nthChild: 2
264+
kind: number_literal
265+
regex: ^(0)$
266+
follows:
267+
regex: ^==$
268+
269+
rule:
270+
any:
271+
- matches: PATTERN_1(identifier)
272+
- matches: PATTERN_2(qualified_identifier)
273+
- matches: PATTERN_3(field_expression)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
id: file-access-before-action-cpp
2+
snapshots:
3+
? |
4+
{
5+
const char *original_key = "path/to/file/filename";
6+
const char *mirror_key = "path/to/another/file/filename";
7+
8+
if ((access(original_key, F_OK) == 0) && (access(mirror_key, F_OK) == 0)){
9+
copy_file("/bin/cp %s %s", original_key, mirror_key);
10+
unlink(original_key);
11+
}
12+
13+
void test_002(){
14+
const char *original_key = "path/to/file/filename";
15+
if (access(original_key, W_OK) == 0){
16+
FILe *fp = fopen(original_key, "wb");
17+
}
18+
}
19+
: labels:
20+
- source: unlink
21+
style: primary
22+
start: 250
23+
end: 256
24+
- source: original_key
25+
style: secondary
26+
start: 257
27+
end: 269
28+
- source: (original_key)
29+
style: secondary
30+
start: 256
31+
end: 270
32+
- source: original_key
33+
style: secondary
34+
start: 125
35+
end: 137
36+
- source: F_OK
37+
style: secondary
38+
start: 139
39+
end: 143
40+
- source: (original_key, F_OK)
41+
style: secondary
42+
start: 124
43+
end: 144
44+
- source: access
45+
style: secondary
46+
start: 118
47+
end: 124
48+
- source: access(original_key, F_OK)
49+
style: secondary
50+
start: 118
51+
end: 144
52+
- source: ==
53+
style: secondary
54+
start: 145
55+
end: 147
56+
- source: '0'
57+
style: secondary
58+
start: 148
59+
end: 149
60+
- source: access(original_key, F_OK) == 0
61+
style: secondary
62+
start: 118
63+
end: 149
64+
- source: (access(original_key, F_OK) == 0)
65+
style: secondary
66+
start: 117
67+
end: 150
68+
- source: (access(original_key, F_OK) == 0) && (access(mirror_key, F_OK) == 0)
69+
style: secondary
70+
start: 117
71+
end: 185
72+
- source: ((access(original_key, F_OK) == 0) && (access(mirror_key, F_OK) == 0))
73+
style: secondary
74+
start: 116
75+
end: 186
76+
- source: |-
77+
if ((access(original_key, F_OK) == 0) && (access(mirror_key, F_OK) == 0)){
78+
copy_file("/bin/cp %s %s", original_key, mirror_key);
79+
unlink(original_key);
80+
}
81+
style: secondary
82+
start: 113
83+
end: 273
84+
- source: |-
85+
{
86+
copy_file("/bin/cp %s %s", original_key, mirror_key);
87+
unlink(original_key);
88+
}
89+
style: secondary
90+
start: 186
91+
end: 273
92+
- source: unlink(original_key)
93+
style: secondary
94+
start: 250
95+
end: 270

tests/c/file-access-before-action-c-test.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ invalid:
1717
const char *original_key = "path/to/file/filename";
1818
1919
if (access(original_key, W_OK) == 0){
20-
// ruleid: file-access-before-action
2120
File *fp = fopen(original_key, "wb");
2221
}
2322
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
id: file-access-before-action-cpp
2+
valid:
3+
- |
4+
5+
invalid:
6+
- |
7+
{
8+
const char *original_key = "path/to/file/filename";
9+
const char *mirror_key = "path/to/another/file/filename";
10+
11+
if ((access(original_key, F_OK) == 0) && (access(mirror_key, F_OK) == 0)){
12+
copy_file("/bin/cp %s %s", original_key, mirror_key);
13+
unlink(original_key);
14+
}
15+
16+
void test_002(){
17+
const char *original_key = "path/to/file/filename";
18+
if (access(original_key, W_OK) == 0){
19+
FILe *fp = fopen(original_key, "wb");
20+
}
21+
}

0 commit comments

Comments
 (0)