mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
split fuzzy read/writes on collections into 2 pseudo-properties
This commit is contained in:
@@ -81,11 +81,6 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
|
||||
) {
|
||||
this.loadStore(pred, succ, loadProp, storeProp)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this step on a collection can load a value with a known key.
|
||||
*/
|
||||
predicate canLoadValueWithKnownKey() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,10 +95,7 @@ module CollectionsTypeTracking {
|
||||
exists(CollectionFlowStep step, PseudoProperty field |
|
||||
summary = LoadStep(field) and
|
||||
step.load(pred, result, field) and
|
||||
not (
|
||||
step.canLoadValueWithKnownKey() and // for a step that could load a known key,
|
||||
field = mapValueUnknownKey() // don't load values with an unknown key.
|
||||
)
|
||||
not field = mapValueUnknownKey() // prune unknown reads in type-tracking
|
||||
or
|
||||
summary = StoreStep(field) and
|
||||
step.store(pred, result, field)
|
||||
@@ -191,7 +183,7 @@ private module CollectionDataFlow {
|
||||
) {
|
||||
pred = this and
|
||||
succ = element and
|
||||
fromProp = mapValueUnknownKey() and
|
||||
fromProp = mapValueAll() and
|
||||
toProp = "1"
|
||||
}
|
||||
}
|
||||
@@ -205,7 +197,7 @@ private module CollectionDataFlow {
|
||||
override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) {
|
||||
obj = this.getReceiver() and
|
||||
element = this.getCallback(0).getParameter(0) and
|
||||
prop = [setElement(), mapValueUnknownKey()]
|
||||
prop = [setElement(), mapValueAll()]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,10 +211,9 @@ private module CollectionDataFlow {
|
||||
override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) {
|
||||
obj = this.getReceiver() and
|
||||
element = this and
|
||||
prop = mapValue(this.getArgument(0))
|
||||
// reading the join of known and unknown values
|
||||
(prop = mapValue(this.getArgument(0)) or prop = mapValueUnknownKey())
|
||||
}
|
||||
|
||||
override predicate canLoadValueWithKnownKey() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,7 +221,8 @@ private module CollectionDataFlow {
|
||||
*
|
||||
* If the key of the call to `set` has a known string value,
|
||||
* then the value will be saved into a pseudo-property corresponding to the known string value.
|
||||
* The value will additionally be saved into a pseudo-property corresponding to values with unknown keys.
|
||||
* Otherwise the value will be saved into a pseudo-property corresponding to values with unknown keys.
|
||||
* The value will additionally be saved into a pseudo-property corresponding to all values.
|
||||
*/
|
||||
class MapSet extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
MapSet() { this.getMethodName() = "set" }
|
||||
@@ -246,9 +238,11 @@ private module CollectionDataFlow {
|
||||
* The pseudo-property represents both values where the key is a known string value (which is encoded in the pseudo-property),
|
||||
* and values where the key is unknown.
|
||||
*
|
||||
* Additionally, all elements are stored into the pseudo-property `mapValueAll()`.
|
||||
*
|
||||
* The return-type is `string` as this predicate is used to define which pseudo-properties exist.
|
||||
*/
|
||||
string getAPseudoProperty() { result = [mapValue(this.getArgument(0)), mapValueUnknownKey()] }
|
||||
string getAPseudoProperty() { result = [mapValue(this.getArgument(0)), mapValueAll()] }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,7 +256,7 @@ private module CollectionDataFlow {
|
||||
) {
|
||||
pred = this.getReceiver() and
|
||||
succ = this and
|
||||
fromProp = [mapValueUnknownKey(), setElement()] and
|
||||
fromProp = [mapValueAll(), setElement()] and
|
||||
toProp = iteratorElement()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,6 +613,11 @@ module PseudoProperties {
|
||||
*/
|
||||
string mapValueUnknownKey() { result = pseudoProperty("unknownMapValue") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of all the values in a map.
|
||||
*/
|
||||
string mapValueAll() { result = pseudoProperty("allMapValues") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
||||
* The string value of the `key` is encoded in the result, and there is only a result if the string value of `key` is known.
|
||||
|
||||
@@ -11,7 +11,9 @@ dataFlow
|
||||
| tst.js:2:16:2:23 | source() | tst.js:46:7:46:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:50:10:50:10 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:53:8:53:21 | map.get("key") |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:55:8:55:28 | map.get ... nKey()) |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:59:8:59:22 | map2.get("foo") |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:64:8:64:26 | map3.get(unknown()) |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:69:8:69:26 | map3.get(unknown()) |
|
||||
typeTracking
|
||||
| tst.js:2:16:2:23 | source() | tst.js:2:16:2:23 | source() |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:6:14:6:14 | e |
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
})
|
||||
|
||||
var map = new Map();
|
||||
map.set("key", source); map.set(unknownKey(), source);
|
||||
map.set("key", source);
|
||||
map.forEach(v => {
|
||||
sink(v);
|
||||
});
|
||||
@@ -52,5 +52,19 @@
|
||||
|
||||
sink(map.get("key")); // NOT OK.
|
||||
sink(map.get("nonExistingKey")); // OK.
|
||||
sink(map.get(unknownKey())); // NOT OK (for data-flow). OK for type-tracking.
|
||||
|
||||
// unknown write, known read
|
||||
var map2 = new map();
|
||||
map2.set(unknown(), source);
|
||||
sink(map2.get("foo")); // NOT OK (for data-flow). OK for type-tracking.
|
||||
|
||||
// unknown write, unknown read
|
||||
var map3 = new map();
|
||||
map3.set(unknown(), source);
|
||||
sink(map3.get(unknown())); // NOT OK (for data-flow). OK for type-tracking.
|
||||
|
||||
// known write, unknown read
|
||||
var map4 = new map();
|
||||
map4.set("foo", source);
|
||||
sink(map3.get(unknown())); // NOT OK (for data-flow). OK for type-tracking.
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user