Skip to content

Commit 1d0cb04

Browse files
author
Dave Bartolomeo
committed
Merge from main
2 parents b9da6ce + ef0ea24 commit 1d0cb04

File tree

82 files changed

+2258
-1164
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+2258
-1164
lines changed

.github/workflows/close-stale.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ jobs:
1515
- uses: actions/stale@v3
1616
with:
1717
repo-token: ${{ secrets.GITHUB_TOKEN }}
18-
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `stale` label in order to avoid having this issue closed in 7 days.'
18+
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'
1919
close-issue-message: 'This issue was closed because it has been inactive for 7 days.'
2020
days-before-stale: 14
2121
days-before-close: 7
22-
only-labels: question
23-
22+
only-labels: awaiting-response
23+
2424
# do not mark PRs as stale
2525
days-before-pr-stale: -1
2626
days-before-pr-close: -1
27-
27+
2828
# Uncomment for dry-run
2929
# debug-only: true
3030
# operations-per-run: 1000

cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import cpp
1515
import semmle.code.cpp.dataflow.EscapesTree
16+
import semmle.code.cpp.models.interfaces.PointerWrapper
1617
import semmle.code.cpp.dataflow.DataFlow
1718

1819
/**
@@ -39,6 +40,10 @@ predicate hasNontrivialConversion(Expr e) {
3940
e instanceof ParenthesisExpr
4041
)
4142
or
43+
// A smart pointer can be stack-allocated while the data it points to is heap-allocated.
44+
// So we exclude such "conversions" from this predicate.
45+
e = any(PointerWrapper wrapper).getAnUnwrapperFunction().getACallToThisFunction()
46+
or
4247
hasNontrivialConversion(e.getConversion())
4348
}
4449

cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.ql

Lines changed: 22 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,54 +11,32 @@
1111
*/
1212

1313
import cpp
14+
import semmle.code.cpp.models.implementations.Strcat
1415
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
1516

