Merge branch 'main' into threat-models

This commit is contained in:
Rasmus Wriedt Larsen
2024-09-23 11:19:58 +02:00
committed by GitHub
6529 changed files with 233607 additions and 131008 deletions

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1134,66 +1134,38 @@ module Make<LocationSig Location, InputSig<Location> Input> {
final class AstCfgNode = AstCfgNodeImpl;
/** A node to be included in the output of `TestOutput`. */
signature class RelevantNodeSig extends Node {
/**
* Gets a string used to resolve ties in node and edge ordering.
*/
string getOrderDisambiguation();
}
signature class RelevantNodeSig extends Node;
/**
* Import this module into a `.ql` file of `@kind graph` to render a CFG. The
* Import this module into a `.ql` file to output a CFG. The
* graph is restricted to nodes from `RelevantNode`.
*/
module TestOutput<RelevantNodeSig RelevantNode> {
/** Holds if `n` is a relevant node in the CFG. */
query predicate nodes(RelevantNode n, string attr, string val) {
attr = "semmle.order" and
val =
any(int i |
n =
rank[i](RelevantNode p, string filePath, int startLine, int startColumn, int endLine,
int endColumn |
p.getLocation().hasLocationInfo(filePath, startLine, startColumn, endLine, endColumn)
|
p
order by
filePath, startLine, startColumn, endLine, endColumn, p.toString(),
p.getOrderDisambiguation()
)
).toString()
}
/** Holds if `pred -> succ` is an edge in the CFG. */
query predicate edges(RelevantNode pred, RelevantNode succ, string attr, string val) {
attr = "semmle.label" and
val =
query predicate edges(RelevantNode pred, RelevantNode succ, string label) {
label =
strictconcat(SuccessorType t, string s |
succ = getASuccessor(pred, t) and
if successorTypeIsSimple(t) then s = "" else s = t.toString()
|
s, ", " order by s
)
or
attr = "semmle.order" and
val =
any(int i |
succ =
rank[i](RelevantNode s, SuccessorType t, string filePath, int startLine,
int startColumn, int endLine, int endColumn |
s = getASuccessor(pred, t) and
s.getLocation().hasLocationInfo(filePath, startLine, startColumn, endLine, endColumn)
|
s
order by
filePath, startLine, startColumn, endLine, endColumn, t.toString(), s.toString(),
s.getOrderDisambiguation()
)
).toString()
}
module Mermaid {
private string nodeId(RelevantNode n) { nodes(n, "semmle.order", result) }
private string nodeId(RelevantNode n) {
result =
any(int i |
n =
rank[i](RelevantNode p, string filePath, int startLine, int startColumn, int endLine,
int endColumn |
p.getLocation()
.hasLocationInfo(filePath, startLine, startColumn, endLine, endColumn)
|
p order by filePath, startLine, startColumn, endLine, endColumn, p.toString()
)
).toString()
}
private string nodes() {
result =
@@ -1205,10 +1177,10 @@ module Make<LocationSig Location, InputSig<Location> Input> {
)
}
private string edge(RelevantNode pred, RelevantNode succ, string ord) {
edges(pred, succ, "semmle.order", ord) and
private string edge(RelevantNode pred, RelevantNode succ) {
edges(pred, succ, _) and
exists(string label |
edges(pred, succ, "semmle.label", label) and
edges(pred, succ, label) and
if label = ""
then result = nodeId(pred) + " --> " + nodeId(succ)
else result = nodeId(pred) + " -- " + label + " --> " + nodeId(succ)
@@ -1217,10 +1189,14 @@ module Make<LocationSig Location, InputSig<Location> Input> {
private string edges() {
result =
concat(RelevantNode pred, RelevantNode succ, string edge, string ord |
edge = edge(pred, succ, ord)
concat(RelevantNode pred, RelevantNode succ, string edge, string filePath, int startLine,
int startColumn, int endLine, int endColumn |
edge = edge(pred, succ) and
pred.getLocation().hasLocationInfo(filePath, startLine, startColumn, endLine, endColumn)
|
edge, "\n" order by ord
edge, "\n"
order by
filePath, startLine, startColumn, endLine, endColumn, pred.toString()
)
}

View File

@@ -1,5 +1,5 @@
name: codeql/controlflow
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
dependencies:

View File

@@ -1,3 +1,17 @@
## 1.1.2
No user-facing changes.
## 1.1.1
No user-facing changes.
## 1.1.0
### Deprecated APIs
* The source/sink grouping feature of the data flow library has been removed. It was introduced primarily for debugging, but has not proven useful.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,5 @@
## 1.1.0
### Deprecated APIs
* The source/sink grouping feature of the data flow library has been removed. It was introduced primarily for debugging, but has not proven useful.

View File

@@ -0,0 +1,3 @@
## 1.1.1
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.1.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.1.2

View File

@@ -298,7 +298,7 @@ signature module InputSig<LocationSig Location> {
/** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue);
predicate knownSourceModel(Node sink, string model);
predicate knownSourceModel(Node source, string model);
predicate knownSinkModel(Node sink, string model);
@@ -424,12 +424,6 @@ module Configs<LocationSig Location, InputSig<Location> Lang> {
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `flowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `flowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
@@ -546,12 +540,6 @@ module Configs<LocationSig Location, InputSig<Location> Lang> {
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `flowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `flowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*

View File

@@ -585,11 +585,13 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
2 <= strictcount(CapturedVariable v | captureAccess(v, c))
or
// Constructors that capture a variable may assign it to a field, which also
// entails a this-to-this summary.
captureAccess(_, c) and c.isConstructor()
// entails a this-to-this summary. If there are multiple constructors, then
// they might call each other, so if one constructor captures a variable we
// allow this-to-this summaries for all of them.
exists(ClosureExpr ce | ce.hasBody(c) and c.isConstructor() and hasConstructorCapture(ce, _))
}
/** Holds if the constructor, if any, for the closure defined by `ce` captures `v`. */
/** Holds if a constructor, if any, for the closure defined by `ce` captures `v`. */
private predicate hasConstructorCapture(ClosureExpr ce, CapturedVariable v) {
exists(Callable c | ce.hasBody(c) and c.isConstructor() and captureAccess(v, c))
}

View File

@@ -0,0 +1,548 @@
/**
* Provides classes for performing global (inter-procedural)
* content-sensitive data flow analyses.
*
* Unlike `DataFlow::Global`, we allow for data to be stored (possibly nested) inside
* contents of sources and sinks.
* We track flow paths of the form
*
* ```
* source --value-->* node
* (--read--> node --value-->* node)*
* --(non-value|value)-->* node
* (--store--> node --value-->* node)*
* --value-->* sink
* ```
*
* where `--value-->` is a value-preserving flow step, `--read-->` is a read
* step, `--store-->` is a store step, and `--(non-value)-->` is a
* non-value-preserving flow step.
*
* That is, first a sequence of 0 or more reads, followed by 0 or more additional
* steps, followed by 0 or more stores, with value-preserving steps allowed in
* between all other steps.
*/
private import codeql.dataflow.DataFlow
private import codeql.util.Boolean
private import codeql.util.Location
module MakeImplContentDataFlow<LocationSig Location, InputSig<Location> Lang> {
private import Lang
private import DataFlowMake<Location, Lang>
private import DataFlowImplCommon::MakeImplCommon<Location, Lang>
/**
* An input configuration for content data flow.
*/
signature module ConfigSig {
/**
* Holds if `source` is a relevant data flow source.
*/
predicate isSource(Node source);
/**
* Holds if `sink` is a relevant data flow sink.
*/
predicate isSink(Node sink);
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrier(Node node) { none() }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
default FlowFeature getAFeature() { none() }
/** Gets a limit on the number of reads out of sources and number of stores into sinks. */
default int accessPathLimit() { result = Lang::accessPathLimit() }
/** Holds if `c` is relevant for reads out of sources or stores into sinks. */
default predicate isRelevantContent(ContentSet c) { any() }
}
/**
* Constructs a global content data flow computation.
*/
module Global<ConfigSig ContentConfig> {
private module FlowConfig implements StateConfigSig {
class FlowState = State;
predicate isSource(Node source, FlowState state) {
ContentConfig::isSource(source) and
state.(InitState).decode(true)
}
predicate isSink(Node sink, FlowState state) {
ContentConfig::isSink(sink) and
(
state instanceof InitState or
state instanceof StoreState or
state instanceof ReadState
)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
storeStep(node1, state1, _, node2, state2) or
readStep(node1, state1, _, node2, state2) or
additionalStep(node1, state1, node2, state2)
}
predicate isBarrier = ContentConfig::isBarrier/1;
FlowFeature getAFeature() { result = ContentConfig::getAFeature() }
predicate accessPathLimit = ContentConfig::accessPathLimit/0;
// needed to record reads/stores inside summarized callables
predicate includeHiddenNodes() { any() }
}
private module Flow = GlobalWithState<FlowConfig>;
/**
* Holds if data stored inside `sourceAp` on `source` flows to `sinkAp` inside `sink`
* for this configuration. `preservesValue` indicates whether any of the additional
* flow steps defined by `isAdditionalFlowStep` are needed.
*
* For the source access path, `sourceAp`, the top of the stack represents the content
* that was last read from. That is, if `sourceAp` is `Field1.Field2` (with `Field1`
* being the top of the stack), then there is flow from `source.Field2.Field1`.
*
* For the sink access path, `sinkAp`, the top of the stack represents the content
* that was last stored into. That is, if `sinkAp` is `Field1.Field2` (with `Field1`
* being the top of the stack), then there is flow into `sink.Field1.Field2`.
*/
predicate flow(
Node source, AccessPath sourceAp, Node sink, AccessPath sinkAp, boolean preservesValue
) {
exists(Flow::PathNode pathSource, Flow::PathNode pathSink |
Flow::flowPath(pathSource, pathSink) and
nodeReaches(pathSource, TAccessPathNil(), TAccessPathNil(), pathSink, sourceAp, sinkAp) and
source = pathSource.getNode() and
sink = pathSink.getNode()
|
pathSink.getState().(InitState).decode(preservesValue)
or
pathSink.getState().(ReadState).decode(_, preservesValue)
or
pathSink.getState().(StoreState).decode(_, preservesValue)
)
}
private newtype TState =
TInitState(Boolean preservesValue) or
TStoreState(int size, Boolean preservesValue) {
size in [1 .. ContentConfig::accessPathLimit()]
} or
TReadState(int size, Boolean preservesValue) {
size in [1 .. ContentConfig::accessPathLimit()]
}
abstract private class State extends TState {
abstract string toString();
}
/** A flow state representing no reads or stores. */
private class InitState extends State, TInitState {
private boolean preservesValue_;
InitState() { this = TInitState(preservesValue_) }
override string toString() { result = "Init(" + preservesValue_ + ")" }
predicate decode(boolean preservesValue) { preservesValue = preservesValue_ }
}
/** A flow state representing that content has been stored into. */
private class StoreState extends State, TStoreState {
private boolean preservesValue_;
private int size_;
StoreState() { this = TStoreState(size_, preservesValue_) }
override string toString() { result = "StoreState(" + size_ + "," + preservesValue_ + ")" }
predicate decode(int size, boolean preservesValue) {
size = size_ and preservesValue = preservesValue_
}
}
/** A flow state representing that content has been read from. */
private class ReadState extends State, TReadState {
private boolean preservesValue_;
private int size_;
ReadState() { this = TReadState(size_, preservesValue_) }
override string toString() { result = "ReadState(" + size_ + "," + preservesValue_ + ")" }
predicate decode(int size, boolean preservesValue) {
size = size_ and preservesValue = preservesValue_
}
}
private predicate storeStep(
Node node1, State state1, ContentSet c, Node node2, StoreState state2
) {
exists(boolean preservesValue, int size |
storeSet(node1, c, node2, _, _) and
ContentConfig::isRelevantContent(c) and
state2.decode(size + 1, preservesValue)
|
state1.(InitState).decode(preservesValue) and size = 0
or
state1.(ReadState).decode(_, preservesValue) and size = 0
or
state1.(StoreState).decode(size, preservesValue)
)
}
private predicate readStep(Node node1, State state1, ContentSet c, Node node2, ReadState state2) {
exists(int size |
readSet(node1, c, node2) and
ContentConfig::isRelevantContent(c) and
state2.decode(size + 1, true)
|
state1.(InitState).decode(true) and
size = 0
or
state1.(ReadState).decode(size, true)
)
}
private predicate additionalStep(Node node1, State state1, Node node2, State state2) {
ContentConfig::isAdditionalFlowStep(node1, node2) and
(
state1 instanceof InitState and
state2.(InitState).decode(false)
or
exists(int size |
state1.(ReadState).decode(size, _) and
state2.(ReadState).decode(size, false)
)
)
}
private newtype TAccessPath =
TAccessPathNil() or
TAccessPathCons(ContentSet head, AccessPath tail) {
nodeReachesStore(_, _, _, _, head, _, tail)
or
nodeReachesRead(_, _, _, _, head, tail, _)
}
/** An access path. */
class AccessPath extends TAccessPath {
/** Gets the head of this access path, if any. */
ContentSet getHead() { this = TAccessPathCons(result, _) }
/** Gets the tail of this access path, if any. */
AccessPath getTail() { this = TAccessPathCons(_, result) }
/**
* Gets a textual representation of this access path.
*
* Elements are dot-separated, and the head of the stack is
* rendered first.
*/
string toString() {
this = TAccessPathNil() and
result = ""
or
exists(ContentSet head, AccessPath tail |
this = TAccessPathCons(head, tail) and
result = head + "." + tail
)
}
private ContentSet getAtIndex(int i) {
i = 0 and
result = this.getHead()
or
i > 0 and
result = this.getTail().getAtIndex(i - 1)
}
private AccessPath reverse0(int i) {
i = -1 and result = TAccessPathNil()
or
i >= 0 and
result = TAccessPathCons(this.getAtIndex(i), this.reverse0(i - 1))
}
/**
* Gets the length of this access path.
*/
private int length() {
result = 0 and this = TAccessPathNil()
or
result = 1 + this.getTail().length()
}
/**
* Gets the reversed access path, if any.
*
* Note that not all access paths have a reverse as these are not
* included by default in the IPA type.
*/
AccessPath reverse() { result = this.reverse0(this.length() - 1) }
}
/**
* Provides a big-step flow relation, where flow stops at read/store steps that
* must be recorded, and flow via `subpaths` such that reads/stores inside
* summarized callables can be recorded as well.
*/
private module BigStepFlow {
private predicate reachesSink(Flow::PathNode node) {
FlowConfig::isSink(node.getNode(), node.getState())
or
reachesSink(node.getASuccessor())
}
/**
* Holds if the flow step `pred -> succ` should not be allowed to be included
* in the big-step relation.
*/
pragma[nomagic]
private predicate excludeStep(Flow::PathNode pred, Flow::PathNode succ) {
pred.getASuccessor() = succ and
(
// we need to record reads/stores inside summarized callables
Flow::PathGraph::subpaths(pred, _, _, succ)
or
// only allow flow into a summarized callable, as part of the big-step
// relation, when flow can reach a sink without going back out
Flow::PathGraph::subpaths(pred, succ, _, _) and
not reachesSink(succ)
)
or
exists(Node predNode, State predState, Node succNode, State succState |
succNodeAndState(pred, predNode, predState, succ, succNode, succState)
|
// needed to record store steps
storeStep(predNode, predState, _, succNode, succState)
or
// needed to record read steps
readStep(predNode, predState, _, succNode, succState)
)
}
pragma[nomagic]
private DataFlowCallable getEnclosingCallableImpl(Flow::PathNode node) {
result = getNodeEnclosingCallable(node.getNode())
}
pragma[inline]
private DataFlowCallable getEnclosingCallable(Flow::PathNode node) {
pragma[only_bind_into](result) = getEnclosingCallableImpl(pragma[only_bind_out](node))
}
pragma[nomagic]
private predicate bigStepEntry(Flow::PathNode node) {
(
FlowConfig::isSource(node.getNode(), node.getState())
or
excludeStep(_, node)
or
Flow::PathGraph::subpaths(_, node, _, _)
)
}
pragma[nomagic]
private predicate bigStepExit(Flow::PathNode node) {
(
bigStepEntry(node)
or
FlowConfig::isSink(node.getNode(), node.getState())
or
excludeStep(node, _)
or
Flow::PathGraph::subpaths(_, _, node, _)
)
}
pragma[nomagic]
private predicate step(Flow::PathNode pred, Flow::PathNode succ) {
pred.getASuccessor() = succ and
not excludeStep(pred, succ)
}
pragma[nomagic]
private predicate stepRec(Flow::PathNode pred, Flow::PathNode succ) {
step(pred, succ) and
not bigStepEntry(pred)
}
private predicate stepRecPlus(Flow::PathNode n1, Flow::PathNode n2) =
fastTC(stepRec/2)(n1, n2)
/**
* Holds if there is flow `pathSucc+(pred) = succ`, and such a flow path does
* not go through any reads/stores that need to be recorded, or summarized
* steps.
*/
pragma[nomagic]
private predicate bigStep(Flow::PathNode pred, Flow::PathNode succ) {
exists(Flow::PathNode mid |
bigStepEntry(pred) and
step(pred, mid)
|
succ = mid
or
stepRecPlus(mid, succ)
) and
bigStepExit(succ)
}
pragma[nomagic]
predicate bigStepNotLocal(Flow::PathNode pred, Flow::PathNode succ) {
bigStep(pred, succ) and
not getEnclosingCallable(pred) = getEnclosingCallable(succ)
}
pragma[nomagic]
predicate bigStepMaybeLocal(Flow::PathNode pred, Flow::PathNode succ) {
bigStep(pred, succ) and
getEnclosingCallable(pred) = getEnclosingCallable(succ)
}
}
/**
* Holds if `source` can reach `node`, having read `reads` from the source and
* written `stores` into `node`.
*
* `source` is either a source from a configuration, in which case `scReads` and
* `scStores` are always empty, or it is the parameter of a summarized callable,
* in which case `scReads` and `scStores` record the reads/stores for a summary
* context, that is, the reads/stores for an argument that can reach the parameter.
*/
pragma[nomagic]
private predicate nodeReaches(
Flow::PathNode source, AccessPath scReads, AccessPath scStores, Flow::PathNode node,
AccessPath reads, AccessPath stores
) {
node = source and
reads = scReads and
stores = scStores and
(
Flow::flowPath(source, _) and
scReads = TAccessPathNil() and
scStores = TAccessPathNil()
or
// the argument in a sub path can be reached, so we start flow from the sub path
// parameter, while recording the read/store summary context
exists(Flow::PathNode arg |
nodeReachesSubpathArg(_, _, _, arg, scReads, scStores) and
Flow::PathGraph::subpaths(arg, source, _, _)
)
)
or
exists(Flow::PathNode mid |
nodeReaches(source, scReads, scStores, mid, reads, stores) and
BigStepFlow::bigStepMaybeLocal(mid, node)
)
or
exists(Flow::PathNode mid |
nodeReaches(source, scReads, scStores, mid, reads, stores) and
BigStepFlow::bigStepNotLocal(mid, node) and
// when flow is not local, we cannot flow back out, so we may stop
// flow early when computing summary flow
Flow::flowPath(source, _) and
scReads = TAccessPathNil() and
scStores = TAccessPathNil()
)
or
// store step
exists(AccessPath storesMid, ContentSet c |
nodeReachesStore(source, scReads, scStores, node, c, reads, storesMid) and
stores = TAccessPathCons(c, storesMid)
)
or
// read step
exists(AccessPath readsMid, ContentSet c |
nodeReachesRead(source, scReads, scStores, node, c, readsMid, stores) and
reads = TAccessPathCons(c, readsMid)
)
or
// flow-through step; match outer stores/reads with inner store/read summary contexts
exists(Flow::PathNode mid, AccessPath innerScReads, AccessPath innerScStores |
nodeReachesSubpathArg(source, scReads, scStores, mid, innerScReads, innerScStores) and
subpathArgReachesOut(mid, innerScReads, innerScStores, node, reads, stores)
)
}
pragma[nomagic]
private predicate succNodeAndState(
Flow::PathNode pre, Node preNode, State preState, Flow::PathNode succ, Node succNode,
State succState
) {
pre.getNode() = preNode and
pre.getState() = preState and
succ.getNode() = succNode and
succ.getState() = succState and
pre.getASuccessor() = succ
}
pragma[nomagic]
private predicate nodeReachesStore(
Flow::PathNode source, AccessPath scReads, AccessPath scStores, Flow::PathNode target,
ContentSet c, AccessPath reads, AccessPath stores
) {
exists(Flow::PathNode mid, State midState, Node midNode, State targetState, Node targetNode |
nodeReaches(source, scReads, scStores, mid, reads, stores) and
succNodeAndState(mid, midNode, midState, target, targetNode, targetState) and
storeStep(midNode, midState, c, targetNode, targetState)
)
}
pragma[nomagic]
private predicate nodeReachesRead(
Flow::PathNode source, AccessPath scReads, AccessPath scStores, Flow::PathNode target,
ContentSet c, AccessPath reads, AccessPath stores
) {
exists(Flow::PathNode mid, State midState, Node midNode, State targetState, Node targetNode |
nodeReaches(source, scReads, scStores, mid, reads, stores) and
succNodeAndState(mid, midNode, midState, target, targetNode, targetState) and
readStep(midNode, midState, c, targetNode, targetState)
)
}
pragma[nomagic]
private predicate nodeReachesSubpathArg(
Flow::PathNode source, AccessPath scReads, AccessPath scStores, Flow::PathNode arg,
AccessPath reads, AccessPath stores
) {
nodeReaches(source, scReads, scStores, arg, reads, stores) and
Flow::PathGraph::subpaths(arg, _, _, _)
}
pragma[nomagic]
private predicate subpathArgReachesOut(
Flow::PathNode arg, AccessPath scReads, AccessPath scStores, Flow::PathNode out,
AccessPath reads, AccessPath stores
) {
exists(Flow::PathNode source, Flow::PathNode ret |
nodeReaches(source, scReads, scStores, ret, reads, stores) and
Flow::PathGraph::subpaths(arg, source, ret, out)
)
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1569,11 +1569,6 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call)
cached
newtype TParamNodeOption =
TParamNodeNone() or
TParamNodeSome(ParamNode p)
cached
newtype TReturnCtx =
TReturnCtxNone() or
@@ -2234,19 +2229,6 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
}
}
/** An optional `ParamNode`. */
class ParamNodeOption extends TParamNodeOption {
string toString() {
this = TParamNodeNone() and
result = "(none)"
or
exists(ParamNode p |
this = TParamNodeSome(p) and
result = p.toString()
)
}
}
/**
* A return context used to calculate flow summaries in reverse flow.
*

View File

@@ -1,5 +1,5 @@
name: codeql/dataflow
version: 1.0.6-dev
version: 1.1.3-dev
groups: shared
library: true
dependencies:

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -64,14 +64,23 @@ module ModelPrintingImpl<ModelPrintingLangSig Lang> {
/**
* Gets the summary model for `api` with `input`, `output` and `kind`.
* The model is lifted in case `lift` is true.
*/
bindingset[input, output, kind]
private string asSummaryModel(Printing::SummaryApi api, string input, string output, string kind) {
result =
asPartialModel(api.lift()) + input + ";" //
+ output + ";" //
+ kind + ";" //
+ Printing::getProvenance()
private string asSummaryModel(
Printing::SummaryApi api, string input, string output, string kind, boolean lift
) {
exists(Lang::Callable c |
lift = true and c = api.lift()
or
lift = false and c = api
|
result =
asPartialModel(c) + input + ";" //
+ output + ";" //
+ kind + ";" //
+ Printing::getProvenance()
)
}
string asNeutralSummaryModel(Printing::SummaryApi api) {
@@ -82,19 +91,35 @@ module ModelPrintingImpl<ModelPrintingLangSig Lang> {
}
/**
* Gets the value summary model for `api` with `input` and `output`.
* Gets the lifted value summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
string asValueModel(Printing::SummaryApi api, string input, string output) {
result = asSummaryModel(api, input, output, "value")
string asLiftedValueModel(Printing::SummaryApi api, string input, string output) {
result = asModel(api, input, output, true, true)
}
/**
* Gets the taint summary model for `api` with `input` and `output`.
* Gets the lifted taint summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
string asTaintModel(Printing::SummaryApi api, string input, string output) {
result = asSummaryModel(api, input, output, "taint")
string asLiftedTaintModel(Printing::SummaryApi api, string input, string output) {
result = asModel(api, input, output, false, true)
}
/**
* Gets the summary model for `api` with `input` and `output`.
* (1) If `preservesValue` is true a "value" model is created.
* (2) If `lift` is true the model is lifted to the best possible type.
*/
bindingset[input, output, preservesValue]
string asModel(
Printing::SummaryApi api, string input, string output, boolean preservesValue, boolean lift
) {
preservesValue = true and
result = asSummaryModel(api, input, output, "value", lift)
or
preservesValue = false and
result = asSummaryModel(api, input, output, "taint", lift)
}
/**

View File

@@ -1,5 +1,5 @@
name: codeql/mad
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
dependencies:

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,5 +1,5 @@
name: codeql/rangeanalysis
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
dependencies:

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,5 +1,5 @@
name: codeql/regex
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
dependencies:

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,5 +1,5 @@
name: codeql/ssa
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
dependencies:

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,5 +1,5 @@
name: codeql/threat-models
version: 1.0.6-dev
version: 1.0.9-dev
library: true
groups: shared
dataExtensions:

View File

@@ -1,7 +1,5 @@
load("@ruby_deps//:defs.bzl", "aliases", "all_crate_deps")
load("@rules_rust//rust:defs.bzl", "rust_library")
package(default_visibility = ["//visibility:public"])
load("@tree_sitter_extractors_deps//:defs.bzl", "aliases", "all_crate_deps")
rust_library(
name = "codeql-extractor",
@@ -12,5 +10,16 @@ rust_library(
compile_data = [
"src/generator/prefix.dbscheme",
],
deps = all_crate_deps(package_name = "ruby/extractor/codeql-extractor-fake-crate"),
deps = all_crate_deps(),
)
alias(
name = "tree-sitter-extractor",
actual = ":codeql-extractor",
visibility = ["//visibility:public"],
)
filegroup(
name = "dbscheme-prefix",
srcs = ["src/generator/prefix.dbscheme"],
)

View File

@@ -7,7 +7,7 @@ authors = ["GitHub"]
[dependencies]
flate2 = "1.0"
globset = "0.4"
tree-sitter = ">= 0.22.6"
tree-sitter = ">= 0.23.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
rayon = "1.5.0"
@@ -24,5 +24,3 @@ tree-sitter-ql = { git = "https://github.com/tree-sitter/tree-sitter-ql" }
tree-sitter-json = {git = "https://github.com/tree-sitter/tree-sitter-json" }
rand = "0.8.5"
[patch.crates-io]
tree-sitter = {git = "https://github.com/redsun82/tree-sitter.git", rev = "1f5c1112ceaa8fc6aff61d1852690407670d2a96"}

View File

@@ -76,8 +76,8 @@ pub fn populate_empty_location(writer: &mut trap::Writer) {
let file_label = populate_empty_file(writer);
let loc_label = global_location(
writer,
file_label,
trap::Location {
file_label,
start_line: 0,
start_column: 0,
end_line: 0,
@@ -127,14 +127,10 @@ pub fn populate_parent_folders(
}
/** Get the label for the given location, defining it a global ID if it doesn't exist yet. */
fn global_location(
writer: &mut trap::Writer,
file_label: trap::Label,
location: trap::Location,
) -> trap::Label {
fn global_location(writer: &mut trap::Writer, location: trap::Location) -> trap::Label {
let (loc_label, fresh) = writer.global_id(&format!(
"loc,{{{}}},{},{},{},{}",
file_label,
location.file_label,
location.start_line,
location.start_column,
location.end_line,
@@ -145,7 +141,7 @@ fn global_location(
"locations_default",
vec![
trap::Arg::Label(loc_label),
trap::Arg::Label(file_label),
trap::Arg::Label(location.file_label),
trap::Arg::Int(location.start_line),
trap::Arg::Int(location.start_column),
trap::Arg::Int(location.end_line),
@@ -158,18 +154,14 @@ fn global_location(
/** Get the label for the given location, creating it as a fresh ID if we haven't seen the location
* yet for this file. */
fn location_label(
writer: &mut trap::Writer,
file_label: trap::Label,
location: trap::Location,
) -> trap::Label {
pub fn location_label(writer: &mut trap::Writer, location: trap::Location) -> trap::Label {
let (loc_label, fresh) = writer.location_label(location);
if fresh {
writer.add_tuple(
"locations_default",
vec![
trap::Arg::Label(loc_label),
trap::Arg::Label(file_label),
trap::Arg::Label(location.file_label),
trap::Arg::Int(location.start_line),
trap::Arg::Int(location.start_column),
trap::Arg::Int(location.end_line),
@@ -312,8 +304,8 @@ impl<'a> Visitor<'a> {
node: Node,
status_page: bool,
) {
let loc = location_for(self, node);
let loc_label = location_label(self.trap_writer, self.file_label, loc);
let loc = location_for(self, self.file_label, node);
let loc_label = location_label(self.trap_writer, loc);
let mut mesg = self.diagnostics_writer.new_entry(
"parse-error",
"Could not process some files due to syntax errors",
@@ -364,8 +356,8 @@ impl<'a> Visitor<'a> {
return;
}
let (id, _, child_nodes) = self.stack.pop().expect("Vistor: empty stack");
let loc = location_for(self, node);
let loc_label = location_label(self.trap_writer, self.file_label, loc);
let loc = location_for(self, self.file_label, node);
let loc_label = location_label(self.trap_writer, loc);
let table = self
.schema
.get(&TypeName {
@@ -627,7 +619,7 @@ fn sliced_source_arg(source: &[u8], n: Node) -> trap::Arg {
// Emit a pair of `TrapEntry`s for the provided node, appropriately calibrated.
// The first is the location and label definition, and the second is the
// 'Located' entry.
fn location_for(visitor: &mut Visitor, n: Node) -> trap::Location {
fn location_for(visitor: &mut Visitor, file_label: trap::Label, n: Node) -> trap::Location {
// Tree-sitter row, column values are 0-based while CodeQL starts
// counting at 1. In addition Tree-sitter's row and column for the
// end position are exclusive while CodeQL's end positions are inclusive.
@@ -685,6 +677,7 @@ fn location_for(visitor: &mut Visitor, n: Node) -> trap::Location {
}
}
trap::Location {
file_label,
start_line,
start_column,
end_line,

View File

@@ -7,6 +7,7 @@ use flate2::write::GzEncoder;
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct Location {
pub file_label: Label,
pub start_line: usize,
pub start_column: usize,
pub end_line: usize,
@@ -136,10 +137,16 @@ impl fmt::Display for Entry {
}
}
#[derive(Debug, Copy, Clone)]
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
// Identifiers of the form #0, #1...
pub struct Label(u32);
impl fmt::Debug for Label {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Label({:#x})", self.0)
}
}
impl fmt::Display for Label {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "#{:x}", self.0)
@@ -170,6 +177,30 @@ impl fmt::Display for Arg {
}
}
impl From<String> for Arg {
fn from(value: String) -> Self {
Arg::String(value)
}
}
impl From<&str> for Arg {
fn from(value: &str) -> Self {
Arg::String(value.into())
}
}
impl From<Label> for Arg {
fn from(value: Label) -> Self {
Arg::Label(value)
}
}
impl From<usize> for Arg {
fn from(value: usize) -> Self {
Arg::Int(value)
}
}
pub struct Program(Vec<Entry>);
impl fmt::Display for Program {

View File

@@ -13,7 +13,7 @@ use common::{create_source_dir, expect_trap_file, SourceArchive};
fn simple_extractor() {
let language = simple::LanguageSpec {
prefix: "ql",
ts_language: tree_sitter_ql::language(),
ts_language: tree_sitter_ql::LANGUAGE.into(),
node_types: tree_sitter_ql::NODE_TYPES,
file_globs: vec!["*.qll".into()],
};

View File

@@ -12,13 +12,13 @@ use common::{create_source_dir, expect_trap_file, SourceArchive};
fn multiple_language_extractor() {
let lang_ql = simple::LanguageSpec {
prefix: "ql",
ts_language: tree_sitter_ql::language(),
ts_language: tree_sitter_ql::LANGUAGE.into(),
node_types: tree_sitter_ql::NODE_TYPES,
file_globs: vec!["*.qll".into()],
};
let lang_json = simple::LanguageSpec {
prefix: "json",
ts_language: tree_sitter_json::language(),
ts_language: tree_sitter_json::LANGUAGE.into(),
node_types: tree_sitter_json::NODE_TYPES,
file_globs: vec!["*.json".into(), "*Jsonfile".into()],
};

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,7 +1,7 @@
name: codeql/tutorial
description: Library for the CodeQL detective tutorials, helping new users learn to
write CodeQL queries.
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
warnOnImplicitThis: true

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,5 +1,5 @@
name: codeql/typeflow
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
dependencies:

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,5 +1,5 @@
name: codeql/typetracking
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
dependencies:

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,5 +1,5 @@
name: codeql/typos
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
warnOnImplicitThis: true

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,5 +1,5 @@
name: codeql/util
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
dependencies: null

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,5 +1,5 @@
name: codeql/xml
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
dependencies:

View File

@@ -1,3 +1,15 @@
## 1.0.8
No user-facing changes.
## 1.0.7
No user-facing changes.
## 1.0.6
No user-facing changes.
## 1.0.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.6
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.7
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.8
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.5
lastReleaseVersion: 1.0.8

View File

@@ -1,5 +1,5 @@
name: codeql/yaml
version: 1.0.6-dev
version: 1.0.9-dev
groups: shared
library: true
warnOnImplicitThis: true