@@ -21,14 +21,6 @@ import semmle.code.cpp.ir.IR
21
21
import semmle.code.cpp.ir.ValueNumbering
22
22
import ScanfChecks
23
23
24
- /** Holds if `n` reaches an argument to a call to a `scanf`-like function. */
25
- pragma [ nomagic]
26
- predicate revFlow0 ( Node n ) {
27
- isSink ( _, _, n , _)
28
- or
29
- exists ( Node succ | revFlow0 ( succ ) | localFlowStep ( n , succ ) )
30
- }
31
-
32
24
/**
33
25
* Holds if `n` represents an uninitialized stack-allocated variable, or a
34
26
* newly (and presumed uninitialized) heap allocation.
@@ -38,30 +30,45 @@ predicate isUninitialized(Node n) {
38
30
n .asIndirectExpr ( 1 ) instanceof AllocationExpr
39
31
}
40
32
41
- pragma [ nomagic]
42
- predicate fwdFlow0 ( Node n ) {
43
- revFlow0 ( n ) and
44
- (
45
- isUninitialized ( n )
46
- or
47
- exists ( Node prev |
48
- fwdFlow0 ( prev ) and
49
- localFlowStep ( prev , n )
50
- )
51
- )
52
- }
53
-
54
33
predicate isSink ( ScanfFunctionCall call , int index , Node n , Expr input ) {
55
34
input = call .getOutputArgument ( index ) and
56
35
n .asIndirectExpr ( ) = input
57
36
}
58
37
38
+ /**
39
+ * A configuration to track a uninitialized data flowing to a `scanf`-like
40
+ * output parameter position.
41
+ *
42
+ * This is meant to be a simple flow to rule out cases like:
43
+ * ```
44
+ * int x = 0;
45
+ * scanf(..., &x);
46
+ * use(x);
47
+ * ```
48
+ * since `x` is already initialized it's not a security concern that `x` is
49
+ * used without checking the return value of `scanf`.
50
+ *
51
+ * Since this flow is meant to be simple, we disable field flow and require the
52
+ * source and the sink to be in the same callable.
53
+ */
54
+ module UninitializedToScanfConfig implements ConfigSig {
55
+ predicate isSource ( Node source ) { isUninitialized ( source ) }
56
+
57
+ predicate isSink ( Node sink ) { isSink ( _, _, sink , _) }
58
+
59
+ FlowFeature getAFeature ( ) { result instanceof FeatureEqualSourceSinkCallContext }
60
+
61
+ int accessPathLimit ( ) { result = 0 }
62
+ }
63
+
64
+ module UninitializedToScanfFlow = Global< UninitializedToScanfConfig > ;
65
+
59
66
/**
60
67
* Holds if `call` is a `scanf`-like call and `output` is the `index`'th
61
68
* argument that has not been previously initialized.
62
69
*/
63
70
predicate isRelevantScanfCall ( ScanfFunctionCall call , int index , Expr output ) {
64
- exists ( Node n | fwdFlow0 ( n ) and isSink ( call , index , n , output ) ) and
71
+ exists ( Node n | UninitializedToScanfFlow :: flowTo ( n ) and isSink ( call , index , n , output ) ) and
65
72
// Exclude results from incorrectky checked scanf query
66
73
not incorrectlyCheckedScanf ( call )
67
74
}
@@ -77,31 +84,6 @@ predicate isSource(ScanfFunctionCall call, int index, Node n, Expr output) {
77
84
n .asDefiningArgument ( ) = output
78
85
}
79
86
80
- /**
81
- * Holds if `n` is reachable from an output argument of a relevant call to
82
- * a `scanf`-like function.
83
- */
84
- pragma [ nomagic]
85
- predicate fwdFlow ( Node n ) {
86
- isSource ( _, _, n , _)
87
- or
88
- exists ( Node prev |
89
- fwdFlow ( prev ) and
90
- localFlowStep ( prev , n ) and
91
- not isSanitizerOut ( prev )
92
- )
93
- }
94
-
95
- /** Holds if `n` should not have outgoing flow. */
96
- predicate isSanitizerOut ( Node n ) {
97
- // We disable flow out of sinks to reduce result duplication
98
- isSink ( n , _)
99
- or
100
- // If the node is being passed to a function it may be
101
- // modified, and thus it's safe to later read the value.
102
- exists ( n .asIndirectArgument ( ) )
103
- }
104
-
105
87
/**
106
88
* Holds if `n` is a node such that `n.asExpr() = e` and `e` is not an
107
89
* argument of a deallocation expression.
@@ -112,39 +94,33 @@ predicate isSink(Node n, Expr e) {
112
94
}
113
95
114
96
/**
115
- * Holds if `n` is part of a path from a call to a `scanf`-like function
116
- * to a use of the written variable.
97
+ * A configuration to track flow from the output argument of a call to a
98
+ * `scanf`-like function, and to a use of the defined variable.
117
99
*/
118
- pragma [ nomagic]
119
- predicate revFlow ( Node n ) {
120
- fwdFlow ( n ) and
121
- (
100
+ module ScanfToUseConfig implements ConfigSig {
101
+ predicate isSource ( Node source ) { isSource ( _, _, source , _) }
102
+
103
+ predicate isSink ( Node sink ) { isSink ( sink , _) }
104
+
105
+ predicate isBarrierOut ( Node n ) {
106
+ // We disable flow out of sinks to reduce result duplication
122
107
isSink ( n , _)
123
108
or
124
- exists ( Node succ |
125
- revFlow ( succ ) and
126
- localFlowStep ( n , succ ) and
127
- not isSanitizerOut ( n )
128
- )
129
- )
130
- }
131
-
132
- /** A local flow step, restricted to relevant dataflow nodes. */
133
- private predicate step ( Node n1 , Node n2 ) {
134
- revFlow ( n1 ) and
135
- revFlow ( n2 ) and
136
- localFlowStep ( n1 , n2 )
109
+ // If the node is being passed to a function it may be
110
+ // modified, and thus it's safe to later read the value.
111
+ exists ( n .asIndirectArgument ( ) )
112
+ }
137
113
}
138
114
139
- predicate hasFlow ( Node n1 , Node n2 ) = fastTC ( step / 2 ) ( n1 , n2 )
115
+ module ScanfToUseFlow = Global < ScanfToUseConfig > ;
140
116
141
117
/**
142
118
* Holds if `source` is the `index`'th argument to the `scanf`-like call `call`, and `sink` is
143
119
* a dataflow node that represents the expression `e`.
144
120
*/
145
121
predicate hasFlow ( Node source , ScanfFunctionCall call , int index , Node sink , Expr e ) {
146
122
isSource ( call , index , source , _) and
147
- hasFlow ( source , sink ) and
123
+ ScanfToUseFlow :: flow ( source , sink ) and
148
124
isSink ( sink , e )
149
125
}
150
126
0 commit comments