Files
codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll
2024-03-11 20:56:38 +01:00

289 lines
9.2 KiB
Plaintext

private import csharp
private import DataFlowDispatch
private import DataFlowPrivate
private import semmle.code.csharp.controlflow.Guards
private import semmle.code.csharp.Unification
/**
* An element, viewed as a node in a data flow graph. Either an expression
* (`ExprNode`) or a parameter (`ParameterNode`).
*/
class Node extends TNode {
/** Gets the expression corresponding to this node, if any. */
Expr asExpr() { result = this.(ExprNode).getExpr() }
/**
* Gets the expression corresponding to this node, at control flow node `cfn`,
* if any.
*/
Expr asExprAtNode(ControlFlow::Nodes::ElementNode cfn) {
result = this.(ExprNode).getExprAtNode(cfn)
}
/** Gets the parameter corresponding to this node, if any. */
Parameter asParameter() { result = this.(ParameterNode).getParameter() }
/** Gets the definition corresponding to this node, if any. */
AssignableDefinition asDefinition() { result = this.asDefinitionAtNode(_) }
/**
* Gets the definition corresponding to this node, at control flow node `cfn`,
* if any.
*/
AssignableDefinition asDefinitionAtNode(ControlFlow::Node cfn) {
result = this.(AssignableDefinitionNode).getDefinitionAtNode(cfn)
}
/** Gets the type of this node. */
final Type getType() { result = this.(NodeImpl).getTypeImpl() }
/** Gets the enclosing callable of this node. */
final Callable getEnclosingCallable() {
result = this.(NodeImpl).getEnclosingCallableImpl().asCallable()
}
/** Gets the control flow node corresponding to this node, if any. */
final ControlFlow::Node getControlFlowNode() { result = this.(NodeImpl).getControlFlowNodeImpl() }
/** Gets a textual representation of this node. */
final string toString() { result = this.(NodeImpl).toStringImpl() }
/** Gets the location of this node. */
final Location getLocation() { result = this.(NodeImpl).getLocationImpl() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
deprecated predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
/**
* An expression, viewed as a node in a data flow graph.
*
* Note that because of control-flow splitting, one `Expr` may correspond
* to multiple `ExprNode`s, just like it may correspond to multiple
* `ControlFlow::Node`s.
*/
class ExprNode extends Node, TExprNode {
/** Gets the expression corresponding to this node. */
Expr getExpr() { result = this.getExprAtNode(_) }
/**
* Gets the expression corresponding to this node, at control flow node `cfn`,
* if any.
*/
Expr getExprAtNode(ControlFlow::Nodes::ElementNode cfn) {
this = TExprNode(cfn) and
result = cfn.getAstNode()
}
}
pragma[nomagic]
private predicate isParameterOf0(DataFlowCallable c, ParameterPosition ppos, Parameter p) {
p.getCallable() = c.asCallable() and
p.getPosition() = ppos.getPosition()
}
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParameterNode extends Node instanceof ParameterNodeImpl {
/** Gets the parameter corresponding to this node, if any. */
Parameter getParameter() {
exists(DataFlowCallable c, ParameterPosition ppos |
super.isParameterOf(c, ppos) and
isParameterOf0(c, ppos, result)
)
}
}
/** A definition, viewed as a node in a data flow graph. */
class AssignableDefinitionNode extends Node instanceof AssignableDefinitionNodeImpl {
/** Gets the underlying definition. */
AssignableDefinition getDefinition() { result = super.getDefinition() }
/** Gets the underlying definition, at control flow node `cfn`, if any. */
AssignableDefinition getDefinitionAtNode(ControlFlow::Node cfn) {
result = super.getDefinitionAtNode(cfn)
}
}
/** Gets a node corresponding to expression `e`. */
ExprNode exprNode(Expr e) { result.getExpr() = e }
/**
* Gets the node corresponding to the value of parameter `p` at function entry.
*/
ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
/** Gets a node corresponding to the definition `def`. */
AssignableDefinitionNode assignableDefinitionNode(AssignableDefinition def) {
result.getDefinition() = def
}
predicate localFlowStep = localFlowStepImpl/2;
/**
* Holds if data flows from `source` to `sink` in zero or more local
* (intra-procedural) steps.
*/
pragma[inline]
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
/**
* Holds if data can flow from `e1` to `e2` in zero or more
* local (intra-procedural) steps.
*/
pragma[inline]
predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
/**
* A data flow node that jumps between callables. This can be extended in
* framework code to add additional data flow steps.
*/
abstract class NonLocalJumpNode extends Node {
/** Gets a successor node that is potentially in another callable. */
abstract Node getAJumpSuccessor(boolean preservesValue);
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `v`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(Guard g, Expr e, AbstractValue v);
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
exists(Guard g, Expr e, AbstractValue v |
guardChecks(g, e, v) and
g.controlsNode(result.getControlFlowNode(), e, v)
)
}
}
/**
* A reference contained in an object. This is either a field, a property,
* or an element in a collection.
*/
class Content extends TContent {
/** Gets a textual representation of this content. */
string toString() { none() }
/** Gets the location of this content. */
Location getLocation() { none() }
}
/** A reference to a field. */
class FieldContent extends Content, TFieldContent {
private Field f;
FieldContent() { this = TFieldContent(f) }
/** Gets the field that is referenced. */
Field getField() { result = f }
override string toString() { result = "field " + f.getName() }
override Location getLocation() { result = f.getLocation() }
}
/** A reference to a synthetic field. */
class SyntheticFieldContent extends Content, TSyntheticFieldContent {
private SyntheticField f;
SyntheticFieldContent() { this = TSyntheticFieldContent(f) }
/** Gets the underlying synthetic field. */
SyntheticField getField() { result = f }
override string toString() { result = "synthetic " + f.toString() }
}
/** A reference to a property. */
class PropertyContent extends Content, TPropertyContent {
private Property p;
PropertyContent() { this = TPropertyContent(p) }
/** Gets the property that is referenced. */
Property getProperty() { result = p }
override string toString() { result = "property " + p.getName() }
override Location getLocation() { result = p.getLocation() }
}
/**
* A reference to a synthetic field corresponding to a
* primary constructor parameter.
*/
class PrimaryConstructorParameterContent extends Content, TPrimaryConstructorParameterContent {
private Parameter p;
PrimaryConstructorParameterContent() { this = TPrimaryConstructorParameterContent(p) }
/** Gets the underlying parameter. */
Parameter getParameter() { result = p }
override string toString() { result = "parameter " + p.getName() }
override Location getLocation() { result = p.getLocation() }
}
/** A reference to an element in a collection. */
class ElementContent extends Content, TElementContent {
override string toString() { result = "element" }
override Location getLocation() { result instanceof EmptyLocation }
}
/** A captured variable. */
class CapturedVariableContent extends Content, TCapturedVariableContent {
private VariableCapture::CapturedVariable v;
CapturedVariableContent() { this = TCapturedVariableContent(v) }
override string toString() { result = "captured " + v }
override Location getLocation() { result = v.getLocation() }
}
/**
* An entity that represents a set of `Content`s.
*
* The set may be interpreted differently depending on whether it is
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
*/
class ContentSet instanceof Content {
/** Gets a content that may be stored into when storing into this set. */
Content getAStoreContent() { result = this }
/** Gets a content that may be read from when reading from this set. */
Content getAReadContent() { result = this }
/** Gets a textual representation of this content set. */
string toString() { result = super.toString() }
/** Gets the location of this content set. */
Location getLocation() { result = super.getLocation() }
}