Skip to content

Commit 99833f1

Browse files
authored
Merge pull request github#5923 from MathiasVP/range-analysis-in-overflow-static
C++: Add range analysis to `cpp/static-buffer-overflow`
2 parents 0c970b5 + 741eed9 commit 99833f1

File tree

3 files changed

+33
-5
lines changed

3 files changed

+33
-5
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm
2+
* The "Static buffer overflow" query (cpp/static-buffer-overflow) has been improved to produce fewer false positives.

cpp/ql/src/Critical/OverflowStatic.ql

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import cpp
1616
import semmle.code.cpp.commons.Buffer
17+
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
1718
import LoopBounds
1819

1920
private predicate staticBufferBase(VariableAccess access, Variable v) {
@@ -51,6 +52,8 @@ predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) {
5152
loop.getStmt().getAChild*() = bufaccess.getEnclosingStmt() and
5253
loop.limit() >= bufaccess.bufferSize() and
5354
loop.counter().getAnAccess() = bufaccess.getArrayOffset() and
55+
// Ensure that we don't have an upper bound on the array index that's less than the buffer size.
56+
not upperBound(bufaccess.getArrayOffset().getFullyConverted()) < bufaccess.bufferSize() and
5457
msg =
5558
"Potential buffer-overflow: counter '" + loop.counter().toString() + "' <= " +
5659
loop.limit().toString() + " but '" + bufaccess.buffer().getName() + "' has " +
@@ -94,17 +97,22 @@ class CallWithBufferSize extends FunctionCall {
9497
}
9598

9699
int statedSizeValue() {
97-
exists(Expr statedSizeSrc |
98-
DataFlow::localExprFlow(statedSizeSrc, statedSizeExpr()) and
99-
result = statedSizeSrc.getValue().toInt()
100-
)
100+
// `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
101+
// result in this case we pick the minimum value obtainable from dataflow and range analysis.
102+
result =
103+
upperBound(statedSizeExpr())
104+
.minimum(min(Expr statedSizeSrc |
105+
DataFlow::localExprFlow(statedSizeSrc, statedSizeExpr())
106+
|
107+
statedSizeSrc.getValue().toInt()
108+
))
101109
}
102110
}
103111

104112
predicate wrongBufferSize(Expr error, string msg) {
105113
exists(CallWithBufferSize call, int bufsize, Variable buf, int statedSize |
106114
staticBuffer(call.buffer(), buf, bufsize) and
107-
statedSize = min(call.statedSizeValue()) and
115+
statedSize = call.statedSizeValue() and
108116
statedSize > bufsize and
109117
error = call.statedSizeExpr() and
110118
msg =

cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/tests.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,23 @@ void test21(bool cond)
586586
if (ptr[-1] == 0) { return; } // GOOD: accesses buffer[1]
587587
}
588588

589+
void test22(bool b, const char* source) {
590+
char buffer[16];
591+
int k;
592+
for (k = 0; k <= 100; k++) {
593+
if(k < 16) {
594+
buffer[k] = 'x'; // GOOD
595+
}
596+
}
597+
598+
char dest[128];
599+
int n = b ? 1024 : 132;
600+
if (n >= 128) {
601+
return;
602+
}
603+
memcpy(dest, source, n); // GOOD
604+
}
605+
589606
int main(int argc, char *argv[])
590607
{
591608
long long arr17[19];
@@ -609,6 +626,7 @@ int main(int argc, char *argv[])
609626
test19(argc == 0);
610627
test20();
611628
test21(argc == 0);
629+
test22(argc == 0, argv[0]);
612630

613631
return 0;
614632
}

0 commit comments

Comments
 (0)