1313 */
1414
1515import 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
1822class 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
4246class 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
8490from
8793 SetuidLikeFunctionCall setuid
8894where
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 ( )
95101select 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