@@ -25,15 +25,15 @@ import semmle.code.cpp.models.implementations.Strcat
25
25
import DataFlow:: PathGraph
26
26
27
27
/**
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`.
32
32
*/
33
- predicate interestingConcatenation ( DataFlow:: Node fst , DataFlow:: Node snd ) {
33
+ predicate interestingConcatenation ( DataFlow:: Node incoming , DataFlow:: Node outgoing ) {
34
34
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
37
37
literal = call .getFormat ( ) and
38
38
not literal .getConvSpecOffset ( index ) = 0 and
39
39
literal .getConversionChar ( index ) = [ "s" , "S" ]
@@ -42,16 +42,16 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
42
42
// strcat and friends
43
43
exists ( StrcatFunction strcatFunc , Call call |
44
44
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 ( ) )
47
47
)
48
48
or
49
49
exists ( Call call , Operator op |
50
50
call .getTarget ( ) = op and
51
51
op .hasQualifiedName ( "std" , "operator+" ) and
52
52
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 ( )
55
55
)
56
56
}
57
57
@@ -60,22 +60,23 @@ class ConcatState extends DataFlow::FlowState {
60
60
}
61
61
62
62
class ExecState extends DataFlow:: FlowState {
63
- DataFlow:: Node fst ;
64
- DataFlow:: Node snd ;
63
+ DataFlow:: Node incoming ;
64
+ DataFlow:: Node outgoing ;
65
65
66
66
ExecState ( ) {
67
67
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 ) )
70
71
}
71
72
72
- DataFlow:: Node getFstNode ( ) { result = fst }
73
+ DataFlow:: Node getIncomingNode ( ) { result = incoming }
73
74
74
- DataFlow:: Node getSndNode ( ) { result = snd }
75
+ DataFlow:: Node getOutgoingNode ( ) { result = outgoing }
75
76
76
77
/** Holds if this is a possible `ExecState` for `sink`. */
77
78
predicate isFeasibleForSink ( DataFlow:: Node sink ) {
78
- any ( ExecStateConfiguration conf ) .hasFlow ( snd , sink )
79
+ any ( ExecStateConfiguration conf ) .hasFlow ( outgoing , sink )
79
80
}
80
81
}
81
82
@@ -84,6 +85,12 @@ predicate isSinkImpl(DataFlow::Node sink, Expr command, string callChain) {
84
85
shellCommand ( command , callChain )
85
86
}
86
87
88
+ predicate isSanitizerImpl ( DataFlow:: Node node ) {
89
+ node .asExpr ( ) .getUnspecifiedType ( ) instanceof IntegralType
90
+ or
91
+ node .asExpr ( ) .getUnspecifiedType ( ) instanceof FloatingPointType
92
+ }
93
+
87
94
/**
88
95
* A `TaintTracking` configuration that's used to find the relevant `ExecState`s for a
89
96
* given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
@@ -93,11 +100,13 @@ class ExecStateConfiguration extends TaintTracking2::Configuration {
93
100
ExecStateConfiguration ( ) { this = "ExecStateConfiguration" }
94
101
95
102
override predicate isSource ( DataFlow:: Node source ) {
96
- exists ( ExecState state | state . getSndNode ( ) = source )
103
+ any ( ExecState state ) . getOutgoingNode ( ) = source
97
104
}
98
105
99
106
override predicate isSink ( DataFlow:: Node sink ) { isSinkImpl ( sink , _, _) }
100
107
108
+ override predicate isSanitizer ( DataFlow:: Node node ) { isSanitizerImpl ( node ) }
109
+
101
110
override predicate isSanitizerOut ( DataFlow:: Node node ) {
102
111
isSink ( node , _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
103
112
}
@@ -121,18 +130,11 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
121
130
DataFlow:: FlowState state2
122
131
) {
123
132
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
126
135
}
127
136
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 ) }
136
138
137
139
override predicate isSanitizerOut ( DataFlow:: Node node ) {
138
140
isSink ( node , _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
@@ -146,7 +148,7 @@ where
146
148
conf .hasFlowPath ( sourceNode , sinkNode ) and
147
149
taintCause = sourceNode .getNode ( ) .( FlowSource ) .getSourceType ( ) and
148
150
isSinkImpl ( sinkNode .getNode ( ) , command , callChain ) and
149
- concatResult = sinkNode .getState ( ) .( ExecState ) .getSndNode ( )
151
+ concatResult = sinkNode .getState ( ) .( ExecState ) .getOutgoingNode ( )
150
152
select command , sourceNode , sinkNode ,
151
153
"This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
152
154
+ callChain + "." , sourceNode , "user input (" + taintCause + ")" , concatResult ,
0 commit comments