@@ -196,25 +196,110 @@ private module StdlibPrivate {
196
196
}
197
197
198
198
/**
199
- * A call to `os.path.normpath`.
200
- * See https://docs.python.org/3/library/os.path.html#os.path.normpath
199
+ * The `os.path` module offers a number of methods for checking if a file exists and/or has certain
200
+ * properties, leading to a file system access.
201
+ * A call to `os.path.exists` or `os.path.lexists` will check if a file exists on the file system.
202
+ * (Although, on some platforms, the check may return `false` due to missing permissions.)
203
+ * A call to `os.path.getatime` will raise `OSError` if the file does not exist or is inaccessible.
204
+ * See:
205
+ * - https://docs.python.org/3/library/os.path.html#os.path.exists
206
+ * - https://docs.python.org/3/library/os.path.html#os.path.lexists
207
+ * - https://docs.python.org/3/library/os.path.html#os.path.isfile
208
+ * - https://docs.python.org/3/library/os.path.html#os.path.isdir
209
+ * - https://docs.python.org/3/library/os.path.html#os.path.islink
210
+ * - https://docs.python.org/3/library/os.path.html#os.path.ismount
211
+ * - https://docs.python.org/3/library/os.path.html#os.path.getatime
212
+ * - https://docs.python.org/3/library/os.path.html#os.path.getmtime
213
+ * - https://docs.python.org/3/library/os.path.html#os.path.getctime
214
+ * - https://docs.python.org/3/library/os.path.html#os.path.getsize
215
+ * - https://docs.python.org/3/library/os.path.html#os.path.realpath
201
216
*/
202
- private class OsPathNormpathCall extends Path:: PathNormalization:: Range , DataFlow:: CallCfgNode {
203
- OsPathNormpathCall ( ) { this = os:: path ( ) .getMember ( "normpath" ) .getACall ( ) }
217
+ private class OsPathProbingCall extends FileSystemAccess:: Range , DataFlow:: CallCfgNode {
218
+ OsPathProbingCall ( ) {
219
+ this =
220
+ os:: path ( )
221
+ .getMember ( [
222
+ // these check if the file exists
223
+ "exists" , "lexists" , "isfile" , "isdir" , "islink" , "ismount" ,
224
+ // these raise errors if the file does not exist
225
+ "getatime" , "getmtime" , "getctime" , "getsize"
226
+ ] )
227
+ .getACall ( )
228
+ }
204
229
205
- DataFlow:: Node getPathArg ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "path" ) ] }
230
+ override DataFlow:: Node getAPathArgument ( ) {
231
+ result in [ this .getArg ( 0 ) , this .getArgByName ( "path" ) ]
232
+ }
233
+ }
234
+
235
+ /** A call to `os.path.samefile` will raise an exception if an `os.stat()` call on either pathname fails. */
236
+ private class OsPathSamefileCall extends FileSystemAccess:: Range , DataFlow:: CallCfgNode {
237
+ OsPathSamefileCall ( ) { this = os:: path ( ) .getMember ( "samefile" ) .getACall ( ) }
238
+
239
+ override DataFlow:: Node getAPathArgument ( ) {
240
+ result in [
241
+ this .getArg ( 0 ) , this .getArgByName ( "path1" ) , this .getArg ( 1 ) , this .getArgByName ( "path2" )
242
+ ]
243
+ }
244
+ }
245
+
246
+ // Functions with non-standard arguments:
247
+ // - os.path.join(path, *paths)
248
+ // - os.path.relpath(path, start=os.curdir)
249
+ // these functions need special treatment when computing `getPathArg`.
250
+ //
251
+ // Functions that excluded because they can act as sanitizers:
252
+ // - os.path.commonpath(paths): takes a sequence
253
+ // - os.path.commonprefix(list): takes a list argument
254
+ // unless the user control all arguments, we are comparing with a known value.
255
+ private string pathComputation ( ) {
256
+ result in [
257
+ "abspath" , "basename" , "commonpath" , "dirname" , "expanduser" , "expandvars" , "join" ,
258
+ "normcase" , "normpath" , "realpath" , "relpath" , "split" , "splitdrive" , "splitext"
259
+ ]
206
260
}
207
261
208
- /** An additional taint step for calls to `os.path.normpath` */
209
- private class OsPathNormpathCallAdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
262
+ /**
263
+ * The `os.path` module offers a number of methods for computing new paths from existing paths.
264
+ * These should all propagate taint.
265
+ */
266
+ private class OsPathComputation extends DataFlow:: CallCfgNode {
267
+ string methodName ;
268
+
269
+ OsPathComputation ( ) {
270
+ methodName = pathComputation ( ) and
271
+ this = os:: path ( ) .getMember ( methodName ) .getACall ( )
272
+ }
273
+
274
+ DataFlow:: Node getPathArg ( ) {
275
+ result in [ this .getArg ( 0 ) , this .getArgByName ( "path" ) ]
276
+ or
277
+ methodName = "join" and result = this .getArg ( _)
278
+ or
279
+ methodName = "relpath" and result in [ this .getArg ( 1 ) , this .getArgByName ( "start" ) ]
280
+ }
281
+ }
282
+
283
+ /** An additional taint step for path computations. */
284
+ private class OsPathComputationAdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
210
285
override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
211
- exists ( OsPathNormpathCall call |
286
+ exists ( OsPathComputation call |
212
287
nodeTo = call and
213
288
nodeFrom = call .getPathArg ( )
214
289
)
215
290
}
216
291
}
217
292
293
+ /**
294
+ * A call to `os.path.normpath`.
295
+ * See https://docs.python.org/3/library/os.path.html#os.path.normpath
296
+ */
297
+ private class OsPathNormpathCall extends Path:: PathNormalization:: Range , DataFlow:: CallCfgNode {
298
+ OsPathNormpathCall ( ) { this = os:: path ( ) .getMember ( "normpath" ) .getACall ( ) }
299
+
300
+ DataFlow:: Node getPathArg ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "path" ) ] }
301
+ }
302
+
218
303
/**
219
304
* A call to `os.path.abspath`.
220
305
* See https://docs.python.org/3/library/os.path.html#os.path.abspath
@@ -225,16 +310,6 @@ private module StdlibPrivate {
225
310
DataFlow:: Node getPathArg ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "path" ) ] }
226
311
}
227
312
228
- /** An additional taint step for calls to `os.path.abspath` */
229
- private class OsPathAbspathCallAdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
230
- override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
231
- exists ( OsPathAbspathCall call |
232
- nodeTo = call and
233
- nodeFrom = call .getPathArg ( )
234
- )
235
- }
236
- }
237
-
238
313
/**
239
314
* A call to `os.path.realpath`.
240
315
* See https://docs.python.org/3/library/os.path.html#os.path.realpath
@@ -245,16 +320,6 @@ private module StdlibPrivate {
245
320
DataFlow:: Node getPathArg ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "path" ) ] }
246
321
}
247
322
248
- /** An additional taint step for calls to `os.path.realpath` */
249
- private class OsPathRealpathCallAdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
250
- override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
251
- exists ( OsPathRealpathCall call |
252
- nodeTo = call and
253
- nodeFrom = call .getPathArg ( )
254
- )
255
- }
256
- }
257
-
258
323
/**
259
324
* A call to `os.system`.
260
325
* See https://docs.python.org/3/library/os.html#os.system
0 commit comments