Python: Use more common name for concept

This commit is contained in:
Rasmus Lerchedahl Petersen
2020-10-14 09:28:58 +02:00
parent a76d276b48
commit 93383747bd
9 changed files with 36 additions and 38 deletions

View File

@@ -24,7 +24,7 @@ class UnsafeDeserializationConfiguration extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
exists(UnmarshalingFunction d |
exists(Decoding d |
d.unsafe() and
sink = d.getAnInput()
)

View File

@@ -40,17 +40,20 @@ module SystemCommandExecution {
}
/**
* A function that decodes data from a binary or textual format.
* A data-flow node that decodes data from a binary or textual format. This
* is intended to include deserialization, unmarshalling, decoding, unpickling,
* unzipping, decrypting, parsing etc.
*
* Doing so should normally preserve taint, but it can also be a problem
* in itself, e.g. if it performs deserialization in a potentially unsafe way.
* in itself, e.g. if it allows code execution or could result in deinal-of-service.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `UnmarshalingFunction::Range` instead.
* extend `Decoding::Range` instead.
*/
class UnmarshalingFunction extends DataFlow::Node {
UnmarshalingFunction::Range self;
class Decoding extends DataFlow::Node {
Decoding::Range self;
UnmarshalingFunction() { this = self }
Decoding() { this = self }
/** Holds if this call is unsafe, e.g. if it may execute arbitrary code. */
predicate unsafe() { self.unsafe() }
@@ -65,15 +68,18 @@ class UnmarshalingFunction extends DataFlow::Node {
string getFormat() { result = self.getFormat() }
}
/** Provides a class for modeling new unmarshaling/decoding/deserialization functions. */
module UnmarshalingFunction {
/** Provides a class for modeling new decoding mechanisms. */
module Decoding {
/**
* A function that decodes data from a binary or textual format.
* Doing so should normally preserve taint, but it can oalso be a problem
* in itself, e.g. if it performs deserialization in a potentially unsafe way.
* A data-flow node that decodes data from a binary or textual format. This
* is intended to include deserialization, unmarshalling, decoding, unpickling,
* unzipping, decrypting, parsing etc.
*
* Doing so should normally preserve taint, but it can also be a problem
* in itself, e.g. if it allows code execution or could result in deinal-of-service.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `UnmarshalingFunction` instead.
* extend `Decoding` instead.
*/
abstract class Range extends DataFlow::Node {
/** Holds if this call is unsafe, e.g. if it may execute arbitrary code. */

View File

@@ -43,10 +43,8 @@ private module Dill {
* See https://pypi.org/project/dill/ (which currently refers you
* to https://docs.python.org/3/library/pickle.html#pickle.loads)
*/
private class DillLoadsCall extends UnmarshalingFunction::Range {
DillLoadsCall() {
this.asCfgNode().(CallNode).getFunction() = Dill::dill::loads().asCfgNode()
}
private class DillLoadsCall extends Decoding::Range {
DillLoadsCall() { this.asCfgNode().(CallNode).getFunction() = Dill::dill::loads().asCfgNode() }
override predicate unsafe() { any() }

View File

@@ -363,10 +363,8 @@ private module Stdlib {
* A call to `marshal.loads`
* See https://docs.python.org/3/library/marshal.html#marshal.loads
*/
private class MarshalLoadsCall extends UnmarshalingFunction::Range {
MarshalLoadsCall() {
this.asCfgNode().(CallNode).getFunction() = marshal::loads().asCfgNode()
}
private class MarshalLoadsCall extends Decoding::Range {
MarshalLoadsCall() { this.asCfgNode().(CallNode).getFunction() = marshal::loads().asCfgNode() }
override predicate unsafe() { any() }
@@ -416,10 +414,8 @@ private module Stdlib {
* A call to `pickle.loads`
* See https://docs.python.org/3/library/pickle.html#pickle.loads
*/
private class PickleLoadsCall extends UnmarshalingFunction::Range {
PickleLoadsCall() {
this.asCfgNode().(CallNode).getFunction() = pickle::loads().asCfgNode()
}
private class PickleLoadsCall extends Decoding::Range {
PickleLoadsCall() { this.asCfgNode().(CallNode).getFunction() = pickle::loads().asCfgNode() }
override predicate unsafe() { any() }

View File

@@ -45,10 +45,8 @@ private module Yaml {
* This function was briefly thought safe until new exploits were found in 2020,
* see https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation for details.
*/
private class YamlDeserialization extends UnmarshalingFunction::Range {
YamlDeserialization() {
this.asCfgNode().(CallNode).getFunction() = Yaml::yaml::load().asCfgNode()
}
private class YamlLoadCall extends Decoding::Range {
YamlLoadCall() { this.asCfgNode().(CallNode).getFunction() = Yaml::yaml::load().asCfgNode() }
override predicate unsafe() {
// If the `Loader` is not set to either `SafeLoader` or `BaseLoader` or not set at all,

View File

@@ -33,18 +33,18 @@ class SystemCommandExecutionTest extends InlineExpectationsTest {
}
}
class UnmarshalingFunctionTest extends InlineExpectationsTest {
UnmarshalingFunctionTest() { this = "UnmarshalingFunctionTest" }
class DecodingTest extends InlineExpectationsTest {
DecodingTest() { this = "DecodingTest" }
override string getARelevantTag() { result in ["getAnInput", "getOutput", "getFormat"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(UnmarshalingFunction ds, string unsafe |
exists(Decoding d, string unsafe |
(
ds.unsafe() and unsafe = "UNSAFE_"
d.unsafe() and unsafe = "UNSAFE_"
or
not ds.unsafe() and unsafe = ""
not d.unsafe() and unsafe = ""
) and
(
exists(DataFlow::Node data |
@@ -52,19 +52,19 @@ class UnmarshalingFunctionTest extends InlineExpectationsTest {
element = data.toString() and
value = value_from_expr(data.asExpr()) and
(
data = ds.getAnInput() and
data = d.getAnInput() and
tag = unsafe + "getAnInput"
or
data = ds.getOutput() and
data = d.getOutput() and
tag = unsafe + "getOutput"
)
)
or
exists(string format |
location = ds.getLocation() and
location = d.getLocation() and
element = format and
value = format and
format = ds.getFormat() and
format = d.getFormat() and
tag = unsafe + "getFormat"
)
)