Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4685f2d

Browse files
committed
Python: Address many review comments
still need to move concept tests
1 parent 433a362 commit 4685f2d

16 files changed

Lines changed: 285 additions & 238 deletions

File tree

python/ql/src/experimental/Security-new-dataflow/CWE-502/JsonGood.py

Lines changed: 0 additions & 10 deletions
This file was deleted.

python/ql/src/experimental/Security-new-dataflow/CWE-502/UnpicklingBad.py

Lines changed: 0 additions & 10 deletions
This file was deleted.

python/ql/src/experimental/Security-new-dataflow/CWE-502/UnsafeDeserialization.qhelp

Lines changed: 0 additions & 61 deletions
This file was deleted.

python/ql/src/experimental/Security-new-dataflow/CWE-502/UnsafeDeserialization.ql

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ class UnsafeDeserializationConfiguration extends TaintTracking::Configuration {
2323

2424
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
2525

26-
override predicate isSink(DataFlow::Node sink) { sink = any(DeserializationSink d).getData() }
26+
override predicate isSink(DataFlow::Node sink) {
27+
exists(UnmarshalingFunction d |
28+
d.unsafe() and
29+
sink = d.getAnInput()
30+
)
31+
}
2732
}
2833

2934
from UnsafeDeserializationConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink

python/ql/src/experimental/semmle/python/Concepts.qll

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,31 +40,52 @@ module SystemCommandExecution {
4040
}
4141

