Skip to content

Commit

Permalink
[analyzer] CStringChecker should check the first byte of the destinat…
Browse files Browse the repository at this point in the history
…ion of strcpy, strncpy

By not checking if the first byte of the destination of strcpy and
strncpy is writable, we missed some reports in the Juliet benchmark.

(Juliet CWE-124 Buffer Underwrite: strcpy, strncpy)
https://discourse.llvm.org/t/patches-inspired-by-the-juliet-benchmark/73106

Differential Revision: https://reviews.llvm.org/D159108
  • Loading branch information
steakhal committed Sep 11, 2023
1 parent 4b9259b commit c3a87dd
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
10 changes: 10 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,11 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
SVal maxLastElement =
svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);

// Check if the first byte of the destination is writable.
state = CheckLocation(C, state, Dst, DstVal, AccessKind::write);
if (!state)
return;
// Check if the last byte of the destination is writable.
state = CheckLocation(C, state, Dst, maxLastElement, AccessKind::write);
if (!state)
return;
Expand All @@ -2021,6 +2026,11 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,

// ...and we haven't checked the bound, we'll check the actual copy.
if (!boundWarning) {
// Check if the first byte of the destination is writable.
state = CheckLocation(C, state, Dst, DstVal, AccessKind::write);
if (!state)
return;
// Check if the last byte of the destination is writable.
state = CheckLocation(C, state, Dst, lastElement, AccessKind::write);
if (!state)
return;
Expand Down
46 changes: 46 additions & 0 deletions clang/test/Analysis/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -1667,3 +1667,49 @@ void strcpy_no_overflow_2(char *y) {
strcpy(x, "12\0");
}
#endif

#ifndef SUPPRESS_OUT_OF_BOUND
void testStrcpyDestinationWritableFirstByte(void) {
char dst[10];
char *p = dst - 8;
strcpy(p, "src"); // expected-warning {{String copy function overflows the destination buffer}}
}

void CWE124_Buffer_Underwrite__malloc_char_cpy() {
char * dataBuffer = (char *)malloc(100*sizeof(char));
if (dataBuffer == NULL) return;
memset(dataBuffer, 'A', 100-1);
dataBuffer[100-1] = '\0';
char * data = dataBuffer - 8;
char source[100];
memset(source, 'C', 100-1); // fill with 'C's
source[100-1] = '\0'; // null terminate
strcpy(data, source); // expected-warning {{String copy function overflows the destination buffer}}
free(dataBuffer);
}
#endif

#ifndef SUPPRESS_OUT_OF_BOUND
void testStrncpyDestinationWritableFirstByte(void) {
char source[100];
use_string(source); // escape
char buf[100];
char *p = buf - 8;
strncpy(p, source, 100-1); // expected-warning {{String copy function overflows the destination buffer}}
}

void CWE124_Buffer_Underwrite__malloc_char_ncpy() {
char * dataBuffer = (char *)malloc(100*sizeof(char));
if (dataBuffer == 0) return;
memset(dataBuffer, 'A', 100-1);
dataBuffer[100-1] = '\0';
char *data = dataBuffer - 8;

char source[100];
memset(source, 'C', 100-1); // fill with 'C's
source[100-1] = '\0'; // null terminate
strncpy(data, source, 100-1); // expected-warning {{String copy function overflows the destination buffer}}
data[100-1] = '\0'; // null terminate
free(dataBuffer);
}
#endif

0 comments on commit c3a87dd

Please sign in to comment.