1617
/**
17-
* A call to `strncat` of the form `strncat(buff, str, someExpr - strlen(buf))`, for some expression `someExpr` equal to `sizeof(buff)`.
18+
* Holds if `call` is a call to `strncat` such that `sizeArg` and `destArg` are the size and
19+
* destination arguments, respectively.
1820
*/
19-
class WrongCallStrncat extends FunctionCall {
20-
Expr leftsomeExpr;
21-
22-
WrongCallStrncat() {
23-
this.getTarget().hasGlobalOrStdName("strncat") and
24-
// the expression of the first argument in `strncat` and `strnlen` is identical
25-
globalValueNumber(this.getArgument(0)) =
26-
globalValueNumber(this.getArgument(2).(SubExpr).getRightOperand().(StrlenCall).getStringExpr()) and
27-
// using a string constant often speaks of manually calculating the length of the required buffer.
28-
(
29-
not this.getArgument(1) instanceof StringLiteral and
30-
not this.getArgument(1) instanceof CharLiteral
31-
) and
32-
// for use in predicates
33-
leftsomeExpr = this.getArgument(2).(SubExpr).getLeftOperand()
34-
}
35-
36-
/**
37-
* Holds if the left side of the expression `someExpr` equal to `sizeof(buf)`.
38-
*/
39-
predicate isExpressionEqualSizeof() {
40-
// the left side of the expression `someExpr` is `sizeof(buf)`.
41-
globalValueNumber(this.getArgument(0)) =
42-
globalValueNumber(leftsomeExpr.(SizeofExprOperator).getExprOperand())
43-
or
44-
// value of the left side of the expression `someExpr` equal `sizeof(buf)` value, and `buf` is array.
45-
leftsomeExpr.getValue().toInt() = this.getArgument(0).getType().getSize()
46-
}
47-
48-
/**
49-
* Holds if the left side of the expression `someExpr` equal to variable containing the length of the memory allocated for the buffer.
50-
*/
51-
predicate isVariableEqualValueSizegBuffer() {
52-
// the left side of expression `someExpr` is the variable that was used in the function of allocating memory for the buffer`.
53-
exists(AllocationExpr alc |
54-
leftsomeExpr.(VariableAccess).getTarget() =
55-
alc.(FunctionCall).getArgument(0).(VariableAccess).getTarget()
56-
)
57-
}
21+
predicate interestringCallWithArgs(Call call, Expr sizeArg, Expr destArg) {
22+
exists(StrcatFunction strcat |
23+
strcat = call.getTarget() and
24+
sizeArg = call.getArgument(strcat.getParamSize()) and
25+
destArg = call.getArgument(strcat.getParamDest())
26+
)
5827
}
5928

60-
from WrongCallStrncat sc
29+
from FunctionCall call, Expr sizeArg, Expr destArg, SubExpr sub, int n
6130
where
62-
sc.isExpressionEqualSizeof() or
63-
sc.isVariableEqualValueSizegBuffer()
64-
select sc, "if the used buffer is full, writing out of the buffer is possible"
31+
interestringCallWithArgs(call, sizeArg, destArg) and
32+
// The destination buffer is an array of size n
33+
destArg.getUnspecifiedType().(ArrayType).getSize() = n and
34+
// The size argument is equivalent to a subtraction
35+
globalValueNumber(sizeArg).getAnExpr() = sub and
36+
// ... where the left side of the subtraction is the constant n
37+
globalValueNumber(sub.getLeftOperand()).getAnExpr().getValue().toInt() = n and
38+
// ... and the right side of the subtraction is a call to `strlen` where the argument is the
39+
// destination buffer.
40+
globalValueNumber(sub.getRightOperand()).getAnExpr().(StrlenCall).getStringExpr() =
41+
globalValueNumber(destArg).getAnExpr()
42+
select call, "Possible out-of-bounds write due to incorrect size argument."
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
| test.c:42:3:42:24 | ... = ... | potential unsafe or redundant assignment. |
2-
| test.c:43:3:43:40 | ... = ... | potential unsafe or redundant assignment. |
3-
| test.c:44:3:44:40 | ... = ... | potential unsafe or redundant assignment. |
4-
| test.c:45:3:45:44 | ... = ... | potential unsafe or redundant assignment. |
5-
| test.c:46:3:46:44 | ... = ... | potential unsafe or redundant assignment. |
6-
| test.c:47:3:47:48 | ... = ... | potential unsafe or redundant assignment. |
7-
| test.c:48:3:48:48 | ... = ... | potential unsafe or redundant assignment. |
8-
| test.c:49:3:49:50 | ... = ... | potential unsafe or redundant assignment. |
9-
| test.c:50:3:50:50 | ... = ... | potential unsafe or redundant assignment. |
1+
| test.c:54:3:54:24 | ... = ... | potential unsafe or redundant assignment. |
2+
| test.c:55:3:55:40 | ... = ... | potential unsafe or redundant assignment. |
3+
| test.c:56:3:56:44 | ... = ... | potential unsafe or redundant assignment. |
4+
| test.c:57:3:57:44 | ... = ... | potential unsafe or redundant assignment. |
5+
| test.c:58:3:58:48 | ... = ... | potential unsafe or redundant assignment. |
6+
| test.c:59:3:59:48 | ... = ... | potential unsafe or redundant assignment. |
7+
| test.c:60:3:60:52 | ... = ... | potential unsafe or redundant assignment. |
8+
| test.c:61:3:61:50 | ... = ... | potential unsafe or redundant assignment. |
9+
| test.c:62:3:62:54 | ... = ... | potential unsafe or redundant assignment. |
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
| test.c:4:3:4:9 | call to strncat | if the used buffer is full, writing out of the buffer is possible |
2-
| test.c:11:3:11:9 | call to strncat | if the used buffer is full, writing out of the buffer is possible |
3-
| test.c:19:3:19:9 | call to strncat | if the used buffer is full, writing out of the buffer is possible |
1+
| test.c:8:3:8:9 | call to strncat | Possible out-of-bounds write due to incorrect size argument. |
2+
| test.c:9:3:9:9 | call to strncat | Possible out-of-bounds write due to incorrect size argument. |
3+
| test.c:17:3:17:9 | call to strncat | Possible out-of-bounds write due to incorrect size argument. |
4+
| test.c:18:3:18:9 | call to strncat | Possible out-of-bounds write due to incorrect size argument. |
5+
| test.c:46:3:46:9 | call to strncat | Possible out-of-bounds write due to incorrect size argument. |

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,84 @@
1-
void workFunction_0(char *s) {
1+
char * strncat(char*, const char*, unsigned);
2+
unsigned strlen(const char*);
3+
void* malloc(unsigned);
4+
5+
void strncat_test1(char *s) {
26
char buf[80];
3-
strncat(buf, s, sizeof(buf)-strlen(buf)-1); // GOOD
4-
strncat(buf, s, sizeof(buf)-strlen(buf)); // BAD
5-
strncat(buf, "fix", sizeof(buf)-strlen(buf)); // BAD [NOT DETECTED]
7+
strncat(buf, s, sizeof(buf) - strlen(buf) - 1); // GOOD
8+
strncat(buf, s, sizeof(buf) - strlen(buf)); // BAD
9+
strncat(buf, "fix", sizeof(buf)-strlen(buf)); // BAD
610
}
7-
void workFunction_1(char *s) {
11+
812
#define MAX_SIZE 80
13+
14+
void strncat_test2(char *s) {
915
char buf[MAX_SIZE];
10-
strncat(buf, s, MAX_SIZE-strlen(buf)-1); // GOOD
11-
strncat(buf, s, MAX_SIZE-strlen(buf)); // BAD
12-
strncat(buf, "fix", MAX_SIZE-strlen(buf)); // BAD [NOT DETECTED]
16+
strncat(buf, s, MAX_SIZE - strlen(buf) - 1); // GOOD
17+
strncat(buf, s, MAX_SIZE - strlen(buf)); // BAD
18+
strncat(buf, "fix", MAX_SIZE - strlen(buf)); // BAD
1319
}
14-
void workFunction_2_0(char *s) {
15-
char * buf;
16-
int len=80;
17-
buf = (char *) malloc(len);
18-
strncat(buf, s, len-strlen(buf)-1); // GOOD
19-
strncat(buf, s, len-strlen(buf)); // BAD
20-
strncat(buf, "fix", len-strlen(buf)); // BAD [NOT DETECTED]
20+
21+
void strncat_test3(char *s) {
22+
int len = 80;
23+
char* buf = (char *) malloc(len);
24+
strncat(buf, s, len - strlen(buf) - 1); // GOOD
25+
strncat(buf, s, len - strlen(buf)); // BAD [NOT DETECTED]
26+
strncat(buf, "fix", len - strlen(buf)); // BAD [NOT DETECTED]
2127
}
22-
void workFunction_2_1(char *s) {
23-
char * buf;
24-
int len=80;
25-
buf = (char *) malloc(len+1);
26-
strncat(buf, s, len-strlen(buf)-1); // GOOD
27-
strncat(buf, s, len-strlen(buf)); // GOOD
28+
29+
void strncat_test4(char *s) {
30+
int len = 80;
31+
char* buf = (char *) malloc(len + 1);
32+
strncat(buf, s, len - strlen(buf) - 1); // GOOD
33+
strncat(buf, s, len - strlen(buf)); // GOOD
2834
}
2935

3036
struct buffers
3137
{
32-
unsigned char buff1[50];
33-
unsigned char *buff2;
38+
unsigned char array[50];
39+
unsigned char *pointer;
3440
} globalBuff1,*globalBuff2,globalBuff1_c,*globalBuff2_c;
3541

42+
void strncat_test5(char* s, struct buffers* buffers) {
43+
unsigned len_array = strlen(buffers->array);
44+
unsigned max_size = sizeof(buffers->array);
45+
unsigned free_size = max_size - len_array;
46+
strncat(buffers->array, s, free_size); // BAD
47+
}
3648

37-
void badFunc0(){
49+
void strlen_test1(){
3850
unsigned char buff1[12];
3951
struct buffers buffAll;
4052
struct buffers * buffAll1;
4153

4254
buff1[strlen(buff1)]=0; // BAD
43-
buffAll.buff1[strlen(buffAll.buff1)]=0; // BAD
44-
buffAll.buff2[strlen(buffAll.buff2)]=0; // BAD
45-
buffAll1->buff1[strlen(buffAll1->buff1)]=0; // BAD
46-
buffAll1->buff2[strlen(buffAll1->buff2)]=0; // BAD
47-
globalBuff1.buff1[strlen(globalBuff1.buff1)]=0; // BAD
48-
globalBuff1.buff2[strlen(globalBuff1.buff2)]=0; // BAD
49-
globalBuff2->buff1[strlen(globalBuff2->buff1)]=0; // BAD
50-
globalBuff2->buff2[strlen(globalBuff2->buff2)]=0; // BAD
55+
buffAll.array[strlen(buffAll.array)]=0; // BAD
56+
buffAll.pointer[strlen(buffAll.pointer)]=0; // BAD
57+
buffAll1->array[strlen(buffAll1->array)]=0; // BAD
58+
buffAll1->pointer[strlen(buffAll1->pointer)]=0; // BAD
59+
globalBuff1.array[strlen(globalBuff1.array)]=0; // BAD
60+
globalBuff1.pointer[strlen(globalBuff1.pointer)]=0; // BAD
61+
globalBuff2->array[strlen(globalBuff2->array)]=0; // BAD
62+
globalBuff2->pointer[strlen(globalBuff2->pointer)]=0; // BAD
5163
}
52-
void noBadFunc0(){
64+
65+
void strlen_test2(){
5366
unsigned char buff1[12],buff1_c[12];
5467
struct buffers buffAll,buffAll_c;
5568
struct buffers * buffAll1,*buffAll1_c;
5669

5770
buff1[strlen(buff1_c)]=0; // GOOD
58-
buffAll.buff1[strlen(buffAll_c.buff1)]=0; // GOOD
59-
buffAll.buff2[strlen(buffAll.buff1)]=0; // GOOD
60-
buffAll1->buff1[strlen(buffAll1_c->buff1)]=0; // GOOD
61-
buffAll1->buff2[strlen(buffAll1->buff1)]=0; // GOOD
62-
globalBuff1.buff1[strlen(globalBuff1_c.buff1)]=0; // GOOD
63-
globalBuff1.buff2[strlen(globalBuff1.buff1)]=0; // GOOD
64-
globalBuff2->buff1[strlen(globalBuff2_c->buff1)]=0; // GOOD
65-
globalBuff2->buff2[strlen(globalBuff2->buff1)]=0; // GOOD
71+
buffAll.array[strlen(buffAll_c.array)]=0; // GOOD
72+
buffAll.pointer[strlen(buffAll.array)]=0; // GOOD
73+
buffAll1->array[strlen(buffAll1_c->array)]=0; // GOOD
74+
buffAll1->pointer[strlen(buffAll1->array)]=0; // GOOD
75+
globalBuff1.array[strlen(globalBuff1_c.array)]=0; // GOOD
76+
globalBuff1.pointer[strlen(globalBuff1.array)]=0; // GOOD
77+
globalBuff2->array[strlen(globalBuff2_c->array)]=0; // GOOD
78+
globalBuff2->pointer[strlen(globalBuff2->array)]=0; // GOOD
6679
}
67-
void goodFunc0(){
80+
81+
void strlen_test3(){
6882
unsigned char buffer[12];
6983
int i;
7084
for(i = 0; i < 6; i++)

cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ void test_unique_ptr_int() {
77
std::unique_ptr<int> p1(new int(source()));
88
std::unique_ptr<int> p2 = std::make_unique<int>(source());
99

10-
sink(*p1); // $ MISSING: ast,ir
10+
sink(*p1); // $ ir MISSING: ast
1111
sink(*p2); // $ ast ir=8:50
1212
}
1313

@@ -21,7 +21,7 @@ void test_unique_ptr_struct() {
2121
std::unique_ptr<A> p1(new A{source(), 0});
2222
std::unique_ptr<A> p2 = std::make_unique<A>(source(), 0);
2323

24-
sink(p1->x); // $ MISSING: ast,ir
24+
sink(p1->x); // $ ir MISSING: ast
2525
sink(p1->y);
2626
sink(p2->x); // $ MISSING: ast,ir
2727
sink(p2->y);
@@ -31,15 +31,15 @@ void test_shared_ptr_int() {
3131
std::shared_ptr<int> p1(new int(source()));
3232
std::shared_ptr<int> p2 = std::make_shared<int>(source());
3333

34-
sink(*p1); // $ ast
34+
sink(*p1); // $ ast ir
3535
sink(*p2); // $ ast ir=32:50
3636
}
3737

3838
void test_shared_ptr_struct() {
3939
std::shared_ptr<A> p1(new A{source(), 0});
4040
std::shared_ptr<A> p2 = std::make_shared<A>(source(), 0);
4141

42-
sink(p1->x); // $ MISSING: ast,ir
42+
sink(p1->x); // $ ir MISSING: ast
4343
sink(p1->y);
4444
sink(p2->x); // $ MISSING: ast,ir
4545
sink(p2->y);

0 commit comments

Comments
 (0)