Skip to content

Commit d42bb11

Browse files
committed
python: align annotations with Ruby
use `result=BAD` for expected alert and `result=OK` on sinks where alerts are not wanted.
1 parent 0a7cfad commit d42bb11

File tree

2 files changed

+36
-21
lines changed

2 files changed

+36
-21
lines changed
Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,43 @@
11
import python
2-
import experimental.dataflow.TestUtil.FlowTest
2+
import semmle.python.dataflow.new.DataFlow
3+
import TestUtilities.InlineExpectationsTest
34
private import semmle.python.dataflow.new.internal.PrintNode
45

5-
class DataFlowQueryTest extends FlowTest {
6+
class DataFlowQueryTest extends InlineExpectationsTest {
67
DataFlowQueryTest() { this = "DataFlowQueryTest" }
78

8-
override string flowTag() { result = "flow" }
9+
override string getARelevantTag() { result = "result" }
910

10-
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
11-
exists(DataFlow::Configuration cfg | cfg.hasFlow(source, sink))
11+
override predicate hasActualResult(Location location, string element, string tag, string value) {
12+
exists(DataFlow::Configuration cfg, DataFlow::Node fromNode, DataFlow::Node toNode |
13+
cfg.hasFlow(fromNode, toNode)
14+
|
15+
location = toNode.getLocation() and
16+
tag = "result" and
17+
value = "BAD" and
18+
element = toNode.toString()
19+
)
1220
}
1321
}
1422

1523
query predicate missingAnnotationOnSink(Location location, string error, string element) {
16-
error = "ERROR, you should add `# $ MISSING: flow` annotation" and
24+
error = "ERROR, you should add `# $ MISSING: result=BAD` or `result=OK` annotation" and
1725
exists(DataFlow::Node sink |
18-
exists(DataFlow::Configuration cfg | cfg.isSink(sink)) and
26+
exists(DataFlow::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _)) and
1927
location = sink.getLocation() and
2028
element = prettyExpr(sink.asExpr()) and
2129
not any(DataFlow::Configuration config).hasFlow(_, sink) and
2230
not exists(FalseNegativeExpectation missingResult |
23-
missingResult.getTag() = "flow" and
31+
missingResult.getTag() = "result" and
32+
missingResult.getValue() = "BAD" and
2433
missingResult.getLocation().getFile() = location.getFile() and
2534
missingResult.getLocation().getStartLine() = location.getStartLine()
35+
) and
36+
not exists(GoodExpectation okResult |
37+
okResult.getTag() = "result" and
38+
okResult.getValue() = "OK" and
39+
okResult.getLocation().getFile() = location.getFile() and
40+
okResult.getLocation().getStartLine() = location.getStartLine()
2641
)
2742
)
2843
}

python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,36 @@
1010
def command_injection1():
1111
files = request.args.get('files', '')
1212
# Don't let files be `; rm -rf /`
13-
os.system("ls " + files) # $flow="ImportMember, l:-8 -> BinaryExpr"
13+
os.system("ls " + files) # $result=BAD
1414

1515

1616
@app.route("/command2")
1717
def command_injection2():
1818
files = request.args.get('files', '')
1919
# Don't let files be `; rm -rf /`
20-
subprocess.Popen("ls " + files, shell=True) # $flow="ImportMember, l:-15 -> BinaryExpr"
20+
subprocess.Popen("ls " + files, shell=True) # $result=BAD
2121

2222

2323
@app.route("/command3")
2424
def first_arg_injection():
2525
cmd = request.args.get('cmd', '')
26-
subprocess.Popen([cmd, "param1"]) # $flow="ImportMember, l:-21 -> cmd"
26+
subprocess.Popen([cmd, "param1"]) # $result=BAD
2727

2828

2929
@app.route("/other_cases")
3030
def others():
3131
files = request.args.get('files', '')
3232
# Don't let files be `; rm -rf /`
33-
os.popen("ls " + files) # $flow="ImportMember, l:-28 -> BinaryExpr"
33+
os.popen("ls " + files) # $result=BAD
3434

3535

3636
@app.route("/multiple")
3737
def multiple():
3838
command = request.args.get('command', '')
3939
# We should mark flow to both calls here, which conflicts with removing flow out of
4040
# a sink due to use-use flow.
41-
os.system(command) # $flow="ImportMember, l:-36 -> command"
42-
os.system(command) # $flow="ImportMember, l:-37 -> command"
41+
os.system(command) # $result=BAD
42+
os.system(command) # $result=BAD
4343

4444

4545
@app.route("/not-into-sink-impl")
@@ -52,11 +52,11 @@ def not_into_sink_impl():
5252
subprocess.call implementation: https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/subprocess.py#L341
5353
"""
5454
command = request.args.get('command', '')
55-
os.system(command) # $flow="ImportMember, l:-50 -> command"
56-
os.popen(command) # $flow="ImportMember, l:-51 -> command"
57-
subprocess.call(command) # $flow="ImportMember, l:-52 -> command"
58-
subprocess.check_call(command) # $flow="ImportMember, l:-53 -> command"
59-
subprocess.run(command) # $flow="ImportMember, l:-54 -> command"
55+
os.system(command) # $result=BAD
56+
os.popen(command) # $result=BAD
57+
subprocess.call(command) # $result=BAD
58+
subprocess.check_call(command) # $result=BAD
59+
subprocess.run(command) # $result=BAD
6060

6161

6262
@app.route("/path-exists-not-sanitizer")
@@ -70,11 +70,11 @@ def path_exists_not_sanitizer():
7070
"""
7171
path = request.args.get('path', '')
7272
if os.path.exists(path):
73-
os.system("ls " + path) # $flow="ImportMember, l:-68 -> BinaryExpr"
73+
os.system("ls " + path) # $result=BAD
7474

7575

7676
@app.route("/restricted-characters")
7777
def restricted_characters():
7878
path = request.args.get('path', '')
7979
if re.match(r'^[a-zA-Z0-9_-]+$', path):
80-
os.system("ls " + path) # $SPURIOUS: flow="ImportMember, l:-75 -> BinaryExpr"
80+
os.system("ls " + path) # $SPURIOUS: result=BAD

0 commit comments

Comments
 (0)