Skip to content

Commit b9239d7

Browse files
committed
Python: Add basic support for environment/commandargs threat-models
1 parent 528f08f commit b9239d7

File tree

4 files changed

+84
-2
lines changed

4 files changed

+84
-2
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/python-all
4+
extensible: sourceModel
5+
data:
6+
- ['os', 'Member[getenv].ReturnValue', 'environment']
7+
- ['os', 'Member[getenvb].ReturnValue', 'environment']
8+
- ['os', 'Member[environ].DictionaryElementAny', 'environment']
9+
- ['os', 'Member[environb].DictionaryElementAny', 'environment']
10+
- ['posix', 'Member[environ].DictionaryElementAny', 'environment']
11+
12+
- ['sys', 'Member[argv].DictionaryElementAny', 'commandargs']
13+
- ['sys', 'Member[orig_argv].DictionaryElementAny', 'commandargs']
14+
15+
# TODO: argparse
16+
# TODO: input / read from stdin

python/ql/test/experimental/meta/ConceptsTest.qll

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import semmle.python.dataflow.new.DataFlow
33
import semmle.python.Concepts
44
import TestUtilities.InlineExpectationsTest
55
private import semmle.python.dataflow.new.internal.PrintNode
6+
private import codeql.threatmodels.ThreatModels
67

78
module SystemCommandExecutionTest implements TestSig {
89
string getARelevantTag() { result = "getCommand" }
@@ -632,6 +633,22 @@ module XmlParsingTest implements TestSig {
632633
}
633634
}
634635

636+
module ThreatModelSourceTest implements TestSig {
637+
string getARelevantTag() {
638+
exists(string kind | knownThreatModel(kind) | result = "threatModelSource" + "[" + kind + "]")
639+
}
640+
641+
predicate hasActualResult(Location location, string element, string tag, string value) {
642+
exists(location.getFile().getRelativePath()) and
643+
exists(ThreatModelSource src | not src.getThreatModel() = "remote" |
644+
location = src.getLocation() and
645+
element = src.toString() and
646+
value = prettyNodeForInlineTest(src) and
647+
tag = "threatModelSource[" + src.getThreatModel() + "]"
648+
)
649+
}
650+
}
651+
635652
import MakeTest<MergeTests5<MergeTests5<SystemCommandExecutionTest, DecodingTest, EncodingTest, LoggingTest,
636653
CodeExecutionTest>,
637654
MergeTests5<SqlConstructionTest, SqlExecutionTest, XPathConstructionTest, XPathExecutionTest,
@@ -642,4 +659,4 @@ import MakeTest<MergeTests5<MergeTests5<SystemCommandExecutionTest, DecodingTest
642659
MergeTests5<FileSystemAccessTest, FileSystemWriteAccessTest, PathNormalizationTest,
643660
SafeAccessCheckTest, PublicKeyGenerationTest>,
644661
MergeTests5<CryptographicOperationTest, HttpClientRequestTest, CsrfProtectionSettingTest,
645-
CsrfLocalProtectionSettingTest, XmlParsingTest>>>
662+
CsrfLocalProtectionSettingTest, MergeTests<XmlParsingTest, ThreatModelSourceTest>>>>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import os
2+
import sys
3+
import posix
4+
5+
os.getenv("foo") # $ threatModelSource[environment]=os.getenv(..)
6+
os.getenvb("bar") # $ threatModelSource[environment]=os.getenvb(..)
7+
8+
os.environ["foo"] # $ threatModelSource[environment]=os.environ["foo"]
9+
os.environ.get("foo") # $ MISSING: threatModelSource[environment]=os.environ.get(..)
10+
11+
os.environb["bar"] # $ threatModelSource[environment]=os.environb["bar"]
12+
posix.environ[b"foo"] # $ threatModelSource[environment]=posix.environ[b"foo"]
13+
14+
15+
sys.argv[1] # $ threatModelSource[commandargs]=sys.argv[1]
16+
sys.orig_argv[1] # $ threatModelSource[commandargs]=sys.orig_argv[1]
17+
18+
########################################
19+
# argparse
20+
########################################
21+
22+
import argparse
23+
parser = argparse.ArgumentParser()
24+
parser.add_argument("foo")
25+
26+
args = parser.parse_args()
27+
args.foo # $ MISSING: threatModelSource[commandargs]=args.foo
28+
29+
explicit_argv_parsing = parser.parse_args(sys.argv)
30+
explicit_argv_parsing.foo # $ MISSING: threatModelSource[commandargs]=explicit_argv_parsing.foo
31+
32+
fake_args = parser.parse_args(["<foo>"])
33+
fake_args.foo
34+
35+
########################################
36+
# reading input from stdin
37+
########################################
38+
39+
sys.stdin.readline() # $ MISSING: threatModelSource
40+
input() # $ MISSING: threatModelSource
41+
42+
########################################
43+
# socket
44+
########################################
45+
46+
import socket
47+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
48+
s.connect(("example.com", 1234))
49+
s.recv(1024) # $ MISSING: threatModelSource[socket]

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def func2(environ, start_response): # $ requestHandler
4545
start_response(status, headers) # $ headerWriteBulk=headers headerWriteBulkUnsanitized=name,value
4646
return [b"Hello"] # $ HttpResponse responseBody=List
4747

48-
case = sys.argv[1]
48+
case = sys.argv[1] # $ threatModelSource[commandargs]=sys.argv[1]
4949
if case == "1":
5050
server = wsgiref.simple_server.WSGIServer(ADDRESS, wsgiref.simple_server.WSGIRequestHandler)
5151
server.set_app(func)

0 commit comments

Comments
 (0)