4242
/**
43-
* A data-flow node that performs deserialization in a potentially unsafe way.
43+
* A function that decodes data from a binary or textual format.
44+
* Doing so should normally preserve taint, but it can also be a problem
45+
* in itself, e.g. if it performs deserialization in a potentially unsafe way.
4446
*
4547
* Extend this class to refine existing API models. If you want to model new APIs,
46-
* extend `DeserializationSink::Range` instead.
48+
* extend `UnmarshalingFunction::Range` instead.
4749
*/
48-
class DeserializationSink extends DataFlow::Node {
49-
DeserializationSink::Range self;
50+
class UnmarshalingFunction extends DataFlow::Node {
51+
UnmarshalingFunction::Range self;
5052

51-
DeserializationSink() { this = self }
53+
UnmarshalingFunction() { this = self }
5254

53-
/** Gets the argument that specifies the command to be executed. */
54-
DataFlow::Node getData() { result = self.getData() }
55+
/** Holds if this call is unsafe, e.g. if it may execute arbitrary code. */
56+
predicate unsafe() { self.unsafe() }
57+
58+
/** Gets an input that is decoded by this function. */
59+
DataFlow::Node getAnInput() { result = self.getAnInput() }
60+
61+
/** Gets the output that contains the decoded data produced by this function. */
62+
DataFlow::Node getOutput() { result = self.getOutput() }
63+
64+
/** Gets an identifier for the format this function decodes from, such as "JSON". */
65+
string getFormat() { result = self.getFormat() }
5566
}
5667

57-
/** Provides a class for modeling new system-command execution APIs. */
58-
module DeserializationSink {
68+
/** Provides a class for modeling new unmarshaling/decoding/deserialization functions. */
69+
module UnmarshalingFunction {
5970
/**
60-
* A data-flow node that executes an operating system command,
61-
* for instance by spawning a new process.
71+
* A function that decodes data from a binary or textual format.
72+
* Doing so should normally preserve taint, but it can oalso be a problem
73+
* in itself, e.g. if it performs deserialization in a potentially unsafe way.
6274
*
6375
* Extend this class to model new APIs. If you want to refine existing API models,
64-
* extend `DeserializationSink` instead.
76+
* extend `UnmarshalingFunction` instead.
6577
*/
6678
abstract class Range extends DataFlow::Node {
67-
/** Gets the argument that specifies the command to be executed. */
68-
abstract DataFlow::Node getData();
79+
/** Holds if this call is unsafe, e.g. if it may execute arbitrary code. */
80+
abstract predicate unsafe();
81+
82+
/** Gets an input that is decoded by this function. */
83+
abstract DataFlow::Node getAnInput();
84+
85+
/** Gets the output that contains the decoded data produced by this function. */
86+
abstract DataFlow::Node getOutput();
87+
88+
/** Gets an identifier for the format this function decodes from, such as "JSON". */
89+
abstract string getFormat();
6990
}
7091
}

python/ql/src/experimental/semmle/python/Frameworks.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
*/
44

55
private import experimental.semmle.python.frameworks.Flask
6+
private import experimental.semmle.python.frameworks.Dill
67
private import experimental.semmle.python.frameworks.Django
7-
private import experimental.semmle.python.frameworks.Marshal
8-
private import experimental.semmle.python.frameworks.Pickle
98
private import experimental.semmle.python.frameworks.Stdlib
109
private import experimental.semmle.python.frameworks.Yaml
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the 'dill' package.
3+
* See https://pypi.org/project/dill/.
4+
*/
5+
6+
private import python
7+
private import experimental.dataflow.DataFlow
8+
private import experimental.dataflow.RemoteFlowSources
9+
private import experimental.semmle.python.Concepts
10+
11+
private module Dill {
12+
/** Gets a reference to the `dill` module. */
13+
private DataFlow::Node dill(DataFlow::TypeTracker t) {
14+
t.start() and
15+
result = DataFlow::importModule("dill")
16+
or
17+
exists(DataFlow::TypeTracker t2 | result = dill(t2).track(t2, t))
18+
}
19+
20+
/** Gets a reference to the `dill` module. */
21+
DataFlow::Node dill() { result = dill(DataFlow::TypeTracker::end()) }
22+
23+
module dill {
24+
/** Gets a reference to the `dill.loads` function. */
25+
private DataFlow::Node loads(DataFlow::TypeTracker t) {
26+
t.start() and
27+
result = DataFlow::importMember("dill", "loads")
28+
or
29+
t.startInAttr("loads") and
30+
result = dill()
31+
or
32+
exists(DataFlow::TypeTracker t2 | result = loads(t2).track(t2, t))
33+
}
34+
35+
/** Gets a reference to the `dill.loads` function. */
36+
DataFlow::Node loads() { result = loads(DataFlow::TypeTracker::end()) }
37+
}
38+
}
39+
40+
/**
41+
* A call to `dill.loads`
42+
* See https://pypi.org/project/dill/ (which currently refers you
43+
* to https://docs.python.org/3/library/pickle.html#pickle.loads)
44+
*/
45+
private class DillDeserialization extends UnmarshalingFunction::Range {
46+
DillDeserialization() {
47+
this.asCfgNode().(CallNode).getFunction() = Dill::dill::loads().asCfgNode()
48+
}
49+
50+
override predicate unsafe() { any() }
51+
52+
override DataFlow::Node getAnInput() {
53+
result.asCfgNode() = this.asCfgNode().(CallNode).getArg(0)
54+
}
55+
56+
override DataFlow::Node getOutput() { result = this }
57+
58+
override string getFormat() { none() }
59+
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ private import experimental.semmle.python.frameworks.Werkzeug
1313
// https://github.com/github/codeql/blob/9f95212e103c68d0c1dfa4b6f30fb5d53954ccef/python/ql/src/semmle/python/web/flask/Request.qll
1414
private module Flask {
1515
/** Gets a reference to the `flask` module. */
16-
DataFlow::Node flask(DataFlow::TypeTracker t) {
16+
private DataFlow::Node flask(DataFlow::TypeTracker t) {
1717
t.start() and
1818
result = DataFlow::importModule("flask")
1919
or
@@ -25,18 +25,18 @@ private module Flask {
2525

2626
module flask {
2727
/** Gets a reference to the `flask.request` object. */
28-
DataFlow::Node request(DataFlow::TypeTracker t) {
28+
private DataFlow::Node request(DataFlow::TypeTracker t) {
2929
t.start() and
3030
result = DataFlow::importMember("flask", "request")
3131
or
3232
t.startInAttr("request") and
3333
result = flask()
3434
or
35-
exists(DataFlow::TypeTracker t2 | result = flask::request(t2).track(t2, t))
35+
exists(DataFlow::TypeTracker t2 | result = request(t2).track(t2, t))
3636
}
3737

3838
/** Gets a reference to the `flask.request` object. */
39-
DataFlow::Node request() { result = flask::request(DataFlow::TypeTracker::end()) }
39+
DataFlow::Node request() { result = request(DataFlow::TypeTracker::end()) }
4040
}
4141

4242
// TODO: Do we even need this class? :|

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

Lines changed: 0 additions & 49 deletions
This file was deleted.

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

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)