@@ -85,14 +85,20 @@ private class AllowedPrefixGuard extends Guard instanceof MethodAccess {
85
85
*/
86
86
private predicate allowedPrefixGuard ( Guard g , Expr e , boolean branch ) {
87
87
branch = true and
88
+ // Local taint-flow is used here to handle cases where the validated expression comes from the
89
+ // expression reaching the sink, but it's not the same one, e.g.:
90
+ // File file = source();
91
+ // String strPath = file.getCanonicalPath();
92
+ // if (strPath.startsWith("/safe/dir"))
93
+ // sink(file);
88
94
TaintTracking:: localExprTaint ( e , g .( AllowedPrefixGuard ) .getCheckedExpr ( ) ) and
89
95
exists ( Expr previousGuard |
90
96
TaintTracking:: localExprTaint ( previousGuard .( PathNormalizeSanitizer ) ,
91
97
g .( AllowedPrefixGuard ) .getCheckedExpr ( ) )
92
98
or
93
99
previousGuard
94
100
.( PathTraversalGuard )
95
- .controls ( g .getBasicBlock ( ) . ( ConditionBlock ) , previousGuard .( PathTraversalGuard ) .getBranch ( ) )
101
+ .controls ( g .getBasicBlock ( ) , previousGuard .( PathTraversalGuard ) .getBranch ( ) )
96
102
)
97
103
}
98
104
@@ -108,12 +114,18 @@ private class AllowedPrefixSanitizer extends PathInjectionSanitizer {
108
114
* been checked for a trusted prefix.
109
115
*/
110
116
private predicate dotDotCheckGuard ( Guard g , Expr e , boolean branch ) {
117
+ // Local taint-flow is used here to handle cases where the validated expression comes from the
118
+ // expression reaching the sink, but it's not the same one, e.g.:
119
+ // Path path = source();
120
+ // String strPath = path.toString();
121
+ // if (!strPath.contains("..") && strPath.startsWith("/safe/dir"))
122
+ // sink(path);
111
123
branch = g .( PathTraversalGuard ) .getBranch ( ) and
112
124
TaintTracking:: localExprTaint ( e , g .( PathTraversalGuard ) .getCheckedExpr ( ) ) and
113
125
exists ( Guard previousGuard |
114
- previousGuard .( AllowedPrefixGuard ) .controls ( g .getBasicBlock ( ) . ( ConditionBlock ) , true )
126
+ previousGuard .( AllowedPrefixGuard ) .controls ( g .getBasicBlock ( ) , true )
115
127
or
116
- previousGuard .( BlockListGuard ) .controls ( g .getBasicBlock ( ) . ( ConditionBlock ) , false )
128
+ previousGuard .( BlockListGuard ) .controls ( g .getBasicBlock ( ) , false )
117
129
)
118
130
}
119
131
@@ -140,14 +152,20 @@ private class BlockListGuard extends Guard instanceof MethodAccess {
140
152
*/
141
153
private predicate blockListGuard ( Guard g , Expr e , boolean branch ) {
142
154
branch = false and
155
+ // Local taint-flow is used here to handle cases where the validated expression comes from the
156
+ // expression reaching the sink, but it's not the same one, e.g.:
157
+ // File file = source();
158
+ // String strPath = file.getCanonicalPath();
159
+ // if (!strPath.contains("..") && !strPath.startsWith("/dangerous/dir"))
160
+ // sink(file);
143
161
TaintTracking:: localExprTaint ( e , g .( BlockListGuard ) .getCheckedExpr ( ) ) and
144
162
exists ( Expr previousGuard |
145
163
TaintTracking:: localExprTaint ( previousGuard .( PathNormalizeSanitizer ) ,
146
164
g .( BlockListGuard ) .getCheckedExpr ( ) )
147
165
or
148
166
previousGuard
149
167
.( PathTraversalGuard )
150
- .controls ( g .getBasicBlock ( ) . ( ConditionBlock ) , previousGuard .( PathTraversalGuard ) .getBranch ( ) )
168
+ .controls ( g .getBasicBlock ( ) , previousGuard .( PathTraversalGuard ) .getBranch ( ) )
151
169
)
152
170
}
153
171
@@ -245,10 +263,3 @@ private class PathNormalizeSanitizer extends MethodAccess {
245
263
this .getMethod ( ) .hasName ( [ "getCanonicalPath" , "getCanonicalFile" ] )
246
264
}
247
265
}
248
-
249
- /** A node with path normalization. */
250
- class NormalizedPathNode extends DataFlow:: Node {
251
- NormalizedPathNode ( ) {
252
- TaintTracking:: localExprTaint ( this .asExpr ( ) , any ( PathNormalizeSanitizer ma ) )
253
- }
254
- }
0 commit comments