Skip to content

Commit 66d284e

Browse files
authored
Merge pull request github#5766 from ihsinme/ihsinme-patch-267
CPP: Add query for CWE-415 Double Free
2 parents 263699d + d808a5b commit 66d284e

File tree

6 files changed

+184
-0
lines changed

6 files changed

+184
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
...
2+
buf = malloc(intSize);
3+
...
4+
free(buf);
5+
buf = NULL;
6+
if(buf) free(buf); // GOOD
7+
...
8+
9+
...
10+
buf = malloc(intSize);
11+
...
12+
free(buf);
13+
if(buf) free(buf); // BAD: the cleanup function does not zero out the pointer
14+
...
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>Freeing a previously allocated resource twice can lead to various vulnerabilities in the program.</p>
7+
8+
</overview>
9+
<recommendation>
10+
<p>We recommend that you exclude situations of possible double release. For example, use the assignment NULL to a freed variable.</p>
11+
12+
</recommendation>
13+
<example>
14+
<p>The following example demonstrates an erroneous and corrected use of freeing a pointer.</p>
15+
<sample src="DoubleFree.c" />
16+
17+
</example>
18+
<references>
19+
20+
<li>
21+
CERT C Coding Standard:
22+
<a href="https://wiki.sei.cmu.edu/confluence/display/c/MEM30-C.+Do+not+access+freed+memory">MEM30-C. Do not access freed memory</a>.
23+
</li>
24+
25+
</references>
26+
</qhelp>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* @name Errors When Double Free
3+
* @description Freeing a previously allocated resource twice can lead to various vulnerabilities in the program.
4+
* @kind problem
5+
* @id cpp/double-free
6+
* @problem.severity warning
7+
* @precision medium
8+
* @tags security
9+
* external/cwe/cwe-415
10+
*/
11+
12+
import cpp
13+
14+
from FunctionCall fc, FunctionCall fc2, LocalScopeVariable v
15+
where
16+
freeCall(fc, v.getAnAccess()) and
17+
freeCall(fc2, v.getAnAccess()) and
18+
fc != fc2 and
19+
fc.getASuccessor*() = fc2 and
20+
not exists(Expr exptmp |
21+
(exptmp = v.getAnAssignedValue() or exptmp.(AddressOfExpr).getOperand() = v.getAnAccess()) and
22+
exptmp = fc.getASuccessor*() and
23+
exptmp = fc2.getAPredecessor*()
24+
) and
25+
not exists(FunctionCall fctmp |
26+
not fctmp instanceof DeallocationExpr and
27+
fctmp = fc.getASuccessor*() and
28+
fctmp = fc2.getAPredecessor*() and
29+
fctmp.getAnArgument().(VariableAccess).getTarget() = v
30+
) and
31+
(
32+
fc.getTarget().hasGlobalOrStdName("realloc") and
33+
(
34+
not fc.getParent*() instanceof IfStmt and
35+
not exists(IfStmt iftmp |
36+
iftmp.getCondition().getAChild*().(VariableAccess).getTarget().getAnAssignedValue() = fc
37+
)
38+
)
39+
or
40+
not fc.getTarget().hasGlobalOrStdName("realloc")
41+
)
42+
select fc2.getArgument(0),
43+
"This pointer may have already been cleared in the line " + fc.getLocation().getStartLine() + "."
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| test.c:11:16:11:18 | buf | This pointer may have already been cleared in the line 10. |
2+
| test.c:18:8:18:10 | buf | This pointer may have already been cleared in the line 17. |
3+
| test.c:57:8:57:10 | buf | This pointer may have already been cleared in the line 55. |
4+
| test.c:78:8:78:10 | buf | This pointer may have already been cleared in the line 77. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-415/DoubleFree.ql
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
typedef unsigned long size_t;
2+
void *malloc(size_t size);
3+
void free(void *ptr);
4+
#define NULL 0
5+
6+
void workFunction_0(char *s) {
7+
int intSize = 10;
8+
char *buf;
9+
buf = (char *) malloc(intSize);
10+
free(buf); // GOOD
11+
if(buf) free(buf); // BAD
12+
}
13+
void workFunction_1(char *s) {
14+
int intSize = 10;
15+
char *buf;
16+
buf = (char *) malloc(intSize);
17+
free(buf); // GOOD
18+
free(buf); // BAD
19+
}
20+
void workFunction_2(char *s) {
21+
int intSize = 10;
22+
char *buf;
23+
buf = (char *) malloc(intSize);
24+
free(buf); // GOOD
25+
buf = NULL;
26+
free(buf); // GOOD
27+
}
28+
void workFunction_3(char *s) {
29+
int intSize = 10;
30+
char *buf;
31+
int intFlag;
32+
buf = (char *) malloc(intSize);
33+
if(buf[1]%5) {
34+
free(buf); // GOOD
35+
buf = NULL;
36+
}
37+
free(buf); // GOOD
38+
}
39+
void workFunction_4(char *s) {
40+
int intSize = 10;
41+
char *buf;
42+
char *tmpbuf;
43+
tmpbuf = (char *) malloc(intSize);
44+
buf = (char *) malloc(intSize);
45+
free(buf); // GOOD
46+
buf = tmpbuf;
47+
free(buf); // GOOD
48+
}
49+
void workFunction_5(char *s, int intFlag) {
50+
int intSize = 10;
51+
char *buf;
52+
53+
buf = (char *) malloc(intSize);
54+
if(intFlag) {
55+
free(buf); // GOOD
56+
}
57+
free(buf); // BAD
58+
}
59+
void workFunction_6(char *s, int intFlag) {
60+
int intSize = 10;
61+
char *buf;
62+
char *tmpbuf;
63+
64+
tmpbuf = (char *) malloc(intSize);
65+
buf = (char *) malloc(intSize);
66+
if(intFlag) {
67+
free(buf); // GOOD
68+
buf = tmpbuf;
69+
}
70+
free(buf); // GOOD
71+
}
72+
void workFunction_7(char *s) {
73+
int intSize = 10;
74+
char *buf;
75+
char *buf1;
76+
buf = (char *) malloc(intSize);
77+
buf1 = (char *) realloc(buf,intSize*4);
78+
free(buf); // BAD
79+
}
80+
void workFunction_8(char *s) {
81+
int intSize = 10;
82+
char *buf;
83+
char *buf1;
84+
buf = (char *) malloc(intSize);
85+
buf1 = (char *) realloc(buf,intSize*4);
86+
if(!buf1)
87+
free(buf); // GOOD
88+
}
89+
void workFunction_9(char *s) {
90+
int intSize = 10;
91+
char *buf;
92+
char *buf1;
93+
buf = (char *) malloc(intSize);
94+
if(!(buf1 = (char *) realloc(buf,intSize*4)))
95+
free(buf); // GOOD
96+
}

0 commit comments

Comments
 (0)