Skip to content

Commit 0b564db

Browse files
authored
Merge branch 'main' into pointers3
2 parents 2f91e33 + 039cd83 commit 0b564db

File tree

81 files changed

+3155
-56
lines changed

Some content is hidden

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

81 files changed

+3155
-56
lines changed

.vscode/tasks.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@
210210
"Declarations4",
211211
"Declarations5",
212212
"Declarations6",
213+
"Declarations7",
213214
"Exceptions1",
214215
"Exceptions2",
215216
"Expressions",
@@ -222,6 +223,8 @@
222223
"Includes",
223224
"Initialization",
224225
"IntegerConversion",
226+
"InvalidMemory1",
227+
"InvalidMemory2",
225228
"Invariants",
226229
"Iterators",
227230
"Lambdas",
@@ -230,6 +233,8 @@
230233
"Literals",
231234
"Loops",
232235
"Macros",
236+
"Memory1",
237+
"Memory2",
233238
"Misc",
234239
"MoveForward",
235240
"Naming",

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ _Carnegie Mellon and CERT are registered trademarks of Carnegie Mellon Universit
99
This repository contains CodeQL queries and libraries which support various Coding Standards for the [C++14](https://www.iso.org/standard/64029.html) programming language.
1010

1111
The following coding standards are supported:
12-
- [AUTOSAR - Guidelines for the use of C++14 language in critical and safety-related systems Release 20-11](https://www.autosar.org/fileadmin/user_upload/standards/adaptive/20-11/AUTOSAR_RS_CPP14Guidelines.pdf)
12+
- [AUTOSAR - Guidelines for the use of C++14 language in critical and safety-related systems Release 20-11](https://www.autosar.org/fileadmin/standards/adaptive/20-11/AUTOSAR_RS_CPP14Guidelines.pdf)
1313
- [MISRA C++:2008](https://www.misra.org.uk) (support limited to the rules specified in AUTOSAR 20-11).
1414
- [SEI CERT C++ Coding Standard: Rules for Developing Safe, Reliable, and Secure Systems (2016 Edition)](https://resources.sei.cmu.edu/library/asset-view.cfm?assetID=494932)
1515

c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.md

Lines changed: 292 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* @id c/cert/information-leakage-across-trust-boundaries-c
3+
* @name DCL39-C: Avoid information leakage when passing a structure across a trust boundary
4+
* @description Passing a structure with uninitialized fields or padding bytes can cause information
5+
* to be unintentionally leaked.
6+
* @kind problem
7+
* @precision medium
8+
* @problem.severity error
9+
* @tags external/cert/id/dcl39-c
10+
* security
11+
* external/cert/obligation/rule
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.cert
16+
import codingstandards.cpp.rules.informationleakageacrossboundaries.InformationLeakageAcrossBoundaries
17+
18+
class InformationLeakageAcrossTrustBoundariesCQuery extends InformationLeakageAcrossBoundariesSharedQuery {
19+
InformationLeakageAcrossTrustBoundariesCQuery() {
20+
this = Declarations7Package::informationLeakageAcrossTrustBoundariesCQuery()
21+
}
22+
}

c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.md

Lines changed: 417 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @id c/cert/do-not-read-uninitialized-memory
3+
* @name EXP33-C: Do not read uninitialized memory
4+
* @description Using the value of an object with automatic storage duration while it is
5+
* indeterminate is undefined behavior.
6+
* @kind problem
7+
* @precision medium
8+
* @problem.severity error
9+
* @tags external/cert/id/exp33-c
10+
* correctness
11+
* security
12+
* external/cert/obligation/rule
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.cert
17+
import codingstandards.cpp.rules.readofuninitializedmemory.ReadOfUninitializedMemory
18+
19+
class DoNotReadUninitializedMemoryQuery extends ReadOfUninitializedMemorySharedQuery {
20+
DoNotReadUninitializedMemoryQuery() {
21+
this = InvalidMemory1Package::doNotReadUninitializedMemoryQuery()
22+
}
23+
}

c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.md

Lines changed: 219 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @id c/cert/do-not-dereference-null-pointers
3+
* @name EXP34-C: Do not dereference null pointers
4+
* @description Dereferencing a null pointer leads to undefined behavior.
5+
* @kind problem
6+
* @precision medium
7+
* @problem.severity error
8+
* @tags external/cert/id/exp34-c
9+
* correctness
10+
* external/cert/obligation/rule
11+
*/
12+
13+
import cpp
14+
import codingstandards.c.cert
15+
import codingstandards.cpp.rules.dereferenceofnullpointer.DereferenceOfNullPointer
16+
17+
class DoNotDereferenceNullPointersQuery extends DereferenceOfNullPointerSharedQuery {
18+
DoNotDereferenceNullPointersQuery() {
19+
this = InvalidMemory1Package::doNotDereferenceNullPointersQuery()
20+
}
21+
}

c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.md

Lines changed: 258 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @id c/cert/do-not-access-freed-memory
3+
* @name MEM30-C: Do not access freed memory
4+
* @description Accessing memory that has been deallocated is undefined behavior.
5+
* @kind problem
6+
* @precision high
7+
* @problem.severity error
8+
* @tags external/cert/id/mem30-c
9+
* correctness
10+
* security
11+
* external/cert/obligation/rule
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.cert
16+
import codingstandards.cpp.Allocations
17+
import semmle.code.cpp.controlflow.StackVariableReachability
18+
19+
/** `e` is an expression that frees the memory pointed to by `v`. */
20+
predicate isFreeExpr(Expr e, StackVariable v) {
21+
exists(VariableAccess va | va.getTarget() = v and freeExprOrIndirect(e, va, _))
22+
}
23+
24+
/** `e` is an expression that accesses `v` but is not the lvalue of an assignment. */
25+
predicate isAccessExpr(Expr e, StackVariable v) {
26+
v.getAnAccess() = e and
27+
not exists(Assignment a | a.getLValue() = e)
28+
or
29+
isDerefByCallExpr(_, _, e, v)
30+
}
31+
32+
/**
33+
* `va` is passed by value as (part of) the `i`th argument in
34+
* call `c`. The target function is either a library function
35+
* or a source code function that dereferences the relevant
36+
* parameter.
37+
*/
38+
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
39+
v.getAnAccess() = va and
40+
va = c.getAnArgumentSubExpr(i) and
41+
not c.passesByReference(i, va) and
42+
(c.getTarget().hasEntryPoint() implies isAccessExpr(_, c.getTarget().getParameter(i)))
43+
}
44+
45+
class UseAfterFreeReachability extends StackVariableReachability {
46+
UseAfterFreeReachability() { this = "UseAfterFree" }
47+
48+
override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }
49+
50+
override predicate isSink(ControlFlowNode node, StackVariable v) { isAccessExpr(node, v) }
51+
52+
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
53+
definitionBarrier(v, node) or
54+
isFreeExpr(node, v)
55+
}
56+
}
57+
58+
// This query is a modified version of the `UseAfterFree.ql`
59+
// (cpp/use-after-free) query from the CodeQL standard library.
60+
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
61+
where
62+
not isExcluded(e, InvalidMemory1Package::doNotAccessFreedMemoryQuery()) and
63+
r.reaches(free, v, e)
64+
select e,
65+
"Pointer '" + v.getName().toString() + "' accessed but may have been previously freed $@.", free,
66+
"here"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
c/common/test/rules/informationleakageacrossboundaries/InformationLeakageAcrossBoundaries.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
c/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
c/common/test/rules/dereferenceofnullpointer/DereferenceOfNullPointer.ql
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| test.c:11:47:11:47 | p | Pointer 'p' accessed but may have been previously freed $@. | test.c:12:5:12:8 | call to free | here |
2+
| test.c:25:10:25:12 | buf | Pointer 'buf' accessed but may have been previously freed $@. | test.c:24:3:24:6 | call to free | here |
3+
| test.c:32:15:32:17 | buf | Pointer 'buf' accessed but may have been previously freed $@. | test.c:31:3:31:6 | call to free | here |
4+
| test.c:33:9:33:11 | buf | Pointer 'buf' accessed but may have been previously freed $@. | test.c:31:3:31:6 | call to free | here |
5+
| test.c:34:16:34:18 | buf | Pointer 'buf' accessed but may have been previously freed $@. | test.c:31:3:31:6 | call to free | here |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/MEM30-C/DoNotAccessFreedMemory.ql

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include <stdlib.h>
2+
#include <string.h>
3+
4+
struct node {
5+
struct node *next;
6+
};
7+
8+
void test_freed_loop_var(struct node *list1, struct node *list2) {
9+
struct node *tmp;
10+
11+
for (struct node *p = list1; p != NULL; p = p->next) { // NON_COMPLIANT
12+
free(p);
13+
}
14+
15+
for (struct node *p = list2; p != NULL; p = tmp) { // COMPLIANT
16+
tmp = p->next;
17+
free(p);
18+
}
19+
}
20+
21+
void test_freed_arg(char *input) {
22+
char *buf = (char *)malloc(strlen(input) + 1);
23+
strcpy(buf, input); // COMPLIANT
24+
free(buf);
25+
strcpy(buf, input); // NON_COMPLIANT
26+
}
27+
28+
void test_freed_access_no_deref(char *input) {
29+
char *buf = (char *)malloc(strlen(input) + 1);
30+
strcpy(buf, input); // COMPLIANT
31+
free(buf);
32+
char *tmp = buf; // NON_COMPLIANT
33+
tmp = buf + 1; // NON_COMPLIANT
34+
char *tmp2 = buf; // NON_COMPLIANT
35+
buf = NULL; // COMPLIANT
36+
(char *)buf; // COMPLIANT
37+
tmp2 = buf + 1; // COMPLIANT
38+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.c:11:4:11:5 | l1 | Null may be dereferenced here because a null value was assigned $@. | test.c:4:21:4:21 | 0 | here |
2+
| test.c:18:6:18:7 | l1 | Null may be dereferenced here because a null value was assigned $@. | test.c:4:21:4:21 | 0 | here |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// GENERATED FILE - DO NOT MODIFY
2+
import codingstandards.cpp.rules.dereferenceofnullpointer.DereferenceOfNullPointer
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <stdlib.h>
2+
3+
void test_null(int p1) {
4+
int *l1 = (void *)0;
5+
6+
if (p1 > 10) {
7+
// l1 is only conditionally initialized
8+
l1 = malloc(10 * sizeof(int));
9+
}
10+
11+
*l1; // NON_COMPLIANT - dereferenced and still null
12+
13+
if (l1) {
14+
*l1; // COMPLIANT - null check before dereference
15+
}
16+
17+
if (!l1) {
18+
*l1; // NON_COMPLIANT - dereferenced and definitely null
19+
} else {
20+
*l1; // COMPLIANT - null check before dereference
21+
}
22+
23+
free(l1); // COMPLIANT - free of `NULL` is not undefined behavior
24+
}
25+
26+
void test_default_value_init() {
27+
int *l1; // indeterminate and thus invalid but non-null state
28+
29+
*l1; // COMPLIANT - considered an uninitialized pointer,
30+
// not a null pointer
31+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
| arrays.c:11:20:11:21 | wa | 'wa' may leak information from {elements of a[...] (arrays.c:7)}. Path: wa (arrays.c:11) --> & ... (arrays.c:12) |
2+
| arrays.c:33:22:33:23 | wa | 'wa' may leak information from {elements of elements of a[...][...] (arrays.c:29)}. Path: wa (arrays.c:33) --> & ... (arrays.c:34) |
3+
| arrays.c:57:22:57:23 | wa | 'wa' may leak information from {WithPointer (arrays.c:52)}. Path: wa (arrays.c:57) --> & ... (arrays.c:59) |
4+
| interprocedural.c:37:9:37:9 | p | 'p' may leak information from {y (interprocedural.c:8)}. Path: p (interprocedural.c:37) --> past assign_x (interprocedural.c:32) --> & ... (interprocedural.c:39) |
5+
| interprocedural.c:104:9:104:9 | p | 'p' may leak information from {x (interprocedural.c:7), y (interprocedural.c:8)}. Path: p (interprocedural.c:104) --> overwrite_after_leak(...) (interprocedural.c:96) --> p (interprocedural.c:97) |
6+
| multilayer.c:16:10:16:10 | s | 's' may leak information from {b (multilayer.c:12)}. Path: s (multilayer.c:16) --> & ... (multilayer.c:18) |
7+
| multilayer.c:29:10:29:10 | s | 's' may leak information from {b (multilayer.c:12), x (multilayer.c:7)}. Path: s (multilayer.c:29) --> & ... (multilayer.c:30) |
8+
| multilayer.c:34:8:34:8 | s | 's' may leak information from {struct <unnamed> (multilayer.c:6)}. Path: s (multilayer.c:34) --> & ... (multilayer.c:35) |
9+
| test.c:12:12:12:12 | s | 's' may leak information from {y (test.c:8)}. Path: s (test.c:12) --> & ... (test.c:14) |
10+
| test.c:18:12:18:12 | s | 's' may leak information from {x (test.c:7)}. Path: s (test.c:18) --> & ... (test.c:20) |
11+
| test.c:24:12:24:12 | s | 's' may leak information from {x (test.c:7), y (test.c:8)}. Path: s (test.c:24) --> & ... (test.c:25) |
12+
| test.c:36:12:36:12 | s | 's' may leak information from {y (test.c:8)}. Path: s (test.c:36) --> & ... (test.c:38) |
13+
| test.c:43:12:43:12 | s | 's' may leak information from {x (test.c:7)}. Path: s (test.c:43) --> & ... (test.c:47) |
14+
| test.c:58:12:58:12 | s | 's' may leak information from {x (test.c:7), y (test.c:8)}. Path: s (test.c:58) --> & ... (test.c:59) |
15+
| test.c:64:12:64:12 | s | 's' may leak information from {y (test.c:8)}. Path: s (test.c:64) --> & ... (test.c:66) |
16+
| test.c:112:16:112:16 | s | 's' may leak information from {buf (test.c:92)}. Path: s (test.c:112) --> & ... (test.c:115) |
17+
| test.c:128:12:128:12 | s | 's' may leak information from {x (test.c:7), y (test.c:8)}. Path: s (test.c:128) --> & ... (test.c:132) |
18+
| test.c:157:22:157:22 | s | 's' may leak information from {2 to 2 bytes of padding in has_padding (test.c:151)}. Path: s (test.c:157) --> & ... (test.c:160) |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// GENERATED FILE - DO NOT MODIFY
2+
import codingstandards.cpp.rules.informationleakageacrossboundaries.InformationLeakageAcrossBoundaries
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include <stddef.h>
2+
#include <string.h>
3+
4+
unsigned long copy_to_user(void *to, const void *from, unsigned long n);
5+
6+
struct WithArray {
7+
int a[2];
8+
};
9+
10+
void forget_array() {
11+
struct WithArray wa;
12+
copy_to_user(0, &wa, sizeof wa); // NON_COMPLIANT
13+
}
14+
15+
void write_partial_array() {
16+
struct WithArray wa;
17+
wa.a[0] = 1;
18+
copy_to_user(0, &wa, sizeof wa); // NON_COMPLIANT[FALSE NEGATIVE]
19+
}
20+
21+
void write_full_array() {
22+
struct WithArray wa;
23+
wa.a[0] = 1;
24+
wa.a[1] = 1;
25+
copy_to_user(0, &wa, sizeof wa); // COMPLIANT
26+
}
27+
28+
struct WithArray2D {
29+
int a[2][1];
30+
};
31+
32+
void forget_array2d() {
33+
struct WithArray2D wa;
34+
copy_to_user(0, &wa, sizeof wa); // NON_COMPLIANT
35+
}
36+
37+
void write_partial_array2d() {
38+
struct WithArray2D wa;
39+
wa.a[0][0] = 1;
40+
copy_to_user(0, &wa, sizeof wa); // NON_COMPLIANT[FALSE NEGATIVE]
41+
}
42+
43+
void write_full_array2d() {
44+
struct WithArray2D wa;
45+
wa.a[0][0] = 1;
46+
wa.a[1][0] = 1;
47+
copy_to_user(0, &wa, sizeof wa); // COMPLIANT
48+
}
49+
50+
// A pointer field allows mostly the same syntactic operations as an array
51+
// field, but the semantics are completely different.
52+
struct WithPointer {
53+
int *a;
54+
};
55+
56+
void pointer_array_expression() {
57+
struct WithPointer wa;
58+
wa.a[0] = 1;
59+
copy_to_user(0, &wa, sizeof wa); // NON_COMPLIANT
60+
}
61+
62+
// TODO: test a struct in an array

0 commit comments

Comments
 (0)