mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge branch 'main' into aeisenberg/remove-upgrades
This commit is contained in:
@@ -7,6 +7,9 @@
|
||||
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
|
||||
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
|
||||
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
|
||||
"csharp/ql/campaigns/Solorigate/lib/qlpack.yml",
|
||||
"csharp/ql/campaigns/Solorigate/src/qlpack.yml",
|
||||
"csharp/ql/campaigns/Solorigate/test/qlpack.yml",
|
||||
"misc/legacy-support/*/qlpack.yml",
|
||||
"misc/suite-helpers/qlpack.yml",
|
||||
"ruby/extractor-pack/codeql-extractor.yml",
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# CodeQL
|
||||
|
||||
This open source repository contains the standard CodeQL libraries and queries that power [LGTM](https://lgtm.com) and the other CodeQL products that [GitHub](https://github.com) makes available to its customers worldwide. For the queries, libraries, and extractor that power Go analysis, visit the [CodeQL for Go repository](https://github.com/github/codeql-go).
|
||||
This open source repository contains the standard CodeQL libraries and queries that power [GitHub Advanced Security](https://github.com/features/security/code) and the other application security products that [GitHub](https://github.com/features/security/) makes available to its customers worldwide. For the queries, libraries, and extractor that power Go analysis, visit the [CodeQL for Go repository](https://github.com/github/codeql-go).
|
||||
|
||||
## How do I learn CodeQL and run queries?
|
||||
|
||||
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL.
|
||||
You can use the [interactive query console](https://lgtm.com/help/lgtm/using-query-console) on LGTM.com or the [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) extension to try out your queries on any open source project that's currently being analyzed.
|
||||
You can use the [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) extension or the [interactive query console](https://lgtm.com/help/lgtm/using-query-console) on LGTM.com (Semmle Legacy product) to try out your queries on any open source project that's currently being analyzed.
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -13,7 +13,7 @@ We welcome contributions to our standard library and standard checks. Do you hav
|
||||
|
||||
## License
|
||||
|
||||
The code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com).
|
||||
The code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com). The use of CodeQL on open source code is licensed under specific [Terms & Conditions](https://securitylab.github.com/tools/codeql/license/) UNLESS you have a commercial license in place. If you'd like to use CodeQL with a commercial codebase, please [contact us](https://github.com/enterprise/contact) for further help.
|
||||
|
||||
## Visual Studio Code integration
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ private module VirtualDispatch {
|
||||
this.flowsFrom(other, allowOtherFromArg)
|
||||
|
|
||||
// Call argument
|
||||
exists(DataFlowCall call, int i |
|
||||
exists(DataFlowCall call, Position i |
|
||||
other
|
||||
.(DataFlow::ParameterNode)
|
||||
.isParameterOf(pragma[only_bind_into](call).getStaticCallTarget(), i) and
|
||||
@@ -268,16 +268,6 @@ Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends int {
|
||||
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }
|
||||
}
|
||||
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition extends int {
|
||||
ArgumentPosition() { any(ArgumentNode a).argumentOf(_, this) }
|
||||
}
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
@@ -27,7 +27,7 @@ abstract class ArgumentNode extends OperandNode {
|
||||
* Holds if this argument occurs at the given position in the given call.
|
||||
* The instance argument is considered to have index `-1`.
|
||||
*/
|
||||
abstract predicate argumentOf(DataFlowCall call, int pos);
|
||||
abstract predicate argumentOf(DataFlowCall call, ArgumentPosition pos);
|
||||
|
||||
/** Gets the call in which this node is an argument. */
|
||||
DataFlowCall getCall() { this.argumentOf(result, _) }
|
||||
@@ -42,7 +42,9 @@ private class PrimaryArgumentNode extends ArgumentNode {
|
||||
|
||||
PrimaryArgumentNode() { exists(CallInstruction call | op = call.getAnArgumentOperand()) }
|
||||
|
||||
override predicate argumentOf(DataFlowCall call, int pos) { op = call.getArgumentOperand(pos) }
|
||||
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
op = call.getArgumentOperand(pos.(DirectPosition).getIndex())
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
exists(Expr unconverted |
|
||||
@@ -71,9 +73,9 @@ private class SideEffectArgumentNode extends ArgumentNode {
|
||||
|
||||
SideEffectArgumentNode() { op = read.getSideEffectOperand() }
|
||||
|
||||
override predicate argumentOf(DataFlowCall call, int pos) {
|
||||
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
read.getPrimaryInstruction() = call and
|
||||
pos = getArgumentPosOfSideEffect(read.getIndex())
|
||||
pos.(IndirectionPosition).getIndex() = read.getIndex()
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
@@ -90,6 +92,54 @@ private class SideEffectArgumentNode extends ArgumentNode {
|
||||
}
|
||||
}
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition = Position;
|
||||
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition = Position;
|
||||
|
||||
class Position extends TPosition {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
class DirectPosition extends TDirectPosition {
|
||||
int index;
|
||||
|
||||
DirectPosition() { this = TDirectPosition(index) }
|
||||
|
||||
string toString() {
|
||||
index = -1 and
|
||||
result = "this"
|
||||
or
|
||||
index != -1 and
|
||||
result = index.toString()
|
||||
}
|
||||
|
||||
int getIndex() { result = index }
|
||||
}
|
||||
|
||||
class IndirectionPosition extends TIndirectionPosition {
|
||||
int index;
|
||||
|
||||
IndirectionPosition() { this = TIndirectionPosition(index) }
|
||||
|
||||
string toString() {
|
||||
index = -1 and
|
||||
result = "this"
|
||||
or
|
||||
index != -1 and
|
||||
result = index.toString()
|
||||
}
|
||||
|
||||
int getIndex() { result = index }
|
||||
}
|
||||
|
||||
newtype TPosition =
|
||||
TDirectPosition(int index) { exists(any(CallInstruction c).getArgument(index)) } or
|
||||
TIndirectionPosition(int index) {
|
||||
exists(ReadSideEffectInstruction instr | instr.getIndex() = index)
|
||||
}
|
||||
|
||||
private newtype TReturnKind =
|
||||
TNormalReturnKind() or
|
||||
TIndirectReturnKind(ParameterIndex index)
|
||||
|
||||
@@ -490,19 +490,6 @@ class ExprNode extends InstructionNode {
|
||||
override string toString() { result = this.asConvertedExpr().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use. Translates a parameter/argument index into a negative
|
||||
* number that denotes the index of its side effect (pointer indirection).
|
||||
*/
|
||||
bindingset[index]
|
||||
int getArgumentPosOfSideEffect(int index) {
|
||||
// -1 -> -2
|
||||
// 0 -> -3
|
||||
// 1 -> -4
|
||||
// ...
|
||||
result = -3 - index
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph. This includes both explicit parameters such as `x` in `f(x)`
|
||||
@@ -525,7 +512,7 @@ class ParameterNode extends InstructionNode {
|
||||
* implicit `this` parameter is considered to have position `-1`, and
|
||||
* pointer-indirection parameters are at further negative positions.
|
||||
*/
|
||||
predicate isParameterOf(Function f, int pos) { none() } // overridden by subclasses
|
||||
predicate isParameterOf(Function f, ParameterPosition pos) { none() } // overridden by subclasses
|
||||
}
|
||||
|
||||
/** An explicit positional parameter, not including `this` or `...`. */
|
||||
@@ -534,8 +521,8 @@ private class ExplicitParameterNode extends ParameterNode {
|
||||
|
||||
ExplicitParameterNode() { exists(instr.getParameter()) }
|
||||
|
||||
override predicate isParameterOf(Function f, int pos) {
|
||||
f.getParameter(pos) = instr.getParameter()
|
||||
override predicate isParameterOf(Function f, ParameterPosition pos) {
|
||||
f.getParameter(pos.(DirectPosition).getIndex()) = instr.getParameter()
|
||||
}
|
||||
|
||||
/** Gets the `Parameter` associated with this node. */
|
||||
@@ -550,8 +537,8 @@ class ThisParameterNode extends ParameterNode {
|
||||
|
||||
ThisParameterNode() { instr.getIRVariable() instanceof IRThisVariable }
|
||||
|
||||
override predicate isParameterOf(Function f, int pos) {
|
||||
pos = -1 and instr.getEnclosingFunction() = f
|
||||
override predicate isParameterOf(Function f, ParameterPosition pos) {
|
||||
pos.(DirectPosition).getIndex() = -1 and instr.getEnclosingFunction() = f
|
||||
}
|
||||
|
||||
override string toString() { result = "this" }
|
||||
@@ -561,12 +548,12 @@ class ThisParameterNode extends ParameterNode {
|
||||
class ParameterIndirectionNode extends ParameterNode {
|
||||
override InitializeIndirectionInstruction instr;
|
||||
|
||||
override predicate isParameterOf(Function f, int pos) {
|
||||
override predicate isParameterOf(Function f, ParameterPosition pos) {
|
||||
exists(int index |
|
||||
instr.getEnclosingFunction() = f and
|
||||
instr.hasIndex(index)
|
||||
|
|
||||
pos = getArgumentPosOfSideEffect(index)
|
||||
pos.(IndirectionPosition).getIndex() = index
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -659,4 +659,15 @@ module Consistency {
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,16 +51,6 @@ private newtype TDefOrUse =
|
||||
TExplicitUse(Operand op) { isExplicitUse(op) } or
|
||||
TReturnParamIndirection(Operand op) { returnParameterIndirection(op, _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private int getRank(DefOrUse defOrUse, IRBlock block) {
|
||||
defOrUse =
|
||||
rank[result](int i, DefOrUse cand |
|
||||
block.getInstruction(i) = toInstruction(cand)
|
||||
|
|
||||
cand order by i
|
||||
)
|
||||
}
|
||||
|
||||
private class DefOrUse extends TDefOrUse {
|
||||
/** Gets the instruction associated with this definition, if any. */
|
||||
Instruction asDef() { none() }
|
||||
@@ -74,9 +64,10 @@ private class DefOrUse extends TDefOrUse {
|
||||
/** Gets the block of this definition or use. */
|
||||
abstract IRBlock getBlock();
|
||||
|
||||
/** Holds if this definition or use has rank `rank` in block `block`. */
|
||||
cached
|
||||
final predicate hasRankInBlock(IRBlock block, int rnk) { rnk = getRank(this, block) }
|
||||
/** Holds if this definition or use has index `index` in block `block`. */
|
||||
final predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
block.getInstruction(index) = toInstruction(this)
|
||||
}
|
||||
|
||||
/** Gets the location of this element. */
|
||||
abstract Cpp::Location getLocation();
|
||||
@@ -313,8 +304,8 @@ cached
|
||||
private module Cached {
|
||||
private predicate defUseFlow(Node nodeFrom, Node nodeTo) {
|
||||
exists(IRBlock bb1, int i1, IRBlock bb2, int i2, DefOrUse defOrUse, Use use |
|
||||
defOrUse.hasRankInBlock(bb1, i1) and
|
||||
use.hasRankInBlock(bb2, i2) and
|
||||
defOrUse.hasIndexInBlock(bb1, i1) and
|
||||
use.hasIndexInBlock(bb2, i2) and
|
||||
adjacentDefRead(_, bb1, i1, bb2, i2) and
|
||||
nodeFrom.asInstruction() = toInstruction(defOrUse) and
|
||||
flowOutOfAddressStep(use.getOperand(), nodeTo)
|
||||
@@ -326,9 +317,9 @@ private module Cached {
|
||||
exists(IRBlock bb1, int i1, IRBlock bb2, int i2, Def def, Use use |
|
||||
nodeFrom.isTerminal() and
|
||||
def.getInstruction() = nodeFrom.getStoreInstruction() and
|
||||
def.hasRankInBlock(bb1, i1) and
|
||||
def.hasIndexInBlock(bb1, i1) and
|
||||
adjacentDefRead(_, bb1, i1, bb2, i2) and
|
||||
use.hasRankInBlock(bb2, i2) and
|
||||
use.hasIndexInBlock(bb2, i2) and
|
||||
flowOutOfAddressStep(use.getOperand(), nodeTo)
|
||||
)
|
||||
or
|
||||
@@ -359,8 +350,8 @@ private module Cached {
|
||||
|
||||
private predicate fromReadNode(ReadNode nodeFrom, Node nodeTo) {
|
||||
exists(IRBlock bb1, int i1, IRBlock bb2, int i2, Use use1, Use use2 |
|
||||
use1.hasRankInBlock(bb1, i1) and
|
||||
use2.hasRankInBlock(bb2, i2) and
|
||||
use1.hasIndexInBlock(bb1, i1) and
|
||||
use2.hasIndexInBlock(bb2, i2) and
|
||||
use1.getOperand().getDef() = nodeFrom.getInstruction() and
|
||||
adjacentDefRead(_, bb1, i1, bb2, i2) and
|
||||
flowOutOfAddressStep(use2.getOperand(), nodeTo)
|
||||
@@ -371,7 +362,7 @@ private module Cached {
|
||||
exists(PhiNode phi, Use use, IRBlock block, int rnk |
|
||||
phi = nodeFrom.getPhiNode() and
|
||||
adjacentDefRead(phi, _, _, block, rnk) and
|
||||
use.hasRankInBlock(block, rnk) and
|
||||
use.hasIndexInBlock(block, rnk) and
|
||||
flowOutOfAddressStep(use.getOperand(), nodeTo)
|
||||
)
|
||||
}
|
||||
@@ -379,7 +370,7 @@ private module Cached {
|
||||
private predicate toPhiNode(Node nodeFrom, SsaPhiNode nodeTo) {
|
||||
// Flow to phi nodes
|
||||
exists(Def def, IRBlock block, int rnk |
|
||||
def.hasRankInBlock(block, rnk) and
|
||||
def.hasIndexInBlock(block, rnk) and
|
||||
nodeTo.hasInputAtRankInBlock(block, rnk)
|
||||
|
|
||||
exists(StoreNodeInstr storeNode |
|
||||
@@ -512,8 +503,8 @@ private module Cached {
|
||||
|
|
||||
store = def.getInstruction() and
|
||||
store.getSourceValueOperand() = operand and
|
||||
def.hasRankInBlock(block1, rnk1) and
|
||||
use.hasRankInBlock(block2, rnk2) and
|
||||
def.hasIndexInBlock(block1, rnk1) and
|
||||
use.hasIndexInBlock(block2, rnk2) and
|
||||
adjacentDefRead(_, block1, rnk1, block2, rnk2)
|
||||
|
|
||||
// The shared SSA library has determined that `use` is the next use of the operand
|
||||
@@ -543,12 +534,12 @@ private module Cached {
|
||||
not operand = getSourceAddressOperand(_) and
|
||||
exists(Use use1, Use use2, IRBlock block1, int rnk1, IRBlock block2, int rnk2 |
|
||||
use1.getOperand() = operand and
|
||||
use1.hasRankInBlock(block1, rnk1) and
|
||||
use1.hasIndexInBlock(block1, rnk1) and
|
||||
// Don't flow to the next use if this use is part of a store operation that totally
|
||||
// overrides a variable.
|
||||
not explicitWrite(true, _, use1.getOperand().getDef()) and
|
||||
adjacentDefRead(_, block1, rnk1, block2, rnk2) and
|
||||
use2.hasRankInBlock(block2, rnk2) and
|
||||
use2.hasIndexInBlock(block2, rnk2) and
|
||||
flowOutOfAddressStep(use2.getOperand(), nodeTo)
|
||||
)
|
||||
or
|
||||
@@ -620,7 +611,7 @@ import Cached
|
||||
predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
exists(Def def |
|
||||
def.hasRankInBlock(bb, i) and
|
||||
def.hasIndexInBlock(bb, i) and
|
||||
v = def.getSourceVariable() and
|
||||
(if def.isCertain() then certain = true else certain = false)
|
||||
)
|
||||
@@ -632,7 +623,7 @@ predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
*/
|
||||
predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(Use use |
|
||||
use.hasRankInBlock(bb, i) and
|
||||
use.hasIndexInBlock(bb, i) and
|
||||
v = use.getSourceVariable() and
|
||||
certain = true
|
||||
)
|
||||
|
||||
@@ -9,6 +9,7 @@ import semmle.code.cpp.controlflow.Dominance
|
||||
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
/**
|
||||
* Holds if the value of `use` is guarded using `abs`.
|
||||
@@ -16,53 +17,16 @@ import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
predicate guardedAbs(Operation e, Expr use) {
|
||||
exists(FunctionCall fc | fc.getTarget().getName() = ["abs", "labs", "llabs", "imaxabs"] |
|
||||
fc.getArgument(0).getAChild*() = use and
|
||||
guardedLesser(e, fc)
|
||||
exists(GuardCondition c | c.ensuresLt(fc, _, _, e.getBasicBlock(), true))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the position of `stmt` in basic block `block` (this is a thin layer
|
||||
* over `BasicBlock.getNode`, intended to improve performance).
|
||||
*/
|
||||
pragma[noinline]
|
||||
private int getStmtIndexInBlock(BasicBlock block, Stmt stmt) { block.getNode(result) = stmt }
|
||||
|
||||
pragma[inline]
|
||||
private predicate stmtDominates(Stmt dominator, Stmt dominated) {
|
||||
// In same block
|
||||
exists(BasicBlock block, int dominatorIndex, int dominatedIndex |
|
||||
dominatorIndex = getStmtIndexInBlock(block, dominator) and
|
||||
dominatedIndex = getStmtIndexInBlock(block, dominated) and
|
||||
dominatedIndex >= dominatorIndex
|
||||
)
|
||||
or
|
||||
// In (possibly) different blocks
|
||||
bbStrictlyDominates(dominator.getBasicBlock(), dominated.getBasicBlock())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `use` is guarded to be less than something, and `e`
|
||||
* is in code controlled by that guard (where the guard condition held).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate guardedLesser(Operation e, Expr use) {
|
||||
exists(IfStmt c, RelationalOperation guard |
|
||||
use = guard.getLesserOperand().getAChild*() and
|
||||
guard = c.getControllingExpr().getAChild*() and
|
||||
stmtDominates(c.getThen(), e.getEnclosingStmt())
|
||||
)
|
||||
or
|
||||
exists(Loop c, RelationalOperation guard |
|
||||
use = guard.getLesserOperand().getAChild*() and
|
||||
guard = c.getControllingExpr().getAChild*() and
|
||||
stmtDominates(c.getStmt(), e.getEnclosingStmt())
|
||||
)
|
||||
or
|
||||
exists(ConditionalExpr c, RelationalOperation guard |
|
||||
use = guard.getLesserOperand().getAChild*() and
|
||||
guard = c.getCondition().getAChild*() and
|
||||
c.getThen().getAChild*() = e
|
||||
)
|
||||
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), true))
|
||||
or
|
||||
guardedAbs(e, use)
|
||||
}
|
||||
@@ -71,25 +35,8 @@ predicate guardedLesser(Operation e, Expr use) {
|
||||
* Holds if the value of `use` is guarded to be greater than something, and `e`
|
||||
* is in code controlled by that guard (where the guard condition held).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate guardedGreater(Operation e, Expr use) {
|
||||
exists(IfStmt c, RelationalOperation guard |
|
||||
use = guard.getGreaterOperand().getAChild*() and
|
||||
guard = c.getControllingExpr().getAChild*() and
|
||||
stmtDominates(c.getThen(), e.getEnclosingStmt())
|
||||
)
|
||||
or
|
||||
exists(Loop c, RelationalOperation guard |
|
||||
use = guard.getGreaterOperand().getAChild*() and
|
||||
guard = c.getControllingExpr().getAChild*() and
|
||||
stmtDominates(c.getStmt(), e.getEnclosingStmt())
|
||||
)
|
||||
or
|
||||
exists(ConditionalExpr c, RelationalOperation guard |
|
||||
use = guard.getGreaterOperand().getAChild*() and
|
||||
guard = c.getCondition().getAChild*() and
|
||||
c.getThen().getAChild*() = e
|
||||
)
|
||||
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), false))
|
||||
or
|
||||
guardedAbs(e, use)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.6
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/uncontrolled-arithmetic
|
||||
* @tags security
|
||||
* external/cwe/cwe-190
|
||||
@@ -82,8 +82,11 @@ predicate missingGuard(VariableAccess va, string effect) {
|
||||
op.getUnspecifiedType().(IntegralType).isUnsigned() and
|
||||
not op instanceof MulExpr
|
||||
or
|
||||
// overflow
|
||||
missingGuardAgainstOverflow(op, va) and effect = "overflow"
|
||||
// overflow - only report signed integer overflow since unsigned overflow
|
||||
// is well-defined.
|
||||
op.getUnspecifiedType().(IntegralType).isSigned() and
|
||||
missingGuardAgainstOverflow(op, va) and
|
||||
effect = "overflow"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -89,45 +89,83 @@ predicate referenceTo(Expr source, Expr use) {
|
||||
)
|
||||
}
|
||||
|
||||
from Expr check, Expr checkPath, FunctionCall use, Expr usePath
|
||||
where
|
||||
// `check` looks like a check on a filename
|
||||
(
|
||||
(
|
||||
// either:
|
||||
// an access check
|
||||
check = accessCheck(checkPath)
|
||||
or
|
||||
// a stat
|
||||
check = stat(checkPath, _)
|
||||
or
|
||||
// access to a member variable on the stat buf
|
||||
// (morally, this should be a use-use pair, but it seems unlikely
|
||||
// that this variable will get reused in practice)
|
||||
exists(Expr call, Expr e, Variable v |
|
||||
call = stat(checkPath, e) and
|
||||
e.getAChild*().(VariableAccess).getTarget() = v and
|
||||
check.(VariableAccess).getTarget() = v and
|
||||
not e.getAChild*() = check // the call that writes to the pointer is not where the pointer is checked.
|
||||
)
|
||||
) and
|
||||
// `op` looks like an operation on a filename
|
||||
use = filenameOperation(usePath)
|
||||
or
|
||||
// another filename operation (null pointers can indicate errors)
|
||||
check = filenameOperation(checkPath) and
|
||||
// `op` looks like a sensitive operation on a filename
|
||||
use = sensitiveFilenameOperation(usePath)
|
||||
) and
|
||||
// `checkPath` and `usePath` refer to the same SSA variable
|
||||
exists(SsaDefinition def, StackVariable v |
|
||||
def.getAUse(v) = checkPath and def.getAUse(v) = usePath
|
||||
) and
|
||||
// the return value of `check` is used (possibly with one step of
|
||||
// variable indirection) in a guard which controls `use`
|
||||
exists(GuardCondition guard | referenceTo(check, guard.getAChild*()) |
|
||||
guard.controls(use.(ControlFlowNode).getBasicBlock(), _)
|
||||
pragma[noinline]
|
||||
predicate statCallWithPointer(Expr checkPath, Expr call, Expr e, Variable v) {
|
||||
call = stat(checkPath, e) and
|
||||
e.getAChild*().(VariableAccess).getTarget() = v
|
||||
}
|
||||
|
||||
predicate checksPath(Expr check, Expr checkPath) {
|
||||
// either:
|
||||
// an access check
|
||||
check = accessCheck(checkPath)
|
||||
or
|
||||
// a stat
|
||||
check = stat(checkPath, _)
|
||||
or
|
||||
// access to a member variable on the stat buf
|
||||
// (morally, this should be a use-use pair, but it seems unlikely
|
||||
// that this variable will get reused in practice)
|
||||
exists(Expr call, Expr e, Variable v |
|
||||
statCallWithPointer(checkPath, call, e, v) and
|
||||
check.(VariableAccess).getTarget() = v and
|
||||
not e.getAChild*() = check // the call that writes to the pointer is not where the pointer is checked.
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate checkPathControlsUse(Expr check, Expr checkPath, Expr use) {
|
||||
exists(GuardCondition guard | referenceTo(check, guard.getAChild*()) |
|
||||
guard.controls(use.getBasicBlock(), _)
|
||||
) and
|
||||
checksPath(pragma[only_bind_into](check), checkPath)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate fileNameOperationControlsUse(Expr check, Expr checkPath, Expr use) {
|
||||
exists(GuardCondition guard | referenceTo(check, guard.getAChild*()) |
|
||||
guard.controls(use.getBasicBlock(), _)
|
||||
) and
|
||||
pragma[only_bind_into](check) = filenameOperation(checkPath)
|
||||
}
|
||||
|
||||
predicate checkUse(Expr check, Expr checkPath, FunctionCall use, Expr usePath) {
|
||||
// `check` is part of a guard that controls `use`
|
||||
checkPathControlsUse(check, checkPath, use) and
|
||||
// `check` looks like a check on a filename
|
||||
checksPath(check, checkPath) and
|
||||
// `op` looks like an operation on a filename
|
||||
use = filenameOperation(usePath)
|
||||
or
|
||||
// `check` is part of a guard that controls `use`
|
||||
fileNameOperationControlsUse(check, checkPath, use) and
|
||||
// another filename operation (null pointers can indicate errors)
|
||||
check = filenameOperation(checkPath) and
|
||||
// `op` looks like a sensitive operation on a filename
|
||||
use = sensitiveFilenameOperation(usePath)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate isCheckedPath(
|
||||
Expr check, SsaDefinition def, StackVariable v, FunctionCall use, Expr usePath, Expr checkPath
|
||||
) {
|
||||
checkUse(check, checkPath, use, usePath) and
|
||||
def.getAUse(v) = checkPath
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate isUsedPath(
|
||||
Expr check, SsaDefinition def, StackVariable v, FunctionCall use, Expr usePath, Expr checkPath
|
||||
) {
|
||||
checkUse(check, checkPath, use, usePath) and
|
||||
def.getAUse(v) = usePath
|
||||
}
|
||||
|
||||
from Expr check, Expr checkPath, FunctionCall use, Expr usePath, SsaDefinition def, StackVariable v
|
||||
where
|
||||
// `checkPath` and `usePath` refer to the same SSA variable
|
||||
isCheckedPath(check, def, v, use, usePath, checkPath) and
|
||||
isUsedPath(check, def, v, use, usePath, checkPath)
|
||||
select use,
|
||||
"The $@ being operated upon was previously $@, but the underlying file may have been changed since then.",
|
||||
usePath, "filename", check, "checked"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* The "Uncontrolled data in arithmetic expression" (cpp/uncontrolled-arithmetic) query has been enhanced to reduce false positive results and its @precision increased to high.
|
||||
@@ -35,8 +35,6 @@ edges
|
||||
| test.cpp:190:10:190:13 | call to rand | test.cpp:205:7:205:7 | y |
|
||||
| test.cpp:190:10:190:13 | call to rand | test.cpp:208:7:208:7 | y |
|
||||
| test.cpp:215:11:215:14 | call to rand | test.cpp:219:8:219:8 | x |
|
||||
| test.cpp:223:20:223:23 | call to rand | test.cpp:227:8:227:8 | x |
|
||||
| test.cpp:223:20:223:25 | (unsigned int)... | test.cpp:227:8:227:8 | x |
|
||||
nodes
|
||||
| test.c:18:13:18:16 | call to rand | semmle.label | call to rand |
|
||||
| test.c:21:17:21:17 | r | semmle.label | r |
|
||||
@@ -92,9 +90,6 @@ nodes
|
||||
| test.cpp:208:7:208:7 | y | semmle.label | y |
|
||||
| test.cpp:215:11:215:14 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:219:8:219:8 | x | semmle.label | x |
|
||||
| test.cpp:223:20:223:23 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:223:20:223:25 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| test.cpp:227:8:227:8 | x | semmle.label | x |
|
||||
subpaths
|
||||
#select
|
||||
| test.c:21:17:21:17 | r | test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:18:13:18:16 | call to rand | Uncontrolled value |
|
||||
@@ -125,5 +120,3 @@ subpaths
|
||||
| test.cpp:205:7:205:7 | y | test.cpp:190:10:190:13 | call to rand | test.cpp:205:7:205:7 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:190:10:190:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:208:7:208:7 | y | test.cpp:190:10:190:13 | call to rand | test.cpp:208:7:208:7 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:190:10:190:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:219:8:219:8 | x | test.cpp:215:11:215:14 | call to rand | test.cpp:219:8:219:8 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:215:11:215:14 | call to rand | Uncontrolled value |
|
||||
| test.cpp:227:8:227:8 | x | test.cpp:223:20:223:23 | call to rand | test.cpp:227:8:227:8 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:223:20:223:23 | call to rand | Uncontrolled value |
|
||||
| test.cpp:227:8:227:8 | x | test.cpp:223:20:223:25 | (unsigned int)... | test.cpp:227:8:227:8 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:223:20:223:23 | call to rand | Uncontrolled value |
|
||||
|
||||
@@ -157,3 +157,11 @@ void moreTests() {
|
||||
r = r - 100; // BAD
|
||||
}
|
||||
}
|
||||
|
||||
void guarded_test(unsigned p) {
|
||||
unsigned data = (unsigned int)rand();
|
||||
if (p >= data) {
|
||||
return;
|
||||
}
|
||||
unsigned z = data - p; // GOOD
|
||||
}
|
||||
@@ -224,6 +224,6 @@ void test_mod_limit()
|
||||
unsigned int y = 100;
|
||||
unsigned int z;
|
||||
|
||||
z = (x + y) % 1000; // DUBIOUS (this could overflow but the result is controlled) [REPORTED]
|
||||
z = (x + y) % 1000; // DUBIOUS (this could overflow but the result is controlled)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package,sink,source,summary,sink:code,sink:html,sink:remote,sink:sql,sink:xss,source:local,summary:taint,summary:value
|
||||
Dapper,55,,,,,,55,,,,
|
||||
Microsoft.ApplicationBlocks.Data,28,,,,,,28,,,,
|
||||
Microsoft.Extensions.Primitives,,,54,,,,,,,54,
|
||||
Microsoft.VisualBasic,,,4,,,,,,,,4
|
||||
MySql.Data.MySqlClient,48,,,,,,48,,,,
|
||||
Newtonsoft.Json,,,91,,,,,,,73,18
|
||||
|
||||
|
@@ -9,6 +9,6 @@ C# framework & library support
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||
System,"``System.*``, ``System``",3,2336,28,5
|
||||
Others,"``Dapper``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.VisualBasic``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``",,95,131,
|
||||
Totals,,3,2438,353,5
|
||||
Others,"``Dapper``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.Extensions.Primitives``, ``Microsoft.VisualBasic``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``",,149,131,
|
||||
Totals,,3,2492,353,5
|
||||
|
||||
|
||||
@@ -113,11 +113,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
trapFile.expr_call(init, target);
|
||||
|
||||
var child = 0;
|
||||
foreach (var arg in initializer.ArgumentList.Arguments)
|
||||
{
|
||||
Expression.Create(Context, arg.Expression, init, child++);
|
||||
}
|
||||
init.PopulateArguments(trapFile, initializer.ArgumentList, 0);
|
||||
}
|
||||
|
||||
private ConstructorDeclarationSyntax? Syntax
|
||||
|
||||
@@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.CSharp.Entities.Expressions;
|
||||
using Semmle.Extraction.Kinds;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
@@ -324,7 +325,12 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public void PopulateArguments(TextWriter trapFile, BaseArgumentListSyntax args, int child)
|
||||
{
|
||||
foreach (var arg in args.Arguments)
|
||||
PopulateArguments(trapFile, args.Arguments, child);
|
||||
}
|
||||
|
||||
public void PopulateArguments(TextWriter trapFile, IEnumerable<ArgumentSyntax> args, int child)
|
||||
{
|
||||
foreach (var arg in args)
|
||||
PopulateArgument(trapFile, arg, child++);
|
||||
}
|
||||
|
||||
|
||||
@@ -105,12 +105,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
if (assignment.Left is ImplicitElementAccessSyntax iea)
|
||||
{
|
||||
// An array/indexer initializer of the form `[...] = ...`
|
||||
|
||||
var indexChild = 0;
|
||||
foreach (var arg in iea.ArgumentList.Arguments)
|
||||
{
|
||||
Expression.Create(Context, arg.Expression, access, indexChild++);
|
||||
}
|
||||
access.PopulateArguments(trapFile, iea.ArgumentList.Arguments, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -15,11 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
var child = 0;
|
||||
foreach (var argument in Syntax.Arguments.Select(a => a.Expression))
|
||||
{
|
||||
Expression.Create(Context, argument, this, child++);
|
||||
}
|
||||
PopulateArguments(trapFile, Syntax.Arguments, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal class NamespaceDeclaration : CachedEntity<NamespaceDeclarationSyntax>
|
||||
internal class NamespaceDeclaration : CachedEntity<BaseNamespaceDeclarationSyntax>
|
||||
{
|
||||
private readonly NamespaceDeclaration parent;
|
||||
private readonly NamespaceDeclarationSyntax node;
|
||||
private readonly BaseNamespaceDeclarationSyntax node;
|
||||
|
||||
public NamespaceDeclaration(Context cx, NamespaceDeclarationSyntax node, NamespaceDeclaration parent)
|
||||
public NamespaceDeclaration(Context cx, BaseNamespaceDeclarationSyntax node, NamespaceDeclaration parent)
|
||||
: base(cx, node)
|
||||
{
|
||||
this.node = node;
|
||||
@@ -46,17 +46,17 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public static NamespaceDeclaration Create(Context cx, NamespaceDeclarationSyntax decl, NamespaceDeclaration parent)
|
||||
public static NamespaceDeclaration Create(Context cx, BaseNamespaceDeclarationSyntax decl, NamespaceDeclaration parent)
|
||||
{
|
||||
var init = (decl, parent);
|
||||
return NamespaceDeclarationFactory.Instance.CreateEntity(cx, decl, init);
|
||||
}
|
||||
|
||||
private class NamespaceDeclarationFactory : CachedEntityFactory<(NamespaceDeclarationSyntax decl, NamespaceDeclaration parent), NamespaceDeclaration>
|
||||
private class NamespaceDeclarationFactory : CachedEntityFactory<(BaseNamespaceDeclarationSyntax decl, NamespaceDeclaration parent), NamespaceDeclaration>
|
||||
{
|
||||
public static readonly NamespaceDeclarationFactory Instance = new NamespaceDeclarationFactory();
|
||||
|
||||
public override NamespaceDeclaration Create(Context cx, (NamespaceDeclarationSyntax decl, NamespaceDeclaration parent) init) =>
|
||||
public override NamespaceDeclaration Create(Context cx, (BaseNamespaceDeclarationSyntax decl, NamespaceDeclaration parent) init) =>
|
||||
new NamespaceDeclaration(cx, init.decl, init.parent);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,13 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
new UsingDirective(Cx, usingDirective, (NamespaceDeclaration)Parent);
|
||||
}
|
||||
|
||||
public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
|
||||
{
|
||||
private void CreateNamespaceDeclaration(BaseNamespaceDeclarationSyntax node) =>
|
||||
NamespaceDeclaration.Create(Cx, node, (NamespaceDeclaration)Parent);
|
||||
}
|
||||
|
||||
public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) =>
|
||||
CreateNamespaceDeclaration(node);
|
||||
|
||||
public override void VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node) =>
|
||||
CreateNamespaceDeclaration(node);
|
||||
}
|
||||
}
|
||||
|
||||
1
csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
Normal file
1
csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
Normal file
@@ -0,0 +1 @@
|
||||
## 1.0.0
|
||||
@@ -0,0 +1 @@
|
||||
## 1.0.0
|
||||
4
csharp/ql/campaigns/Solorigate/lib/codeql-pack.lock.yml
Normal file
4
csharp/ql/campaigns/Solorigate/lib/codeql-pack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.1
|
||||
8
csharp/ql/campaigns/Solorigate/lib/qlpack.yml
Normal file
8
csharp/ql/campaigns/Solorigate/lib/qlpack.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.0.2-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/csharp-all: ~0.0.3
|
||||
28
csharp/ql/campaigns/Solorigate/publish.sh
Executable file
28
csharp/ql/campaigns/Solorigate/publish.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
SOLORIGATE_ROOT="$(dirname $0)"
|
||||
WORKSPACE_ROOT="$SOLORIGATE_ROOT/../../../.."
|
||||
GRPS="solorigate,-test"
|
||||
|
||||
if [ -z "$CODEQL_DIST" ]; then
|
||||
echo "CODEQL_DIST not set"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
cd "$SOLORIGATE_ROOT"
|
||||
echo Testing solorigate queries
|
||||
"${CODEQL_DIST}/codeql" test run test
|
||||
|
||||
cd "$WORKSPACE_ROOT"
|
||||
|
||||
echo Preparing release
|
||||
"${CODEQL_DIST}/codeql" pack release --groups $GRPS
|
||||
|
||||
echo Publishing solorigate
|
||||
"${CODEQL_DIST}/codeql" pack publish --groups $GRPS
|
||||
|
||||
echo Bumping versions
|
||||
"${CODEQL_DIST}/codeql" pack post-release --groups $GRPS
|
||||
|
||||
echo Solorigate packs successfully published. Please commit and push the version changes.
|
||||
1
csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
Normal file
1
csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
Normal file
@@ -0,0 +1 @@
|
||||
## 1.0.0
|
||||
@@ -0,0 +1 @@
|
||||
## 1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.1
|
||||
4
csharp/ql/campaigns/Solorigate/src/qlpack.lock.yml
Normal file
4
csharp/ql/campaigns/Solorigate/src/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
9
csharp/ql/campaigns/Solorigate/src/qlpack.yml
Normal file
9
csharp/ql/campaigns/Solorigate/src/qlpack.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.0.2-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
defaultSuiteFile: codeql-suites/solorigate.qls
|
||||
dependencies:
|
||||
codeql/csharp-all: ~0.0.3
|
||||
codeql/csharp-solorigate-all: ^1.0
|
||||
@@ -0,0 +1 @@
|
||||
ModifiedFnvFunctionDetection.ql
|
||||
@@ -0,0 +1 @@
|
||||
NumberOfKnownCommandsAboveThreshold.ql
|
||||
@@ -0,0 +1 @@
|
||||
NumberOfKnownHashesAboveThreshold.ql
|
||||
@@ -0,0 +1 @@
|
||||
NumberOfKnownLiteralsAboveThreshold.ql
|
||||
@@ -0,0 +1 @@
|
||||
NumberOfKnownMethodNamesAboveThreshold.ql
|
||||
@@ -0,0 +1 @@
|
||||
SwallowEverythingExceptionHandler.ql
|
||||
4
csharp/ql/campaigns/Solorigate/test/qlpack.lock.yml
Normal file
4
csharp/ql/campaigns/Solorigate/test/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
12
csharp/ql/campaigns/Solorigate/test/qlpack.yml
Normal file
12
csharp/ql/campaigns/Solorigate/test/qlpack.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
name: csharp-solorigate-tests
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
- test
|
||||
dependencies:
|
||||
codeql/csharp-all: "*"
|
||||
codeql/csharp-queries: "*"
|
||||
codeql/charp-solorigate-all: "*"
|
||||
codeql/charp-solorigate-queries: "*"
|
||||
extractor: csharp
|
||||
tests: .
|
||||
19
csharp/ql/consistency-queries/AstConsistency.qll
Normal file
19
csharp/ql/consistency-queries/AstConsistency.qll
Normal file
@@ -0,0 +1,19 @@
|
||||
import csharp
|
||||
|
||||
query predicate missingLocation(Element e) {
|
||||
(
|
||||
e instanceof Declaration or
|
||||
e instanceof Expr or
|
||||
e instanceof Stmt
|
||||
) and
|
||||
not e instanceof ImplicitAccessorParameter and
|
||||
not e instanceof NullType and
|
||||
not e instanceof Parameter and // Bug in Roslyn - params occasionally lack locations
|
||||
not e.(Operator).getDeclaringType() instanceof IntType and // Roslyn quirk
|
||||
not e instanceof Constructor and
|
||||
not e instanceof ArrayType and
|
||||
not e instanceof UnknownType and
|
||||
not e instanceof ArglistType and
|
||||
not exists(TupleType t | e = t or e = t.getAField()) and
|
||||
not exists(e.getLocation())
|
||||
}
|
||||
9
csharp/ql/consistency-queries/GenericsConsistency.qll
Normal file
9
csharp/ql/consistency-queries/GenericsConsistency.qll
Normal file
@@ -0,0 +1,9 @@
|
||||
import csharp
|
||||
|
||||
query predicate missingUnbound(ConstructedGeneric g) { not exists(g.getUnboundGeneric()) }
|
||||
|
||||
query predicate missingArgs(ConstructedGeneric g) { g.getNumberOfTypeArguments() = 0 }
|
||||
|
||||
query predicate inconsistentArgCount(ConstructedGeneric g) {
|
||||
g.getUnboundGeneric().getNumberOfTypeParameters() != g.getNumberOfTypeArguments()
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.internal.SsaImplCommon::Consistency
|
||||
import Ssa
|
||||
|
||||
class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
override predicate hasLocationInfo(
|
||||
@@ -8,3 +9,18 @@ class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate localDeclWithSsaDef(LocalVariableDeclExpr d) {
|
||||
// Local variables in C# must be initialized before every use, so uninitialized
|
||||
// local variables should not have an SSA definition, as that would imply that
|
||||
// the declaration is live (can reach a use without passing through a definition)
|
||||
exists(ExplicitDefinition def |
|
||||
d = def.getADefinition().(AssignableDefinitions::LocalVariableDefinition).getDeclaration()
|
||||
|
|
||||
not d = any(ForeachStmt fs).getVariableDeclExpr() and
|
||||
not d = any(SpecificCatchClause scc).getVariableDeclExpr() and
|
||||
not d.getVariable().getType() instanceof Struct and
|
||||
not d instanceof PatternExpr and
|
||||
not d.getVariable().isCaptured()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,5 +2,40 @@
|
||||
* The default C# QL library.
|
||||
*/
|
||||
|
||||
// Do not add other imports here; add to `semmle.code.csharp.internal.csharp` instead
|
||||
import semmle.code.csharp.internal.csharp
|
||||
import Customizations
|
||||
import semmle.code.csharp.Attribute
|
||||
import semmle.code.csharp.Callable
|
||||
import semmle.code.csharp.Comments
|
||||
import semmle.code.csharp.Element
|
||||
import semmle.code.csharp.Event
|
||||
import semmle.code.csharp.File
|
||||
import semmle.code.csharp.Generics
|
||||
import semmle.code.csharp.Location
|
||||
import semmle.code.csharp.Member
|
||||
import semmle.code.csharp.Namespace
|
||||
import semmle.code.csharp.AnnotatedType
|
||||
import semmle.code.csharp.Property
|
||||
import semmle.code.csharp.Stmt
|
||||
import semmle.code.csharp.Type
|
||||
import semmle.code.csharp.Using
|
||||
import semmle.code.csharp.Variable
|
||||
import semmle.code.csharp.XML
|
||||
import semmle.code.csharp.Preprocessor
|
||||
import semmle.code.csharp.exprs.Access
|
||||
import semmle.code.csharp.exprs.ArithmeticOperation
|
||||
import semmle.code.csharp.exprs.Assignment
|
||||
import semmle.code.csharp.exprs.BitwiseOperation
|
||||
import semmle.code.csharp.exprs.Call
|
||||
import semmle.code.csharp.exprs.ComparisonOperation
|
||||
import semmle.code.csharp.exprs.Creation
|
||||
import semmle.code.csharp.exprs.Dynamic
|
||||
import semmle.code.csharp.exprs.Expr
|
||||
import semmle.code.csharp.exprs.Literal
|
||||
import semmle.code.csharp.exprs.LogicalOperation
|
||||
import semmle.code.csharp.controlflow.ControlFlowGraph
|
||||
import semmle.code.csharp.dataflow.DataFlow
|
||||
import semmle.code.csharp.dataflow.TaintTracking
|
||||
import semmle.code.csharp.dataflow.SSA
|
||||
|
||||
/** Whether the source was extracted without a build command. */
|
||||
predicate extractionIsStandalone() { exists(SourceFile f | f.extractedStandalone()) }
|
||||
|
||||
@@ -659,4 +659,15 @@ module Consistency {
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* Provides classes representing filesystem files and folders.
|
||||
*/
|
||||
|
||||
private import Comments
|
||||
|
||||
/** A file or folder. */
|
||||
class Container extends @container {
|
||||
/**
|
||||
@@ -195,11 +197,18 @@ class File extends Container, @file {
|
||||
|
||||
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
|
||||
|
||||
/** Holds if this file is a QL test stub file. */
|
||||
pragma[noinline]
|
||||
private predicate isStub() { this.getAbsolutePath().matches("%resources/stubs/%") }
|
||||
|
||||
/** Holds if this file contains source code. */
|
||||
predicate fromSource() { this.getExtension() = "cs" }
|
||||
final predicate fromSource() {
|
||||
this.getExtension() = "cs" and
|
||||
not this.isStub()
|
||||
}
|
||||
|
||||
/** Holds if this file is a library. */
|
||||
predicate fromLibrary() {
|
||||
final predicate fromLibrary() {
|
||||
not this.getBaseName() = "" and
|
||||
not this.fromSource()
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides functionality for validating that the database and library are in a
|
||||
* consistent state.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
||||
private predicate missingLocation(Element e, string m) {
|
||||
(
|
||||
e instanceof Declaration or
|
||||
e instanceof Expr or
|
||||
e instanceof Stmt
|
||||
) and
|
||||
not e instanceof ImplicitAccessorParameter and
|
||||
not e instanceof NullType and
|
||||
not e instanceof Parameter and // Bug in Roslyn - params occasionally lack locations
|
||||
not e.(Operator).getDeclaringType() instanceof IntType and // Roslyn quirk
|
||||
not e instanceof Constructor and
|
||||
not e instanceof ArrayType and
|
||||
not e instanceof UnknownType and
|
||||
not e instanceof ArglistType and
|
||||
not exists(TupleType t | e = t or e = t.getAField()) and
|
||||
not exists(e.getLocation()) and
|
||||
m = "Element does not have a location"
|
||||
}
|
||||
|
||||
private predicate inconsistentGeneric(ConstructedGeneric g, string m) {
|
||||
not exists(g.getUnboundGeneric()) and
|
||||
m = "Constructed generic does not have an unbound generic"
|
||||
or
|
||||
g.getNumberOfTypeArguments() = 0 and
|
||||
m = "Constructed generic has no type arguments"
|
||||
or
|
||||
g.getUnboundGeneric().getNumberOfTypeParameters() != g.getNumberOfTypeArguments() and
|
||||
m = "Inconsistent number of type arguments/parameters"
|
||||
}
|
||||
|
||||
module SsaChecks {
|
||||
import Ssa
|
||||
|
||||
predicate nonUniqueSsaDef(AssignableRead read, string m) {
|
||||
exists(ControlFlow::Node cfn | strictcount(Definition def | def.getAReadAtNode(cfn) = read) > 1) and
|
||||
m = "Read is associated with multiple SSA definitions"
|
||||
}
|
||||
|
||||
predicate notDominatedByDef(AssignableRead read, string m) {
|
||||
exists(
|
||||
Definition def, ControlFlow::BasicBlock bb, ControlFlow::Node rnode, ControlFlow::Node dnode,
|
||||
int i
|
||||
|
|
||||
def.getAReadAtNode(rnode) = read
|
||||
|
|
||||
def.definesAt(_, bb, i) and
|
||||
dnode = bb.getNode(max(int j | j = i or j = 0)) and
|
||||
not dnode.dominates(rnode)
|
||||
) and
|
||||
m = "Read is not dominated by SSA definition"
|
||||
}
|
||||
|
||||
predicate localDeclWithSsaDef(LocalVariableDeclExpr d, string m) {
|
||||
// Local variables in C# must be initialized before every use, so uninitialized
|
||||
// local variables should not have an SSA definition, as that would imply that
|
||||
// the declaration is live (can reach a use without passing through a definition)
|
||||
exists(ExplicitDefinition def |
|
||||
d = def.getADefinition().(AssignableDefinitions::LocalVariableDefinition).getDeclaration()
|
||||
|
|
||||
not d = any(ForeachStmt fs).getVariableDeclExpr() and
|
||||
not d = any(SpecificCatchClause scc).getVariableDeclExpr() and
|
||||
not d.getVariable().getType() instanceof Struct and
|
||||
not d = any(BindingPatternExpr bpe).getVariableDeclExpr()
|
||||
) and
|
||||
m = "Local variable declaration has unexpected SSA definition"
|
||||
}
|
||||
|
||||
predicate ssaConsistencyFailure(Element e, string m) {
|
||||
nonUniqueSsaDef(e, m) or
|
||||
notDominatedByDef(e, m) or
|
||||
localDeclWithSsaDef(e, m)
|
||||
}
|
||||
}
|
||||
|
||||
module CfgChecks {
|
||||
predicate multipleSuccessors(ControlFlowElement cfe, string m) {
|
||||
exists(ControlFlow::Node cfn | cfn = cfe.getAControlFlowNode() |
|
||||
strictcount(cfn.getASuccessorByType(any(ControlFlow::SuccessorTypes::NormalSuccessor e))) > 1 and
|
||||
m = "Multiple (non-conditional/exceptional) successors"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if element `e` has a consistency failure, as described by
|
||||
* the message in `m`.
|
||||
*/
|
||||
predicate consistencyFailure(Element e, string m) {
|
||||
missingLocation(e, m) or
|
||||
inconsistentGeneric(e, m) or
|
||||
SsaChecks::ssaConsistencyFailure(e, m) or
|
||||
CfgChecks::multipleSuccessors(e, m)
|
||||
}
|
||||
@@ -71,7 +71,7 @@ newtype CompilationExt =
|
||||
TBuildless() { extractionIsStandalone() }
|
||||
|
||||
/** Gets the compilation that source file `f` belongs to. */
|
||||
CompilationExt getCompilation(SourceFile f) {
|
||||
CompilationExt getCompilation(File f) {
|
||||
exists(Compilation c |
|
||||
f = c.getAFileCompiled() and
|
||||
result = TCompilation(c)
|
||||
|
||||
@@ -659,4 +659,15 @@ module Consistency {
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ private import internal.FlowSummaryImplSpecific
|
||||
private module Frameworks {
|
||||
private import semmle.code.csharp.frameworks.EntityFramework
|
||||
private import semmle.code.csharp.frameworks.JsonNET
|
||||
private import semmle.code.csharp.frameworks.microsoft.extensions.Primitives
|
||||
private import semmle.code.csharp.frameworks.microsoft.VisualBasic
|
||||
private import semmle.code.csharp.frameworks.ServiceStack
|
||||
private import semmle.code.csharp.frameworks.Sql
|
||||
@@ -348,6 +349,24 @@ module CsvValidation {
|
||||
msg = "Invalid boolean \"" + b + "\" in " + pred + " model."
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(string row, string kind | summaryModel(row) |
|
||||
kind = row.splitAt(";", 8) and
|
||||
not kind = ["taint", "value"] and
|
||||
msg = "Invalid kind \"" + kind + "\" in summary model."
|
||||
)
|
||||
or
|
||||
exists(string row, string kind | sinkModel(row) |
|
||||
kind = row.splitAt(";", 7) and
|
||||
not kind = ["code", "sql", "xss", "remote", "html"] and
|
||||
msg = "Invalid kind \"" + kind + "\" in sink model."
|
||||
)
|
||||
or
|
||||
exists(string row, string kind | sourceModel(row) |
|
||||
kind = row.splitAt(";", 7) and
|
||||
not kind = "local" and
|
||||
msg = "Invalid kind \"" + kind + "\" in source model."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ class ArgumentPosition = DataFlowDispatch::ArgumentPosition;
|
||||
|
||||
// import all instances below
|
||||
private module Summaries {
|
||||
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
|
||||
private import semmle.code.csharp.frameworks.EntityFramework
|
||||
}
|
||||
|
||||
@@ -111,6 +110,29 @@ module SummaryComponentStack {
|
||||
|
||||
class SummarizedCallable = Impl::Public::SummarizedCallable;
|
||||
|
||||
private predicate recordConstructorFlow(Constructor c, int i, Property p) {
|
||||
c = any(Record r).getAMember() and
|
||||
exists(string name |
|
||||
c.getParameter(i).getName() = name and
|
||||
c.getDeclaringType().getAMember(name) = p
|
||||
)
|
||||
}
|
||||
|
||||
private class RecordConstructorFlow extends SummarizedCallable {
|
||||
RecordConstructorFlow() { recordConstructorFlow(this, _, _) }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
exists(int i, Property p |
|
||||
recordConstructorFlow(this, i, p) and
|
||||
input = SummaryComponentStack::argument(i) and
|
||||
output = SummaryComponentStack::propertyOf(p, SummaryComponentStack::return()) and
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SummarizedCallableDefaultClearsContent extends Impl::Public::SummarizedCallable {
|
||||
SummarizedCallableDefaultClearsContent() {
|
||||
this instanceof Impl::Public::SummarizedCallable or none()
|
||||
@@ -129,3 +151,17 @@ private class SummarizedCallableDefaultClearsContent extends Impl::Public::Summa
|
||||
}
|
||||
|
||||
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
|
||||
|
||||
private class RecordConstructorFlowRequiredSummaryComponentStack extends RequiredSummaryComponentStack {
|
||||
private SummaryComponent head;
|
||||
|
||||
RecordConstructorFlowRequiredSummaryComponentStack() {
|
||||
exists(Property p |
|
||||
recordConstructorFlow(_, _, p) and
|
||||
head = SummaryComponent::property(p) and
|
||||
this = SummaryComponentStack::return()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate required(SummaryComponent c) { c = head }
|
||||
}
|
||||
|
||||
@@ -1,571 +0,0 @@
|
||||
/**
|
||||
* Provides classes and predicates for tracking data flow through library types.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.system.Collections
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
private import semmle.code.csharp.frameworks.system.Text
|
||||
private import semmle.code.csharp.frameworks.system.runtime.CompilerServices
|
||||
private import semmle.code.csharp.frameworks.system.threading.Tasks
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPublic
|
||||
private import semmle.code.csharp.dataflow.internal.DelegateDataFlow
|
||||
// import `LibraryTypeDataFlow` definitions from other files to avoid potential reevaluation
|
||||
private import semmle.code.csharp.frameworks.EntityFramework
|
||||
private import FlowSummary
|
||||
|
||||
private newtype TAccessPath =
|
||||
TNilAccessPath() or
|
||||
TConsAccessPath(Content head, AccessPath tail) {
|
||||
tail = TNilAccessPath()
|
||||
or
|
||||
exists(LibraryTypeDataFlow ltdf |
|
||||
ltdf.requiresAccessPath(head, tail) and
|
||||
tail.length() < accessPathLimit()
|
||||
)
|
||||
or
|
||||
tail = AccessPath::singleton(_) and
|
||||
head instanceof ElementContent
|
||||
or
|
||||
tail = AccessPath::element()
|
||||
}
|
||||
|
||||
/** An access path. */
|
||||
class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
Content getHead() { this = TConsAccessPath(result, _) }
|
||||
|
||||
/** Gets the tail of this access path, if any. */
|
||||
AccessPath getTail() { this = TConsAccessPath(_, result) }
|
||||
|
||||
/** Gets the length of this access path. */
|
||||
int length() {
|
||||
this = TNilAccessPath() and result = 0
|
||||
or
|
||||
result = 1 + this.getTail().length()
|
||||
}
|
||||
|
||||
/** Gets the access path obtained by dropping the first `i` elements, if any. */
|
||||
AccessPath drop(int i) {
|
||||
i = 0 and result = this
|
||||
or
|
||||
result = this.getTail().drop(i - 1)
|
||||
}
|
||||
|
||||
/** Holds if this access path contains content `c`. */
|
||||
predicate contains(Content c) { c = this.drop(_).getHead() }
|
||||
|
||||
/** Gets a textual representation of this access path. */
|
||||
string toString() {
|
||||
exists(Content head, AccessPath tail |
|
||||
head = this.getHead() and
|
||||
tail = this.getTail() and
|
||||
if tail.length() = 0 then result = head.toString() else result = head + ", " + tail
|
||||
)
|
||||
or
|
||||
this = TNilAccessPath() and
|
||||
result = "<empty>"
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides predicates for constructing access paths. */
|
||||
module AccessPath {
|
||||
/** Gets the empty access path. */
|
||||
AccessPath empty() { result = TNilAccessPath() }
|
||||
|
||||
/** Gets a singleton access path containing `c`. */
|
||||
AccessPath singleton(Content c) { result = TConsAccessPath(c, TNilAccessPath()) }
|
||||
|
||||
/** Gets the access path obtained by concatenating `head` onto `tail`. */
|
||||
AccessPath cons(Content head, AccessPath tail) { result = TConsAccessPath(head, tail) }
|
||||
|
||||
/** Gets the singleton "element content" access path. */
|
||||
AccessPath element() { result = singleton(any(ElementContent c)) }
|
||||
|
||||
/** Gets a singleton property access path. */
|
||||
AccessPath property(Property p) {
|
||||
result = singleton(any(PropertyContent c | c.getProperty() = p.getUnboundDeclaration()))
|
||||
}
|
||||
|
||||
/** Gets a singleton field access path. */
|
||||
AccessPath field(Field f) {
|
||||
result = singleton(any(FieldContent c | c.getField() = f.getUnboundDeclaration()))
|
||||
}
|
||||
|
||||
/** Gets a singleton synthetic field access path. */
|
||||
AccessPath synthetic(SyntheticField f) {
|
||||
result = singleton(any(SyntheticFieldContent c | c.getField() = f))
|
||||
}
|
||||
|
||||
/** Gets an access path representing a property inside a collection. */
|
||||
AccessPath properties(Property p) { result = TConsAccessPath(any(ElementContent c), property(p)) }
|
||||
}
|
||||
|
||||
/** An unbound callable. */
|
||||
class SourceDeclarationCallable extends Callable {
|
||||
SourceDeclarationCallable() { this.isUnboundDeclaration() }
|
||||
}
|
||||
|
||||
/** An unbound method. */
|
||||
class SourceDeclarationMethod extends SourceDeclarationCallable, Method { }
|
||||
|
||||
private newtype TCallableFlowSource =
|
||||
TCallableFlowSourceQualifier() or
|
||||
TCallableFlowSourceArg(int i) { i = any(Parameter p).getPosition() } or
|
||||
TCallableFlowSourceDelegateArg(int i) { hasDelegateArgumentPosition(_, i) }
|
||||
|
||||
private predicate hasDelegateArgumentPosition(SourceDeclarationCallable c, int i) {
|
||||
exists(DelegateType dt |
|
||||
dt = c.getParameter(i).getType().(SystemLinqExpressions::DelegateExtType).getDelegateType()
|
||||
|
|
||||
not dt.getReturnType() instanceof VoidType
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasDelegateArgumentPosition2(SourceDeclarationCallable c, int i, int j) {
|
||||
exists(DelegateType dt |
|
||||
dt = c.getParameter(i).getType().(SystemLinqExpressions::DelegateExtType).getDelegateType()
|
||||
|
|
||||
exists(dt.getParameter(j))
|
||||
)
|
||||
}
|
||||
|
||||
/** A flow source specification. */
|
||||
class CallableFlowSource extends TCallableFlowSource {
|
||||
/** Gets a textual representation of this flow source specification. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the source of flow for call `c`, if any. */
|
||||
Expr getSource(Call c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type of the source for call `c`. Unlike `getSource()`, this
|
||||
* is defined for all flow source specifications.
|
||||
*/
|
||||
Type getSourceType(Call c) { result = this.getSource(c).getType() }
|
||||
}
|
||||
|
||||
/** A flow source specification: (method call) qualifier. */
|
||||
class CallableFlowSourceQualifier extends CallableFlowSource, TCallableFlowSourceQualifier {
|
||||
override string toString() { result = "qualifier" }
|
||||
|
||||
override Expr getSource(Call c) { result = c.getChild(-1) }
|
||||
}
|
||||
|
||||
/** A flow source specification: (method call) argument. */
|
||||
class CallableFlowSourceArg extends CallableFlowSource, TCallableFlowSourceArg {
|
||||
private int i;
|
||||
|
||||
CallableFlowSourceArg() { this = TCallableFlowSourceArg(i) }
|
||||
|
||||
/** Gets the index of this argument. */
|
||||
int getArgumentIndex() { result = i }
|
||||
|
||||
override string toString() { result = "argument " + i }
|
||||
|
||||
override Expr getSource(Call c) { result = c.getArgument(i) }
|
||||
}
|
||||
|
||||
/** A flow source specification: output from delegate argument. */
|
||||
class CallableFlowSourceDelegateArg extends CallableFlowSource, TCallableFlowSourceDelegateArg {
|
||||
private int i;
|
||||
|
||||
CallableFlowSourceDelegateArg() { this = TCallableFlowSourceDelegateArg(i) }
|
||||
|
||||
/** Gets the index of this delegate argument. */
|
||||
int getArgumentIndex() { result = i }
|
||||
|
||||
override string toString() { result = "output from argument " + i }
|
||||
|
||||
override Expr getSource(Call c) { none() }
|
||||
|
||||
override Type getSourceType(Call c) { result = c.getArgument(i).getType() }
|
||||
}
|
||||
|
||||
private newtype TCallableFlowSink =
|
||||
TCallableFlowSinkQualifier() or
|
||||
TCallableFlowSinkReturn() or
|
||||
TCallableFlowSinkArg(int i) { exists(SourceDeclarationCallable c | exists(c.getParameter(i))) } or
|
||||
TCallableFlowSinkDelegateArg(int i, int j) { hasDelegateArgumentPosition2(_, i, j) }
|
||||
|
||||
/** A flow sink specification. */
|
||||
class CallableFlowSink extends TCallableFlowSink {
|
||||
/** Gets a textual representation of this flow sink specification. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the sink of flow for call `c`, if any. */
|
||||
Expr getSink(Call c) { none() }
|
||||
}
|
||||
|
||||
/** A flow sink specification: (method call) qualifier. */
|
||||
class CallableFlowSinkQualifier extends CallableFlowSink, TCallableFlowSinkQualifier {
|
||||
override string toString() { result = "qualifier" }
|
||||
|
||||
override Expr getSink(Call c) { result = c.getChild(-1) }
|
||||
}
|
||||
|
||||
/** A flow sink specification: return value. */
|
||||
class CallableFlowSinkReturn extends CallableFlowSink, TCallableFlowSinkReturn {
|
||||
override string toString() { result = "return" }
|
||||
|
||||
override Expr getSink(Call c) { result = c }
|
||||
}
|
||||
|
||||
/** A flow sink specification: (method call) argument. */
|
||||
class CallableFlowSinkArg extends CallableFlowSink, TCallableFlowSinkArg {
|
||||
private int i;
|
||||
|
||||
CallableFlowSinkArg() { this = TCallableFlowSinkArg(i) }
|
||||
|
||||
/** Gets the index of this `out`/`ref` argument. */
|
||||
int getArgumentIndex() { result = i }
|
||||
|
||||
/** Gets the `out`/`ref` argument of method call `mc` matching this specification. */
|
||||
Expr getArgument(MethodCall mc) {
|
||||
exists(Parameter p |
|
||||
p = mc.getTarget().getParameter(i) and
|
||||
p.isOutOrRef() and
|
||||
result = mc.getArgumentForParameter(p)
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "argument " + i }
|
||||
|
||||
override Expr getSink(Call c) {
|
||||
// The uses of the `i`th argument are the actual sinks
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/** A flow sink specification: parameter of a delegate argument. */
|
||||
class CallableFlowSinkDelegateArg extends CallableFlowSink, TCallableFlowSinkDelegateArg {
|
||||
private int delegateIndex;
|
||||
private int parameterIndex;
|
||||
|
||||
CallableFlowSinkDelegateArg() {
|
||||
this = TCallableFlowSinkDelegateArg(delegateIndex, parameterIndex)
|
||||
}
|
||||
|
||||
/** Gets the index of the delegate argument. */
|
||||
int getDelegateIndex() { result = delegateIndex }
|
||||
|
||||
/** Gets the index of the delegate parameter. */
|
||||
int getDelegateParameterIndex() { result = parameterIndex }
|
||||
|
||||
override string toString() {
|
||||
result = "parameter " + parameterIndex + " of argument " + delegateIndex
|
||||
}
|
||||
|
||||
override Expr getSink(Call c) {
|
||||
// The uses of the `j`th parameter are the actual sinks
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/** A specification of data flow for a library (non-source code) type. */
|
||||
abstract class LibraryTypeDataFlow extends Type {
|
||||
LibraryTypeDataFlow() { this = this.getUnboundDeclaration() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` when calling callable `c`.
|
||||
*
|
||||
* `preservesValue` indicates whether the value from `source` is preserved
|
||||
* (possibly copied) to `sink`. For example, the value is preserved from `x`
|
||||
* to `x.ToString()` when `x` is a `string`, but not from `x` to `x.ToLower()`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate callableFlow(
|
||||
CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c,
|
||||
boolean preservesValue
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` when calling callable `c`.
|
||||
*
|
||||
* `sourceAp` describes the contents of `source` that flows to `sink`
|
||||
* (if any), and `sinkAp` describes the contents of `sink` that it
|
||||
* flows to (if any).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate callableFlow(
|
||||
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
|
||||
SourceDeclarationCallable c, boolean preservesValue
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the access path obtained by concatenating `head` onto `tail` is
|
||||
* needed for a summary specified by `callableFlow()`.
|
||||
*
|
||||
* This predicate is needed for QL technical reasons only (the IPA type used
|
||||
* to represent access paths needs to be bounded).
|
||||
*/
|
||||
predicate requiresAccessPath(Content head, AccessPath tail) { none() }
|
||||
|
||||
/**
|
||||
* Holds if values stored inside `content` are cleared on objects passed as
|
||||
* arguments of type `source` to calls that target `callable`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate clearsContent(
|
||||
CallableFlowSource source, Content content, SourceDeclarationCallable callable
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal module for translating old `LibraryTypeDataFlow`-style
|
||||
* flow summaries into the new style.
|
||||
*/
|
||||
private module FrameworkDataFlowAdaptor {
|
||||
private CallableFlowSource toCallableFlowSource(SummaryComponentStack input) {
|
||||
result = TCallableFlowSourceQualifier() and
|
||||
input = SummaryComponentStack::qualifier()
|
||||
or
|
||||
exists(int i |
|
||||
result = TCallableFlowSourceArg(i) and
|
||||
input = SummaryComponentStack::argument(i)
|
||||
)
|
||||
or
|
||||
exists(int i | result = TCallableFlowSourceDelegateArg(i) |
|
||||
input =
|
||||
SummaryComponentStack::push(SummaryComponent::return(), SummaryComponentStack::argument(i))
|
||||
)
|
||||
}
|
||||
|
||||
private CallableFlowSink toCallableFlowSink(SummaryComponentStack output) {
|
||||
result = TCallableFlowSinkQualifier() and
|
||||
output = SummaryComponentStack::qualifier()
|
||||
or
|
||||
result = TCallableFlowSinkReturn() and
|
||||
output = SummaryComponentStack::return()
|
||||
or
|
||||
exists(int i |
|
||||
result = TCallableFlowSinkArg(i) and
|
||||
output = SummaryComponentStack::argument(i)
|
||||
)
|
||||
or
|
||||
exists(int i, int j | result = TCallableFlowSinkDelegateArg(i, j) |
|
||||
output =
|
||||
SummaryComponentStack::push(SummaryComponent::parameter(j),
|
||||
SummaryComponentStack::argument(i))
|
||||
)
|
||||
}
|
||||
|
||||
private class FrameworkDataFlowAdaptor extends SummarizedCallable {
|
||||
private LibraryTypeDataFlow ltdf;
|
||||
|
||||
FrameworkDataFlowAdaptor() {
|
||||
ltdf.callableFlow(_, _, this, _) or
|
||||
ltdf.callableFlow(_, _, _, _, this, _) or
|
||||
ltdf.clearsContent(_, _, this)
|
||||
}
|
||||
|
||||
predicate input(
|
||||
CallableFlowSource source, AccessPath sourceAp, SummaryComponent head,
|
||||
SummaryComponentStack tail, int i
|
||||
) {
|
||||
ltdf.callableFlow(source, sourceAp, _, _, this, _) and
|
||||
source = toCallableFlowSource(tail) and
|
||||
head = SummaryComponent::content(sourceAp.getHead()) and
|
||||
i = 0
|
||||
or
|
||||
exists(SummaryComponent tailHead, SummaryComponentStack tailTail |
|
||||
this.input(source, sourceAp, tailHead, tailTail, i - 1) and
|
||||
head = SummaryComponent::content(sourceAp.drop(i).getHead()) and
|
||||
tail = SummaryComponentStack::push(tailHead, tailTail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate output(
|
||||
CallableFlowSink sink, AccessPath sinkAp, SummaryComponent head, SummaryComponentStack tail,
|
||||
int i
|
||||
) {
|
||||
ltdf.callableFlow(_, _, sink, sinkAp, this, _) and
|
||||
sink = toCallableFlowSink(tail) and
|
||||
head = SummaryComponent::content(sinkAp.getHead()) and
|
||||
i = 0
|
||||
or
|
||||
exists(SummaryComponent tailHead, SummaryComponentStack tailTail |
|
||||
this.output(sink, sinkAp, tailHead, tailTail, i - 1) and
|
||||
head = SummaryComponent::content(sinkAp.drop(i).getHead()) and
|
||||
tail = SummaryComponentStack::push(tailHead, tailTail)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
ltdf.callableFlow(toCallableFlowSource(input), toCallableFlowSink(output), this,
|
||||
preservesValue)
|
||||
or
|
||||
exists(
|
||||
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp
|
||||
|
|
||||
ltdf.callableFlow(source, sourceAp, sink, sinkAp, this, preservesValue) and
|
||||
(
|
||||
exists(SummaryComponent head, SummaryComponentStack tail |
|
||||
this.input(source, sourceAp, head, tail, sourceAp.length() - 1) and
|
||||
input = SummaryComponentStack::push(head, tail)
|
||||
)
|
||||
or
|
||||
sourceAp.length() = 0 and
|
||||
source = toCallableFlowSource(input)
|
||||
) and
|
||||
(
|
||||
exists(SummaryComponent head, SummaryComponentStack tail |
|
||||
this.output(sink, sinkAp, head, tail, sinkAp.length() - 1) and
|
||||
output = SummaryComponentStack::push(head, tail)
|
||||
)
|
||||
or
|
||||
sinkAp.length() = 0 and
|
||||
sink = toCallableFlowSink(output)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate clearsContent(ParameterPosition pos, Content content) {
|
||||
exists(SummaryComponentStack input |
|
||||
ltdf.clearsContent(toCallableFlowSource(input), content, this) and
|
||||
input = SummaryComponentStack::argument(pos.getPosition())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class AdaptorRequiredSummaryComponentStack extends RequiredSummaryComponentStack {
|
||||
private SummaryComponent head;
|
||||
|
||||
AdaptorRequiredSummaryComponentStack() {
|
||||
exists(int i |
|
||||
exists(TCallableFlowSourceDelegateArg(i)) and
|
||||
head = SummaryComponent::return() and
|
||||
this = SummaryComponentStack::singleton(SummaryComponent::argument(i))
|
||||
)
|
||||
or
|
||||
exists(int i, int j | exists(TCallableFlowSinkDelegateArg(i, j)) |
|
||||
head = SummaryComponent::parameter(j) and
|
||||
this = SummaryComponentStack::singleton(SummaryComponent::argument(i))
|
||||
)
|
||||
or
|
||||
exists(FrameworkDataFlowAdaptor adaptor |
|
||||
adaptor.input(_, _, head, this, _)
|
||||
or
|
||||
adaptor.output(_, _, head, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate required(SummaryComponent c) { c = head }
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Text.StringBuilder`. */
|
||||
class SystemTextStringBuilderFlow extends LibraryTypeDataFlow, SystemTextStringBuilderClass {
|
||||
override predicate clearsContent(
|
||||
CallableFlowSource source, Content content, SourceDeclarationCallable callable
|
||||
) {
|
||||
source = TCallableFlowSourceQualifier() and
|
||||
callable = this.getAMethod("Clear") and
|
||||
content instanceof ElementContent
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Collections.IEnumerable` (and sub types). */
|
||||
class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
IEnumerableFlow() { this.getABaseType*() instanceof SystemCollectionsIEnumerableInterface }
|
||||
|
||||
override predicate clearsContent(
|
||||
CallableFlowSource source, Content content, SourceDeclarationCallable callable
|
||||
) {
|
||||
source = TCallableFlowSourceQualifier() and
|
||||
callable = this.getAMethod("Clear") and
|
||||
content instanceof ElementContent
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class SyntheticTaskField extends SyntheticField {
|
||||
bindingset[this]
|
||||
SyntheticTaskField() { any() }
|
||||
|
||||
override Type getType() { result instanceof SystemThreadingTasksTaskTClass }
|
||||
}
|
||||
|
||||
private class SyntheticTaskAwaiterUnderlyingTaskField extends SyntheticTaskField {
|
||||
SyntheticTaskAwaiterUnderlyingTaskField() { this = "m_task_task_awaiter" }
|
||||
}
|
||||
|
||||
private class SyntheticConfiguredTaskAwaitableUnderlyingTaskField extends SyntheticTaskField {
|
||||
SyntheticConfiguredTaskAwaitableUnderlyingTaskField() {
|
||||
this = "m_task_configured_task_awaitable"
|
||||
}
|
||||
}
|
||||
|
||||
private class SyntheticConfiguredTaskAwaiterField extends SyntheticField {
|
||||
SyntheticConfiguredTaskAwaiterField() { this = "m_configuredTaskAwaiter" }
|
||||
|
||||
override Type getType() {
|
||||
result instanceof
|
||||
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom flow through `StringValues` library class.
|
||||
*/
|
||||
class StringValuesFlow extends LibraryTypeDataFlow, Struct {
|
||||
StringValuesFlow() { this.hasQualifiedName("Microsoft.Extensions.Primitives", "StringValues") }
|
||||
|
||||
override predicate callableFlow(
|
||||
CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c,
|
||||
boolean preservesValue
|
||||
) {
|
||||
c.getDeclaringType() = this and
|
||||
(
|
||||
source instanceof CallableFlowSourceArg or
|
||||
source instanceof CallableFlowSourceQualifier
|
||||
) and
|
||||
sink instanceof CallableFlowSinkReturn and
|
||||
preservesValue = false
|
||||
}
|
||||
}
|
||||
|
||||
private predicate recordConstructorFlow(Constructor c, int i, Property p) {
|
||||
c = any(Record r).getAMember() and
|
||||
exists(string name |
|
||||
c.getParameter(i).getName() = name and
|
||||
c.getDeclaringType().getAMember(name) = p
|
||||
)
|
||||
}
|
||||
|
||||
private class RecordConstructorFlowRequiredSummaryComponentStack extends RequiredSummaryComponentStack {
|
||||
private SummaryComponent head;
|
||||
|
||||
RecordConstructorFlowRequiredSummaryComponentStack() {
|
||||
exists(Property p |
|
||||
recordConstructorFlow(_, _, p) and
|
||||
head = SummaryComponent::property(p) and
|
||||
this = SummaryComponentStack::singleton(SummaryComponent::return())
|
||||
)
|
||||
}
|
||||
|
||||
override predicate required(SummaryComponent c) { c = head }
|
||||
}
|
||||
|
||||
private class RecordConstructorFlow extends SummarizedCallable {
|
||||
RecordConstructorFlow() { recordConstructorFlow(this, _, _) }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
exists(int i, Property p |
|
||||
recordConstructorFlow(this, i, p) and
|
||||
input = SummaryComponentStack::argument(i) and
|
||||
output = SummaryComponentStack::propertyOf(p, SummaryComponentStack::return()) and
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -659,4 +659,15 @@ module Consistency {
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,4 +659,15 @@ module Consistency {
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,6 +316,12 @@ private predicate hasChildPattern(ControlFlowElement pm, Expr child) {
|
||||
child = mid.getChildExpr(0) or
|
||||
child = mid.getChildExpr(1)
|
||||
)
|
||||
or
|
||||
exists(Expr mid |
|
||||
hasChildPattern(pm, mid) and
|
||||
mid instanceof @tuple_expr and
|
||||
child = mid.getAChildExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,13 +426,10 @@ class TypeAccessPatternExpr extends TypePatternExpr, TypeAccess {
|
||||
override string getAPrimaryQlClass() { result = "TypeAccessPatternExpr" }
|
||||
}
|
||||
|
||||
/** A pattern that may bind a variable, for example `string s` in `x is string s`. */
|
||||
class BindingPatternExpr extends PatternExpr {
|
||||
BindingPatternExpr() {
|
||||
this instanceof LocalVariableDeclExpr or
|
||||
this instanceof @recursive_pattern_expr
|
||||
}
|
||||
private class TBindingPatternExpr = @local_var_decl_expr or @recursive_pattern_expr;
|
||||
|
||||
/** A pattern that may bind a variable, for example `string s` in `x is string s`. */
|
||||
class BindingPatternExpr extends PatternExpr, TBindingPatternExpr {
|
||||
/**
|
||||
* Gets the local variable declaration of this pattern, if any. For example,
|
||||
* `string s` in `string { Length: 5 } s`.
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/** Provides definitions related to the `Microsoft.Extensions.Primitives` namespace. */
|
||||
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
|
||||
/** Data flow for `Microsoft.Extensions.Primitives.StringValues`. */
|
||||
private class MicrosoftExtensionsPrimitivesStringValuesFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Add;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Add;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(Microsoft.Extensions.Primitives.StringValues,System.String);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(System.String,Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Concat;(System.String,Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Contains;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Contains;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;CopyTo;(System.String[],System.Int32);;Element of Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;CopyTo;(System.String[],System.Int32);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;CopyTo;(System.String[],System.Int32);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,System.String);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,System.String[]);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(Microsoft.Extensions.Primitives.StringValues,System.String[]);;Element of Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.Object);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.Object);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String,Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String,Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String[]);;Element of Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String[]);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String[],Microsoft.Extensions.Primitives.StringValues);;Element of Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Equals;(System.String[],Microsoft.Extensions.Primitives.StringValues);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;GetEnumerator;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;GetHashCode;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;IndexOf;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;IndexOf;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Insert;(System.Int32,System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Insert;(System.Int32,System.String);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Insert;(System.Int32,System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;IsNullOrEmpty;(Microsoft.Extensions.Primitives.StringValues);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Remove;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;Remove;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;RemoveAt;(System.Int32);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;RemoveAt;(System.Int32);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;StringValues;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;StringValues;(System.String[]);;Element of Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;ToArray;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;ToString;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;get_Count;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;get_IsReadOnly;();;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;get_Item;(System.Int32);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;get_Item;(System.Int32);;Argument[-1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;set_Item;(System.Int32,System.String);;Argument[0];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;set_Item;(System.Int32,System.String);;Argument[1];ReturnValue;taint",
|
||||
"Microsoft.Extensions.Primitives;StringValues;false;set_Item;(System.Int32,System.String);;Argument[-1];ReturnValue;taint",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
|
||||
/** The `System.Collections` namespace. */
|
||||
class SystemCollectionsNamespace extends Namespace {
|
||||
@@ -45,6 +46,20 @@ private class SystemCollectionIEnumerableFlowModelCsv extends SummaryModelCsv {
|
||||
}
|
||||
}
|
||||
|
||||
/** Clear content for Clear methods in all subtypes of `System.Collections.IEnumerable`. */
|
||||
private class SystemCollectionsIEnumerableClearFlow extends SummarizedCallable {
|
||||
SystemCollectionsIEnumerableClearFlow() {
|
||||
this.getDeclaringType().(RefType).getABaseType*() instanceof
|
||||
SystemCollectionsIEnumerableInterface and
|
||||
this.hasName("Clear")
|
||||
}
|
||||
|
||||
override predicate clearsContent(ParameterPosition pos, DataFlow::Content content) {
|
||||
pos.getPosition() = -1 and
|
||||
content instanceof DataFlow::ElementContent
|
||||
}
|
||||
}
|
||||
|
||||
/** The `System.Collections.IEnumerator` interface. */
|
||||
class SystemCollectionsIEnumeratorInterface extends SystemCollectionsInterface {
|
||||
SystemCollectionsIEnumeratorInterface() { this.hasName("IEnumerator") }
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
|
||||
/** The `System.Text` namespace. */
|
||||
class SystemTextNamespace extends Namespace {
|
||||
@@ -25,6 +26,18 @@ class SystemTextStringBuilderClass extends SystemTextClass {
|
||||
Method getAppendFormatMethod() { result = this.getAMethod("AppendFormat") }
|
||||
}
|
||||
|
||||
/** Clear content for `System.Text.StringBuilder.Clear`. */
|
||||
private class SystemTextStringBuilderClearFlow extends SummarizedCallable {
|
||||
SystemTextStringBuilderClearFlow() {
|
||||
this = any(SystemTextStringBuilderClass s).getAMethod("Clear")
|
||||
}
|
||||
|
||||
override predicate clearsContent(ParameterPosition pos, DataFlow::Content content) {
|
||||
pos.getPosition() = -1 and
|
||||
content instanceof DataFlow::ElementContent
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Text.StringBuilder`. */
|
||||
private class SystemTextStringBuilderFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.system.Runtime
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
|
||||
/** The `System.Runtime.CompilerServices` namespace. */
|
||||
@@ -53,6 +54,15 @@ class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct extends System
|
||||
}
|
||||
}
|
||||
|
||||
private class SyntheticConfiguredTaskAwaiterField extends SyntheticField {
|
||||
SyntheticConfiguredTaskAwaiterField() { this = "m_configuredTaskAwaiter" }
|
||||
|
||||
override Type getType() {
|
||||
result instanceof
|
||||
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>`. */
|
||||
private class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.system.Threading
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
|
||||
/** The `System.Threading.Tasks` namespace. */
|
||||
@@ -91,6 +92,23 @@ class SystemThreadingTasksTaskTClass extends SystemThreadingTasksUnboundGenericC
|
||||
Method getConfigureAwaitMethod() { result = this.getAMethod("ConfigureAwait") }
|
||||
}
|
||||
|
||||
abstract private class SyntheticTaskField extends SyntheticField {
|
||||
bindingset[this]
|
||||
SyntheticTaskField() { any() }
|
||||
|
||||
override Type getType() { result instanceof SystemThreadingTasksTaskTClass }
|
||||
}
|
||||
|
||||
private class SyntheticTaskAwaiterUnderlyingTaskField extends SyntheticTaskField {
|
||||
SyntheticTaskAwaiterUnderlyingTaskField() { this = "m_task_task_awaiter" }
|
||||
}
|
||||
|
||||
private class SyntheticConfiguredTaskAwaitableUnderlyingTaskField extends SyntheticTaskField {
|
||||
SyntheticConfiguredTaskAwaitableUnderlyingTaskField() {
|
||||
this = "m_task_configured_task_awaitable"
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Threading.Tasks.Task<>`. */
|
||||
private class SystemThreadingTasksTaskTFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* The default C# QL library.
|
||||
*/
|
||||
|
||||
import Customizations
|
||||
import semmle.code.csharp.Attribute
|
||||
import semmle.code.csharp.Callable
|
||||
import semmle.code.csharp.Comments
|
||||
import semmle.code.csharp.Element
|
||||
import semmle.code.csharp.Event
|
||||
import semmle.code.csharp.File
|
||||
import semmle.code.csharp.Generics
|
||||
import semmle.code.csharp.Location
|
||||
import semmle.code.csharp.Member
|
||||
import semmle.code.csharp.Namespace
|
||||
import semmle.code.csharp.AnnotatedType
|
||||
import semmle.code.csharp.Property
|
||||
import semmle.code.csharp.Stmt
|
||||
import semmle.code.csharp.Type
|
||||
import semmle.code.csharp.Using
|
||||
import semmle.code.csharp.Variable
|
||||
import semmle.code.csharp.XML
|
||||
import semmle.code.csharp.Preprocessor
|
||||
import semmle.code.csharp.exprs.Access
|
||||
import semmle.code.csharp.exprs.ArithmeticOperation
|
||||
import semmle.code.csharp.exprs.Assignment
|
||||
import semmle.code.csharp.exprs.BitwiseOperation
|
||||
import semmle.code.csharp.exprs.Call
|
||||
import semmle.code.csharp.exprs.ComparisonOperation
|
||||
import semmle.code.csharp.exprs.Creation
|
||||
import semmle.code.csharp.exprs.Dynamic
|
||||
import semmle.code.csharp.exprs.Expr
|
||||
import semmle.code.csharp.exprs.Literal
|
||||
import semmle.code.csharp.exprs.LogicalOperation
|
||||
import semmle.code.csharp.controlflow.ControlFlowGraph
|
||||
import semmle.code.csharp.dataflow.DataFlow
|
||||
import semmle.code.csharp.dataflow.TaintTracking
|
||||
import semmle.code.csharp.dataflow.SSA
|
||||
|
||||
/** Whether the source was extracted without a build command. */
|
||||
predicate extractionIsStandalone() { exists(SourceFile f | f.extractedStandalone()) }
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* The default C# QL library.
|
||||
*/
|
||||
|
||||
import semmle.code.csharp.internal.csharp
|
||||
|
||||
private class FileAdjusted extends File {
|
||||
override predicate fromSource() {
|
||||
super.fromSource() and
|
||||
not this.getAbsolutePath().matches("%resources/stubs/%")
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.ql
|
||||
@@ -24,13 +24,21 @@
|
||||
| arguments.cs:45:35:45:38 | null | 0 |
|
||||
| arguments.cs:55:21:55:21 | 1 | 0 |
|
||||
| arguments.cs:55:24:55:24 | 2 | 0 |
|
||||
| arguments.cs:56:10:56:13 | access to property Prop | 0 |
|
||||
| arguments.cs:56:16:56:25 | access to indexer | 0 |
|
||||
| arguments.cs:56:21:56:21 | 3 | 0 |
|
||||
| arguments.cs:56:24:56:24 | 4 | 0 |
|
||||
| arguments.cs:56:31:56:31 | 5 | 0 |
|
||||
| arguments.cs:56:34:56:34 | 6 | 0 |
|
||||
| arguments.cs:59:14:59:14 | 8 | 0 |
|
||||
| arguments.cs:59:17:59:17 | 9 | 0 |
|
||||
| arguments.cs:60:14:60:15 | 10 | 0 |
|
||||
| arguments.cs:60:14:60:15 | 10 | 0 |
|
||||
| arguments.cs:60:18:60:19 | 11 | 0 |
|
||||
| arguments.cs:60:18:60:19 | 11 | 0 |
|
||||
| arguments.cs:61:22:61:23 | 13 | 0 |
|
||||
| arguments.cs:61:26:61:27 | 14 | 0 |
|
||||
| arguments.cs:62:10:62:13 | access to property Prop | 0 |
|
||||
| arguments.cs:62:16:62:27 | access to indexer | 0 |
|
||||
| arguments.cs:62:21:62:22 | 15 | 0 |
|
||||
| arguments.cs:62:25:62:26 | 16 | 0 |
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
public class MyConstStringInterpolationClass
|
||||
{
|
||||
public const string hello = "Hello";
|
||||
public const string helloWorld = $"{hello} World";
|
||||
public const string reallyHelloWorld = $"Really {helloWorld}";
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace MyFileScopedNamespace;
|
||||
|
||||
public class MyFileScopedNamespaceClass
|
||||
{
|
||||
private readonly object myField = new object();
|
||||
public object MyProp { get; set; }
|
||||
public void MyMethod() { }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
inserts
|
||||
| ConstInterpolatedString.cs:6:38:6:53 | $"..." | ConstInterpolatedString.cs:6:41:6:45 | access to constant hello |
|
||||
| ConstInterpolatedString.cs:7:44:7:65 | $"..." | ConstInterpolatedString.cs:7:54:7:63 | access to constant helloWorld |
|
||||
texts
|
||||
| ConstInterpolatedString.cs:6:38:6:53 | $"..." | ConstInterpolatedString.cs:6:47:6:52 | " World" |
|
||||
| ConstInterpolatedString.cs:7:44:7:65 | $"..." | ConstInterpolatedString.cs:7:46:7:52 | "Really " |
|
||||
@@ -0,0 +1,7 @@
|
||||
import csharp
|
||||
|
||||
query predicate inserts(InterpolatedStringExpr expr, Expr e) { expr.getAnInsert() = e }
|
||||
|
||||
query predicate texts(InterpolatedStringExpr expr, StringLiteral literal) {
|
||||
expr.getAText() = literal
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileScopedNamespace
|
||||
| FileScopedNamespace.cs:1:11:1:31 | MyFileScopedNamespace | FileScopedNamespace.cs:3:14:3:39 | MyFileScopedNamespaceClass |
|
||||
| FileScopedNamespace.cs:1:11:1:31 | MyFileScopedNamespace | FileScopedNamespace.cs:5:29:5:35 | myField |
|
||||
| FileScopedNamespace.cs:1:11:1:31 | MyFileScopedNamespace | FileScopedNamespace.cs:6:19:6:24 | MyProp |
|
||||
| FileScopedNamespace.cs:1:11:1:31 | MyFileScopedNamespace | FileScopedNamespace.cs:7:17:7:24 | MyMethod |
|
||||
namespaceDeclaration
|
||||
| FileScopedNamespace.cs:1:11:1:31 | namespace ... { ... } | FileScopedNamespace.cs:1:11:1:31 | MyFileScopedNamespace |
|
||||
12
csharp/ql/test/library-tests/csharp10/fileScopedNamespace.ql
Normal file
12
csharp/ql/test/library-tests/csharp10/fileScopedNamespace.ql
Normal file
@@ -0,0 +1,12 @@
|
||||
import csharp
|
||||
|
||||
query predicate fileScopedNamespace(Namespace n, Member m) {
|
||||
n.hasQualifiedName("MyFileScopedNamespace") and
|
||||
exists(Class c |
|
||||
c.getNamespace() = n and
|
||||
c.hasMember(m) and
|
||||
m.getLocation().toString().matches("%FileScopedNamespace.cs%")
|
||||
)
|
||||
}
|
||||
|
||||
query predicate namespaceDeclaration(NamespaceDeclaration nd, Namespace n) { n = nd.getNamespace() }
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user