diff --git a/cpp/ql/lib/change-notes/2025-02-20-getbuffersize.md b/cpp/ql/lib/change-notes/2025-02-20-getbuffersize.md new file mode 100644 index 00000000000..07646d96ddd --- /dev/null +++ b/cpp/ql/lib/change-notes/2025-02-20-getbuffersize.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Fixed an issue where the `getBufferSize` predicate in `commons/Buffer.qll` was returning results for references inside `offsetof` expressions, which are not accesses to a buffer. diff --git a/cpp/ql/lib/change-notes/2025-02-25-getbuffersize.md b/cpp/ql/lib/change-notes/2025-02-25-getbuffersize.md new file mode 100644 index 00000000000..cbc7e86d8d2 --- /dev/null +++ b/cpp/ql/lib/change-notes/2025-02-25-getbuffersize.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Modified the `getBufferSize` predicate in `commons/Buffer.qll` to be more tolerant in some cases involving member variables in a larger struct or class. diff --git a/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll b/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll index 70d6795f76b..565c15d0d5c 100644 --- a/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll +++ b/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll @@ -71,7 +71,7 @@ private int getSize(VariableAccess va) { result = t.getSize() ) or - exists(Class c | + exists(Class c, int trueSize | // Otherwise, we find the "outermost" object and compute the size // as the difference between the size of the type of the "outermost // object" and the offset of the field relative to that type. @@ -91,7 +91,9 @@ private int getSize(VariableAccess va) { // of `y` relative to the type `S2` (i.e., `4`). So the size of the // buffer is `12 - 4 = 8`. c = getRootType(va) and - result = c.getSize() - v.(Field).getOffsetInClass(c) + // we calculate the size based on the last field, to avoid including any padding after it + trueSize = max(Field f | | f.getOffsetInClass(c) + f.getUnspecifiedType().getSize()) and + result = trueSize - v.(Field).getOffsetInClass(c) ) ) } @@ -105,9 +107,16 @@ private int getSize(VariableAccess va) { private int isSource(Expr bufferExpr, Element why) { exists(Variable bufferVar | bufferVar = bufferExpr.(VariableAccess).getTarget() | // buffer is a fixed size array - result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and + exists(bufferVar.getUnspecifiedType().(ArrayType).getSize()) and + result = + unique(int size | // more generous than .getSize() itself, when the array is a class field or similar. + size = getSize(bufferExpr) + | + size + ) and why = bufferVar and not memberMayBeVarSize(_, bufferVar) and + not exists(BuiltInOperationBuiltInOffsetOf offsetof | offsetof.getAChild*() = bufferExpr) and // zero sized arrays are likely to have special usage, for example // behaving a bit like a 'union' overlapping other fields. not result = 0 diff --git a/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql b/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql index 37892682814..4ca77b524e3 100644 --- a/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql +++ b/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql @@ -5,8 +5,9 @@ * buffer. * @kind problem * @id cpp/overflow-buffer - * @problem.severity recommendation + * @problem.severity warning * @security-severity 9.3 + * @precision medium * @tags security * external/cwe/cwe-119 * external/cwe/cwe-121 diff --git a/cpp/ql/src/change-notes/2025-02-20-overflow-buffer.md b/cpp/ql/src/change-notes/2025-02-20-overflow-buffer.md new file mode 100644 index 00000000000..11e9b1ac48b --- /dev/null +++ b/cpp/ql/src/change-notes/2025-02-20-overflow-buffer.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The query "Call to memory access function may overflow buffer" (`cpp/overflow-buffer`) has been added to the security-extended query suite. The query detects a range of buffer overflow and underflow issues. diff --git a/cpp/ql/src/change-notes/2025-02-27-static-buffer-overflow.md b/cpp/ql/src/change-notes/2025-02-27-static-buffer-overflow.md new file mode 100644 index 00000000000..91e893c5ee9 --- /dev/null +++ b/cpp/ql/src/change-notes/2025-02-27-static-buffer-overflow.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Due to changes in libraries the query "Static array access may cause overflow" (`cpp/static-buffer-overflow`) will no longer report cases where multiple fields of a struct or class are written with a single `memset` or similar operation. diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowBuffer.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowBuffer.expected index 770fcd0e3a3..48942648903 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowBuffer.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowBuffer.expected @@ -1,5 +1,3 @@ -| tests.cpp:45:9:45:14 | call to memcpy | This 'memcpy' operation accesses 32 bytes but the $@ is only 16 bytes. | tests.cpp:32:10:32:18 | charFirst | destination buffer | -| tests.cpp:60:9:60:14 | call to memcpy | This 'memcpy' operation accesses 32 bytes but the $@ is only 16 bytes. | tests.cpp:32:10:32:18 | charFirst | destination buffer | | tests.cpp:171:9:171:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:164:20:164:25 | call to malloc | destination buffer | | tests.cpp:172:9:172:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:164:20:164:25 | call to malloc | array | | tests.cpp:192:9:192:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:181:10:181:22 | dataBadBuffer | destination buffer | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowStatic.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowStatic.expected index ab9263b8544..e69de29bb2d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowStatic.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowStatic.expected @@ -1,2 +0,0 @@ -| tests.cpp:45:51:45:72 | sizeof() | Potential buffer-overflow: 'charFirst' has size 16 not 32. | -| tests.cpp:60:52:60:74 | sizeof() | Potential buffer-overflow: 'charFirst' has size 16 not 32. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/tests.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/tests.cpp index b33b00507b2..61b69d95185 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/tests.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/tests.cpp @@ -42,7 +42,7 @@ void CWE121_Stack_Based_Buffer_Overflow__char_type_overrun_memcpy_01_bad() /* Print the initial block pointed to by structCharVoid.voidSecond */ printLine((char *)structCharVoid.voidSecond); /* FLAW: Use the sizeof(structCharVoid) which will overwrite the pointer voidSecond */ - memcpy(structCharVoid.charFirst, SRC_STR, sizeof(structCharVoid)); + memcpy(structCharVoid.charFirst, SRC_STR, sizeof(structCharVoid)); // [NOT DETECTED] structCharVoid.charFirst[(sizeof(structCharVoid.charFirst)/sizeof(char))-1] = '\0'; /* null terminate the string */ printLine((char *)structCharVoid.charFirst); printLine((char *)structCharVoid.voidSecond); @@ -57,7 +57,7 @@ void CWE122_Heap_Based_Buffer_Overflow__char_type_overrun_memcpy_01_bad() /* Print the initial block pointed to by structCharVoid->voidSecond */ printLine((char *)structCharVoid->voidSecond); /* FLAW: Use the sizeof(*structCharVoid) which will overwrite the pointer y */ - memcpy(structCharVoid->charFirst, SRC_STR, sizeof(*structCharVoid)); + memcpy(structCharVoid->charFirst, SRC_STR, sizeof(*structCharVoid)); // [NOT DETECTED] structCharVoid->charFirst[(sizeof(structCharVoid->charFirst)/sizeof(char))-1] = '\0'; /* null terminate the string */ printLine((char *)structCharVoid->charFirst); printLine((char *)structCharVoid->voidSecond); @@ -292,7 +292,7 @@ namespace CWE122_Heap_Based_Buffer_Overflow__cpp_CWE193_wchar_t_ncpy_01 delete [] data; } } - + static void goodG2B() { wchar_t * data; @@ -459,7 +459,7 @@ void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_ncpy_01_bad() #ifdef _WIN32 int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format, ...); #define SNPRINTF _snwprintf -#else +#else int snprintf(char *s, size_t n, const char *format, ...); int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...); //#define SNPRINTF snprintf --- original code; using snprintf appears to be a mistake in samate? @@ -485,14 +485,14 @@ void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_snprintf_01_bad() } /* classes used in some test cases as a custom type */ -class TwoIntsClass +class TwoIntsClass { public: // Needed to access variables from label files int intOne; int intTwo; }; -class OneIntClass +class OneIntClass { public: // Needed to access variables from label files int intOne; @@ -636,7 +636,7 @@ void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_snprintf_31_bad() int rand(void); -int globalReturnsTrueOrFalse() +int globalReturnsTrueOrFalse() { return (rand() % 2); } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/BadlyBoundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/BadlyBoundedWrite.expected index cb268b69c1a..2c7cd16231c 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/BadlyBoundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/BadlyBoundedWrite.expected @@ -1,2 +1,4 @@ +| tests.cpp:1055:2:1055:8 | call to strncpy | This 'call to strncpy' operation is limited to 131 bytes but the destination is only 128 bytes. | +| tests.cpp:1057:2:1057:8 | call to strncpy | This 'call to strncpy' operation is limited to 131 bytes but the destination is only 64 bytes. | | var_size_struct.cpp:73:3:73:9 | call to strncpy | This 'call to strncpy' operation is limited to 1025 bytes but the destination is only 1024 bytes. | | var_size_struct.cpp:103:3:103:9 | call to strncpy | This 'call to strncpy' operation is limited to 129 bytes but the destination is only 128 bytes. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected index 068a6171989..ac0e8d3a25a 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected @@ -17,69 +17,81 @@ | tests.cpp:285:3:285:8 | call to memset | This 'memset' operation accesses 128 bytes but the $@ is only 64 bytes. | tests.cpp:283:12:283:23 | new[] | destination buffer | | tests.cpp:292:3:292:8 | call to memset | This 'memset' operation accesses 11 bytes but the $@ is only 10 bytes. | tests.cpp:289:8:289:12 | array | destination buffer | | tests.cpp:310:2:310:7 | call to memset | This 'memset' operation accesses 21 bytes but the $@ is only 20 bytes. | tests.cpp:301:10:301:14 | myVar | destination buffer | -| tests.cpp:312:2:312:7 | call to memset | This 'memset' operation accesses 17 bytes but the $@ is only 16 bytes. | tests.cpp:298:7:298:12 | buffer | destination buffer | | tests.cpp:314:2:314:7 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:299:6:299:10 | field | destination buffer | -| tests.cpp:346:2:346:14 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:342:7:342:15 | charArray | array | -| tests.cpp:349:2:349:14 | access to array | This array indexing operation accesses byte offset 10 but the $@ is only 10 bytes. | tests.cpp:342:7:342:15 | charArray | array | -| tests.cpp:350:17:350:29 | access to array | This array indexing operation accesses byte offset 10 but the $@ is only 10 bytes. | tests.cpp:342:7:342:15 | charArray | array | -| tests.cpp:352:2:352:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:343:6:343:13 | intArray | array | -| tests.cpp:355:2:355:13 | access to array | This array indexing operation accesses byte offset 43 but the $@ is only 40 bytes. | tests.cpp:343:6:343:13 | intArray | array | -| tests.cpp:356:16:356:27 | access to array | This array indexing operation accesses byte offset 43 but the $@ is only 40 bytes. | tests.cpp:343:6:343:13 | intArray | array | -| tests.cpp:358:2:358:16 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:344:11:344:21 | structArray | array | -| tests.cpp:361:2:361:16 | access to array | This array indexing operation accesses byte offset 219 but the $@ is only 200 bytes. | tests.cpp:344:11:344:21 | structArray | array | -| tests.cpp:362:25:362:39 | access to array | This array indexing operation accesses byte offset 219 but the $@ is only 200 bytes. | tests.cpp:344:11:344:21 | structArray | array | -| tests.cpp:365:23:365:34 | access to array | This array indexing operation accesses byte offset 43 but the $@ is only 40 bytes. | tests.cpp:343:6:343:13 | intArray | array | -| tests.cpp:373:3:373:13 | access to array | This array indexing operation accesses byte offset 101 but the $@ is only 100 bytes. | tests.cpp:368:47:368:52 | call to malloc | array | -| tests.cpp:376:3:376:13 | access to array | This array indexing operation accesses byte offset 101 but the $@ is only 101 bytes. | tests.cpp:369:47:369:52 | call to malloc | array | -| tests.cpp:446:3:446:24 | access to array | This array indexing operation accesses a negative index -3 on the $@. | tests.cpp:444:7:444:14 | intArray | array | -| tests.cpp:454:3:454:11 | access to array | This array indexing operation accesses a negative index -21 on the $@. | tests.cpp:450:7:450:11 | multi | array | -| tests.cpp:456:3:456:11 | access to array | This array indexing operation accesses a negative index -21 on the $@. | tests.cpp:450:7:450:11 | multi | array | -| tests.cpp:459:3:459:11 | access to array | This array indexing operation accesses byte offset 639 but the $@ is only 400 bytes. | tests.cpp:450:7:450:11 | multi | array | -| tests.cpp:461:3:461:11 | access to array | This array indexing operation accesses byte offset 639 but the $@ is only 400 bytes. | tests.cpp:450:7:450:11 | multi | array | -| tests.cpp:476:2:476:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:469:7:469:12 | buffer | array | -| tests.cpp:477:2:477:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:469:7:469:12 | buffer | array | -| tests.cpp:481:2:481:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:469:7:469:12 | buffer | array | -| tests.cpp:487:2:487:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:473:21:473:26 | call to malloc | array | -| tests.cpp:491:2:491:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:474:21:474:26 | call to malloc | array | -| tests.cpp:519:3:519:8 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 10 bytes. | tests.cpp:502:15:502:20 | call to malloc | destination buffer | -| tests.cpp:519:3:519:8 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 10 bytes. | tests.cpp:510:16:510:21 | call to malloc | destination buffer | -| tests.cpp:541:6:541:10 | call to fread | This 'fread' operation may access 101 bytes but the $@ is only 100 bytes. | tests.cpp:532:7:532:16 | charBuffer | destination buffer | -| tests.cpp:546:6:546:10 | call to fread | This 'fread' operation may access 400 bytes but the $@ is only 100 bytes. | tests.cpp:532:7:532:16 | charBuffer | destination buffer | -| tests.cpp:569:6:569:15 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:565:7:565:12 | buffer | array | -| tests.cpp:577:7:577:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:565:7:565:12 | buffer | array | -| tests.cpp:637:6:637:15 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:633:7:633:12 | buffer | array | -| tests.cpp:645:7:645:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:633:7:633:12 | buffer | array | -| tests.cpp:708:3:708:8 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 8 bytes. | tests.cpp:693:16:693:16 | c | destination buffer | -| tests.cpp:712:3:712:8 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:693:16:693:16 | c | destination buffer | -| tests.cpp:716:3:716:8 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 16 bytes. | tests.cpp:692:16:692:16 | b | destination buffer | -| tests.cpp:727:2:727:7 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 8 bytes. | tests.cpp:693:16:693:16 | c | destination buffer | -| tests.cpp:753:5:753:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:735:20:735:22 | b_1 | destination buffer | -| tests.cpp:756:5:756:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:735:20:735:22 | b_1 | destination buffer | -| tests.cpp:760:5:760:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer | -| tests.cpp:761:5:761:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer | -| tests.cpp:763:5:763:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer | -| tests.cpp:764:5:764:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer | -| tests.cpp:774:5:774:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:740:20:740:22 | b_2 | destination buffer | -| tests.cpp:777:5:777:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:740:20:740:22 | b_2 | destination buffer | -| tests.cpp:795:5:795:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:790:16:790:16 | b | destination buffer | -| tests.cpp:822:5:822:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:801:16:801:16 | b | destination buffer | -| tests.cpp:825:5:825:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:801:16:801:16 | b | destination buffer | -| tests.cpp:827:5:827:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:801:16:801:16 | b | destination buffer | -| tests.cpp:830:5:830:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:802:16:802:16 | c | destination buffer | -| tests.cpp:831:5:831:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:802:16:802:16 | c | destination buffer | -| tests.cpp:833:5:833:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:802:16:802:16 | c | destination buffer | -| tests.cpp:835:5:835:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:802:16:802:16 | c | destination buffer | -| tests.cpp:846:5:846:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | -| tests.cpp:847:5:847:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | -| tests.cpp:848:5:848:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | -| tests.cpp:849:5:849:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | -| tests.cpp:851:5:851:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | -| tests.cpp:862:5:862:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | -| tests.cpp:863:5:863:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | -| tests.cpp:864:5:864:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | -| tests.cpp:865:5:865:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | -| tests.cpp:866:5:866:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | -| tests.cpp:867:5:867:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | +| tests.cpp:348:2:348:14 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:342:7:342:15 | charArray | array | +| tests.cpp:351:2:351:14 | access to array | This array indexing operation accesses byte offset 10 but the $@ is only 10 bytes. | tests.cpp:342:7:342:15 | charArray | array | +| tests.cpp:352:17:352:29 | access to array | This array indexing operation accesses byte offset 10 but the $@ is only 10 bytes. | tests.cpp:342:7:342:15 | charArray | array | +| tests.cpp:354:2:354:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:343:6:343:13 | intArray | array | +| tests.cpp:357:2:357:13 | access to array | This array indexing operation accesses byte offset 43 but the $@ is only 40 bytes. | tests.cpp:343:6:343:13 | intArray | array | +| tests.cpp:358:16:358:27 | access to array | This array indexing operation accesses byte offset 43 but the $@ is only 40 bytes. | tests.cpp:343:6:343:13 | intArray | array | +| tests.cpp:360:2:360:16 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:344:11:344:21 | structArray | array | +| tests.cpp:363:2:363:16 | access to array | This array indexing operation accesses byte offset 219 but the $@ is only 200 bytes. | tests.cpp:344:11:344:21 | structArray | array | +| tests.cpp:364:25:364:39 | access to array | This array indexing operation accesses byte offset 219 but the $@ is only 200 bytes. | tests.cpp:344:11:344:21 | structArray | array | +| tests.cpp:367:23:367:34 | access to array | This array indexing operation accesses byte offset 43 but the $@ is only 40 bytes. | tests.cpp:343:6:343:13 | intArray | array | +| tests.cpp:369:2:369:13 | access to array | This array indexing operation accesses a negative index -2 on the $@. | tests.cpp:342:7:342:15 | charArray | array | +| tests.cpp:370:2:370:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:342:7:342:15 | charArray | array | +| tests.cpp:374:2:374:13 | access to array | This array indexing operation accesses byte offset 10 but the $@ is only 10 bytes. | tests.cpp:342:7:342:15 | charArray | array | +| tests.cpp:394:3:394:13 | access to array | This array indexing operation accesses byte offset 101 but the $@ is only 100 bytes. | tests.cpp:389:47:389:52 | call to malloc | array | +| tests.cpp:397:3:397:13 | access to array | This array indexing operation accesses byte offset 101 but the $@ is only 101 bytes. | tests.cpp:390:47:390:52 | call to malloc | array | +| tests.cpp:467:3:467:24 | access to array | This array indexing operation accesses a negative index -3 on the $@. | tests.cpp:465:7:465:14 | intArray | array | +| tests.cpp:475:3:475:11 | access to array | This array indexing operation accesses a negative index -21 on the $@. | tests.cpp:471:7:471:11 | multi | array | +| tests.cpp:477:3:477:11 | access to array | This array indexing operation accesses a negative index -21 on the $@. | tests.cpp:471:7:471:11 | multi | array | +| tests.cpp:480:3:480:11 | access to array | This array indexing operation accesses byte offset 639 but the $@ is only 400 bytes. | tests.cpp:471:7:471:11 | multi | array | +| tests.cpp:482:3:482:11 | access to array | This array indexing operation accesses byte offset 639 but the $@ is only 400 bytes. | tests.cpp:471:7:471:11 | multi | array | +| tests.cpp:497:2:497:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:490:7:490:12 | buffer | array | +| tests.cpp:498:2:498:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:490:7:490:12 | buffer | array | +| tests.cpp:502:2:502:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:490:7:490:12 | buffer | array | +| tests.cpp:508:2:508:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:494:21:494:26 | call to malloc | array | +| tests.cpp:512:2:512:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:495:21:495:26 | call to malloc | array | +| tests.cpp:540:3:540:8 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 10 bytes. | tests.cpp:523:15:523:20 | call to malloc | destination buffer | +| tests.cpp:540:3:540:8 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 10 bytes. | tests.cpp:531:16:531:21 | call to malloc | destination buffer | +| tests.cpp:562:6:562:10 | call to fread | This 'fread' operation may access 101 bytes but the $@ is only 100 bytes. | tests.cpp:553:7:553:16 | charBuffer | destination buffer | +| tests.cpp:567:6:567:10 | call to fread | This 'fread' operation may access 400 bytes but the $@ is only 100 bytes. | tests.cpp:553:7:553:16 | charBuffer | destination buffer | +| tests.cpp:590:6:590:15 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:586:7:586:12 | buffer | array | +| tests.cpp:598:7:598:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:586:7:586:12 | buffer | array | +| tests.cpp:658:6:658:15 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:654:7:654:12 | buffer | array | +| tests.cpp:666:7:666:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:654:7:654:12 | buffer | array | +| tests.cpp:729:3:729:8 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 8 bytes. | tests.cpp:714:16:714:16 | c | destination buffer | +| tests.cpp:733:3:733:8 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:714:16:714:16 | c | destination buffer | +| tests.cpp:737:3:737:8 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 16 bytes. | tests.cpp:713:16:713:16 | b | destination buffer | +| tests.cpp:748:2:748:7 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 8 bytes. | tests.cpp:714:16:714:16 | c | destination buffer | +| tests.cpp:774:5:774:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:756:20:756:22 | b_1 | destination buffer | +| tests.cpp:777:5:777:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:756:20:756:22 | b_1 | destination buffer | +| tests.cpp:781:5:781:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:757:20:757:22 | c_1 | destination buffer | +| tests.cpp:782:5:782:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:757:20:757:22 | c_1 | destination buffer | +| tests.cpp:784:5:784:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:757:20:757:22 | c_1 | destination buffer | +| tests.cpp:785:5:785:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:757:20:757:22 | c_1 | destination buffer | +| tests.cpp:795:5:795:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:761:20:761:22 | b_2 | destination buffer | +| tests.cpp:798:5:798:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:761:20:761:22 | b_2 | destination buffer | +| tests.cpp:816:5:816:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:811:16:811:16 | b | destination buffer | +| tests.cpp:843:5:843:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:822:16:822:16 | b | destination buffer | +| tests.cpp:846:5:846:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:822:16:822:16 | b | destination buffer | +| tests.cpp:848:5:848:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:822:16:822:16 | b | destination buffer | +| tests.cpp:851:5:851:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:823:16:823:16 | c | destination buffer | +| tests.cpp:852:5:852:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:823:16:823:16 | c | destination buffer | +| tests.cpp:854:5:854:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:823:16:823:16 | c | destination buffer | +| tests.cpp:856:5:856:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:823:16:823:16 | c | destination buffer | +| tests.cpp:867:5:867:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:828:16:828:16 | x | destination buffer | +| tests.cpp:868:5:868:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:828:16:828:16 | x | destination buffer | +| tests.cpp:869:5:869:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:828:16:828:16 | x | destination buffer | +| tests.cpp:870:5:870:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:828:16:828:16 | x | destination buffer | +| tests.cpp:872:5:872:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:828:16:828:16 | x | destination buffer | +| tests.cpp:883:5:883:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:833:12:833:12 | u | destination buffer | +| tests.cpp:884:5:884:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 4 bytes. | tests.cpp:833:12:833:12 | u | destination buffer | +| tests.cpp:885:5:885:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 4 bytes. | tests.cpp:833:12:833:12 | u | destination buffer | +| tests.cpp:886:5:886:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:833:12:833:12 | u | destination buffer | +| tests.cpp:887:5:887:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:833:12:833:12 | u | destination buffer | +| tests.cpp:888:5:888:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:833:12:833:12 | u | destination buffer | +| tests.cpp:984:2:984:9 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:981:6:981:8 | arr | array | +| tests.cpp:989:2:989:9 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:981:6:981:8 | arr | array | +| tests.cpp:994:2:994:9 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:981:6:981:8 | arr | array | +| tests.cpp:1001:2:1001:9 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:981:6:981:8 | arr | array | +| tests.cpp:1009:2:1009:9 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:981:6:981:8 | arr | array | +| tests.cpp:1031:2:1031:7 | call to memset | This 'memset' operation accesses 130 bytes but the $@ is only 120 bytes. | tests.cpp:1020:12:1020:15 | arr1 | destination buffer | +| tests.cpp:1050:2:1050:7 | call to memset | This 'memset' operation accesses 132 bytes but the $@ is only 128 bytes. | tests.cpp:1037:8:1037:14 | buffer1 | destination buffer | +| tests.cpp:1052:2:1052:7 | call to memset | This 'memset' operation accesses 132 bytes but the $@ is only 64 bytes. | tests.cpp:1041:8:1041:14 | buffer2 | destination buffer | +| tests.cpp:1055:2:1055:8 | call to strncpy | This 'strncpy' operation may access 131 bytes but the $@ is only 128 bytes. | tests.cpp:1037:8:1037:14 | buffer1 | destination buffer | +| tests.cpp:1057:2:1057:8 | call to strncpy | This 'strncpy' operation may access 131 bytes but the $@ is only 64 bytes. | tests.cpp:1041:8:1041:14 | buffer2 | destination buffer | | tests_restrict.c:12:2:12:7 | call to memcpy | This 'memcpy' operation accesses 2 bytes but the $@ is only 1 byte. | tests_restrict.c:7:6:7:13 | smallbuf | source buffer | | unions.cpp:26:2:26:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:21:10:21:11 | mu | destination buffer | | unions.cpp:30:2:30:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:15:7:15:11 | small | destination buffer | @@ -88,5 +100,4 @@ | var_size_struct.cpp:73:3:73:9 | call to strncpy | This 'strncpy' operation may access 1025 bytes but the $@ is only 1024 bytes. | var_size_struct.cpp:63:8:63:11 | data | destination buffer | | var_size_struct.cpp:87:3:87:19 | access to array | This array indexing operation accesses byte offset 67 but the $@ is only 64 bytes. | var_size_struct.cpp:78:7:78:14 | elements | array | | var_size_struct.cpp:99:3:99:8 | call to memset | This 'memset' operation accesses 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer | -| var_size_struct.cpp:101:3:101:8 | call to memset | This 'memset' operation accesses 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer | | var_size_struct.cpp:103:3:103:9 | call to strncpy | This 'strncpy' operation may access 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowStatic.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowStatic.expected index ac44bbf028d..d810f436d87 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowStatic.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowStatic.expected @@ -3,6 +3,8 @@ | tests.cpp:163:3:163:11 | access to array | Potential buffer-overflow: counter 'k' <= 100 but 'buffer' has 100 elements. | | tests.cpp:164:8:164:16 | access to array | Potential buffer-overflow: counter 'k' <= 100 but 'buffer' has 100 elements. | | tests.cpp:245:42:245:42 | 6 | Potential buffer-overflow: 'global_array_5' has size 5 not 6. | -| tests.cpp:349:2:349:14 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' may be accessed here. | -| tests.cpp:350:17:350:29 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' may be accessed here. | +| tests.cpp:351:2:351:14 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' may be accessed here. | +| tests.cpp:352:17:352:29 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' may be accessed here. | +| tests.cpp:1055:26:1055:39 | ... - ... | Potential buffer-overflow: 'buffer1' has size 128 not 131. | +| tests.cpp:1057:26:1057:39 | ... - ... | Potential buffer-overflow: 'buffer2' has size 64 not 131. | | var_size_struct.cpp:103:39:103:41 | 129 | Potential buffer-overflow: 'str' has size 128 not 129. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected index 575229672a8..30b78aa875c 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected @@ -27,26 +27,26 @@ edges | main.cpp:9:29:9:32 | *argv | tests_restrict.c:15:41:15:44 | *argv | provenance | | | main.cpp:9:29:9:32 | tests_restrict_main output argument | main.cpp:10:20:10:23 | **argv | provenance | | | main.cpp:9:29:9:32 | tests_restrict_main output argument | main.cpp:10:20:10:23 | *argv | provenance | | -| main.cpp:10:20:10:23 | **argv | tests.cpp:872:32:872:35 | **argv | provenance | | -| main.cpp:10:20:10:23 | *argv | tests.cpp:872:32:872:35 | *argv | provenance | | +| main.cpp:10:20:10:23 | **argv | tests.cpp:1060:32:1060:35 | **argv | provenance | | +| main.cpp:10:20:10:23 | *argv | tests.cpp:1060:32:1060:35 | *argv | provenance | | | overflowdestination.cpp:23:45:23:48 | **argv | overflowdestination.cpp:23:45:23:48 | **argv | provenance | | | overflowdestination.cpp:23:45:23:48 | **argv | overflowdestination.cpp:23:45:23:48 | *argv | provenance | | | test_buffer_overrun.cpp:32:46:32:49 | **argv | test_buffer_overrun.cpp:32:46:32:49 | **argv | provenance | | | test_buffer_overrun.cpp:32:46:32:49 | **argv | test_buffer_overrun.cpp:32:46:32:49 | *argv | provenance | | | test_buffer_overrun.cpp:32:46:32:49 | *argv | test_buffer_overrun.cpp:32:46:32:49 | *argv | provenance | | -| tests.cpp:613:19:613:24 | *source | tests.cpp:615:17:615:22 | *source | provenance | | -| tests.cpp:622:19:622:24 | *source | tests.cpp:625:2:625:16 | *... = ... | provenance | | -| tests.cpp:625:2:625:2 | *s [post update] [*home] | tests.cpp:628:14:628:14 | *s [*home] | provenance | | -| tests.cpp:625:2:625:16 | *... = ... | tests.cpp:625:2:625:2 | *s [post update] [*home] | provenance | | -| tests.cpp:628:14:628:14 | *s [*home] | tests.cpp:628:14:628:19 | *home | provenance | | -| tests.cpp:628:14:628:14 | *s [*home] | tests.cpp:628:16:628:19 | *home | provenance | | -| tests.cpp:628:16:628:19 | *home | tests.cpp:628:14:628:19 | *home | provenance | | -| tests.cpp:872:32:872:35 | **argv | tests.cpp:897:9:897:15 | *access to array | provenance | | -| tests.cpp:872:32:872:35 | **argv | tests.cpp:898:9:898:15 | *access to array | provenance | | -| tests.cpp:872:32:872:35 | *argv | tests.cpp:897:9:897:15 | *access to array | provenance | | -| tests.cpp:872:32:872:35 | *argv | tests.cpp:898:9:898:15 | *access to array | provenance | | -| tests.cpp:897:9:897:15 | *access to array | tests.cpp:613:19:613:24 | *source | provenance | | -| tests.cpp:898:9:898:15 | *access to array | tests.cpp:622:19:622:24 | *source | provenance | | +| tests.cpp:634:19:634:24 | *source | tests.cpp:636:17:636:22 | *source | provenance | | +| tests.cpp:643:19:643:24 | *source | tests.cpp:646:2:646:16 | *... = ... | provenance | | +| tests.cpp:646:2:646:2 | *s [post update] [*home] | tests.cpp:649:14:649:14 | *s [*home] | provenance | | +| tests.cpp:646:2:646:16 | *... = ... | tests.cpp:646:2:646:2 | *s [post update] [*home] | provenance | | +| tests.cpp:649:14:649:14 | *s [*home] | tests.cpp:649:14:649:19 | *home | provenance | | +| tests.cpp:649:14:649:14 | *s [*home] | tests.cpp:649:16:649:19 | *home | provenance | | +| tests.cpp:649:16:649:19 | *home | tests.cpp:649:14:649:19 | *home | provenance | | +| tests.cpp:1060:32:1060:35 | **argv | tests.cpp:1085:9:1085:15 | *access to array | provenance | | +| tests.cpp:1060:32:1060:35 | **argv | tests.cpp:1086:9:1086:15 | *access to array | provenance | | +| tests.cpp:1060:32:1060:35 | *argv | tests.cpp:1085:9:1085:15 | *access to array | provenance | | +| tests.cpp:1060:32:1060:35 | *argv | tests.cpp:1086:9:1086:15 | *access to array | provenance | | +| tests.cpp:1085:9:1085:15 | *access to array | tests.cpp:634:19:634:24 | *source | provenance | | +| tests.cpp:1086:9:1086:15 | *access to array | tests.cpp:643:19:643:24 | *source | provenance | | | tests_restrict.c:15:41:15:44 | **argv | tests_restrict.c:15:41:15:44 | **argv | provenance | | | tests_restrict.c:15:41:15:44 | *argv | tests_restrict.c:15:41:15:44 | *argv | provenance | | nodes @@ -72,18 +72,18 @@ nodes | test_buffer_overrun.cpp:32:46:32:49 | *argv | semmle.label | *argv | | test_buffer_overrun.cpp:32:46:32:49 | *argv | semmle.label | *argv | | test_buffer_overrun.cpp:32:46:32:49 | *argv | semmle.label | *argv | -| tests.cpp:613:19:613:24 | *source | semmle.label | *source | -| tests.cpp:615:17:615:22 | *source | semmle.label | *source | -| tests.cpp:622:19:622:24 | *source | semmle.label | *source | -| tests.cpp:625:2:625:2 | *s [post update] [*home] | semmle.label | *s [post update] [*home] | -| tests.cpp:625:2:625:16 | *... = ... | semmle.label | *... = ... | -| tests.cpp:628:14:628:14 | *s [*home] | semmle.label | *s [*home] | -| tests.cpp:628:14:628:19 | *home | semmle.label | *home | -| tests.cpp:628:16:628:19 | *home | semmle.label | *home | -| tests.cpp:872:32:872:35 | **argv | semmle.label | **argv | -| tests.cpp:872:32:872:35 | *argv | semmle.label | *argv | -| tests.cpp:897:9:897:15 | *access to array | semmle.label | *access to array | -| tests.cpp:898:9:898:15 | *access to array | semmle.label | *access to array | +| tests.cpp:634:19:634:24 | *source | semmle.label | *source | +| tests.cpp:636:17:636:22 | *source | semmle.label | *source | +| tests.cpp:643:19:643:24 | *source | semmle.label | *source | +| tests.cpp:646:2:646:2 | *s [post update] [*home] | semmle.label | *s [post update] [*home] | +| tests.cpp:646:2:646:16 | *... = ... | semmle.label | *... = ... | +| tests.cpp:649:14:649:14 | *s [*home] | semmle.label | *s [*home] | +| tests.cpp:649:14:649:19 | *home | semmle.label | *home | +| tests.cpp:649:16:649:19 | *home | semmle.label | *home | +| tests.cpp:1060:32:1060:35 | **argv | semmle.label | **argv | +| tests.cpp:1060:32:1060:35 | *argv | semmle.label | *argv | +| tests.cpp:1085:9:1085:15 | *access to array | semmle.label | *access to array | +| tests.cpp:1086:9:1086:15 | *access to array | semmle.label | *access to array | | tests_restrict.c:15:41:15:44 | **argv | semmle.label | **argv | | tests_restrict.c:15:41:15:44 | **argv | semmle.label | **argv | | tests_restrict.c:15:41:15:44 | *argv | semmle.label | *argv | @@ -97,5 +97,5 @@ subpaths | main.cpp:9:29:9:32 | **argv | tests_restrict.c:15:41:15:44 | **argv | tests_restrict.c:15:41:15:44 | **argv | main.cpp:9:29:9:32 | tests_restrict_main output argument | | main.cpp:9:29:9:32 | *argv | tests_restrict.c:15:41:15:44 | *argv | tests_restrict.c:15:41:15:44 | *argv | main.cpp:9:29:9:32 | tests_restrict_main output argument | #select -| tests.cpp:615:2:615:7 | call to strcpy | main.cpp:6:27:6:30 | **argv | tests.cpp:615:17:615:22 | *source | This 'call to strcpy' with input from $@ may overflow the destination. | main.cpp:6:27:6:30 | **argv | a command-line argument | -| tests.cpp:628:2:628:7 | call to strcpy | main.cpp:6:27:6:30 | **argv | tests.cpp:628:14:628:19 | *home | This 'call to strcpy' with input from $@ may overflow the destination. | main.cpp:6:27:6:30 | **argv | a command-line argument | +| tests.cpp:636:2:636:7 | call to strcpy | main.cpp:6:27:6:30 | **argv | tests.cpp:636:17:636:22 | *source | This 'call to strcpy' with input from $@ may overflow the destination. | main.cpp:6:27:6:30 | **argv | a command-line argument | +| tests.cpp:649:2:649:7 | call to strcpy | main.cpp:6:27:6:30 | **argv | tests.cpp:649:14:649:19 | *home | This 'call to strcpy' with input from $@ may overflow the destination. | main.cpp:6:27:6:30 | **argv | a command-line argument | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/tests.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/tests.cpp index a8173bba1ba..cdef965314b 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/tests.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/tests.cpp @@ -18,7 +18,7 @@ void test1() { char smallbuffer[10]; char bigbuffer[20]; - + memcpy(bigbuffer, smallbuffer, sizeof(smallbuffer)); // GOOD memcpy(bigbuffer, smallbuffer, sizeof(bigbuffer)); // BAD: over-read memcpy(smallbuffer, bigbuffer, sizeof(smallbuffer)); // GOOD @@ -29,7 +29,7 @@ void test2() { char *smallbuffer = (char *)malloc(sizeof(char) * 10); char *bigbuffer = (char *)malloc(sizeof(char) * 20); - + memcpy(bigbuffer, smallbuffer, sizeof(smallbuffer)); // GOOD memcpy(bigbuffer, smallbuffer, sizeof(bigbuffer)); // BAD: over-read [NOT DETECTED] memcpy(smallbuffer, bigbuffer, sizeof(smallbuffer)); // GOOD @@ -59,7 +59,7 @@ void test4(int unbounded) { int bounded = 100; char buffer1[100], buffer2[100]; - + memmove(buffer1, buffer2, bounded); // GOOD memmove(buffer1, buffer2, unbounded); // BAD: may over-write [NOT DETECTED] } @@ -107,11 +107,11 @@ void test6(bool cond) a = -1; buffer[a] = 'x'; // BAD: under-write [NOT DETECTED] ch = buffer[a]; // BAD: under-read [NOT DETECTED] - + b = 0; buffer[b] = 'x'; // GOOD ch = buffer[b]; // GOOD - + c = 100; buffer[c] = 'x'; // BAD: over-write [NOT DETECTED] ch = buffer[c]; // BAD: over-read [NOT DETECTED] @@ -120,7 +120,7 @@ void test6(bool cond) d = 1000; buffer[d] = 'x'; // BAD: over-write [NOT DETECTED] ch = buffer[d]; // BAD: over-read [NOT DETECTED] - + e = 1000; e = 0; buffer[e] = 'x'; // GOOD @@ -130,12 +130,12 @@ void test6(bool cond) if (cond) {f = 1000;} buffer[f] = 'x'; // BAD: may over-write [NOT DETECTED] ch = buffer[f]; // BAD: may over-read [NOT DETECTED] - + g = 1000; if (cond) {g = 0;} buffer[g] = 'x'; // BAD: may over-write [NOT DETECTED] ch = buffer[g]; // BAD: may over-read [NOT DETECTED] - + h = 1000; if (cond) { @@ -151,13 +151,13 @@ void test6(bool cond) buffer[i] = 'x'; // GOOD ch = buffer[i]; // GOOD } - + for (j = -1; j < 100; j++) { buffer[j] = 'x'; // BAD: under-write [NOT DETECTED] ch = buffer[j]; // BAD: under-read [NOT DETECTED] } - + for (k = 0; k <= 100; k++) { buffer[k] = 'x'; // BAD: over-write @@ -187,7 +187,7 @@ void test8(int unbounded) { buffer[i] = 0; // GOOD } - + for (i = 0; i < v2; i++) { buffer[i] = 0; // BAD: over-write [NOT DETECTED] @@ -226,7 +226,7 @@ void test9(int param) memset(buffer3, 0, 33); // BAD: overrun write of buffer3 memset(buffer4, 0, 32); // GOOD memset(buffer4, 0, 33); // BAD: overrun write of buffer4 (buffer3) - + memcmp(buffer1, buffer2, 32); // GOOD memcmp(buffer1, buffer2, 33); // BAD: overrun read of buffer1, buffer2 } @@ -274,7 +274,7 @@ void test11() memset(string, 0, 14); // GOOD memset(string, 0, 15); // BAD: overrun write of string } - + { char *buffer = new char[128]; @@ -284,7 +284,7 @@ void test11() memset(buffer, 0, 128); // BAD: overrun write of buffer } - + { char array[10] = "123"; @@ -309,7 +309,7 @@ void test12() memset(&myVar, 0, sizeof(myVar)); // GOOD memset(&myVar, 0, sizeof(myVar) + 1); // BAD: overrun write of myVar memset(myVar.buffer, 0, 16); // GOOD - memset(myVar.buffer, 0, 17); // BAD: overrun write of myVar.buffer + memset(myVar.buffer, 0, 17); // DUBIOUS: overrun write of myVar.buffer, but not out of myVar itself [NOT DETECTED] memset(&(myVar.field), 0, sizeof(int)); // GOOD memset(&(myVar.field), 0, sizeof(int) * 2); // BAD: overrun write of myVar.field @@ -317,7 +317,7 @@ void test12() memset(buf + 8, 0, 9); // BAD: overrun write of buf [NOT DETECTED] memset(dbuf + 8, 0, 8); // GOOD memset(dbuf + 8, 0, 9); // BAD: overrun write of dbuf [NOT DETECTED] - + { myStruct *myPtr1 = &myVar; myStruct *myPtr2; @@ -331,17 +331,19 @@ void test12() { void *myPtr3 = (void *)(&myVar); - + memset(myPtr3, 0, sizeof(myStruct)); // GOOD memset(myPtr3, 0, sizeof(myStruct) + 1); // BAD: overrun write of myVar } } -void test13() +void test13(char *argArray) { char charArray[10]; int intArray[10]; myStruct structArray[10]; + char *ptrArray = charArray; + char *ptrArrayOffset = charArray + 1; charArray[-1] = 1; // BAD: underrun write charArray[0] = 1; // GOOD @@ -363,7 +365,26 @@ void test13() charArray[9] = (char)intArray[9]; // GOOD charArray[9] = (char)intArray[10]; // BAD: overrun read - + + ptrArray[-2] = 1; // BAD: underrun write + ptrArray[-1] = 1; // BAD: underrun write + ptrArray[0] = 1; // GOOD + ptrArray[8] = 1; // GOOD + ptrArray[9] = 1; // GOOD + ptrArray[10] = 1; // BAD: overrun write + + ptrArrayOffset[-2] = 1; // BAD: underrun write [NOT DETECTED] + ptrArrayOffset[-1] = 1; // GOOD (there is room for this) + ptrArrayOffset[0] = 1; // GOOD + ptrArrayOffset[8] = 1; // GOOD + ptrArrayOffset[9] = 1; // BAD: overrun write [NOT DETECTED] + ptrArrayOffset[10] = 1; // BAD: overrun write [NOT DETECTED] + + argArray[-1] = 1; // BAD: underrun write [NOT DETECTED] + argArray[0] = 1; // GOOD + argArray[1] = 1; // GOOD (we can't tell the length of this array) + argArray[999] = 1; // GOOD (we can't tell the length of this array) + { unsigned short *buffer1 = (unsigned short *)malloc(sizeof(short) * 50); unsigned short *buffer2 = (unsigned short *)malloc(101); // 50.5 shorts @@ -442,13 +463,13 @@ void test17(long long *longArray) { int intArray[5]; - + ((char *)intArray)[-3] = 0; // BAD: underrun write } { int multi[10][10]; - + multi[5][5] = 0; // GOOD multi[-5][5] = 0; // BAD: underrun write [INCORRECT MESSAGE] @@ -511,7 +532,7 @@ void test19(bool b) p2 = (char *)malloc(20); p3 = (char *)malloc(20); } - + // ... if (b) @@ -663,7 +684,7 @@ void test27(){ char buffer[MAX_SIZE]; strncpy(dest, src, 8); // GOOD, strncpy will not read past null terminator of source - + if(IND < MAX_SIZE){ buffer[IND] = 0; // GOOD: out of bounds, but inaccessible code } @@ -739,7 +760,7 @@ struct AnonUnionInStruct unsigned int a_2; unsigned int b_2; }; - }; + }; unsigned int d; void test37() { @@ -869,6 +890,173 @@ struct S2 { } }; +typedef int MyArray[10]; + +typedef struct _MyArrayArray { + struct { + int as[10]; + } bs[10]; + + union { + int i; + char cs[4]; + } ds[10]; + + struct { + MyArray xs; + } ys[10]; +} MyArrayArray; + +void test26() { + MyArrayArray maa; + + maa.bs[0].as[-1] = 0; // BAD: underrun write [NOT DETECTED] + maa.bs[0].as[0] = 0; // GOOD + maa.bs[0].as[99] = 0; // GOOD (overflows into bs[9]) + maa.bs[0].as[100] = 0; // BAD: overrun write [NOT DETECTED] + maa.bs[1].as[-1] = 0; // GOOD (underflows into bs[0]) + maa.bs[1].as[0] = 0; // GOOD + maa.bs[1].as[99] = 0; // BAD: overrun write [NOT DETECTED] + maa.bs[1].as[100] = 0; // BAD: overrun write[ NOT DETECTED] + + maa.ds[0].i = 0; // GOOD + maa.ds[9].i = 0; // GOOD + maa.ds[10].i = 0; // BAD: overrun write [NOT DETECTED] + maa.ds[0].cs[0] = 0; // GOOD + maa.ds[0].cs[3] = 0; // GOOD + maa.ds[0].cs[4] = 0; // GOOD (overflows into vs[1]) + maa.ds[0].cs[39] = 0; // GOOD (overflows into vs[9]) + maa.ds[0].cs[40] = 0; // BAD: overrun write [NOT DETECTED] + maa.ds[9].cs[0] = 0; // GOOD + maa.ds[9].cs[3] = 0; // GOOD + maa.ds[9].cs[4] = 0; // BAD: overrun write [NOT DETECTED] + + maa.ys[0].xs[-1] = 0; // BAD: underrun write [NOT DETECTED] + maa.ys[0].xs[0] = 0; // GOOD + maa.ys[0].xs[99] = 0; // GOOD (overflows into bs[9]) + maa.ys[0].xs[100] = 0; // BAD: overrun write [NOT DETECTED] + maa.ys[1].xs[-1] = 0; // GOOD (underflows into ys[0]) + maa.ys[1].xs[0] = 0; // GOOD + maa.ys[1].xs[99] = 0; // BAD: overrun write [NOT DETECTED] + maa.ys[1].xs[100] = 0; // BAD: overrun write [NOT DETECTED] + + char zs[2][2]; + zs[0][-1] = 0; // BAD: underrun write [NOT DETECTED] + zs[0][0] = 0; // GOOD + zs[0][1] = 0; // GOOD + zs[0][2] = 0; // GOOD + zs[0][3] = 0; // GOOD + zs[0][4] = 0; // BAD: overrun write [NOT DETECTED] + zs[1][-3] = 0; // BAD: underrun write [NOT DETECTED] + zs[1][-2] = 0; // GOOD + zs[1][-1] = 0; // GOOD + zs[1][0] = 0; // GOOD + zs[1][1] = 0; // GOOD + zs[1][2] = 0; // BAD: overrun write [NOT DETECTED] +} + +struct Array10 { + int values[10]; +}; + +void test27(size_t s) { + Array10 arr; + + if (s < sizeof(arr.values[10])) { // GOOD (harmless) + // ... + } + + if (s < offsetof(Array10, values[10])) { // GOOD (harmless) + // ... + } + + if (s < &(arr.values[10]) - &(arr.values[0])) { // GOOD (harmless) + // ... + } +} + +bool cond(); + +void test28() { + int arr[10]; + + int *ptr1 = arr; + ptr1[-1] = 0; // BAD: underrun write + ptr1++; + ptr1[-1] = 0; // GOOD + + int *ptr2 = arr; + ptr2[-1] = 0; // BAD: underrun write + *ptr2++; + ptr2[-1] = 0; // GOOD + + int *ptr3 = arr; + ptr3[-1] = 0; // BAD: underrun write + if (cond()) { + ptr3++; + } + ptr3[-1] = 0; // GOOD (depending what cond() does) + + int *ptr4 = arr; + ptr4[-1] = 0; // BAD: underrun write + while (true) { + ptr4++; + if (cond()) break; + } + ptr4[-1] = 0; // GOOD + + int *ptr5 = arr; + ptr5[-1] = 0; // BAD: underrun write + while (true) { + if (cond()) ptr5++; + if (cond()) break; + } + ptr5[-1] = 0; // GOOD (depending what cond() does) +} + +typedef int myInt29; +typedef myInt29 myArray29[10]; +struct _myStruct29 { + myArray29 arr1; + myInt29 arr2[20]; +}; +typedef _myStruct29 myStruct29; + +void test29() { + myStruct29 *ptr; + + memset(ptr->arr1, 0, sizeof(ptr->arr1) + sizeof(ptr->arr2)); // GOOD (overwrites arr1, arr2) + memset(&(ptr->arr1[0]), 0, sizeof(ptr->arr1) + sizeof(ptr->arr2)); // GOOD (overwrites arr1, arr2) + + memset(ptr->arr1, 0, sizeof(ptr->arr1) + sizeof(ptr->arr2) + 10); // BAD +} + +struct UnionStruct { + int a; + union { + char buffer1[64]; + int b; + }; + union { + char buffer2[64]; + int c; + }; +}; + +void test30() { + UnionStruct us; + + memset(us.buffer1, 0, sizeof(us.buffer1)); // GOOD + memset(us.buffer1, 0, sizeof(us)); // BAD + memset(us.buffer2, 0, sizeof(us.buffer2)); // GOOD + memset(us.buffer2, 0, sizeof(us)); // BAD + + strncpy(us.buffer1, "", sizeof(us.buffer1) - 1); // GOOD + strncpy(us.buffer1, "", sizeof(us) - 1); // BAD + strncpy(us.buffer2, "", sizeof(us.buffer2) - 1); // GOOD + strncpy(us.buffer2, "", sizeof(us) - 1); // BAD +} + int tests_main(int argc, char *argv[]) { long long arr17[19]; @@ -896,6 +1084,11 @@ int tests_main(int argc, char *argv[]) test23(); test24(argv[0]); test25(argv[0]); + test26(); + test27(argc); + test28(); + test29(); + test30(); return 0; } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/var_size_struct.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/var_size_struct.cpp index a514135f348..d4fe3da48bd 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/var_size_struct.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/var_size_struct.cpp @@ -96,9 +96,9 @@ void testNotVarStruct1() { notVarStruct1 *nvs1 = (notVarStruct1 *)malloc(sizeof(notVarStruct1) * 2); memset(nvs1->str, 0, 128); // GOOD - memset(nvs1->str, 0, 129); // BAD: buffer overflow + memset(nvs1->str, 0, 129); // DUBIOUS: buffer overflow (overflows nvs1->str but not nvs1 overall) memset(nvs1[1].str, 0, 128); // GOOD - memset(nvs1[1].str, 0, 129); // BAD: buffer overflow + memset(nvs1[1].str, 0, 129); // BAD: buffer overflow [NOT DETECTED] strncpy(nvs1->str, "Hello, world!", 128); // GOOD strncpy(nvs1->str, "Hello, world!", 129); // BAD } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/VeryLikelyOverrunWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/VeryLikelyOverrunWrite.expected index 641be44149e..7e0acd37525 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/VeryLikelyOverrunWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/VeryLikelyOverrunWrite.expected @@ -16,6 +16,17 @@ | tests.c:136:2:136:8 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 10 bytes. | | tests.c:186:3:186:9 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 2 bytes. | | tests.c:189:3:189:9 | call to sprintf | This 'call to sprintf' operation requires 3 bytes but the destination is only 2 bytes. | -| unions.c:26:2:26:7 | call to strcpy | This 'call to strcpy' operation requires 21 bytes but the destination is only 16 bytes. | -| unions.c:27:2:27:7 | call to strcpy | This 'call to strcpy' operation requires 21 bytes but the destination is only 16 bytes. | +| unions.c:26:2:26:7 | call to strcpy | This 'call to strcpy' operation requires 21 bytes but the destination is only 15 bytes. | +| unions.c:27:2:27:7 | call to strcpy | This 'call to strcpy' operation requires 21 bytes but the destination is only 15 bytes. | | var_size_struct.cpp:22:3:22:8 | call to strcpy | This 'call to strcpy' operation requires 10 bytes but the destination is only 9 bytes. | +| varbuffer.c:15:5:15:10 | call to strcpy | This 'call to strcpy' operation requires 2 bytes but the destination is only 1 bytes. | +| varbuffer.c:16:5:16:10 | call to strcpy | This 'call to strcpy' operation requires 10 bytes but the destination is only 1 bytes. | +| varbuffer.c:23:5:23:10 | call to strcpy | This 'call to strcpy' operation requires 12 bytes but the destination is only 11 bytes. | +| varbuffer.c:24:5:24:10 | call to strcpy | This 'call to strcpy' operation requires 17 bytes but the destination is only 11 bytes. | +| varbuffer.c:39:5:39:10 | call to strcpy | This 'call to strcpy' operation requires 3 bytes but the destination is only 2 bytes. | +| varbuffer.c:40:5:40:10 | call to strcpy | This 'call to strcpy' operation requires 10 bytes but the destination is only 2 bytes. | +| varbuffer.c:45:5:45:10 | call to strcpy | This 'call to strcpy' operation requires 10 bytes but the destination is only 2 bytes. | +| varbuffer.c:46:5:46:10 | call to strcpy | This 'call to strcpy' operation requires 17 bytes but the destination is only 2 bytes. | +| varbuffer.c:60:5:60:10 | call to strcpy | This 'call to strcpy' operation requires 2 bytes but the destination is only 1 bytes. | +| varbuffer.c:61:5:61:10 | call to strcpy | This 'call to strcpy' operation requires 10 bytes but the destination is only 1 bytes. | +| varbuffer.c:67:5:67:10 | call to strcpy | This 'call to strcpy' operation requires 17 bytes but the destination is only 11 bytes. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/varbuffer.c b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/varbuffer.c new file mode 100644 index 00000000000..c4eed5068e5 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/varbuffer.c @@ -0,0 +1,69 @@ +// Further test cases for CWE-120. + +typedef unsigned long size_t; + +typedef struct _MyVarStruct { + size_t len; + char buffer[1]; // variable size buffer +} MyVarStruct; + +void testMyVarStruct() +{ + MyVarStruct *ptr1 = (MyVarStruct*)malloc(sizeof(MyVarStruct)); + ptr1->len = 0; + strcpy(ptr1->buffer, ""); // GOOD + strcpy(ptr1->buffer, "1"); // BAD: length 2, but destination only has length 1 + strcpy(ptr1->buffer, "123456789"); // BAD: length 10, but destination only has length 1 + // ... + + MyVarStruct *ptr2 = (MyVarStruct*)malloc(sizeof(MyVarStruct) + (sizeof(char) * 10)); + ptr2->len = 10; + strcpy(ptr2->buffer, "123456789"); // GOOD + strcpy(ptr2->buffer, "1234567890"); // GOOD + strcpy(ptr2->buffer, "1234567890a"); // BAD: length 12, but destination only has length 11 + strcpy(ptr2->buffer, "1234567890abcdef"); // BAD: length 17, but destination only has length 11 + // ... +} + +typedef struct MyFixedStruct1 { + int len; + char buffer[2]; // assumed to be a fixed size buffer +} MyFixedStruct1; + +void testMyFixedStruct() +{ + MyFixedStruct1 *ptr1 = (MyFixedStruct1 *)malloc(sizeof(MyFixedStruct1)); + ptr1->len = 1; + strcpy(ptr1->buffer, ""); // GOOD + strcpy(ptr1->buffer, "1"); // GOOD + strcpy(ptr1->buffer, "12"); // BAD: length 3, but destination only has length 2 + strcpy(ptr1->buffer, "123456789"); // BAD: length 10, but destination only has length 2 + // ... + + MyFixedStruct1 *ptr2 = (MyFixedStruct1*)malloc(sizeof(MyFixedStruct1) + (sizeof(char) * 10)); + ptr2->len = 11; + strcpy(ptr2->buffer, "123456789"); // BAD / DUBIOUS: length 10, but destination only has length 2 + strcpy(ptr2->buffer, "1234567890abcdef"); // BAD: length 17, but destination only has length 2 + // ... +} + +typedef struct _MyFixedStruct2 { + char buffer[1]; // fixed size buffer + size_t len; +} MyFixedStruct2; + +void testMyFixedStruct2() +{ + MyFixedStruct2 *ptr1 = (MyFixedStruct2 *)malloc(sizeof(MyFixedStruct2)); + ptr1->len = 1; + strcpy(ptr1->buffer, ""); // GOOD + strcpy(ptr1->buffer, "1"); // BAD: length 2, but destination only has length 1 + strcpy(ptr1->buffer, "123456789"); // BAD: length 10, but destination only has length 1 + // ... + + MyFixedStruct2 *ptr2 = (MyFixedStruct2*)malloc(sizeof(MyFixedStruct2) + (sizeof(char) * 10)); + ptr2->len = 11; + strcpy(ptr2->buffer, "123456789"); // BAD: length 10, but destination only has length 1 [NOT DETECTED] + strcpy(ptr2->buffer, "1234567890abcdef"); // BAD: length 17, but destination only has length 1 + // ... +}