Skip to content

Commit aeae208

Browse files
authored
Merge pull request #15456 from MathiasVP/fix-scanf-fp
C++: Fix FP in `cpp/incorrectly-checked-scanf`
2 parents 391ca5d + 044d94c commit aeae208

File tree

4 files changed

+44
-0
lines changed

4 files changed

+44
-0
lines changed

Diff for: cpp/ql/src/Critical/ScanfChecks.qll

+27
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,37 @@ private predicate isLinuxKernel() {
2020
exists(Macro macro | macro.getName() in ["_LINUX_KERNEL_SPRINTF_H_", "_LINUX_KERNEL_H"])
2121
}
2222

23+
/**
24+
* Gets the value of the EOF macro.
25+
*
26+
* This is typically `"-1"`, but this is not guaranteed to be the case on all
27+
* systems.
28+
*/
29+
private string getEofValue() {
30+
exists(MacroInvocation mi |
31+
mi.getMacroName() = "EOF" and
32+
result = unique( | | mi.getExpr().getValue())
33+
)
34+
}
35+
36+
/**
37+
* Holds if the value of `call` has been checked to not equal `EOF`.
38+
*/
39+
private predicate checkedForEof(ScanfFunctionCall call) {
40+
exists(IRGuardCondition gc |
41+
exists(Instruction i, ConstantInstruction eof |
42+
eof.getValue() = getEofValue() and
43+
i.getUnconvertedResultExpression() = call and
44+
gc.comparesEq(valueNumber(i).getAUse(), eof.getAUse(), 0, _, _)
45+
)
46+
)
47+
}
48+
2349
/**
2450
* Holds if `call` is a `scanf`-like call were the result is only checked against 0, but it can also return EOF.
2551
*/
2652
predicate incorrectlyCheckedScanf(ScanfFunctionCall call) {
2753
exprInBooleanContext(call) and
54+
not checkedForEof(call) and
2855
not isLinuxKernel() // scanf in the linux kernel can't return EOF
2956
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The "Incorrect return-value check for a 'scanf'-like function" query (`cpp/incorrectly-checked-scanf`) no longer reports an alert when an explicit check for EOF is added.

Diff for: cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.expected

+1
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
| test.cpp:404:25:404:25 | u | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:403:6:403:11 | call to sscanf | call to sscanf |
1515
| test.cpp:416:7:416:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:413:7:413:11 | call to scanf | call to scanf |
1616
| test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
17+
| test.cpp:460:6:460:10 | value | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:455:12:455:17 | call to sscanf | call to sscanf |

Diff for: cpp/ql/test/query-tests/Critical/MissingCheckScanf/test.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -446,4 +446,16 @@ void bad_check() {
446446
}
447447
use(i); // GOOD [FALSE POSITIVE]: Technically no security issue, but code is incorrect.
448448
}
449+
}
450+
451+
#define EOF (-1)
452+
453+
void disjunct_boolean_condition(const char* modifier_data) {
454+
long value;
455+
auto rc = sscanf(modifier_data, "%lx", &value);
456+
457+
if((rc == EOF) || (rc == 0)) {
458+
return;
459+
}
460+
use(value); // GOOD
449461
}

0 commit comments

Comments
 (0)