Skip to content

Commit a425e5f

Browse files
author
Ted Reed
committed
Reduce false positives with small heuristics
1 parent 8e1a7fe commit a425e5f

File tree

1 file changed

+26
-19
lines changed

1 file changed

+26
-19
lines changed

cpp/ql/src/Security/CWE/CWE-273/PrivilegeDroppingOutoforder.ql

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,17 @@
1313
*/
1414

1515
import cpp
16-
import semmle.code.cpp.dataflow.TaintTracking
16+
17+
predicate argumentMayBeRoot(Expr e) {
18+
e.getValue() = "0" or
19+
e.(VariableAccess).getTarget().getName().matches("%oot%")
20+
}
1721

1822
class SetuidLikeFunctionCall extends FunctionCall {
1923
SetuidLikeFunctionCall() {
24+
(getTarget().hasGlobalName("setuid") or getTarget().hasGlobalName("setresuid")) and
2025
// setuid/setresuid with the root user are false positives.
21-
getTarget().hasGlobalName("setuid") or
22-
getTarget().hasGlobalName("setresuid")
26+
not argumentMayBeRoot(getArgument(0))
2327
}
2428
}
2529

@@ -41,13 +45,16 @@ class SetuidLikeWrapperCall extends FunctionCall {
4145

4246
class CallBeforeSetuidFunctionCall extends FunctionCall {
4347
CallBeforeSetuidFunctionCall() {
44-
// setgid/setresgid with the root group are false positives.
45-
getTarget().hasGlobalName("setgid") or
46-
getTarget().hasGlobalName("setresgid") or
47-
// Compatibility may require skipping initgroups and setgroups return checks.
48-
// A stricter best practice is to check the result and errnor for EPERM.
49-
getTarget().hasGlobalName("initgroups") or
50-
getTarget().hasGlobalName("setgroups")
48+
(
49+
getTarget().hasGlobalName("setgid") or
50+
getTarget().hasGlobalName("setresgid") or
51+
// Compatibility may require skipping initgroups and setgroups return checks.
52+
// A stricter best practice is to check the result and errnor for EPERM.
53+
getTarget().hasGlobalName("initgroups") or
54+
getTarget().hasGlobalName("setgroups")
55+
) and
56+
// setgid/setresgid/etc with the root group are false positives.
57+
not argumentMayBeRoot(getArgument(0))
5158
}
5259
}
5360

@@ -73,12 +80,11 @@ predicate setuidBeforeSetgid(
7380
setgidWrapper.getAPredecessor+() = setuidWrapper
7481
}
7582

76-
predicate flowsToCondition(Expr fc) {
77-
exists(DataFlow::Node source, DataFlow::Node sink |
78-
TaintTracking::localTaint(source, sink) and
79-
fc = source.asExpr() and
80-
(sink.asExpr().getParent*().(ControlFlowNode).isCondition() or sink.asExpr().isCondition())
81-
)
83+
predicate isAccessed(FunctionCall fc) {
84+
exists(Variable v | v.getAnAssignedValue() = fc) or
85+
exists(Operation c | fc = c.getAChild() | c.isCondition()) or
86+
// ignore pattern where result is intentionally ignored by a cast to void.
87+
fc.hasExplicitConversion()
8288
}
8389

8490
from
@@ -87,11 +93,12 @@ from
8793
SetuidLikeFunctionCall setuid
8894
where
8995
setuidBeforeSetgid(setuid, fc) and
90-
// Require the call return code to be used in a condition.
96+
// Require the call return code to be used in a condition or assigned.
9197
// This introduces false negatives where the return is checked but then
9298
// errno == EPERM allows execution to continue.
93-
(not flowsToCondition(fc) or not flowsToCondition(setuid)) and
99+
not isAccessed(fc) and
94100
func = fc.getEnclosingFunction()
95101
select fc, "This function is called within " + func + ", and potentially after " +
96-
"$@, and may not succeed. Be sure to check the return code and errno.",
102+
"$@, and may not succeed. Be sure to check the return code and errno, otherwise permissions " +
103+
"may not be dropped.",
97104
setuid, setuid.getTarget().getName()

0 commit comments

Comments
 (0)