Ruby: Introduce ContentSet::isElementOfType[OrUnknown]/1

This commit is contained in:
Tom Hvitved
2023-03-20 09:33:30 +01:00
parent 540542ceb5
commit a9ef3f95a2
7 changed files with 101 additions and 12 deletions

View File

@@ -1,3 +1,4 @@
private import codeql.util.Boolean
private import codeql.ruby.AST
private import codeql.ruby.ast.internal.Synthesis
private import codeql.ruby.CFG
@@ -456,12 +457,15 @@ private module Cached {
FlowSummaryImplSpecific::ParsePositions::isParsedElementLowerBoundPosition(_, includeUnknown,
lower)
} or
TElementContentOfTypeContent(string type, Boolean includeUnknown) {
type = any(Content::KnownElementContent content).getIndex().getValueType()
} or
TNoContentSet() // Only used by type-tracking
cached
class TContentSet =
TSingletonContent or TAnyElementContent or TKnownOrUnknownElementContent or
TElementLowerBoundContent;
TElementLowerBoundContent or TElementContentOfTypeContent;
private predicate trackKnownValue(ConstantValue cv) {
not cv.isFloat(_) and

View File

@@ -534,6 +534,21 @@ class ContentSet extends TContentSet {
this = TElementLowerBoundContent(lower, true)
}
/**
* Holds if this content set represents all `KnownElementContent`s where
* the index is of type `type`, as per `ConstantValue::getValueType/0`.
*/
predicate isElementOfType(string type) { this = TElementContentOfTypeContent(type, false) }
/**
* Holds if this content set represents `UnknownElementContent` unioned with
* all `KnownElementContent`s where the index is of type `type`, as per
* `ConstantValue::getValueType/0`.
*/
predicate isElementOfTypeOrUnknown(string type) {
this = TElementContentOfTypeContent(type, true)
}
/** Gets a textual representation of this content set. */
string toString() {
exists(Content c |
@@ -558,6 +573,16 @@ class ContentSet extends TContentSet {
includeUnknown = true and
result = lower + ".."
)
or
exists(string type, boolean includeUnknown |
this = TElementContentOfTypeContent(type, includeUnknown)
|
includeUnknown = false and
result = "any(" + type + ")!"
or
includeUnknown = true and
result = "any(" + type + ")"
)
}
/** Gets a content that may be stored into when storing into this set. */
@@ -576,7 +601,14 @@ class ContentSet extends TContentSet {
// step that store only into `1`
this.isKnownOrUnknownElement(result)
or
this.isElementLowerBound(_) and
// These reverse stores are not as accurate as they could be, but making
// them more accurate would result in a large fan-out
(
this.isElementLowerBound(_) or
this.isElementLowerBoundOrUnknown(_) or
this.isElementOfType(_) or
this.isElementOfTypeOrUnknown(_)
) and
result = TUnknownElementContent()
}
@@ -603,6 +635,15 @@ class ContentSet extends TContentSet {
includeUnknown = true and
result = TUnknownElementContent()
)
or
exists(string type, boolean includeUnknown |
this = TElementContentOfTypeContent(type, includeUnknown)
|
type = result.(Content::KnownElementContent).getIndex().getValueType()
or
includeUnknown = true and
result = TUnknownElementContent()
)
}
}

View File

@@ -34,8 +34,6 @@ class Configuration extends TaintTracking::Configuration {
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet set) {
// allow implicit reads of array elements
this.isSink(node) and
set.isKnownOrUnknownElement(any(DataFlow::Content::KnownElementContent content |
content.getIndex().getValueType() = "int"
))
set.isElementOfTypeOrUnknown("int")
}
}

View File

@@ -36,8 +36,6 @@ class Configuration extends TaintTracking::Configuration {
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet set) {
// allow implicit reads of array elements
this.isSink(node) and
set.isKnownOrUnknownElement(any(DataFlow::Content::KnownElementContent content |
content.getIndex().getValueType() = "int"
))
set.isElementOfTypeOrUnknown("int")
}
}

View File

@@ -449,6 +449,8 @@ private ContentFilter getFilterFromWithoutContentStep(DataFlow::ContentSet conte
or
content.isElementLowerBoundOrUnknown(_)
or
content.isElementOfTypeOrUnknown(_)
or
content.isSingleton(any(DataFlow::Content::UnknownElementContent c))
) and
result = MkElementFilter()
@@ -484,6 +486,10 @@ private ContentFilter getFilterFromWithContentStep(DataFlow::ContentSet content)
or
content.isElementLowerBoundOrUnknown(_)
or
content.isElementOfType(_)
or
content.isElementOfTypeOrUnknown(_)
or
content.isSingleton(any(DataFlow::Content::ElementContent c))
) and
result = MkElementFilter()

View File

