Skip to content

Commit 887df47

Browse files
committed
Python: Update queries to be compatible with the new dependencies.
1 parent b916658 commit 887df47

19 files changed

+257
-242
lines changed

python/lib/ghsl/DefaultPasswordDB.qll

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,38 @@
11
private import python
22

33
// password = db.Column(..., server_default=...)
4-
54
class DBColumn extends Call {
6-
CallNode call;
7-
string name;
8-
ControlFlowNode object;
9-
Name var;
10-
string id;
5+
CallNode call;
6+
string name;
7+
ControlFlowNode object;
8+
Name var;
9+
string id;
1110

12-
DBColumn() {
13-
call.getFunction().(AttrNode).getObject(name) = object
14-
and name = "Column"
15-
and call = this.getAFlowNode()
16-
and object.getNode() = var.getVariable().getAnAccess()
17-
and var.getId() = id
18-
}
11+
DBColumn() {
12+
call.getFunction().(AttrNode).getObject(name) = object and
13+
name = "Column" and
14+
call = this.getAFlowNode() and
15+
object.getNode() = var.getVariable().getAnAccess() and
16+
var.getId() = id
17+
}
1918

20-
string getDbId() {
21-
result = id
22-
}
19+
string getDbId() { result = id }
2320

24-
predicate hasStaticDefault() {
25-
exists(DictItem arg |
26-
arg = call.getNode().getANamedArg()
27-
and arg.(Keyword).getArg() in ["server_default", "default"]
28-
and arg.(Keyword).getValue() instanceof ImmutableLiteral
29-
)
30-
}
21+
predicate hasStaticDefault() {
22+
exists(DictItem arg |
23+
arg = call.getNode().getANamedArg() and
24+
arg.(Keyword).getArg() in ["server_default", "default"] and
25+
arg.(Keyword).getValue() instanceof ImmutableLiteral
26+
)
27+
}
3128

32-
string assignedToVariable() {
33-
exists(AssignStmt assign, Variable v|
34-
assign.defines(v)
35-
and v.getId() = result
36-
and assign.getValue() = this
37-
)
38-
}
29+
string assignedToVariable() {
30+
exists(AssignStmt assign, Variable v |
31+
assign.defines(v) and
32+
v.getId() = result and
33+
assign.getValue() = this
34+
)
35+
}
3936

40-
string getColumnName() {
41-
result = call.getNode().getArg(0).(StrConst).getText()
42-
}
37+
string getColumnName() { result = call.getNode().getArg(0).(StringLiteral).getText() }
4338
}

python/lib/ghsl/HardcodedSecretSinks.qll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ private import semmle.python.Concepts
55
private import semmle.python.dataflow.new.RemoteFlowSources
66
private import semmle.python.dataflow.new.BarrierGuards
77
private import semmle.python.ApiGraphs
8-
private import DataFlow::PathGraph
98
private import semmle.python.frameworks.Flask
109

