Skip to content

Commit a980f26

Browse files
committed
Python: Model os.stat (and friends)
1 parent 9f4107d commit a980f26

File tree

3 files changed

+30
-0
lines changed

3 files changed

+30
-0
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 `os.stat`, `os.lstat`, `os.statvfs`, `os.fstat`, and `os.fstatvfs`, which 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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,29 @@ private module StdlibPrivate {
273273
}
274274
}
275275

276+
/**
277+
* The `os` module has multiple methods for getting the status of a file, like
278+
* a stat() system call.
279+
*
280+
* Note: `os.fstat` and `os.fstatvfs` operate on file-descriptors.
281+
*
282+
* See:
283+
* - https://docs.python.org/3.10/library/os.html#os.stat
284+
* - https://docs.python.org/3.10/library/os.html#os.lstat
285+
* - https://docs.python.org/3.10/library/os.html#os.statvfs
286+
* - https://docs.python.org/3.10/library/os.html#os.fstat
287+
* - https://docs.python.org/3.10/library/os.html#os.fstatvfs
288+
*/
289+
private class OsProbingCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
290+
OsProbingCall() {
291+
this = os().getMember(["stat", "lstat", "statvfs", "fstat", "fstatvfs"]).getACall()
292+
}
293+
294+
override DataFlow::Node getAPathArgument() {
295+
result in [this.getArg(0), this.getArgByName("path")]
296+
}
297+
}
298+
276299
/**
277300
* The `os.path` module offers a number of methods for checking if a file exists and/or has certain
278301
* properties, leading to a file system access.

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,8 @@ def through_function(open_file):
4242
posixpath.exists("filepath") # $ getAPathArgument="filepath"
4343
ntpath.exists("filepath") # $ getAPathArgument="filepath"
4444
genericpath.exists("filepath") # $ getAPathArgument="filepath"
45+
46+
import os
47+
48+
os.stat("filepath") # $ getAPathArgument="filepath"
49+
os.stat(path="filepath") # $ getAPathArgument="filepath"

0 commit comments

Comments
 (0)