@@ -248,6 +248,26 @@ edges
| semantics.rb:221:14:221:14 | h [element 2] : | semantics.rb:221:10:221:15 | call to s27 |
| semantics.rb:221:14:221:14 | h [element] : | semantics.rb:221:10:221:15 | call to s27 |
| semantics.rb:221:14:221:14 | h [element] : | semantics.rb:221:10:221:15 | call to s27 |
| semantics.rb:225:9:225:18 | call to source : | semantics.rb:226:13:226:13 | a : |
| semantics.rb:225:9:225:18 | call to source : | semantics.rb:226:13:226:13 | a : |
| semantics.rb:226:9:226:14 | call to s28 [element] : | semantics.rb:227:10:227:10 | x [element] : |
| semantics.rb:226:9:226:14 | call to s28 [element] : | semantics.rb:227:10:227:10 | x [element] : |
| semantics.rb:226:9:226:14 | call to s28 [element] : | semantics.rb:228:10:228:10 | x [element] : |
| semantics.rb:226:9:226:14 | call to s28 [element] : | semantics.rb:228:10:228:10 | x [element] : |
| semantics.rb:226:9:226:14 | call to s28 [element] : | semantics.rb:229:10:229:10 | x [element] : |
| semantics.rb:226:9:226:14 | call to s28 [element] : | semantics.rb:229:10:229:10 | x [element] : |
| semantics.rb:226:9:226:14 | call to s28 [element] : | semantics.rb:230:10:230:10 | x [element] : |
| semantics.rb:226:9:226:14 | call to s28 [element] : | semantics.rb:230:10:230:10 | x [element] : |
| semantics.rb:226:13:226:13 | a : | semantics.rb:226:9:226:14 | call to s28 [element] : |
| semantics.rb:226:13:226:13 | a : | semantics.rb:226:9:226:14 | call to s28 [element] : |
| semantics.rb:227:10:227:10 | x [element] : | semantics.rb:227:10:227:13 | ...[...] |
| semantics.rb:227:10:227:10 | x [element] : | semantics.rb:227:10:227:13 | ...[...] |
| semantics.rb:228:10:228:10 | x [element] : | semantics.rb:228:10:228:13 | ...[...] |
| semantics.rb:228:10:228:10 | x [element] : | semantics.rb:228:10:228:13 | ...[...] |
| semantics.rb:229:10:229:10 | x [element] : | semantics.rb:229:10:229:13 | ...[...] |
| semantics.rb:229:10:229:10 | x [element] : | semantics.rb:229:10:229:13 | ...[...] |
| semantics.rb:230:10:230:10 | x [element] : | semantics.rb:230:10:230:13 | ...[...] |
| semantics.rb:230:10:230:10 | x [element] : | semantics.rb:230:10:230:13 | ...[...] |
| semantics.rb:235:9:235:18 | call to source : | semantics.rb:240:5:240:5 | [post] h [element 1] : |
| semantics.rb:235:9:235:18 | call to source : | semantics.rb:240:5:240:5 | [post] h [element 1] : |
| semantics.rb:236:9:236:18 | call to source : | semantics.rb:241:5:241:5 | [post] h [element 2] : |
@@ -1206,6 +1226,28 @@ nodes
| semantics.rb:221:14:221:14 | h [element 2] : | semmle.label | h [element 2] : |
| semantics.rb:221:14:221:14 | h [element] : | semmle.label | h [element] : |
| semantics.rb:221:14:221:14 | h [element] : | semmle.label | h [element] : |
| semantics.rb:225:9:225:18 | call to source : | semmle.label | call to source : |
| semantics.rb:225:9:225:18 | call to source : | semmle.label | call to source : |
| semantics.rb:226:9:226:14 | call to s28 [element] : | semmle.label | call to s28 [element] : |
| semantics.rb:226:9:226:14 | call to s28 [element] : | semmle.label | call to s28 [element] : |
| semantics.rb:226:13:226:13 | a : | semmle.label | a : |
| semantics.rb:226:13:226:13 | a : | semmle.label | a : |
| semantics.rb:227:10:227:10 | x [element] : | semmle.label | x [element] : |
| semantics.rb:227:10:227:10 | x [element] : | semmle.label | x [element] : |
| semantics.rb:227:10:227:13 | ...[...] | semmle.label | ...[...] |
| semantics.rb:227:10:227:13 | ...[...] | semmle.label | ...[...] |
| semantics.rb:228:10:228:10 | x [element] : | semmle.label | x [element] : |
| semantics.rb:228:10:228:10 | x [element] : | semmle.label | x [element] : |
| semantics.rb:228:10:228:13 | ...[...] | semmle.label | ...[...] |
| semantics.rb:228:10:228:13 | ...[...] | semmle.label | ...[...] |
| semantics.rb:229:10:229:10 | x [element] : | semmle.label | x [element] : |
| semantics.rb:229:10:229:10 | x [element] : | semmle.label | x [element] : |
| semantics.rb:229:10:229:13 | ...[...] | semmle.label | ...[...] |
| semantics.rb:229:10:229:13 | ...[...] | semmle.label | ...[...] |
| semantics.rb:230:10:230:10 | x [element] : | semmle.label | x [element] : |
| semantics.rb:230:10:230:10 | x [element] : | semmle.label | x [element] : |
| semantics.rb:230:10:230:13 | ...[...] | semmle.label | ...[...] |
| semantics.rb:230:10:230:13 | ...[...] | semmle.label | ...[...] |
| semantics.rb:235:9:235:18 | call to source : | semmle.label | call to source : |
| semantics.rb:235:9:235:18 | call to source : | semmle.label | call to source : |
| semantics.rb:236:9:236:18 | call to source : | semmle.label | call to source : |

View File

@@ -224,10 +224,10 @@ end
def m28(i)
a = source "a"
x = s28(a)
sink x[0]
sink x[1] # $ MISSING: hasValueFlow=a
sink x[2] # $ MISSING: hasValueFlow=a
sink x[i] # $ MISSING: hasValueFlow=a
sink x[0] # $ SPURIOUS: hasValueFlow=a
sink x[1] # $ hasValueFlow=a
sink x[2] # $ hasValueFlow=a
sink x[i] # $ hasValueFlow=a
end
def m29(i)