Skip to content

Commit c2961f3

Browse files
authored
Merge pull request #281 from kraiouchkine/OutOfBounds
Implement OutOfBounds package
2 parents d25e575 + ea9b0f4 commit c2961f3

24 files changed

+3565
-0
lines changed

.vscode/tasks.json

+1
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@
249249
"Null",
250250
"OperatorInvariants",
251251
"Operators",
252+
"OutOfBounds",
252253
"Pointers",
253254
"Pointers1",
254255
"Pointers2",

c/cert/src/rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.md

+485
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @id c/cert/do-not-form-out-of-bounds-pointers-or-array-subscripts
3+
* @name ARR30-C: Do not form or use out-of-bounds pointers or array subscripts
4+
* @description Forming or using an out-of-bounds pointer is undefined behavior and can result in
5+
* invalid memory accesses.
6+
* @kind problem
7+
* @precision medium
8+
* @problem.severity error
9+
* @tags external/cert/id/arr30-c
10+
* correctness
11+
* security
12+
* external/cert/obligation/rule
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.cert
17+
import codingstandards.c.OutOfBounds
18+
19+
from
20+
OOB::BufferAccess ba, Expr bufferArg, Expr sizeArg, OOB::PointerToObjectSource bufferSource,
21+
string message
22+
where
23+
not isExcluded(ba, OutOfBoundsPackage::doNotFormOutOfBoundsPointersOrArraySubscriptsQuery()) and
24+
// exclude loops
25+
not exists(Loop loop | loop.getStmt().getChildStmt*() = ba.getEnclosingStmt()) and
26+
// exclude size arguments that are of type ssize_t
27+
not sizeArg.getAChild*().(VariableAccess).getTarget().getType() instanceof Ssize_t and
28+
// exclude size arguments that are assigned the result of a function call e.g. ftell
29+
not sizeArg.getAChild*().(VariableAccess).getTarget().getAnAssignedValue() instanceof FunctionCall and
30+
// exclude field or array accesses for the size arguments
31+
not sizeArg.getAChild*() instanceof FieldAccess and
32+
not sizeArg.getAChild*() instanceof ArrayExpr and
33+
(
34+
exists(int sizeArgValue, int bufferArgSize |
35+
OOB::isSizeArgGreaterThanBufferSize(bufferArg, sizeArg, bufferSource, bufferArgSize, sizeArgValue, ba) and
36+
message =
37+
"Buffer accesses offset " + sizeArgValue +
38+
" which is greater than the fixed size " + bufferArgSize + " of the $@."
39+
)
40+
or
41+
exists(int sizeArgUpperBound, int sizeMult, int bufferArgSize |
42+
OOB::isSizeArgNotCheckedLessThanFixedBufferSize(bufferArg, sizeArg, bufferSource,
43+
bufferArgSize, ba, sizeArgUpperBound, sizeMult) and
44+
message =
45+
"Buffer may access up to offset " + sizeArgUpperBound + "*" + sizeMult +
46+
" which is greater than the fixed size " + bufferArgSize + " of the $@."
47+
)
48+
or
49+
OOB::isSizeArgNotCheckedGreaterThanZero(bufferArg, sizeArg, bufferSource, ba) and
50+
message = "Buffer access may be to a negative index in the buffer."
51+
)
52+
select ba, message, bufferSource, "buffer"

c/cert/src/rules/ARR38-C/LibraryFunctionArgumentOutOfBounds.md

