Skip to content

Commit ff1c971

Browse files
committed
Add query for missing mode argument in open/openat calls
1 parent dbac927 commit ff1c971

File tree

7 files changed

+90
-4
lines changed

7 files changed

+90
-4
lines changed

cpp/ql/src/Security/CWE/CWE-732/FilePermissions.qll

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,22 @@ abstract class FileCreationExpr extends FunctionCall {
8383
abstract int getMode();
8484
}
8585

86-
class OpenCreationExpr extends FileCreationExpr {
86+
abstract class FileCreationWithOptionalModeExpr extends FileCreationExpr {
87+
abstract predicate hasModeArgument();
88+
}
89+
90+
class OpenCreationExpr extends FileCreationWithOptionalModeExpr {
8791
OpenCreationExpr() {
8892
this.getTarget().getName() = ["open", "_open", "_wopen"] and
8993
sets(this.getArgument(1).getValue().toInt(), o_creat())
9094
}
9195

9296
override Expr getPath() { result = this.getArgument(0) }
9397

98+
override predicate hasModeArgument() { exists(this.getArgument(2)) }
99+
94100
override int getMode() {
95-
if exists(this.getArgument(2))
101+
if hasModeArgument()
96102
then result = this.getArgument(2).getValue().toInt()
97103
else
98104
// assume anything is permitted
@@ -108,16 +114,18 @@ class CreatCreationExpr extends FileCreationExpr {
108114
override int getMode() { result = this.getArgument(1).getValue().toInt() }
109115
}
110116

111-
class OpenatCreationExpr extends FileCreationExpr {
117+
class OpenatCreationExpr extends FileCreationWithOptionalModeExpr {
112118
OpenatCreationExpr() {
113119
this.getTarget().getName() = "openat" and
114120
sets(this.getArgument(2).getValue().toInt(), o_creat())
115121
}
116122

117123
override Expr getPath() { result = this.getArgument(1) }
118124

125+
override predicate hasModeArgument() { exists(this.getArgument(3)) }
126+
119127
override int getMode() {
120-
if exists(this.getArgument(3))
128+
if hasModeArgument()
121129
then result = this.getArgument(3).getValue().toInt()
122130
else
123131
// assume anything is permitted
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
int open_file_bad() {
2+
// BAD - this uses arbitrary bytes from the stack as mode argument
3+
return open(FILE, O_CREAT)
4+
}
5+
6+
int open_file_good() {
7+
// GOOD - the mode argument is supplied
8+
return open(FILE, O_CREAT, S_IRUSR | S_IWUSR)
9+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>
8+
When opening a file with the <code>O_CREAT</code> flag, the <code>mode</code> must be supplied. If the
9+
<code>mode</code> argument is omitted, some arbitrary bytes from the stack will be used as the file mode.
10+
This leaks some bits from the stack into the permissions of the file.
11+
</p>
12+
</overview>
13+
14+
<recommendation>
15+
<p>
16+
The <code>mode</code> must be supplied when <code>O_CREAT</code> is specified.
17+
</p>
18+
</recommendation>
19+
20+
<example>
21+
<p>
22+
The first example opens a file with the <code>O_CREAT</code> flag without supplying the <code>mode</code>
23+
argument. In this case arbitrary bytes from the stack will be used as <code>mode</code> argument. The
24+
second example correctly supplies the <code>mode</code> argument and creates a file that is user readable
25+
and writable.
26+
</p>
27+
28+
<sample src="OpenCallMissingModeArgument.c" />
29+
30+
</example>
31+
</qhelp>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @name File opened with O_CREAT flag but without mode argument
3+
* @description Opening a file with the O_CREAT flag but without mode argument reads arbitrary bytes from the stack.
4+
* @kind problem
5+
* @problem.severity warning
6+
* @security-severity 7.8
7+
* @precision medium
8+
* @id cpp/open-call-with-mode-argument
9+
* @tags security
10+
* external/cwe/cwe-732
11+
*/
12+
13+
import cpp
14+
import FilePermissions
15+
16+
from FileCreationWithOptionalModeExpr fc
17+
where not fc.hasModeArgument()
18+
select fc,
19+
"A file is created here without providing a mode argument, which may leak bits from the stack"
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
typedef unsigned int mode_t;
2+
3+
#define O_CREAT 0100
4+
5+
int open(const char *pathname, int flags, ...);
6+
7+
int openat(int dirfd, const char *pathname, int flags, ...);
8+
9+
const char *a_file = "/a_file";
10+
11+
void test_open() {
12+
open(a_file, O_CREAT);
13+
open(a_file, O_CREAT, 0);
14+
openat(0, a_file, O_CREAT);
15+
openat(0, a_file, O_CREAT, 0);
16+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| OpenCallMissingModeArgument.c:12:3:12:6 | call to open | A file is created here without providing a mode argument, which may leak bits from the stack |
2+
| OpenCallMissingModeArgument.c:14:3:14:8 | call to openat | A file is created here without providing a mode argument, which may leak bits from the stack |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-732/OpenCallMissingModeArgument.ql

0 commit comments

Comments
 (0)