Skip to content

Commit 752ca94

Browse files
authored
Merge pull request #854 from geoffw0/taintedmalloc
CPP: Improve TaintedAllocationSize.ql
2 parents fcf04ab + 68a19d7 commit 752ca94

File tree

8 files changed

+94
-21
lines changed

8 files changed

+94
-21
lines changed

change-notes/1.21/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
| **Query** | **Expected impact** | **Change** |
1313
|----------------------------|------------------------|------------------------------------------------------------------|
1414
| Mismatching new/free or malloc/delete (`cpp/new-free-mismatch`) | Fewer false positive results | Fixed an issue where functions were being identified as allocation functions inappropriately. Also affects `cpp/new-array-delete-mismatch` and `cpp/new-delete-array-mismatch`. |
15+
| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | More correct results | This query has been reworked so that it can find a wider variety of results. |
1516
| Memory may not be freed (`cpp/memory-may-not-be-freed`) | More correct results | Support added for more Microsoft-specific allocation functions, including `LocalAlloc`, `GlobalAlloc`, `HeapAlloc` and `CoTaskMemAlloc`. |
1617
| Memory is never freed (`cpp/memory-never-freed`) | More correct results | Support added for more Microsoft-specific allocation functions, including `LocalAlloc`, `GlobalAlloc`, `HeapAlloc` and `CoTaskMemAlloc`. |
1718
| Resource not released in destructor (`cpp/resource-not-released-in-destructor`) | Fewer false positive results | Resource allocation and deallocation functions are now determined more accurately. |

cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,20 @@
1414
import cpp
1515
import semmle.code.cpp.security.TaintTracking
1616

17-
from Expr source, Expr tainted, BinaryArithmeticOperation oper,
18-
SizeofOperator sizeof, string taintCause
19-
where tainted(source, tainted)
20-
and oper.getAnOperand() = tainted
21-
and oper.getOperator() = "*"
22-
and oper.getAnOperand() = sizeof
23-
and oper != tainted
24-
and sizeof.getValue().toInt() > 1
25-
and isUserInput(source, taintCause)
26-
select
27-
oper, "This allocation size is derived from $@ and might overflow",
28-
source, "user input (" + taintCause + ")"
17+
predicate taintedAllocSize(Expr e, Expr source, string taintCause) {
18+
(
19+
isAllocationExpr(e) or
20+
any(MulExpr me | me.getAChild() instanceof SizeofOperator) = e
21+
) and
22+
exists(Expr tainted |
23+
tainted = e.getAChild() and
24+
tainted.getType().getUnspecifiedType() instanceof IntegralType and
25+
isUserInput(source, taintCause) and
26+
tainted(source, tainted)
27+
)
28+
}
29+
30+
from Expr e, Expr source, string taintCause
31+
where taintedAllocSize(e, source, taintCause)
32+
select e, "This allocation size is derived from $@ and might overflow", source,
33+
"user input (" + taintCause + ")"

cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,14 @@ predicate insideFunctionValueMoveTo(Element src, Element dest)
245245
and format.getConversionChar(arg - formattingSend.getTarget().getNumberOfParameters()) = argFormat
246246
and (argFormat = "s" or argFormat = "S" or argFormat = "@"))
247247
// Expressions computed from tainted data are also tainted
248-
or (exists (FunctionCall call | dest = call and isPureFunction(call.getTarget().getName()) |
249-
call.getAnArgument() = src
250-
and forall(Expr arg | arg = call.getAnArgument() | arg = src or predictable(arg))))
248+
or exists(FunctionCall call | dest = call and isPureFunction(call.getTarget().getName()) |
249+
call.getAnArgument() = src and
250+
forall(Expr arg | arg = call.getAnArgument() | arg = src or predictable(arg)) and
251+
252+
// flow through `strlen` tends to cause dubious results, if the length is
253+
// bounded.
254+
not call.getTarget().getName() = "strlen"
255+
)
251256
or exists(Element a, Element b |
252257
moveToDependingOnSide(a, b) and
253258
if insideValueSource(a) then
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| test.cpp:42:31:42:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
2+
| test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
3+
| test.cpp:48:25:48:30 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
4+
| test.cpp:49:17:49:30 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
5+
| test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
6+
| test.cpp:55:11:55:24 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-190/TaintedAllocationSize.ql
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Associated with CWE-190: Integer Overflow or Wraparound. http://cwe.mitre.org/data/definitions/190.html
2+
3+
typedef unsigned long size_t;
4+
typedef struct {} FILE;
5+
6+
void *malloc(size_t size);
7+
void *realloc(void *ptr, size_t size);
8+
int atoi(const char *nptr);
9+
10+
struct MyStruct
11+
{
12+
char data[256];
13+
};
14+
15+
namespace std
16+
{
17+
template<class charT> struct char_traits;
18+
19+
template <class charT, class traits = char_traits<charT> >
20+
class basic_istream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
21+
public:
22+
basic_istream<charT,traits>& operator>>(int& n);
23+
};
24+
25+
typedef basic_istream<char> istream;
26+
27+
extern istream cin;
28+
}
29+
30+
int getTainted() {
31+
int i;
32+
33+
std::cin >> i;
34+
35+
return i;
36+
}
37+
38+
int main(int argc, char **argv) {
39+
int tainted = atoi(argv[1]);
40+
41+
MyStruct *arr1 = (MyStruct *)malloc(sizeof(MyStruct)); // GOOD
42+
MyStruct *arr2 = (MyStruct *)malloc(tainted); // BAD
43+
MyStruct *arr3 = (MyStruct *)malloc(tainted * sizeof(MyStruct)); // BAD
44+
MyStruct *arr4 = (MyStruct *)malloc(getTainted() * sizeof(MyStruct)); // BAD [NOT DETECTED]
45+
MyStruct *arr5 = (MyStruct *)malloc(sizeof(MyStruct) + tainted); // BAD [NOT DETECTED]
46+
47+
int size = tainted * 8;
48+
char *chars1 = (char *)malloc(size); // BAD
49+
char *chars2 = new char[size]; // BAD
50+
char *chars3 = new char[8]; // GOOD
51+
52+
arr1 = (MyStruct *)realloc(arr1, sizeof(MyStruct) * tainted); // BAD
53+
54+
size = 8;
55+
chars3 = new char[size]; // GOOD [FALSE POSITIVE]
56+
57+
return 0;
58+
}

cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,3 @@
88
| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
99
| test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
1010
| test.c:54:7:54:10 | len3 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value |
11-
| test.c:74:7:74:10 | len5 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:71:19:71:22 | argv | User-provided value |
12-
| test.c:84:7:84:10 | len6 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:19:81:22 | argv | User-provided value |
13-
| test.c:94:7:94:10 | len7 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:91:19:91:22 | argv | User-provided value |

cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/test.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ int main(int argc, char** argv) {
7171
len5 = strlen(argv[1]);
7272
while (len5)
7373
{
74-
len5--; // GOOD: can't underflow [FALSE POSITIVE]
74+
len5--; // GOOD: can't underflow
7575
}
7676
}
7777

@@ -81,7 +81,7 @@ int main(int argc, char** argv) {
8181
len6 = strlen(argv[1]);
8282
while (len6 != 0)
8383
{
84-
len6--; // GOOD: can't underflow [FALSE POSITIVE]
84+
len6--; // GOOD: can't underflow
8585
}
8686
}
8787

@@ -91,7 +91,7 @@ int main(int argc, char** argv) {
9191
len7 = strlen(argv[1]);
9292
while ((len7) && (1))
9393
{
94-
len7--; // GOOD: can't underflow [FALSE POSITIVE]
94+
len7--; // GOOD: can't underflow
9595
}
9696
}
9797

0 commit comments

Comments
 (0)