Merge branch 'main' into aeisenberg/remove-upgrades

This commit is contained in:
Andrew Eisenberg
2022-01-11 11:25:27 -08:00
216 changed files with 8415 additions and 1980 deletions

View File

@@ -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",

View File

@@ -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

View File

@@ -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 }

View File

@@ -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)

View File

@@ -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
)
}

View File

@@ -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), _)
)
}
}

View File

@@ -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
)

View File

@@ -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)
}

View File

@@ -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"
)
}

View File

@@ -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"

View File

@@ -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.

View File

@@ -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 |

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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
1 package sink source summary sink:code sink:html sink:remote sink:sql sink:xss source:local summary:taint summary:value
2 Dapper 55 55
3 Microsoft.ApplicationBlocks.Data 28 28
4 Microsoft.Extensions.Primitives 54 54
5 Microsoft.VisualBasic 4 4
6 MySql.Data.MySqlClient 48 48
7 Newtonsoft.Json 91 73 18

View File

@@ -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

View File

@@ -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

View File

@@ -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++);
}

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1 @@
## 1.0.0

View File

@@ -0,0 +1 @@
## 1.0.0

View File

@@ -0,0 +1,4 @@
---
dependencies: {}
compiled: false
lockVersion: 1.0.0

View File

@@ -0,0 +1,2 @@
---
lastReleaseVersion: 1.0.1

View 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

View 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.

View File

@@ -0,0 +1 @@
## 1.0.0

View File

@@ -0,0 +1 @@
## 1.0.0

View File

@@ -0,0 +1,2 @@
---
lastReleaseVersion: 1.0.1

View File

@@ -0,0 +1,4 @@
---
dependencies: {}
compiled: false
lockVersion: 1.0.0

View 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

View File

@@ -0,0 +1 @@
ModifiedFnvFunctionDetection.ql

View File

@@ -0,0 +1 @@
NumberOfKnownCommandsAboveThreshold.ql

View File

@@ -0,0 +1 @@
NumberOfKnownHashesAboveThreshold.ql

View File

@@ -0,0 +1 @@
NumberOfKnownLiteralsAboveThreshold.ql

View File

@@ -0,0 +1 @@
NumberOfKnownMethodNamesAboveThreshold.ql

View File

@@ -0,0 +1 @@
SwallowEverythingExceptionHandler.ql

View File

@@ -0,0 +1,4 @@
---
dependencies: {}
compiled: false
lockVersion: 1.0.0

View 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: .

View 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())
}

View 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()
}

View File

@@ -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()
)
}

View File

@@ -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()) }

View File

@@ -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), _)
)
}
}

View File

@@ -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()
}

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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), _)
)
}
}

View File

@@ -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."
)
}
}

View File

@@ -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 }
}

View File

@@ -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
)
}
}

View File

@@ -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), _)
)
}
}

View File

@@ -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), _)
)
}
}

View File

@@ -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`.

View File

@@ -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",
]
}
}

View File

@@ -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") }

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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()) }

View File

@@ -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/%")
}
}

View File

@@ -1 +0,0 @@
experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql

View File

@@ -1 +0,0 @@
experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql

View File

@@ -1 +0,0 @@
experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql

View File

@@ -1 +0,0 @@
experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql

View File

@@ -1 +0,0 @@
experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql

View File

@@ -1 +0,0 @@
experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.ql

View File

@@ -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 |

View File

@@ -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}";
}

View File

@@ -0,0 +1,8 @@
namespace MyFileScopedNamespace;
public class MyFileScopedNamespaceClass
{
private readonly object myField = new object();
public object MyProp { get; set; }
public void MyMethod() { }
}

View File

@@ -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 " |

View File

@@ -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
}

View File

@@ -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 |

View 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