@@ -25,15 +25,15 @@ import semmle.code.cpp.models.implementations.Strcat
2525import DataFlow:: PathGraph
2626
2727/**
28- * Holds if `fst ` is a string that is used in a format or concatenation function resulting in `snd`,
29- * and is *not* placed at the start of the resulting string. This indicates that the author did not
30- * expect `fst ` to control what program is run if the resulting string is eventually interpreted as
31- * a command line, for example as an argument to `system`.
28+ * Holds if `incoming ` is a string that is used in a format or concatenation function resulting
29+ * in `outgoing`, and is *not* placed at the start of the resulting string. This indicates that
30+ * the author did not expect `incoming ` to control what program is run if the resulting string
31+ * is eventually interpreted as a command line, for example as an argument to `system`.
3232 */
33- predicate interestingConcatenation ( DataFlow:: Node fst , DataFlow:: Node snd ) {
33+ predicate interestingConcatenation ( DataFlow:: Node incoming , DataFlow:: Node outgoing ) {
3434 exists ( FormattingFunctionCall call , int index , FormatLiteral literal |
35- fst .asIndirectArgument ( ) = call .getConversionArgument ( index ) and
36- snd .asDefiningArgument ( ) = call .getOutputArgument ( false ) and
35+ incoming .asIndirectArgument ( ) = call .getConversionArgument ( index ) and
36+ outgoing .asDefiningArgument ( ) = call .getOutputArgument ( false ) and
3737 literal = call .getFormat ( ) and
3838 not literal .getConvSpecOffset ( index ) = 0 and
3939 literal .getConversionChar ( index ) = [ "s" , "S" ]
@@ -42,16 +42,16 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
4242 // strcat and friends
4343 exists ( StrcatFunction strcatFunc , Call call |
4444 call .getTarget ( ) = strcatFunc and
45- fst .asIndirectArgument ( ) = call .getArgument ( strcatFunc .getParamSrc ( ) ) and
46- snd .asDefiningArgument ( ) = call .getArgument ( strcatFunc .getParamDest ( ) )
45+ incoming .asIndirectArgument ( ) = call .getArgument ( strcatFunc .getParamSrc ( ) ) and
46+ outgoing .asDefiningArgument ( ) = call .getArgument ( strcatFunc .getParamDest ( ) )
4747 )
4848 or
4949 exists ( Call call , Operator op |
5050 call .getTarget ( ) = op and
5151 op .hasQualifiedName ( "std" , "operator+" ) and
5252 op .getType ( ) .( UserType ) .hasQualifiedName ( "std" , "basic_string" ) and
53- fst .asIndirectArgument ( ) = call .getArgument ( 1 ) and // left operand
54- call = snd .asInstruction ( ) .getUnconvertedResultExpression ( )
53+ incoming .asIndirectArgument ( ) = call .getArgument ( 1 ) and // left operand
54+ call = outgoing .asInstruction ( ) .getUnconvertedResultExpression ( )
5555 )
5656}
5757
@@ -60,22 +60,23 @@ class ConcatState extends DataFlow::FlowState {
6060}
6161
6262class ExecState extends DataFlow:: FlowState {
63- DataFlow:: Node fst ;
64- DataFlow:: Node snd ;
63+ DataFlow:: Node incoming ;
64+ DataFlow:: Node outgoing ;
6565
6666 ExecState ( ) {
6767 this =
68- "ExecState (" + fst .getLocation ( ) + " | " + fst + ", " + snd .getLocation ( ) + " | " + snd + ")" and
69- interestingConcatenation ( pragma [ only_bind_into ] ( fst ) , pragma [ only_bind_into ] ( snd ) )
68+ "ExecState (" + incoming .getLocation ( ) + " | " + incoming + ", " + outgoing .getLocation ( ) +
69+ " | " + outgoing + ")" and
70+ interestingConcatenation ( pragma [ only_bind_into ] ( incoming ) , pragma [ only_bind_into ] ( outgoing ) )
7071 }
7172
72- DataFlow:: Node getFstNode ( ) { result = fst }
73+ DataFlow:: Node getIncomingNode ( ) { result = incoming }
7374
74- DataFlow:: Node getSndNode ( ) { result = snd }
75+ DataFlow:: Node getOutgoingNode ( ) { result = outgoing }
7576
7677 /** Holds if this is a possible `ExecState` for `sink`. */
7778 predicate isFeasibleForSink ( DataFlow:: Node sink ) {
78- any ( ExecStateConfiguration conf ) .hasFlow ( snd , sink )
79+ any ( ExecStateConfiguration conf ) .hasFlow ( outgoing , sink )
7980 }
8081}
8182
@@ -84,6 +85,12 @@ predicate isSinkImpl(DataFlow::Node sink, Expr command, string callChain) {
8485 shellCommand ( command , callChain )
8586}
8687
88+ predicate isSanitizerImpl ( DataFlow:: Node node ) {
89+ node .asExpr ( ) .getUnspecifiedType ( ) instanceof IntegralType
90+ or
91+ node .asExpr ( ) .getUnspecifiedType ( ) instanceof FloatingPointType
92+ }
93+
8794/**
8895 * A `TaintTracking` configuration that's used to find the relevant `ExecState`s for a
8996 * given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
@@ -93,11 +100,13 @@ class ExecStateConfiguration extends TaintTracking2::Configuration {
93100 ExecStateConfiguration ( ) { this = "ExecStateConfiguration" }
94101
95102 override predicate isSource ( DataFlow:: Node source ) {
96- exists ( ExecState state | state . getSndNode ( ) = source )
103+ any ( ExecState state ) . getOutgoingNode ( ) = source
97104 }
98105
99106 override predicate isSink ( DataFlow:: Node sink ) { isSinkImpl ( sink , _, _) }
100107
108+ override predicate isSanitizer ( DataFlow:: Node node ) { isSanitizerImpl ( node ) }
109+
101110 override predicate isSanitizerOut ( DataFlow:: Node node ) {
102111 isSink ( node , _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
103112 }
@@ -121,18 +130,11 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
121130 DataFlow:: FlowState state2
122131 ) {
123132 state1 instanceof ConcatState and
124- state2 .( ExecState ) .getFstNode ( ) = node1 and
125- state2 .( ExecState ) .getSndNode ( ) = node2
133+ state2 .( ExecState ) .getIncomingNode ( ) = node1 and
134+ state2 .( ExecState ) .getOutgoingNode ( ) = node2
126135 }
127136
128- override predicate isSanitizer ( DataFlow:: Node node , DataFlow:: FlowState state ) {
129- (
130- node .asInstruction ( ) .getResultType ( ) instanceof IntegralType
131- or
132- node .asInstruction ( ) .getResultType ( ) instanceof FloatingPointType
133- ) and
134- state instanceof ConcatState
135- }
137+ override predicate isSanitizer ( DataFlow:: Node node ) { isSanitizerImpl ( node ) }
136138
137139 override predicate isSanitizerOut ( DataFlow:: Node node ) {
138140 isSink ( node , _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
@@ -146,7 +148,7 @@ where
146148 conf .hasFlowPath ( sourceNode , sinkNode ) and
147149 taintCause = sourceNode .getNode ( ) .( FlowSource ) .getSourceType ( ) and
148150 isSinkImpl ( sinkNode .getNode ( ) , command , callChain ) and
149- concatResult = sinkNode .getState ( ) .( ExecState ) .getSndNode ( )
151+ concatResult = sinkNode .getState ( ) .( ExecState ) .getOutgoingNode ( )
150152select command , sourceNode , sinkNode ,
151153 "This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
152154 + callChain + "." , sourceNode , "user input (" + taintCause + ")" , concatResult ,
0 commit comments