Skip to content

Commit a633783

Browse files
authored
Merge pull request #9340 from geoffw0/nocheckbeforeunsafeputuser
C++: Improve cpp/linux-kernel-no-check-before-unsafe-put-user
2 parents e3ef258 + 2bcf7e1 commit a633783

File tree

3 files changed

+54
-17
lines changed

3 files changed

+54
-17
lines changed

cpp/ql/src/experimental/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser.ql

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,36 @@
1717
import cpp
1818
import semmle.code.cpp.dataflow.DataFlow
1919

20+
/**
21+
* A Linux system call.
22+
*/
23+
class SystemCallFunction extends Function {
24+
SystemCallFunction() {
25+
exists(MacroInvocation m |
26+
m.getMacro().getName().matches("SYSCALL\\_DEFINE%") and
27+
this = m.getEnclosingFunction()
28+
)
29+
}
30+
}
31+
32+
/**
33+
* A value that comes from a Linux system call (sources).
34+
*/
35+
class SystemCallSource extends DataFlow::Node {
36+
SystemCallSource() {
37+
exists(FunctionCall fc |
38+
fc.getTarget() instanceof SystemCallFunction and
39+
(
40+
this.asDefiningArgument() = fc.getAnArgument().getAChild*() or
41+
this.asExpr() = fc
42+
)
43+
)
44+
}
45+
}
46+
47+
/**
48+
* Macros used to check the value (barriers).
49+
*/
2050
class WriteAccessCheckMacro extends Macro {
2151
VariableAccess va;
2252

@@ -28,6 +58,9 @@ class WriteAccessCheckMacro extends Macro {
2858
VariableAccess getArgument() { result = va }
2959
}
3060

61+
/**
62+
* The `unsafe_put_user` macro and its uses (sinks).
63+
*/
3164
class UnSafePutUserMacro extends Macro {
3265
PointerDereferenceExpr writeUserPtr;
3366

@@ -42,15 +75,13 @@ class UnSafePutUserMacro extends Macro {
4275
}
4376
}
4477

45-
class ExploitableUserModePtrParam extends Parameter {
78+
class ExploitableUserModePtrParam extends SystemCallSource {
4679
ExploitableUserModePtrParam() {
47-
not exists(WriteAccessCheckMacro writeAccessCheck |
48-
DataFlow::localFlow(DataFlow::parameterNode(this),
49-
DataFlow::exprNode(writeAccessCheck.getArgument()))
50-
) and
5180
exists(UnSafePutUserMacro unsafePutUser |
52-
DataFlow::localFlow(DataFlow::parameterNode(this),
53-
DataFlow::exprNode(unsafePutUser.getUserModePtr()))
81+
DataFlow::localFlow(this, DataFlow::exprNode(unsafePutUser.getUserModePtr()))
82+
) and
83+
not exists(WriteAccessCheckMacro writeAccessCheck |
84+
DataFlow::localFlow(this, DataFlow::exprNode(writeAccessCheck.getArgument()))
5485
)
5586
}
5687
}
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
| test.cpp:14:16:14:16 | p | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:14:16:14:16 | p | p |
1+
| test.cpp:20:21:20:22 | ref arg & ... | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:20:21:20:22 | ref arg & ... | ref arg & ... |
2+
| test.cpp:41:21:41:22 | ref arg & ... | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:41:21:41:22 | ref arg & ... | ref arg & ... |
3+
| test.cpp:69:21:69:27 | ref arg & ... | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:69:21:69:27 | ref arg & ... | ref arg & ... |

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/test.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11

22
typedef unsigned long size_t;
33

4-
void SYSC_SOMESYSTEMCALL(void *param);
4+
#define SYSCALL_DEFINE(name, ...) \
5+
void do_sys_##name(); \
6+
void sys_##name(...) { do_sys_##name(); } \
7+
void do_sys_##name()
8+
SYSCALL_DEFINE(somesystemcall, void *param) {};
59

610
bool user_access_begin_impl(const void *where, size_t sz);
711
void user_access_end_impl();
@@ -13,14 +17,14 @@ void unsafe_put_user_impl(int what, const void *where, size_t sz);
1317

1418
void test1(int p)
1519
{
16-
SYSC_SOMESYSTEMCALL(&p);
20+
sys_somesystemcall(&p);
1721

1822
unsafe_put_user(123, &p); // BAD
1923
}
2024

2125
void test2(int p)
2226
{
23-
SYSC_SOMESYSTEMCALL(&p);
27+
sys_somesystemcall(&p);
2428

2529
if (user_access_begin(&p, sizeof(p)))
2630
{
@@ -34,16 +38,16 @@ void test3()
3438
{
3539
int v;
3640

37-
SYSC_SOMESYSTEMCALL(&v);
41+
sys_somesystemcall(&v);
3842

39-
unsafe_put_user(123, &v); // BAD [NOT DETECTED]
43+
unsafe_put_user(123, &v); // BAD
4044
}
4145

4246
void test4()
4347
{
4448
int v;
4549

46-
SYSC_SOMESYSTEMCALL(&v);
50+
sys_somesystemcall(&v);
4751

4852
if (user_access_begin(&v, sizeof(v)))
4953
{
@@ -62,16 +66,16 @@ void test5()
6266
{
6367
data myData;
6468

65-
SYSC_SOMESYSTEMCALL(&myData);
69+
sys_somesystemcall(&myData);
6670

67-
unsafe_put_user(123, &(myData.x)); // BAD [NOT DETECTED]
71+
unsafe_put_user(123, &(myData.x)); // BAD
6872
}
6973

7074
void test6()
7175
{
7276
data myData;
7377

74-
SYSC_SOMESYSTEMCALL(&myData);
78+
sys_somesystemcall(&myData);
7579

7680
if (user_access_begin(&myData, sizeof(myData)))
7781
{

0 commit comments

Comments
 (0)