@@ -864,6 +864,194 @@ private module Stdlib {
864
864
class Sqlite3 extends PEP249ModuleApiNode {
865
865
Sqlite3 ( ) { this = API:: moduleImport ( "sqlite3" ) }
866
866
}
867
+
868
+ // ---------------------------------------------------------------------------
869
+ // pathlib
870
+ // ---------------------------------------------------------------------------
871
+ /** Gets a reference to the `pathlib` module. */
872
+ private API:: Node pathlib ( ) { result = API:: moduleImport ( "pathlib" ) }
873
+
874
+ /**
875
+ * Gets a name of a constructor for a `pathlib.Path` object.
876
+ * We include the pure paths, as they can be "exported" (say with `as_posix`) and then used to acces the underlying file system.
877
+ */
878
+ private string pathlibPathConstructor ( ) {
879
+ result in [ "Path" , "PurePath" , "PurePosixPath" , "PureWindowsPath" , "PosixPath" , "WindowsPath" ]
880
+ }
881
+
882
+ /**
883
+ * Gets a name of an attribute of a `pathlib.Path` object that is also a `pathlib.Path` object.
884
+ */
885
+ private string pathlibPathAttribute ( ) { result in [ "parent" ] }
886
+
887
+ /**
888
+ * Gets a name of a method of a `pathlib.Path` object that returns a `pathlib.Path` object.
889
+ */
890
+ private string pathlibPathMethod ( ) {
891
+ result in [ "absolute" , "relative_to" , "rename" , "replace" , "resolve" ]
892
+ }
893
+
894
+ /**
895
+ * Gets a name of a method of a `pathlib.Path` object that modifies a `pathlib.Path` object based on new data.
896
+ */
897
+ private string pathlibPathInjection ( ) {
898
+ result in [ "joinpath" , "with_name" , "with_stem" , "with_suffix" ]
899
+ }
900
+
901
+ /**
902
+ * Gets a name of an attribute of a `pathlib.Path` object that exports information about the `pathlib.Path` object.
903
+ */
904
+ private string pathlibPathAttributeExport ( ) {
905
+ result in [ "drive" , "root" , "anchor" , "name" , "suffix" , "stem" ]
906
+ }
907
+
908
+ /**
909
+ * Gets a name of a method of a `pathlib.Path` object that exports information about the `pathlib.Path` object.
910
+ */
911
+ private string pathlibPathMethodExport ( ) { result in [ "as_posix" , "as_uri" ] }
912
+
913
+ /**
914
+ * Flow for attributes and methods that return a `pathlib.Path` object.
915
+ */
916
+ private predicate pathlibPathStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
917
+ exists ( DataFlow:: AttrRead returnsPath |
918
+ (
919
+ // attribute access
920
+ returnsPath .getAttributeName ( ) = pathlibPathAttribute ( ) and
921
+ nodeTo = returnsPath
922
+ or
923
+ // method call
924
+ returnsPath .getAttributeName ( ) = pathlibPathMethod ( ) and
925
+ returnsPath
926
+ .( DataFlow:: LocalSourceNode )
927
+ .flowsTo ( nodeTo .( DataFlow:: CallCfgNode ) .getFunction ( ) )
928
+ ) and
929
+ nodeFrom = returnsPath .getObject ( )
930
+ )
931
+ }
932
+
933
+ /**
934
+ * Gets a reference to a `pathlib.Path` object.
935
+ * This type tracker makes the monomorphic API use assumption.
936
+ */
937
+ private DataFlow:: LocalSourceNode pathlibPath ( DataFlow:: TypeTracker t ) {
938
+ // Type construction
939
+ t .start ( ) and
940
+ result = pathlib ( ) .getMember ( pathlibPathConstructor ( ) ) .getACall ( )
941
+ or
942
+ // Type-preserving step
943
+ exists ( DataFlow:: Node nodeFrom , DataFlow:: TypeTracker t2 |
944
+ pathlibPath ( t2 ) .flowsTo ( nodeFrom ) and
945
+ t2 .end ( )
946
+ |
947
+ t .start ( ) and
948
+ pathlibPathStep ( nodeFrom , result )
949
+ )
950
+ or
951
+ // Data injection
952
+ // Special handling of the `/` operator
953
+ exists ( BinaryExprNode slash , DataFlow:: Node pathOperand , DataFlow:: TypeTracker t2 |
954
+ slash .getOp ( ) instanceof Div and
955
+ pathOperand .asCfgNode ( ) = slash .getAnOperand ( ) and
956
+ pathlibPath ( t2 ) .flowsTo ( pathOperand ) and
957
+ t2 .end ( )
958
+ |
959
+ t .start ( ) and
960
+ result .asCfgNode ( ) = slash
961
+ )
962
+ or
963
+ // standard case
964
+ exists ( DataFlow:: AttrRead returnsPath , DataFlow:: TypeTracker t2 |
965
+ returnsPath .getAttributeName ( ) = pathlibPathInjection ( ) and
966
+ pathlibPath ( t2 ) .flowsTo ( returnsPath .getObject ( ) ) and
967
+ t2 .end ( )
968
+ |
969
+ t .start ( ) and
970
+ result .( DataFlow:: CallCfgNode ) .getFunction ( ) = returnsPath
971
+ )
972
+ or
973
+ // Track further
974
+ exists ( DataFlow:: TypeTracker t2 | result = pathlibPath ( t2 ) .track ( t2 , t ) )
975
+ }
976
+
977
+ /** Gets a reference to a `pathlib.Path` object. */
978
+ DataFlow:: LocalSourceNode pathlibPath ( ) { result = pathlibPath ( DataFlow:: TypeTracker:: end ( ) ) }
979
+
980
+ private class PathlibFileAccess extends FileSystemAccess:: Range , DataFlow:: CallCfgNode {
981
+ DataFlow:: AttrRead fileAccess ;
982
+
983
+ PathlibFileAccess ( ) {
984
+ fileAccess .getAttributeName ( ) in [
985
+ "stat" , "chmod" , "exists" , "expanduser" , "glob" , "group" , "is_dir" , "is_file" , "is_mount" ,
986
+ "is_symlink" , "is_socket" , "is_fifo" , "is_block_device" , "is_char_device" , "iter_dir" ,
987
+ "lchmod" , "lstat" , "mkdir" , "open" , "owner" , "read_bytes" , "read_text" , "readlink" ,
988
+ "rename" , "replace" , "resolve" , "rglob" , "rmdir" , "samefile" , "symlink_to" , "touch" ,
989
+ "unlink" , "link_to" , "write_bytes" , "write_text"
990
+ ] and
991
+ pathlibPath ( ) .flowsTo ( fileAccess .getObject ( ) ) and
992
+ fileAccess .( DataFlow:: LocalSourceNode ) .flowsTo ( this .getFunction ( ) )
993
+ }
994
+
995
+ override DataFlow:: Node getAPathArgument ( ) { result = fileAccess .getObject ( ) }
996
+ }
997
+
998
+ /** An additional taint steps for objects of type `pathlib.Path` */
999
+ private class PathlibPathTaintStep extends TaintTracking:: AdditionalTaintStep {
1000
+ override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
1001
+ // Type construction
1002
+ nodeTo = pathlib ( ) .getMember ( pathlibPathConstructor ( ) ) .getACall ( ) and
1003
+ nodeFrom = nodeTo .( DataFlow:: CallCfgNode ) .getArg ( _)
1004
+ or
1005
+ // Type preservation
1006
+ pathlibPath ( ) .flowsTo ( nodeFrom ) and
1007
+ pathlibPathStep ( nodeFrom , nodeTo )
1008
+ or
1009
+ // Data injection
1010
+ pathlibPath ( ) .flowsTo ( nodeTo ) and
1011
+ (
1012
+ // Special handling of the `/` operator
1013
+ exists ( BinaryExprNode slash , DataFlow:: Node pathOperand |
1014
+ slash .getOp ( ) instanceof Div and
1015
+ pathOperand .asCfgNode ( ) = slash .getAnOperand ( ) and
1016
+ pathlibPath ( ) .flowsTo ( pathOperand )
1017
+ |
1018
+ nodeTo .asCfgNode ( ) = slash and
1019
+ // Taint can flow either from the left or the right operand as long as one of them is a path.
1020
+ nodeFrom .asCfgNode ( ) = slash .getAnOperand ( )
1021
+ )
1022
+ or
1023
+ // standard case
1024
+ exists ( DataFlow:: AttrRead augmentsPath |
1025
+ augmentsPath .getAttributeName ( ) = pathlibPathInjection ( )
1026
+ |
1027
+ augmentsPath
1028
+ .( DataFlow:: LocalSourceNode )
1029
+ .flowsTo ( nodeTo .( DataFlow:: CallCfgNode ) .getFunction ( ) ) and
1030
+ (
1031
+ // type-preserving call
1032
+ nodeFrom = augmentsPath .getObject ( )
1033
+ or
1034
+ // data injection
1035
+ nodeFrom = nodeTo .( DataFlow:: CallCfgNode ) .getArg ( _)
1036
+ )
1037
+ )
1038
+ )
1039
+ or
1040
+ // Export data from type
1041
+ pathlibPath ( ) .flowsTo ( nodeFrom ) and
1042
+ exists ( DataFlow:: AttrRead exportPath |
1043
+ // exporting attribute
1044
+ exportPath .getAttributeName ( ) = pathlibPathAttributeExport ( ) and
1045
+ nodeTo = exportPath
1046
+ or
1047
+ // exporting method
1048
+ exportPath .getAttributeName ( ) = pathlibPathMethodExport ( ) and
1049
+ exportPath .( DataFlow:: LocalSourceNode ) .flowsTo ( nodeTo .( DataFlow:: CallCfgNode ) .getFunction ( ) )
1050
+ |
1051
+ nodeFrom = exportPath .getObject ( )
1052
+ )
1053
+ }
1054
+ }
867
1055
}
868
1056
869
1057
// ---------------------------------------------------------------------------
0 commit comments