Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Brodes/overflow buffer fixes upstream #17384

Merged
merged 11 commits into from
Sep 11, 2024
2 changes: 1 addition & 1 deletion cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ private int isSource(Expr bufferExpr, Element why) {
exists(Type bufferType |
// buffer is the address of a variable
why = bufferExpr.(AddressOfExpr).getAddressable() and
bufferType = why.(Variable).getType() and
bufferType = why.(Variable).getUnspecifiedType() and
result = bufferType.getSize() and
not bufferType instanceof ReferenceType and
not any(Union u).getAMemberVariable() = why
Expand Down
10 changes: 8 additions & 2 deletions cpp/ql/lib/semmle/code/cpp/security/BufferAccess.qll
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ int getPointedSize(Type t) {
* BufferWrite differ.
*/
abstract class BufferAccess extends Expr {
BufferAccess() { not this.isUnevaluated() }
BufferAccess() {
not this.isUnevaluated() and
//A buffer access must be reachable (not in dead code)
reachable(this)
}

abstract string getName();

Expand All @@ -26,6 +30,8 @@ abstract class BufferAccess extends Expr {
* - 1 = buffer range [0, getSize) is accessed entirely.
* - 2 = buffer range [0, getSize) may be accessed partially or entirely.
* - 3 = buffer is accessed at offset getSize - 1.
* - 4 = buffer is accessed with null terminator read protections
* (does not read past null terminator, regardless of access size)
*/
abstract Expr getBuffer(string bufferDesc, int accessType);

Expand Down Expand Up @@ -128,7 +134,7 @@ class StrncpyBA extends BufferAccess {
or
result = this.(FunctionCall).getArgument(1) and
bufferDesc = "source buffer" and
accessType = 2
geoffw0 marked this conversation as resolved.
Show resolved Hide resolved
accessType = 4
}

override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
Expand Down
4 changes: 3 additions & 1 deletion cpp/ql/src/Critical/OverflowStatic.ql
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ class BufferAccess extends ArrayExpr {
not exists(Macro m |
m.getName() = "strcmp" and
m.getAnInvocation().getAnExpandedElement() = this
)
) and
//A buffer access must be reachable (not in dead code)
reachable(this)
}

int bufferSize() { staticBuffer(this.getArrayBase(), _, result) }
Expand Down
1 change: 1 addition & 0 deletions cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ from
BufferAccess ba, string bufferDesc, int accessSize, int accessType, Element bufferAlloc,
int bufferSize, string message
where
accessType != 4 and
accessSize = ba.getSize() and
bufferSize = getBufferSize(ba.getBuffer(bufferDesc, accessType), bufferAlloc) and
(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Removed false positives caused by buffer accesses in unreachable code
* Removed false positives caused by inconsistent type checking
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ 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:657:32:657:35 | **argv | provenance | |
| main.cpp:10:20:10:23 | *argv | tests.cpp:657:32:657:35 | **argv | provenance | |
| main.cpp:10:20:10:23 | *argv | tests.cpp:657:32:657:35 | *argv | provenance | |
| main.cpp:10:20:10:23 | **argv | tests.cpp:689:32:689:35 | **argv | provenance | |
| main.cpp:10:20:10:23 | *argv | tests.cpp:689:32:689:35 | **argv | provenance | |
| main.cpp:10:20:10:23 | *argv | tests.cpp:689:32:689: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 | |
Expand All @@ -46,12 +46,12 @@ edges
| 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:657:32:657:35 | **argv | tests.cpp:682:9:682:15 | *access to array | provenance | |
| tests.cpp:657:32:657:35 | **argv | tests.cpp:683:9:683:15 | *access to array | provenance | |
| tests.cpp:657:32:657:35 | *argv | tests.cpp:682:9:682:15 | *access to array | provenance | |
| tests.cpp:657:32:657:35 | *argv | tests.cpp:683:9:683:15 | *access to array | provenance | |
| tests.cpp:682:9:682:15 | *access to array | tests.cpp:613:19:613:24 | *source | provenance | |
| tests.cpp:683:9:683:15 | *access to array | tests.cpp:622:19:622:24 | *source | provenance | |
| tests.cpp:689:32:689:35 | **argv | tests.cpp:714:9:714:15 | *access to array | provenance | |
| tests.cpp:689:32:689:35 | **argv | tests.cpp:715:9:715:15 | *access to array | provenance | |
| tests.cpp:689:32:689:35 | *argv | tests.cpp:714:9:714:15 | *access to array | provenance | |
| tests.cpp:689:32:689:35 | *argv | tests.cpp:715:9:715:15 | *access to array | provenance | |
| tests.cpp:714:9:714:15 | *access to array | tests.cpp:613:19:613:24 | *source | provenance | |
| tests.cpp:715:9:715:15 | *access to array | tests.cpp:622:19:622: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
Expand Down Expand Up @@ -85,10 +85,10 @@ nodes
| 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:657:32:657:35 | **argv | semmle.label | **argv |
| tests.cpp:657:32:657:35 | *argv | semmle.label | *argv |
| tests.cpp:682:9:682:15 | *access to array | semmle.label | *access to array |
| tests.cpp:683:9:683:15 | *access to array | semmle.label | *access to array |
| tests.cpp:689:32:689:35 | **argv | semmle.label | **argv |
| tests.cpp:689:32:689:35 | *argv | semmle.label | *argv |
| tests.cpp:714:9:714:15 | *access to array | semmle.label | *access to array |
| tests.cpp:715:9:715: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 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,38 @@ void test26(bool cond)
if (ptr[-1] == 0) { return; } // GOOD: accesses buffer[1]
}

#define IND 100
#define MAX_SIZE 100
void test27(){
char *src = "";
char *dest = "abcdefgh";
int ind = 100;
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
}
}

typedef struct _MYSTRUCT {
unsigned long a;
unsigned short b;
unsigned char z[ 100 ];
} MYSTRUCT;


const MYSTRUCT _myStruct = { 0 };
typedef const MYSTRUCT& MYSTRUCTREF;

// False positive case due to use of typedefs
int test28(MYSTRUCTREF g)
{
return memcmp(&g, &_myStruct, sizeof(MYSTRUCT)); // GOOD
}


int tests_main(int argc, char *argv[])
{
long long arr17[19];
Expand Down
Loading