Skip to content

C++: Fix FP in cpp/incorrectly-checked-scanf #15456

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

Merged
merged 4 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions cpp/ql/src/Critical/ScanfChecks.qll
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,37 @@ private predicate isLinuxKernel() {
exists(Macro macro | macro.getName() in ["_LINUX_KERNEL_SPRINTF_H_", "_LINUX_KERNEL_H"])
}

/**
* Gets the value of the EOF macro.
*
* This is typically `"-1"`, but this is not guaranteed to be the case on all
* systems.
*/
private string getEofValue() {
exists(MacroInvocation mi |
mi.getMacroName() = "EOF" and
result = unique( | | mi.getExpr().getValue())
)
}

/**
* Holds if the value of `call` has been checked to not equal `EOF`.
*/
private predicate checkedForEof(ScanfFunctionCall call) {
exists(IRGuardCondition gc |
exists(Instruction i, ConstantInstruction eof |
eof.getValue() = getEofValue() and
i.getUnconvertedResultExpression() = call and
gc.comparesEq(valueNumber(i).getAUse(), eof.getAUse(), 0, _, _)
)
)
}

/**
* Holds if `call` is a `scanf`-like call were the result is only checked against 0, but it can also return EOF.
*/
predicate incorrectlyCheckedScanf(ScanfFunctionCall call) {
exprInBooleanContext(call) and
not checkedForEof(call) and
not isLinuxKernel() // scanf in the linux kernel can't return EOF
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* 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.
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
| 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 |
| 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 |
| 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 |
| 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 |
12 changes: 12 additions & 0 deletions cpp/ql/test/query-tests/Critical/MissingCheckScanf/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,4 +446,16 @@ void bad_check() {
}
use(i); // GOOD [FALSE POSITIVE]: Technically no security issue, but code is incorrect.
}
}

#define EOF (-1)

void disjunct_boolean_condition(const char* modifier_data) {
long value;
auto rc = sscanf(modifier_data, "%lx", &value);

if((rc == EOF) || (rc == 0)) {
return;
}
use(value); // GOOD
}