+486
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @id c/cert/library-function-argument-out-of-bounds
3+
* @name ARR38-C: Guarantee that library functions do not form invalid pointers
4+
* @description Passing out-of-bounds pointers or erroneous size arguments to standard library
5+
* functions can result in out-of-bounds accesses and other undefined behavior.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/cert/id/arr38-c
10+
* correctness
11+
* security
12+
* external/cert/obligation/rule
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.cert
17+
import codingstandards.c.OutOfBounds
18+
19+
from
20+
OOB::BufferAccessLibraryFunctionCall fc, string message, Expr bufferArg, string bufferArgStr,
21+
Expr sizeOrOtherBufferArg, string otherStr
22+
where
23+
not isExcluded(fc, OutOfBoundsPackage::libraryFunctionArgumentOutOfBoundsQuery()) and
24+
OOB::problems(fc, message, bufferArg, bufferArgStr, sizeOrOtherBufferArg, otherStr)
25+
select fc, message, bufferArg, bufferArgStr, sizeOrOtherBufferArg, otherStr
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
| test.c:8:3:8:11 | ... + ... | Buffer accesses offset 404 which is greater than the fixed size 400 of the $@. | test.c:8:3:8:5 | arr | buffer |
2+
| test.c:16:3:16:13 | ... + ... | Buffer access may be to a negative index in the buffer. | test.c:16:3:16:5 | arr | buffer |
3+
| test.c:21:5:21:15 | ... + ... | Buffer access may be to a negative index in the buffer. | test.c:21:5:21:7 | arr | buffer |
4+
| test.c:41:17:41:30 | ... + ... | Buffer access may be to a negative index in the buffer. | test.c:41:17:41:22 | buffer | buffer |
5+
| test.c:45:17:45:30 | ... + ... | Buffer may access up to offset 101*1 which is greater than the fixed size 100 of the $@. | test.c:45:17:45:22 | buffer | buffer |
6+
| test.c:55:5:55:13 | ... - ... | Buffer access may be to a negative index in the buffer. | test.c:55:5:55:9 | ptr16 | buffer |
7+
| test.c:57:5:57:14 | ... + ... | Buffer accesses offset 22 which is greater than the fixed size 20 of the $@. | test.c:57:5:57:9 | ptr16 | buffer |
8+
| test.c:58:5:58:14 | ... - ... | Buffer access may be to a negative index in the buffer. | test.c:58:5:58:9 | ptr16 | buffer |
9+
| test.c:63:3:63:9 | access to array | Buffer access may be to a negative index in the buffer. | test.c:63:3:63:5 | arr | buffer |
10+
| test.c:65:3:65:9 | access to array | Buffer accesses offset 44 which is greater than the fixed size 40 of the $@. | test.c:65:3:65:5 | arr | buffer |
11+
| test.c:66:3:66:10 | access to array | Buffer access may be to a negative index in the buffer. | test.c:66:3:66:5 | arr | buffer |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.ql

c/cert/test/rules/ARR30-C/test.c

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
2+
3+
enum { ARRAY_SIZE = 100 };
4+
5+
static int arr[ARRAY_SIZE];
6+
7+
void test_fixed_wrong(void) {
8+
arr + 101; // NON_COMPLIANT
9+
}
10+
11+
void test_fixed_right(void) {
12+
arr + 2; // COMPLIANT
13+
}
14+
15+
void test_no_check(int index) {
16+
arr + index; // NON_COMPLIANT
17+
}
18+
19+
void test_invalid_check(int index) {
20+
if (index < ARRAY_SIZE) {
21+
arr + index; // NON_COMPLIANT - `index` could be negative
22+
}
23+
}
24+
25+
void test_valid_check(int index) {
26+
if (index > 0 && index < ARRAY_SIZE) {
27+
arr + index; // COMPLIANT - `index` cannot be negative
28+
}
29+
}
30+
31+
void test_valid_check_by_type(unsigned int index) {
32+
if (index < ARRAY_SIZE) {
33+
arr + index; // COMPLIANT - `index` cannot be be negative
34+
}
35+
}
36+
37+
void test_local_buffer_invalid_check(int index) {
38+
char buffer[ARRAY_SIZE];
39+
40+
if (index < ARRAY_SIZE) {
41+
char *ptr = buffer + index; // NON_COMPLIANT - `index` could be negative
42+
}
43+
44+
if (index >= 0 && index < ARRAY_SIZE + 2) {
45+
char *ptr = buffer + index; // NON_COMPLIANT - `index` could be too large
46+
}
47+
48+
if (index >= 0 && index < ARRAY_SIZE) {
49+
char *ptr = buffer + index; // COMPLIANT
50+
}
51+
}
52+
53+
void test_dereference_pointer_arithmetic_const(void) {
54+
short ptr16[10];
55+
*(ptr16 - 1); // NON_COMPLIANT - offset is negative
56+
*(ptr16 + 5); // COMPLIANT
57+
*(ptr16 + 11); // NON_COMPLIANT - offset is too large
58+
*(ptr16 - 11); // NON_COMPLIANT - offset is negative
59+
}
60+
61+
void test_array_expr_const(void) {
62+
int arr[10];
63+
arr[-1]; // NON_COMPLIANT - offset is negative
64+
arr[5]; // COMPLIANT
65+
arr[11]; // NON_COMPLIANT - offset is too large
66+
arr[-11]; // NON_COMPLIANT - offset is negative
67+
}

0 commit comments

Comments
 (0)