Skip to content

Commit cbd7434

Browse files
committed
Python: Add modeling of tempfile module
1 parent b685383 commit cbd7434

File tree

3 files changed

+124
-12
lines changed

3 files changed

+124
-12
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Added modeling of the `tempfile` module for creating temporary files and directories, such as the functions `tempfile.NamedTemporaryFile` and `tempfile.TemporaryDirectory`. The `suffix`, `prefix`, and `dir` arguments are all vulnerable to path-injection, and these are new sinks for the _Uncontrolled data used in path expression_ (`py/path-injection`) query.

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

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2637,6 +2637,116 @@ private module StdlibPrivate {
26372637
nodeTo.(UrllibParseUrlsplitCall).getUrl() = nodeFrom
26382638
}
26392639
}
2640+
2641+
// ---------------------------------------------------------------------------
2642+
// tempfile
2643+
// ---------------------------------------------------------------------------
2644+
/**
2645+
* A call to `tempfile.mkstemp`.
2646+
*
2647+
* See https://docs.python.org/3/library/tempfile.html#tempfile.mkstemp
2648+
*/
2649+
private class TempfileMkstempCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
2650+
TempfileMkstempCall() { this = API::moduleImport("tempfile").getMember("mkstemp").getACall() }
2651+
2652+
override DataFlow::Node getAPathArgument() {
2653+
result in [
2654+
this.getArg(0), this.getArgByName("suffix"), this.getArg(1), this.getArgByName("prefix"),
2655+
this.getArg(2), this.getArgByName("dir")
2656+
]
2657+
}
2658+
}
2659+
2660+
/**
2661+
* A call to `tempfile.NamedTemporaryFile`.
2662+
*
2663+
* See https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile
2664+
*/
2665+
private class TempfileNamedTemporaryFileCall extends FileSystemAccess::Range,
2666+
DataFlow::CallCfgNode {
2667+
TempfileNamedTemporaryFileCall() {
2668+
this = API::moduleImport("tempfile").getMember("NamedTemporaryFile").getACall()
2669+
}
2670+
2671+
override DataFlow::Node getAPathArgument() {
2672+
result in [
2673+
this.getArg(4), this.getArgByName("suffix"), this.getArg(5), this.getArgByName("prefix"),
2674+
this.getArg(6), this.getArgByName("dir")
2675+
]
2676+
}
2677+
}
2678+
2679+
/**
2680+
* A call to `tempfile.TemporaryFile`.
2681+
*
2682+
* See https://docs.python.org/3/library/tempfile.html#tempfile.TemporaryFile
2683+
*/
2684+
private class TempfileTemporaryFileCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
2685+
TempfileTemporaryFileCall() {
2686+
this = API::moduleImport("tempfile").getMember("TemporaryFile").getACall()
2687+
}
2688+
2689+
override DataFlow::Node getAPathArgument() {
2690+
result in [
2691+
this.getArg(4), this.getArgByName("suffix"), this.getArg(5), this.getArgByName("prefix"),
2692+
this.getArg(6), this.getArgByName("dir")
2693+
]
2694+
}
2695+
}
2696+
2697+
/**
2698+
* A call to `tempfile.SpooledTemporaryFile`.
2699+
*
2700+
* See https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile
2701+
*/
2702+
private class TempfileSpooledTemporaryFileCall extends FileSystemAccess::Range,
2703+
DataFlow::CallCfgNode {
2704+
TempfileSpooledTemporaryFileCall() {
2705+
this = API::moduleImport("tempfile").getMember("SpooledTemporaryFile").getACall()
2706+
}
2707+
2708+
override DataFlow::Node getAPathArgument() {
2709+
result in [
2710+
this.getArg(5), this.getArgByName("suffix"), this.getArg(6), this.getArgByName("prefix"),
2711+
this.getArg(7), this.getArgByName("dir")
2712+
]
2713+
}
2714+
}
2715+
2716+
/**
2717+
* A call to `tempfile.mkdtemp`.
2718+
*
2719+
* See https://docs.python.org/3/library/tempfile.html#tempfile.mkdtemp
2720+
*/
2721+
private class TempfileMkdtempCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
2722+
TempfileMkdtempCall() { this = API::moduleImport("tempfile").getMember("mkdtemp").getACall() }
2723+
2724+
override DataFlow::Node getAPathArgument() {
2725+
result in [
2726+
this.getArg(0), this.getArgByName("suffix"), this.getArg(1), this.getArgByName("prefix"),
2727+
this.getArg(2), this.getArgByName("dir")
2728+
]
2729+
}
2730+
}
2731+
2732+
/**
2733+
* A call to `tempfile.TemporaryDirectory`.
2734+
*
2735+
* See https://docs.python.org/3/library/tempfile.html#tempfile.TemporaryDirectory
2736+
*/
2737+
private class TempfileTemporaryDirectoryCall extends FileSystemAccess::Range,
2738+
DataFlow::CallCfgNode {
2739+
TempfileTemporaryDirectoryCall() {
2740+
this = API::moduleImport("tempfile").getMember("TemporaryDirectory").getACall()
2741+
}
2742+
2743+
override DataFlow::Node getAPathArgument() {
2744+
result in [
2745+
this.getArg(0), this.getArgByName("suffix"), this.getArg(1), this.getArgByName("prefix"),
2746+
this.getArg(2), this.getArgByName("dir")
2747+
]
2748+
}
2749+
}
26402750
}
26412751

