Skip to content

Commit 8c2f55f

Browse files
committed
Python: Model Python 2 only os.popen2, popen3, popen4 functions
1 parent 6ec7ab2 commit 8c2f55f

File tree

3 files changed

+16
-10
lines changed

3 files changed

+16
-10
lines changed

python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ private module Stdlib {
3232
* For example, using `attr_name = "system"` will get all uses of `os.system`.
3333
*/
3434
private DataFlow::Node os_attr(DataFlow::TypeTracker t, string attr_name) {
35-
attr_name in ["system", "popen",
35+
attr_name in ["system", "popen", "popen2", "popen3", "popen4",
3636
// exec
3737
"execl", "execle", "execlp", "execlpe", "execv", "execve", "execvp", "execvpe",
3838
// spawn
@@ -111,14 +111,26 @@ private module Stdlib {
111111
}
112112

113113
/**
114-
* A call to `os.popen`
114+
* A call to any of the `os.popen*` functions
115115
* See https://docs.python.org/3/library/os.html#os.popen
116+
*
117+
* Note that in Python 2, there are also `popen2`, `popen3`, and `popen4` functions.
118+
* Although deprecated since version 2.6, they still work in 2.7.
119+
* See https://docs.python.org/2.7/library/os.html#os.popen2
116120
*/
117121
private class OsPopenCall extends SystemCommandExecution::Range {
118-
OsPopenCall() { this.asCfgNode().(CallNode).getFunction() = os_attr("popen").asCfgNode() }
122+
string name;
123+
124+
OsPopenCall() {
125+
name in ["popen", "popen2", "popen3", "popen4"] and
126+
this.asCfgNode().(CallNode).getFunction() = os_attr(name).asCfgNode()
127+
}
119128

120129
override DataFlow::Node getCommand() {
121130
result.asCfgNode() = this.asCfgNode().(CallNode).getArg(0)
131+
or
132+
not name = "popen" and
133+
result.asCfgNode() = this.asCfgNode().(CallNode).getArgByName("cmd")
122134
}
123135
}
124136

python/ql/test/experimental/library-tests/frameworks/stdlib-py2/ConceptsTest.expected

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
| SystemCommandExecution.py:4:26:4:51 | Comment # $getCommand="cmd1; cmd2" | Missing result:getCommand="cmd1; cmd2" |
2-
| SystemCommandExecution.py:5:26:5:51 | Comment # $getCommand="cmd1; cmd2" | Missing result:getCommand="cmd1; cmd2" |
3-
| SystemCommandExecution.py:6:26:6:51 | Comment # $getCommand="cmd1; cmd2" | Missing result:getCommand="cmd1; cmd2" |
4-
| SystemCommandExecution.py:9:30:9:55 | Comment # $getCommand="cmd1; cmd2" | Missing result:getCommand="cmd1; cmd2" |
5-
| SystemCommandExecution.py:10:30:10:55 | Comment # $getCommand="cmd1; cmd2" | Missing result:getCommand="cmd1; cmd2" |
6-
| SystemCommandExecution.py:11:30:11:55 | Comment # $getCommand="cmd1; cmd2" | Missing result:getCommand="cmd1; cmd2" |
71
| SystemCommandExecution.py:19:31:19:56 | Comment # $getCommand="cmd1; cmd2" | Missing result:getCommand="cmd1; cmd2" |
82
| SystemCommandExecution.py:20:35:20:60 | Comment # $getCommand="cmd1; cmd2" | Missing result:getCommand="cmd1; cmd2" |
93
| SystemCommandExecution.py:26:30:26:55 | Comment # $getCommand="cmd1; cmd2" | Missing result:getCommand="cmd1; cmd2" |

python/ql/test/experimental/library-tests/frameworks/stdlib-py2/SystemCommandExecution.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
os.popen3(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
1111
os.popen4(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
1212

13-
# os.popen does not support keyword arguments
13+
# os.popen does not support keyword arguments, so this is a TypeError
1414
os.popen(cmd="cmd1; cmd2")
1515

1616
########################################

0 commit comments

Comments
 (0)