1110
abstract class CredentialSink extends DataFlow::Node { }
@@ -14,7 +13,7 @@ Expr getDictValueByKey(Dict dict, string key) {
1413
exists(KeyValuePair item |
1514
// d = {KEY: VALUE}
1615
item = dict.getAnItem() and
17-
key = item.getKey().(StrConst).getS() and
16+
key = item.getKey().(StringLiteral).getS() and
1817
result = item.getValue()
1918
)
2019
}
@@ -25,7 +24,7 @@ Expr getAssignStmtByKey(AssignStmt assign, string key) {
2524
sub = assign.getASubExpression() and
2625
// Make sure the keys match
2726
// TODO: What happens if this value itself is not static?
28-
key = sub.getASubExpression().(StrConst).getS() and
27+
key = sub.getASubExpression().(StringLiteral).getS() and
2928
// TODO: Only supports static strings, resolve the value??
3029
// result = assign.getASubExpression().(StrConst)
3130
result = sub.getValue()

python/lib/ghsl/InsecurelyStoredPassword.qll

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,16 @@ class User extends ClassDef {
5757

5858
predicate hasSecureInit() {
5959
this.hasInit() and
60-
not exists(InsecureHashTrackingConfiguration conf, DataFlow::Node source, DataFlow::Node sink |
60+
not exists(DataFlow::Node source, DataFlow::Node sink |
6161
this.inInit(sink) and
6262
this.isPasswordArg(source) and
63-
conf.hasFlow(source, sink)
63+
InsecureHashTaint::flow(source, sink)
6464
)
6565
}
6666

6767
predicate usedSecurely() {
68-
not exists(InsecureTaintTrackingConfiguration conf, DataFlow::Node source, DataFlow::Node sink |
69-
conf.hasFlow(source, sink) and
68+
not exists(DataFlow::Node source, DataFlow::Node sink |
69+
InsecurelyStoredPasswordTaint::flow(source, sink) and
7070
sink.(PasswordArg).getUser() = this
7171
)
7272
}
@@ -78,15 +78,13 @@ class User extends ClassDef {
7878
}
7979
}
8080

81-
class InsecureTaintTrackingConfiguration extends TaintTracking::Configuration {
82-
// is the password used in the init of the User protected by a secure hash?
83-
InsecureTaintTrackingConfiguration() { this = "InsecureTaintTrackingConfiguration" }
81+
// is the password used in the init of the User protected by a secure hash?
82+
module InsecurelyStoredPasswordTaintConfig implements DataFlow::ConfigSig {
83+
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
8484

85-
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
85+
predicate isSink(DataFlow::Node sink) { sink instanceof PasswordArg }
8686

87-
override predicate isSink(DataFlow::Node sink) { sink instanceof PasswordArg }
88-
89-
override predicate isAdditionalTaintStep(DataFlow::Node a, DataFlow::Node b) {
87+
predicate isAdditionalFlowStep(DataFlow::Node a, DataFlow::Node b) {
9088
// from a dict key to the dict, if the key is "password"
9189
exists(Dict dict, KeyValuePair pair |
9290
dict.getAnItem() = pair and
@@ -96,25 +94,25 @@ class InsecureTaintTrackingConfiguration extends TaintTracking::Configuration {
9694
)
9795
}
9896

99-
override predicate isSanitizer(DataFlow::Node node) { node instanceof HashSanitizer }
97+
predicate isBarrier(DataFlow::Node node) { node instanceof HashSanitizer }
10098
}
10199

102-
class InsecureHashTrackingConfiguration extends TaintTracking::Configuration {
103-
User user;
104-
105-
// does the body of the init of the User hash the password?
106-
InsecureHashTrackingConfiguration() { this = "InsecureHashTrackingConfiguration" }
100+
module InsecurelyStoredPasswordTaint = TaintTracking::Global<InsecurelyStoredPasswordTaintConfig>;
107101

108-
override predicate isSource(DataFlow::Node source) { user.isPasswordArg(source) }
102+
// does the body of the init of the User hash the password?
103+
module InsecureHashTaintConfig implements DataFlow::ConfigSig {
104+
predicate isSource(DataFlow::Node source) { any(User x).isPasswordArg(source) }
109105

110-
override predicate isSink(DataFlow::Node sink) {
111-
user.passwordAssignedFrom(sink) and
106+
predicate isSink(DataFlow::Node sink) {
107+
any(User x).passwordAssignedFrom(sink) and
112108
not sink instanceof HashSanitizer
113109
}
114110

115-
override predicate isSanitizer(DataFlow::Node node) { node instanceof HashSanitizer }
111+
predicate isBarrier(DataFlow::Node node) { node instanceof HashSanitizer }
116112
}
117113

114+
module InsecureHashTaint = TaintTracking::Global<InsecureHashTaintConfig>;
115+
118116
// assigment to self.password
119117
class SelfPasswordAttribute extends DataFlow::Node {
120118
Variable self;
@@ -204,8 +202,8 @@ private import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowD
204202

205203
/** Holds if the `call` is a call to the function `target`. */
206204
private predicate resolveCall(CallNode call, Function target) {
207-
// TODO: This should be exposed better from the standard library API
208-
DataFlowDispatch::resolveCall(call, target, _)
205+
// TODO: This should be exposed better from the standard library API
206+
DataFlowDispatch::resolveCall(call, target, _)
209207
}
210208

211209
/**
@@ -219,9 +217,9 @@ private predicate resolveCall(CallNode call, Function target) {
219217
class HashSanitizerWrapperFunction extends HashSanitizer {
220218
HashSanitizerWrapperFunction() {
221219
exists(CallNode hashCall, Function hashWrapper |
222-
hashWrapper.contains(any(HashSanitizerConcrete hsc).asExpr()) and
223-
resolveCall(hashCall, hashWrapper) and
224-
this.asCfgNode() = hashCall.getArg(0)
220+
hashWrapper.contains(any(HashSanitizerConcrete hsc).asExpr()) and
221+
resolveCall(hashCall, hashWrapper) and
222+
this.asCfgNode() = hashCall.getArg(0)
225223
)
226224
}
227225
}

python/lib/ghsl/LocalSources.qll

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ module LocalSources {
77
private import semmle.python.Concepts
88
private import semmle.python.dataflow.new.BarrierGuards
99
private import semmle.python.ApiGraphs
10-
private import DataFlow::PathGraph
1110

1211
abstract class Range extends DataFlow::Node { }
1312

@@ -95,18 +94,26 @@ module LocalSources {
9594
call = API::moduleImport(["json", "simplejson"]).getMember("load").getACall()
9695
or
9796
// yaml.load
98-
call = API::moduleImport("yaml").getMember(["load", "load_all", "safe_load", "safe_load_all"]).getACall()
97+
call =
98+
API::moduleImport("yaml")
99+
.getMember(["load", "load_all", "safe_load", "safe_load_all"])
100+
.getACall()
99101
or
100102
// msgpack.load
101103
call = API::moduleImport("msgpack").getMember("load").getACall()
102104
or
103105
// pickle.load
104106
// dill.load
105-
call = API::moduleImport(["cPickle", "_pickle", "pickle", "dill"]).getMember("load").getACall()
107+
call =
108+
API::moduleImport(["cPickle", "_pickle", "pickle", "dill"]).getMember("load").getACall()
106109
or
107110
// pickle.Unpickler.load
108111
// dill.Unpickler.load
109-
call = API::moduleImport(["cPickle", "pickle", "dill"]).getMember("Unpickler").getACall().getAMethodCall("load")
112+
call =
113+
API::moduleImport(["cPickle", "pickle", "dill"])
114+
.getMember("Unpickler")
115+
.getACall()
116+
.getAMethodCall("load")
110117
or
111118
// shelve.open
112119
call = API::moduleImport("shelve").getMember("open").getACall()
@@ -137,45 +144,57 @@ module LocalSources {
137144
// pandas.read_gbq
138145
// pandas.read_stata
139146
// generate call expressions for each of the above pandas functions including ExcelFile.parse and HDFStore.* that have to be handled separately
140-
call = API::moduleImport("pandas")
141-
.getMember([
142-
"read_csv", "read_fwf", "read_excel", "read_json", "read_html", "read_xml",
143-
"read_hdf", "read_feather", "read_parquet", "read_orc", "read_sas", "read_spss", "read_sql_table",
144-
"read_sql_query", "read_sql", "read_gbq", "read_stata"
145-
])
146-
.getACall()
147+
call =
148+
API::moduleImport("pandas")
149+
.getMember([
150+
"read_csv", "read_fwf", "read_excel", "read_json", "read_html", "read_xml",
151+
"read_hdf", "read_feather", "read_parquet", "read_orc", "read_sas", "read_spss",
152+
"read_sql_table", "read_sql_query", "read_sql", "read_gbq", "read_stata"
153+
])
154+
.getACall()
147155
or
148156
// pandas.ExcelFile.parse
149-
call = API::moduleImport("pandas")
150-
.getMember("ExcelFile")
151-
.getACall()
152-
.getAMethodCall("parse")
157+
call =
158+
API::moduleImport("pandas").getMember("ExcelFile").getACall().getAMethodCall("parse")
153159
or
154160
// pandas.HDFStore.get
155161
// pandas.HDFStore.select
156162
// pandas.HDFStore.info
157163
// pandas.HDFStore.keys
158164
// pandas.HDFStore.groups
159165
// pandas.HDFStore.walk
160-
call = API::moduleImport("pandas")
161-
.getMember("HDFStore")
162-
.getACall()
163-
.getAMethodCall(["get", "select", "info", "keys", "groups", "walk"])
166+
call =
167+
API::moduleImport("pandas")
168+
.getMember("HDFStore")
169+
.getACall()
170+
.getAMethodCall(["get", "select", "info", "keys", "groups", "walk"])
164171
or
165172
// polars.read_csv
166-
call = API::moduleImport("polars").getMember(["read_csv", "read_csv_batched", "scan_csv"]).getACall()
173+
call =
174+
API::moduleImport("polars")
175+
.getMember(["read_csv", "read_csv_batched", "scan_csv"])
176+
.getACall()
167177
or
168178
// polars.read_ipc
169-
call = API::moduleImport("polars").getMember(["read_ipc", "scan_ipc", "read_ipc_schema"]).getACall()
179+
call =
180+
API::moduleImport("polars")
181+
.getMember(["read_ipc", "scan_ipc", "read_ipc_schema"])
182+
.getACall()
170183
or
171184
// polars.read_parquet, polars.scan_parquet, polars.read_parquet_schema
172-
call = API::moduleImport("polars").getMember(["read_parquet", "scan_parquet", "read_parquet_schema"]).getACall()
185+
call =
186+
API::moduleImport("polars")
187+
.getMember(["read_parquet", "scan_parquet", "read_parquet_schema"])
188+
.getACall()
173189
or
174190
// polars.read_sql
175191
call = API::moduleImport("polars").getMember("read_sql").getACall()
176192
or
177193
// polars.read_json, polars.read_ndjson, polars.scan_ndjson
178-
call = API::moduleImport("polars").getMember(["read_json", "read_ndjson", "scan_ndjson"]).getACall()
194+
call =
195+
API::moduleImport("polars")
196+
.getMember(["read_json", "read_ndjson", "scan_ndjson"])
197+
.getACall()
179198
or
180199
// polars.read_avro
181200
call = API::moduleImport("polars").getMember("read_avro").getACall()
@@ -186,24 +205,37 @@ module LocalSources {
186205
// pyarrow.csv.read_csv
187206
// pyarrow.csv.open_csv
188207
// pyarrow.csv.CSVStreamingReader
189-
call = API::moduleImport("pyarrow").getMember("csv").getMember(["read_csv", "open_csv", "CSVStreamingReader"]).getACall()
208+
call =
209+
API::moduleImport("pyarrow")
210+
.getMember("csv")
211+
.getMember(["read_csv", "open_csv", "CSVStreamingReader"])
212+
.getACall()
190213
or
191214
// pyarrow.feather.read_feather
192215
// pyarrow.feather.read_table
193-
call = API::moduleImport("pyarrow").getMember("feather").getMember(["read_feather", "read_table"]).getACall()
216+
call =
217+
API::moduleImport("pyarrow")
218+
.getMember("feather")
219+
.getMember(["read_feather", "read_table"])
220+
.getACall()
194221
or
195222
// pyarrow.json.read_json
196223
call = API::moduleImport("pyarrow").getMember("json").getMember("read_json").getACall()
224+
or
197225
// pyarrow.parquet.ParquetDataset
198226
// pyarrow.parquet.ParquetFile
199227
// pyarrow.parquet.read_table
200228
// pyarrow.parquet.read_metadata
201229
// pyarrow.parquet.read_pandas
202230
// pyarrow.parquet.read_schema
203-
or
204-
call = API::moduleImport("pyarrow").getMember("parquet").getMember([
205-
"ParquetDataset", "ParquetFile", "read_table", "read_metadata", "read_pandas", "read_schema"
206-
]).getACall()
231+
call =
232+
API::moduleImport("pyarrow")
233+
.getMember("parquet")
234+
.getMember([
235+
"ParquetDataset", "ParquetFile", "read_table", "read_metadata", "read_pandas",
236+
"read_schema"
237+
])
238+
.getACall()
207239
) and
208240
this = call
209241
) and

0 commit comments

Comments
 (0)