Skip to content

Commit de04b7d

Browse files
authored
[analyzer] Fix core.VLASize checker false positive taint reports (#68140)
The checker reported a false positive on this code void testTaintedSanitizedVLASize(void) { int x; scanf("%d", &x); if (x<1) return; int vla[x]; // no-warning } After the fix, the checker only emits tainted warning if the vla size is coming from a tainted source and it cannot prove that it is positive.
1 parent 4419b2c commit de04b7d

File tree

4 files changed

+44
-14
lines changed

4 files changed

+44
-14
lines changed

clang/docs/analyzer/checkers.rst

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,8 @@ Check for undefined results of binary operators.
213213
214214
core.VLASize (C)
215215
""""""""""""""""
216-
Check for declarations of Variable Length Arrays of undefined or zero size.
217-
218-
Check for declarations of VLA of undefined or zero size.
216+
Check for declarations of Variable Length Arrays (VLA) of undefined, zero or negative
217+
size.
219218
220219
.. code-block:: c
221220
@@ -229,6 +228,28 @@ Check for declarations of Variable Length Arrays of undefined or zero size.
229228
int vla2[x]; // warn: zero size
230229
}
231230
231+
232+
The checker also gives warning if the `TaintPropagation` checker is switched on
233+
and an unbound, attacker controlled (tainted) value is used to define
234+
the size of the VLA.
235+
236+
.. code-block:: c
237+
238+
void taintedVLA(void) {
239+
int x;
240+
scanf("%d", &x);
241+
int vla[x]; // Declared variable-length array (VLA) has tainted (attacker controlled) size, that can be 0 or negative
242+
}
243+
244+
void taintedVerfieidVLA(void) {
245+
int x;
246+
scanf("%d", &x);
247+
if (x<1)
248+
return;
249+
int vla[x]; // no-warning. The analyzer can prove that x must be positive.
250+
}
251+
252+
232253
.. _core-uninitialized-ArraySubscript:
233254
234255
core.uninitialized.ArraySubscript (C)

clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,6 @@ ProgramStateRef VLASizeChecker::checkVLAIndexSize(CheckerContext &C,
164164
if (SizeV.isUnknown())
165165
return nullptr;
166166

167-
// Check if the size is tainted.
168-
if (isTainted(State, SizeV)) {
169-
reportTaintBug(SizeE, State, C, SizeV);
170-
return nullptr;
171-
}
172-
173167
// Check if the size is zero.
174168
DefinedSVal SizeD = SizeV.castAs<DefinedSVal>();
175169

@@ -192,10 +186,10 @@ ProgramStateRef VLASizeChecker::checkVLAIndexSize(CheckerContext &C,
192186

193187
SVal LessThanZeroVal =
194188
SVB.evalBinOp(State, BO_LT, SizeD, Zero, SVB.getConditionType());
189+
ProgramStateRef StatePos, StateNeg;
195190
if (std::optional<DefinedSVal> LessThanZeroDVal =
196191
LessThanZeroVal.getAs<DefinedSVal>()) {
197192
ConstraintManager &CM = C.getConstraintManager();
198-
ProgramStateRef StatePos, StateNeg;
199193

200194
std::tie(StateNeg, StatePos) = CM.assumeDual(State, *LessThanZeroDVal);
201195
if (StateNeg && !StatePos) {
@@ -205,6 +199,12 @@ ProgramStateRef VLASizeChecker::checkVLAIndexSize(CheckerContext &C,
205199
State = StatePos;
206200
}
207201

202+
// Check if the size is tainted.
203+
if ((StateNeg || StateZero) && isTainted(State, SizeV)) {
204+
reportTaintBug(SizeE, State, C, SizeV);
205+
return nullptr;
206+
}
207+
208208
return State;
209209
}
210210

@@ -218,7 +218,7 @@ void VLASizeChecker::reportTaintBug(const Expr *SizeE, ProgramStateRef State,
218218
SmallString<256> buf;
219219
llvm::raw_svector_ostream os(buf);
220220
os << "Declared variable-length array (VLA) ";
221-
os << "has tainted size";
221+
os << "has tainted (attacker controlled) size that can be 0 or negative";
222222

223223
auto report = std::make_unique<PathSensitiveBugReport>(TaintBT, os.str(), N);
224224
report->addRange(SizeE->getSourceRange());

clang/test/Analysis/taint-diagnostic-visitor.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ void taintDiagnosticVLA(void) {
4646
scanf("%d", &x); // expected-note {{Value assigned to 'x'}}
4747
// expected-note@-1 {{Taint originated here}}
4848
// expected-note@-2 {{Taint propagated to the 2nd argument}}
49-
int vla[x]; // expected-warning {{Declared variable-length array (VLA) has tainted size}}
50-
// expected-note@-1 {{Declared variable-length array (VLA) has tainted size}}
49+
int vla[x]; // expected-warning {{Declared variable-length array (VLA) has tainted}}
50+
// expected-note@-1 {{Declared variable-length array (VLA) has tainted}}
5151
}
5252

5353

clang/test/Analysis/taint-generic.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,16 @@ int testDivByZero(void) {
405405
void testTaintedVLASize(void) {
406406
int x;
407407
scanf("%d", &x);
408-
int vla[x]; // expected-warning{{Declared variable-length array (VLA) has tainted size}}
408+
int vla[x]; // expected-warning{{Declared variable-length array (VLA) has tainted (attacker controlled) size that can be 0 or negative}}
409+
}
410+
411+
// Tainted-sanitized VLAs.
412+
void testTaintedSanitizedVLASize(void) {
413+
int x;
414+
scanf("%d", &x);
415+
if (x<1)
416+
return;
417+
int vla[x]; // no-warning
409418
}
410419

411420
int testTaintedAllocaMem() {

0 commit comments

Comments
 (0)