@@ -383,23 +383,45 @@ private module Stdlib {
383
383
}
384
384
}
385
385
386
+ /** Gets a reference to the builtin `open` function */
387
+ private API:: Node getOpenFunctionRef ( ) {
388
+ result = API:: builtin ( "open" )
389
+ or
390
+ // io.open is a special case, since it is an alias for the builtin `open`
391
+ result = API:: moduleImport ( "io" ) .getMember ( "open" )
392
+ }
393
+
386
394
/**
387
395
* A call to the builtin `open` function.
388
396
* See https://docs.python.org/3/library/functions.html#open
389
397
*/
390
398
private class OpenCall extends FileSystemAccess:: Range , DataFlow:: CallCfgNode {
391
- OpenCall ( ) {
392
- this = API:: builtin ( "open" ) .getACall ( )
393
- or
394
- // io.open is a special case, since it is an alias for the builtin `open`
395
- this = API:: moduleImport ( "io" ) .getMember ( "open" ) .getACall ( )
396
- }
399
+ OpenCall ( ) { this = getOpenFunctionRef ( ) .getACall ( ) }
397
400
398
401
override DataFlow:: Node getAPathArgument ( ) {
399
402
result in [ this .getArg ( 0 ) , this .getArgByName ( "file" ) ]
400
403
}
401
404
}
402
405
406
+ /** A call to the `write` or `writelines` method on an opened file, such as `open("foo", "w").write(...)`. */
407
+ private class WriteOnOpenFile extends FileSystemWriteAccess:: Range , DataFlow:: CallCfgNode {
408
+ WriteOnOpenFile ( ) {
409
+ this = getOpenFunctionRef ( ) .getReturn ( ) .getMember ( [ "write" , "writelines" ] ) .getACall ( )
410
+ }
411
+
412
+ override DataFlow:: Node getAPathArgument ( ) {
413
+ // best effort attempt to give the path argument, that was initially given to the `open` call.
414
+ exists ( OpenCall openCall , DataFlow:: AttrRead read |
415
+ read .getAttributeName ( ) in [ "write" , "writelines" ] and
416
+ openCall .flowsTo ( read .getObject ( ) ) and
417
+ read .( DataFlow:: LocalSourceNode ) .flowsTo ( this .getFunction ( ) ) and
418
+ result = openCall .getAPathArgument ( )
419
+ )
420
+ }
421
+
422
+ override DataFlow:: Node getADataNode ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "data" ) ] }
423
+ }
424
+
403
425
/**
404
426
* An exec statement (only Python 2).
405
427
* See https://docs.python.org/2/reference/simple_stmts.html#the-exec-statement.
@@ -1001,11 +1023,14 @@ private module Stdlib {
1001
1023
/** Gets a reference to a `pathlib.Path` object. */
1002
1024
DataFlow:: LocalSourceNode pathlibPath ( ) { result = pathlibPath ( DataFlow:: TypeTracker:: end ( ) ) }
1003
1025
1026
+ /** A file system access from a `pathlib.Path` method call. */
1004
1027
private class PathlibFileAccess extends FileSystemAccess:: Range , DataFlow:: CallCfgNode {
1005
1028
DataFlow:: AttrRead fileAccess ;
1029
+ string attrbuteName ;
1006
1030
1007
1031
PathlibFileAccess ( ) {
1008
- fileAccess .getAttributeName ( ) in [
1032
+ attrbuteName = fileAccess .getAttributeName ( ) and
1033
+ attrbuteName in [
1009
1034
"stat" , "chmod" , "exists" , "expanduser" , "glob" , "group" , "is_dir" , "is_file" , "is_mount" ,
1010
1035
"is_symlink" , "is_socket" , "is_fifo" , "is_block_device" , "is_char_device" , "iter_dir" ,
1011
1036
"lchmod" , "lstat" , "mkdir" , "open" , "owner" , "read_bytes" , "read_text" , "readlink" ,
@@ -1019,6 +1044,13 @@ private module Stdlib {
1019
1044
override DataFlow:: Node getAPathArgument ( ) { result = fileAccess .getObject ( ) }
1020
1045
}
1021
1046
1047
+ /** A file system write from a `pathlib.Path` method call. */
1048
+ private class PathlibFileWrites extends PathlibFileAccess , FileSystemWriteAccess:: Range {
1049
+ PathlibFileWrites ( ) { attrbuteName in [ "write_bytes" , "write_text" ] }
1050
+
1051
+ override DataFlow:: Node getADataNode ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "data" ) ] }
1052
+ }
1053
+
1022
1054
/** An additional taint steps for objects of type `pathlib.Path` */
1023
1055
private class PathlibPathTaintStep extends TaintTracking:: AdditionalTaintStep {
1024
1056
override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
0 commit comments