Skip to content

Commit 3013180

Browse files
authored
Merge pull request github#7455 from haby0/py/add-shutil-module-path-injection-sinks
Python: Add shutil module sinks for path injection query
2 parents 497c878 + 759ec31 commit 3013180

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

python/ql/lib/semmle/python/frameworks/Stdlib.qll

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2942,6 +2942,90 @@ private module StdlibPrivate {
29422942
]
29432943
}
29442944
}
2945+
2946+
// ---------------------------------------------------------------------------
2947+
// shutil
2948+
// ---------------------------------------------------------------------------
2949+
/** Gets a reference to the `shutil` module. */
2950+
private API::Node shutil() { result = API::moduleImport("shutil") }
2951+
2952+
/**
2953+
* A call to the `shutil.rmtree` function.
2954+
*
2955+
* See https://docs.python.org/3/library/shutil.html#shutil.rmtree
2956+
*/
2957+
private class ShutilRmtreeCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
2958+
ShutilRmtreeCall() { this = shutil().getMember("rmtree").getACall() }
2959+
2960+
override DataFlow::Node getAPathArgument() {
2961+
result in [this.getArg(0), this.getArgByName("path")]
2962+
}
2963+
}
2964+
2965+
/**
2966+
* The `shutil` module provides methods to copy, move files or copy file attributes.
2967+
* See:
2968+
* - https://docs.python.org/3/library/shutil.html#shutil.copyfile
2969+
* - https://docs.python.org/3/library/shutil.html#shutil.copymode
2970+
* - https://docs.python.org/3/library/shutil.html#shutil.copystat
2971+
* - https://docs.python.org/3/library/shutil.html#shutil.copy
2972+
* - https://docs.python.org/3/library/shutil.html#shutil.copy2
2973+
* - https://docs.python.org/3/library/shutil.html#shutil.copytree
2974+
* - https://docs.python.org/3/library/shutil.html#shutil.move
2975+
*/
2976+
private class ShutilCopyCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
2977+
ShutilCopyCall() {
2978+
this =
2979+
shutil()
2980+
.getMember([
2981+
// these are used to copy files
2982+
"copyfile", "copy", "copy2", "copytree",
2983+
// these are used to move files
2984+
"move",
2985+
// these are used to copy some attributes of the file
2986+
"copymode", "copystat"
2987+
])
2988+
.getACall()
2989+
}
2990+
2991+
override DataFlow::Node getAPathArgument() {
2992+
result in [this.getArg(0), this.getArgByName("src"), this.getArg(1), this.getArgByName("dst")]
2993+
}
2994+
}
2995+
2996+
// TODO: once we have flow summaries, model `shutil.copyfileobj` which copies the content between its' file-like arguments.
2997+
// See https://docs.python.org/3/library/shutil.html#shutil.copyfileobj
2998+
private class ShutilCopyfileobjCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
2999+
ShutilCopyfileobjCall() { this = shutil().getMember("copyfileobj").getACall() }
3000+
3001+
override DataFlow::Node getAPathArgument() { none() }
3002+
}
3003+
3004+
/**
3005+
* A call to the `shutil.disk_usage` function.
3006+
*
3007+
* See https://docs.python.org/3/library/shutil.html#shutil.disk_usage
3008+
*/
3009+
private class ShutilDiskUsageCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
3010+
ShutilDiskUsageCall() { this = shutil().getMember("disk_usage").getACall() }
3011+
3012+
override DataFlow::Node getAPathArgument() {
3013+
result in [this.getArg(0), this.getArgByName("path")]
3014+
}
3015+
}
3016+
3017+
/**
3018+
* A call to the `shutil.chown` function.
3019+
*
3020+
* See https://docs.python.org/3/library/shutil.html#shutil.chown
3021+
*/
3022+
private class ShutilChownCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
3023+
ShutilChownCall() { this = shutil().getMember("chown").getACall() }
3024+
3025+
override DataFlow::Node getAPathArgument() {
3026+
result in [this.getArg(0), this.getArgByName("path")]
3027+
}
3028+
}
29453029
}
29463030

29473031
// ---------------------------------------------------------------------------

python/ql/test/library-tests/frameworks/stdlib/FileSystemAccess.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import stat
55
import tempfile
6+
import shutil
67

78
open("file") # $ getAPathArgument="file"
89
open(file="file") # $ getAPathArgument="file"
@@ -238,3 +239,34 @@ def test_fspath():
238239

239240
tempfile.TemporaryDirectory("suffix", "prefix", "dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
240241
tempfile.TemporaryDirectory(suffix="suffix", prefix="prefix", dir="dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
242+
243+
# ------------------------------------------------------------------------------
244+
# shutil
245+
# ------------------------------------------------------------------------------
246+
247+
shutil.rmtree("path") # $ getAPathArgument="path"
248+
shutil.rmtree(path="path") # $ getAPathArgument="path"
249+
250+
shutil.copyfile("src", "dst") # $ getAPathArgument="src" getAPathArgument="dst"
251+
shutil.copyfile(src="src", dst="dst") # $ getAPathArgument="src" getAPathArgument="dst"
252+
253+
shutil.copy("src", "dst") # $ getAPathArgument="src" getAPathArgument="dst"
254+
shutil.copy(src="src", dst="dst") # $ getAPathArgument="src" getAPathArgument="dst"
255+
256+
shutil.copy2("src", "dst") # $ getAPathArgument="src" getAPathArgument="dst"
257+
shutil.copy2(src="src", dst="dst") # $ getAPathArgument="src" getAPathArgument="dst"
258+
259+
shutil.copytree("src", "dst") # $ getAPathArgument="src" getAPathArgument="dst"
260+
shutil.copytree(src="src", dst="dst") # $ getAPathArgument="src" getAPathArgument="dst"
261+
262+
shutil.move("src", "dst") # $ getAPathArgument="src" getAPathArgument="dst"
263+
shutil.move(src="src", dst="dst") # $ getAPathArgument="src" getAPathArgument="dst"
264+
265+
shutil.copymode("src", "dst") # $ getAPathArgument="src" getAPathArgument="dst"
266+
shutil.copymode(src="src", dst="dst") # $ getAPathArgument="src" getAPathArgument="dst"
267+
268+
shutil.copystat("src", "dst") # $ getAPathArgument="src" getAPathArgument="dst"
269+
shutil.copystat(src="src", dst="dst") # $ getAPathArgument="src" getAPathArgument="dst"
270+
271+
shutil.disk_usage("path") # $ getAPathArgument="path"
272+
shutil.disk_usage(path="path") # $ getAPathArgument="path"

0 commit comments

Comments
 (0)