26422752
// ---------------------------------------------------------------------------

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -220,21 +220,21 @@ def test_fspath():
220220

221221
# _mkstemp_inner does `_os.path.join(dir, pre + name + suf)`
222222

223-
tempfile.mkstemp("suffix", "prefix", "dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
224-
tempfile.mkstemp(suffix="suffix", prefix="prefix", dir="dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
223+
tempfile.mkstemp("suffix", "prefix", "dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
224+
tempfile.mkstemp(suffix="suffix", prefix="prefix", dir="dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
225225

226-
tempfile.NamedTemporaryFile('w+b', -1, None, None, "suffix", "prefix", "dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
227-
tempfile.NamedTemporaryFile(suffix="suffix", prefix="prefix", dir="dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
226+
tempfile.NamedTemporaryFile('w+b', -1, None, None, "suffix", "prefix", "dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
227+
tempfile.NamedTemporaryFile(suffix="suffix", prefix="prefix", dir="dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
228228

229-
tempfile.TemporaryFile('w+b', -1, None, None, "suffix", "prefix", "dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
230-
tempfile.TemporaryFile(suffix="suffix", prefix="prefix", dir="dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
229+
tempfile.TemporaryFile('w+b', -1, None, None, "suffix", "prefix", "dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
230+
tempfile.TemporaryFile(suffix="suffix", prefix="prefix", dir="dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
231231

232-
tempfile.SpooledTemporaryFile(0, 'w+b', -1, None, None, "suffix", "prefix", "dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
233-
tempfile.SpooledTemporaryFile(suffix="suffix", prefix="prefix", dir="dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
232+
tempfile.SpooledTemporaryFile(0, 'w+b', -1, None, None, "suffix", "prefix", "dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
233+
tempfile.SpooledTemporaryFile(suffix="suffix", prefix="prefix", dir="dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
234234

235235
# mkdtemp does `_os.path.join(dir, prefix + name + suffix)`
236-
tempfile.mkdtemp("suffix", "prefix", "dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
237-
tempfile.mkdtemp(suffix="suffix", prefix="prefix", dir="dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
236+
tempfile.mkdtemp("suffix", "prefix", "dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
237+
tempfile.mkdtemp(suffix="suffix", prefix="prefix", dir="dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
238238

239-
tempfile.TemporaryDirectory("suffix", "prefix", "dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
240-
tempfile.TemporaryDirectory(suffix="suffix", prefix="prefix", dir="dir") # $ MISSING: getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
239+
tempfile.TemporaryDirectory("suffix", "prefix", "dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"
240+
tempfile.TemporaryDirectory(suffix="suffix", prefix="prefix", dir="dir") # $ getAPathArgument="suffix" getAPathArgument="prefix" getAPathArgument="dir"

0 commit comments

Comments
 (0)