Compare commits

..

8 Commits

Author SHA1 Message Date
Michael B. Gale
4feb56bc8d Use named return parameters 2023-10-06 11:44:55 +01:00
Michael B. Gale
6729718d23 Allow version suffixes
We allow them, but don't do anything with them yet.
2023-10-06 11:44:54 +01:00
Michael B. Gale
fbbbac017e Fix toolchain regex 2023-10-06 11:44:54 +01:00
Michael B. Gale
19104ff45b Go: Update newer-go-version-needed test
- Use a version that is accepted by Go tooling
- Run is no longer successful with Go 1.21
2023-10-06 11:44:54 +01:00
Michael B. Gale
ed1b1a29de Do not call EmitNewerGoVersionNeeded for v1.21+ 2023-10-06 11:44:54 +01:00
Michael B. Gale
88d5d4cee3 Go: Run go version with GOTOOLCHAIN=local 2023-10-06 11:44:54 +01:00
Michael B. Gale
0ffbd232b5 Go: Find toolchain version in go.mod files 2023-10-06 11:44:51 +01:00
Michael B. Gale
98edaf8ae1 Go: Add GoVersionInfo type
Refactors `tryReadGoDirective` to return this instead of a pair.
This will make it easier to return multiple versions.
2023-10-06 11:44:13 +01:00
954 changed files with 9387 additions and 44350 deletions

View File

@@ -17,17 +17,3 @@ updates:
ignore:
- dependency-name: '*'
update-types: ['version-update:semver-patch', 'version-update:semver-minor']
- package-ecosystem: "gomod"
directory: "go/extractor"
schedule:
interval: "daily"
allow:
- dependency-name: "golang.org/x/mod"
- dependency-name: "golang.org/x/tools"
group:
extractor-dependencies:
patterns:
- "golang.org/x/*"
reviewers:
- "github/codeql-go"

View File

@@ -29,9 +29,9 @@ jobs:
# run with --check-only if running in a PR (github.sha != main)
if : ${{ github.event_name == 'pull_request' }}
shell: bash
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
- name: compile queries - full
# do full compile if running on main - this populates the cache
if : ${{ github.event_name != 'pull_request' }}
shell: bash
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"

View File

@@ -91,7 +91,7 @@ jobs:
run: |
# Generate (Asp)NetCore stubs
STUBS_PATH=stubs_output
python3 ql/src/Stubs/make_stubs_nuget.py webapp Swashbuckle.AspNetCore.Swagger 6.5.0 "$STUBS_PATH"
python3 ql/src/Stubs/make_stubs_nuget.py webapp Swashbuckle.AspNetCore.Swagger latest "$STUBS_PATH"
rm -rf ql/test/resources/stubs/_frameworks
# Update existing stubs in the repo with the freshly generated ones
mv "$STUBS_PATH/output/stubs/_frameworks" ql/test/resources/stubs/

View File

@@ -498,6 +498,22 @@
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsExtensions.qll",
"python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsExtensions.qll"
],
"TaintedFormatStringQuery Ruby/JS": [
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringQuery.qll",
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringQuery.qll"
],
"TaintedFormatStringCustomizations Ruby/JS": [
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringCustomizations.qll",
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringCustomizations.qll"
],
"HttpToFileAccessQuery JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessQuery.qll",
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessQuery.qll"
],
"HttpToFileAccessCustomizations JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
],
"Typo database": [
"javascript/ql/src/Expressions/TypoDatabase.qll",
"ql/ql/src/codeql_ql/style/TypoDatabase.qll"

View File

@@ -1,20 +1,3 @@
## 0.10.1
### Minor Analysis Improvements
* Deleted the deprecated `AnalysedString` class, use the new name `AnalyzedString`.
* Deleted the deprecated `isBarrierGuard` predicate from the dataflow library and its uses, use `isBarrier` and the `BarrierGuard` module instead.
## 0.10.0
### Minor Analysis Improvements
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
non-returning in the IR and dataflow.
* Treat functions that reach the end of the function as returning in the IR.
They used to be treated as unreachable but it is allowed in C.
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.
## 0.9.3
No user-facing changes.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Treat functions that reach the end of the function as returning in the IR.
They used to be treated as unreachable but it is allowed in C.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
non-returning in the IR and dataflow.

View File

@@ -1,9 +0,0 @@
## 0.10.0
### Minor Analysis Improvements
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
non-returning in the IR and dataflow.
* Treat functions that reach the end of the function as returning in the IR.
They used to be treated as unreachable but it is allowed in C.
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.

View File

@@ -1,6 +0,0 @@
## 0.10.1
### Minor Analysis Improvements
* Deleted the deprecated `AnalysedString` class, use the new name `AnalyzedString`.
* Deleted the deprecated `isBarrierGuard` predicate from the dataflow library and its uses, use `isBarrier` and the `BarrierGuard` module instead.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.10.1
lastReleaseVersion: 0.9.3

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.10.1
version: 0.10.0-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -158,7 +158,9 @@ class NameQualifyingElement extends Element, @namequalifyingelement {
/**
* A special name-qualifying element. For example: `__super`.
*/
class SpecialNameQualifyingElement extends NameQualifyingElement, @specialnamequalifyingelement {
library class SpecialNameQualifyingElement extends NameQualifyingElement,
@specialnamequalifyingelement
{
/** Gets the name of this special qualifying element. */
override string getName() { specialnamequalifyingelements(underlyingElement(this), result) }

View File

@@ -73,10 +73,6 @@ private int isSource(Expr bufferExpr, Element why) {
)
}
/** Same as `getBufferSize`, but with the `why` column projected away to prevent large duplications. */
pragma[nomagic]
int getBufferSizeProj(Expr bufferExpr) { result = getBufferSize(bufferExpr, _) }
/**
* Get the size in bytes of the buffer pointed to by an expression (if this can be determined).
*/
@@ -91,7 +87,7 @@ int getBufferSize(Expr bufferExpr, Element why) {
why = bufferVar and
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
result = getBufferSizeProj(parentPtr) + bufferSize - parentClass.getSize()
result = getBufferSize(parentPtr, _) + bufferSize - parentClass.getSize()
|
if exists(bufferVar.getType().getSize())
then bufferSize = bufferVar.getType().getSize()
@@ -99,6 +95,7 @@ int getBufferSize(Expr bufferExpr, Element why) {
)
or
// dataflow (all sources must be the same size)
result = unique(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | getBufferSizeProj(def)) and
result = unique(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | getBufferSize(def, _)) and
// find reason
exists(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | exists(getBufferSize(def, why)))
}

View File

@@ -27,6 +27,9 @@ predicate canValueFlow(Expr fromExpr, Expr toExpr) {
fromExpr = toExpr.(ConditionalExpr).getElse()
}
/** DEPRECATED: Alias for AnalyzedString */
deprecated class AnalysedString = AnalyzedString;
/**
* An analyzed null terminated string.
*/

View File

@@ -78,7 +78,7 @@ predicate parameterUsePair(Parameter p, VariableAccess va) {
/**
* Utility class: A definition or use of a stack variable.
*/
class DefOrUse extends ControlFlowNodeBase {
library class DefOrUse extends ControlFlowNodeBase {
DefOrUse() {
// Uninstantiated templates are purely syntax, and only on instantiation
// will they be complete with information about types, conversions, call
@@ -140,7 +140,7 @@ class DefOrUse extends ControlFlowNodeBase {
}
/** A definition of a stack variable. */
class Def extends DefOrUse {
library class Def extends DefOrUse {
Def() { definition(_, this) }
override SemanticStackVariable getVariable(boolean isDef) {
@@ -155,7 +155,7 @@ private predicate parameterIsOverwritten(Function f, Parameter p) {
}
/** A definition of a parameter. */
class ParameterDef extends DefOrUse {
library class ParameterDef extends DefOrUse {
ParameterDef() {
// Optimization: parameters that are not overwritten do not require
// reachability analysis
@@ -169,7 +169,7 @@ class ParameterDef extends DefOrUse {
}
/** A use of a stack variable. */
class Use extends DefOrUse {
library class Use extends DefOrUse {
Use() { useOfVar(_, this) }
override SemanticStackVariable getVariable(boolean isDef) {

View File

@@ -10,7 +10,7 @@ import SSAUtils
* The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA.
* This class provides the standard SSA logic.
*/
class StandardSsa extends SsaHelper {
library class StandardSsa extends SsaHelper {
StandardSsa() { this = 0 }
}

View File

@@ -114,7 +114,7 @@ private predicate live_at_exit_of_bb(StackVariable v, BasicBlock b) {
/** Common SSA logic for standard SSA and range-analysis SSA. */
cached
class SsaHelper extends int {
library class SsaHelper extends int {
/* 0 = StandardSSA, 1 = RangeSSA */
cached
SsaHelper() { this in [0 .. 1] }

View File

@@ -366,12 +366,12 @@ class CompileTimeConstantInt extends Expr {
int getIntValue() { result = val }
}
class CompileTimeVariableExpr extends Expr {
library class CompileTimeVariableExpr extends Expr {
CompileTimeVariableExpr() { not this instanceof CompileTimeConstantInt }
}
/** A helper class for evaluation of expressions. */
class ExprEvaluator extends int {
library class ExprEvaluator extends int {
/*
* 0 = ConditionEvaluator,
* 1 = SwitchEvaluator,
@@ -956,7 +956,7 @@ private predicate returnStmt(Function f, Expr value) {
}
/** A helper class for evaluation of conditions. */
class ConditionEvaluator extends ExprEvaluator {
library class ConditionEvaluator extends ExprEvaluator {
ConditionEvaluator() { this = 0 }
override predicate interesting(Expr e) {
@@ -967,7 +967,7 @@ class ConditionEvaluator extends ExprEvaluator {
}
/** A helper class for evaluation of switch expressions. */
class SwitchEvaluator extends ExprEvaluator {
library class SwitchEvaluator extends ExprEvaluator {
SwitchEvaluator() { this = 1 }
override predicate interesting(Expr e) { e = getASwitchExpr(_, _) }
@@ -976,7 +976,7 @@ class SwitchEvaluator extends ExprEvaluator {
private int getSwitchValue(Expr e) { exists(SwitchEvaluator x | result = x.getValue(e)) }
/** A helper class for evaluation of loop entry conditions. */
class LoopEntryConditionEvaluator extends ExprEvaluator {
library class LoopEntryConditionEvaluator extends ExprEvaluator {
LoopEntryConditionEvaluator() { this in [2 .. 3] }
abstract override predicate interesting(Expr e);
@@ -1149,7 +1149,7 @@ class LoopEntryConditionEvaluator extends ExprEvaluator {
}
/** A helper class for evaluation of while-loop entry conditions. */
class WhileLoopEntryConditionEvaluator extends LoopEntryConditionEvaluator {
library class WhileLoopEntryConditionEvaluator extends LoopEntryConditionEvaluator {
WhileLoopEntryConditionEvaluator() { this = 2 }
override predicate interesting(Expr e) { exists(WhileStmt while | e = while.getCondition()) }
@@ -1162,7 +1162,7 @@ class WhileLoopEntryConditionEvaluator extends LoopEntryConditionEvaluator {
}
/** A helper class for evaluation of for-loop entry conditions. */
class ForLoopEntryConditionEvaluator extends LoopEntryConditionEvaluator {
library class ForLoopEntryConditionEvaluator extends LoopEntryConditionEvaluator {
ForLoopEntryConditionEvaluator() { this = 3 }
override predicate interesting(Expr e) { exists(ForStmt for | e = for.getCondition()) }

View File

@@ -91,6 +91,21 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
@@ -210,6 +225,29 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
@@ -250,7 +288,9 @@ private module Config implements FullStateConfigSig {
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node)
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }

View File

@@ -91,6 +91,21 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
@@ -210,6 +225,29 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
@@ -250,7 +288,9 @@ private module Config implements FullStateConfigSig {
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node)
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }

View File

@@ -91,6 +91,21 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
@@ -210,6 +225,29 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
@@ -250,7 +288,9 @@ private module Config implements FullStateConfigSig {
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node)
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }

View File

@@ -91,6 +91,21 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
@@ -210,6 +225,29 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
@@ -250,7 +288,9 @@ private module Config implements FullStateConfigSig {
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node)
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }

View File

@@ -91,6 +91,21 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
@@ -210,6 +225,29 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
@@ -250,7 +288,9 @@ private module Config implements FullStateConfigSig {
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node)
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }

View File

@@ -874,3 +874,28 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
)
}
}
/**
* DEPRECATED: Use `BarrierGuard` module instead.
*
* A guard that validates some expression.
*
* To use this in a configuration, extend the class and provide a
* characteristic predicate precisely specifying the guard, and override
* `checks` to specify what is being validated and in which branch.
*
* It is important that all extending classes in scope are disjoint.
*/
deprecated class BarrierGuard extends GuardCondition {
/** Override this predicate to hold if this guard validates `e` upon evaluating to `b`. */
abstract predicate checks(Expr e, boolean b);
/** Gets a node guarded by this guard. */
final ExprNode getAGuardedNode() {
exists(SsaDefinition def, Variable v, boolean branch |
result.getExpr() = def.getAUse(v) and
this.checks(def.getAUse(v), branch) and
this.controls(result.getExpr().getBasicBlock(), branch)
)
}
}

View File

@@ -116,6 +116,33 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
*/

View File

@@ -116,6 +116,33 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
*/

View File

@@ -91,6 +91,21 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
@@ -210,6 +225,29 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
@@ -250,7 +288,9 @@ private module Config implements FullStateConfigSig {
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node)
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }

View File

@@ -91,6 +91,21 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
@@ -210,6 +225,29 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
@@ -250,7 +288,9 @@ private module Config implements FullStateConfigSig {
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node)
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }

View File

@@ -91,6 +91,21 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
@@ -210,6 +225,29 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
@@ -250,7 +288,9 @@ private module Config implements FullStateConfigSig {
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node)
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }

View File

@@ -91,6 +91,21 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
@@ -210,6 +225,29 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
@@ -250,7 +288,9 @@ private module Config implements FullStateConfigSig {
predicate isBarrier(Node node, FlowState state) {
getConfig(state).isBarrier(node, getState(state)) or
getConfig(state).isBarrier(node)
getConfig(state).isBarrier(node) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
}
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }

View File

@@ -555,7 +555,7 @@ predicate instructionForFullyConvertedCall(Instruction instr, CallInstruction ca
}
/** Holds if `node` represents the output node for `call`. */
predicate simpleOutNode(Node node, CallInstruction call) {
private predicate simpleOutNode(Node node, CallInstruction call) {
operandForFullyConvertedCall(node.asOperand(), call)
or
instructionForFullyConvertedCall(node.asInstruction(), call)

View File

@@ -2237,3 +2237,35 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
)
}
}
/**
* DEPRECATED: Use `BarrierGuard` module instead.
*
* A guard that validates some instruction.
*
* To use this in a configuration, extend the class and provide a
* characteristic predicate precisely specifying the guard, and override
* `checks` to specify what is being validated and in which branch.
*
* It is important that all extending classes in scope are disjoint.
*/
deprecated class BarrierGuard extends IRGuardCondition {
/** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */
predicate checksInstr(Instruction instr, boolean b) { none() }
/** Override this predicate to hold if this guard validates `expr` upon evaluating to `b`. */
predicate checks(Expr e, boolean b) { none() }
/** Gets a node guarded by this guard. */
final Node getAGuardedNode() {
exists(ValueNumber value, boolean edge |
(
this.checksInstr(value.getAnInstruction(), edge)
or
this.checks(value.getAnInstruction().getConvertedResultExpression(), edge)
) and
result.asInstruction() = value.getAnInstruction() and
this.controls(result.asInstruction().getBlock(), edge)
)
}
}

View File

@@ -6,7 +6,6 @@
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow
private import DataFlowUtil
private import DataFlowPrivate
private import SsaInternals as Ssa
/**
@@ -36,7 +35,7 @@ DataFlow::Node callInput(CallInstruction call, FunctionInput input) {
*/
Node callOutput(CallInstruction call, FunctionOutput output) {
// The return value
simpleOutNode(result, call) and
result.asInstruction() = call and
output.isReturnValue()
or
// The side effect of a call on the value pointed to by an argument or qualifier
@@ -83,7 +82,7 @@ Node callOutput(CallInstruction call, FunctionOutput output, int d) {
// If there isn't an indirect out node for the call with indirection `d` then
// we conflate this with the underlying `CallInstruction`.
not exists(getIndirectReturnOutNode(call, d)) and
n = result
n.asInstruction() = result.asInstruction()
or
// The side effect of a call on the value pointed to by an argument or qualifier
exists(Operand operand, int indirectionIndex |

View File

@@ -116,6 +116,33 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
*/

View File

@@ -116,6 +116,33 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
*/

View File

@@ -116,6 +116,33 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
*/

View File

@@ -8,22 +8,6 @@ private import internal.IRBlockImports as Imports
import Imports::EdgeKind
private import Cached
/**
* Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the
* sort keys of the block (derived from its first instruction)
*/
pragma[nomagic]
private predicate blockSortKeys(
IRFunction func, IRBlockBase block, int sortOverride, int sortKey1, int sortKey2
) {
block.getEnclosingIRFunction() = func and
block.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
// Ensure that the block containing `EnterFunction` always comes first.
if block.getFirstInstruction() instanceof EnterFunctionInstruction
then sortOverride = 0
else sortOverride = 1
}
/**
* A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only
* incoming edges at the beginning of the sequence and the only outgoing edges at the end of the
@@ -53,14 +37,17 @@ class IRBlockBase extends TIRBlock {
exists(IRConfiguration::IRConfiguration config |
config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction())
) and
exists(IRFunction func |
this =
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
blockSortKeys(func, funcBlock, sortOverride, sortKey1, sortKey2)
|
funcBlock order by sortOverride, sortKey1, sortKey2
)
)
this =
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
// Ensure that the block containing `EnterFunction` always comes first.
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
then sortOverride = 0
else sortOverride = 1
|
funcBlock order by sortOverride, sortKey1, sortKey2
)
}
/**

View File

@@ -116,14 +116,14 @@ class Instruction extends Construction::TStageInstruction {
private int getLineRank() {
this.shouldGenerateDumpStrings() and
exists(IRFunction enclosing, Language::File file, int line |
this =
rank[result](Instruction instr |
instr = getAnInstructionAtLine(enclosing, file, line)
|
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
)
this =
rank[result](Instruction instr |
instr =
getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(),
this.getLocation().getStartLine())
|
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
}
/**

View File

@@ -8,22 +8,6 @@ private import internal.IRBlockImports as Imports
import Imports::EdgeKind
private import Cached
/**
* Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the
* sort keys of the block (derived from its first instruction)
*/
pragma[nomagic]
private predicate blockSortKeys(
IRFunction func, IRBlockBase block, int sortOverride, int sortKey1, int sortKey2
) {
block.getEnclosingIRFunction() = func and
block.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
// Ensure that the block containing `EnterFunction` always comes first.
if block.getFirstInstruction() instanceof EnterFunctionInstruction
then sortOverride = 0
else sortOverride = 1
}
/**
* A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only
* incoming edges at the beginning of the sequence and the only outgoing edges at the end of the
@@ -53,14 +37,17 @@ class IRBlockBase extends TIRBlock {
exists(IRConfiguration::IRConfiguration config |
config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction())
) and
exists(IRFunction func |
this =
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
blockSortKeys(func, funcBlock, sortOverride, sortKey1, sortKey2)
|
funcBlock order by sortOverride, sortKey1, sortKey2
)
)
this =
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
// Ensure that the block containing `EnterFunction` always comes first.
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
then sortOverride = 0
else sortOverride = 1
|
funcBlock order by sortOverride, sortKey1, sortKey2
)
}
/**

View File

@@ -116,14 +116,14 @@ class Instruction extends Construction::TStageInstruction {
private int getLineRank() {
this.shouldGenerateDumpStrings() and
exists(IRFunction enclosing, Language::File file, int line |
this =
rank[result](Instruction instr |
instr = getAnInstructionAtLine(enclosing, file, line)
|
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
)
this =
rank[result](Instruction instr |
instr =
getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(),
this.getLocation().getStartLine())
|
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
}
/**

View File

@@ -423,12 +423,7 @@ private module CachedForDebugging {
cached
predicate instructionHasSortKeys(Instruction instruction, int key1, int key2) {
key1 = getInstructionTranslatedElement(instruction).getId() and
getInstructionTag(instruction) = tagByRank(key2)
}
pragma[nomagic]
private InstructionTag tagByRank(int key2) {
result =
getInstructionTag(instruction) =
rank[key2](InstructionTag tag, string tagId |
tagId = getInstructionTagId(tag)
|

View File

@@ -8,22 +8,6 @@ private import internal.IRBlockImports as Imports
import Imports::EdgeKind
private import Cached
/**
* Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the
* sort keys of the block (derived from its first instruction)
*/
pragma[nomagic]
private predicate blockSortKeys(
IRFunction func, IRBlockBase block, int sortOverride, int sortKey1, int sortKey2
) {
block.getEnclosingIRFunction() = func and
block.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
// Ensure that the block containing `EnterFunction` always comes first.
if block.getFirstInstruction() instanceof EnterFunctionInstruction
then sortOverride = 0
else sortOverride = 1
}
/**
* A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only
* incoming edges at the beginning of the sequence and the only outgoing edges at the end of the
@@ -53,14 +37,17 @@ class IRBlockBase extends TIRBlock {
exists(IRConfiguration::IRConfiguration config |
config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction())
) and
exists(IRFunction func |
this =
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
blockSortKeys(func, funcBlock, sortOverride, sortKey1, sortKey2)
|
funcBlock order by sortOverride, sortKey1, sortKey2
)
)
this =
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
// Ensure that the block containing `EnterFunction` always comes first.
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
then sortOverride = 0
else sortOverride = 1
|
funcBlock order by sortOverride, sortKey1, sortKey2
)
}
/**

View File

@@ -116,14 +116,14 @@ class Instruction extends Construction::TStageInstruction {
private int getLineRank() {
this.shouldGenerateDumpStrings() and
exists(IRFunction enclosing, Language::File file, int line |
this =
rank[result](Instruction instr |
instr = getAnInstructionAtLine(enclosing, file, line)
|
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
)
this =
rank[result](Instruction instr |
instr =
getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(),
this.getLocation().getStartLine())
|
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
}
/**

View File

@@ -29,7 +29,7 @@ private import RangeAnalysisUtils
* The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA.
* This class provides the range-analysis SSA logic.
*/
class RangeSsa extends SsaHelper {
library class RangeSsa extends SsaHelper {
RangeSsa() { this = 1 }
/**

View File

@@ -60,31 +60,17 @@ private import semmle.code.cpp.rangeanalysis.new.RangeAnalysisUtil
private VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
/**
* Gets a (sub)expression that may be the result of evaluating `size`.
*
* For example, `getASizeCandidate(a ? b : c)` gives `a ? b : c`, `b` and `c`.
*/
bindingset[size]
pragma[inline_late]
private Expr getASizeCandidate(Expr size) {
result = size
or
result = [size.(ConditionalExpr).getThen(), size.(ConditionalExpr).getElse()]
}
/**
* Holds if the `(n, state)` pair represents the source of flow for the size
* expression associated with `alloc`.
*/
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
exists(VariableAccess va, Expr size, int delta, Expr s |
exists(VariableAccess va, Expr size, int delta |
size = alloc.getSizeExpr() and
s = getASizeCandidate(size) and
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
va = unique( | | getAVariableAccess(s)) and
va = unique( | | getAVariableAccess(size)) and
// Compute `delta` as the constant difference between `x` and `x + 1`.
bounded1(any(Instruction instr | instr.getUnconvertedResultExpression() = s),
bounded1(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
n.asExpr() = va and
state = delta

View File

@@ -1,24 +1,3 @@
## 0.8.1
### New Queries
* The query `cpp/redundant-null-check-simple` has been promoted to Code Scanning. The query finds cases where a pointer is compared to null after it has already been dereferenced. Such comparisons likely indicate a bug at the place where the pointer is dereferenced, or where the pointer is compared to null.
Note: This query was incorrectly noted as being promoted to Code Scanning in CodeQL version 2.14.6.
## 0.8.0
### Query Metadata Changes
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
### Minor Analysis Improvements
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
in cases where a non-returning function is called.
* The number of duplicated dataflow paths reported by queries has been significantly reduced.
## 0.7.5
No user-facing changes.

View File

@@ -5,12 +5,10 @@
* it should be moved before the dereference.
* @kind path-problem
* @problem.severity error
* @security-severity 7.5
* @precision high
* @id cpp/redundant-null-check-simple
* @tags reliability
* correctness
* security
* external/cwe/cwe-476
*/

View File

@@ -161,7 +161,7 @@ private predicate annotatesAtPosition(SalPosition pos, DeclarationEntry d, File
* A SAL element, that is, a SAL annotation or a declaration entry
* that may have SAL annotations.
*/
class SalElement extends Element {
library class SalElement extends Element {
SalElement() {
containsSalAnnotation(this.(DeclarationEntry).getFile()) or
this instanceof SalAnnotation

View File

@@ -13,13 +13,15 @@
import cpp
import semmle.code.cpp.commons.Environment
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.IR
import Flow::PathGraph
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
import TaintedWithPath
/** A call that prints its arguments to `stdout`. */
class PrintStdoutCall extends FunctionCall {
PrintStdoutCall() { this.getTarget().hasGlobalOrStdName(["puts", "printf"]) }
PrintStdoutCall() {
this.getTarget().hasGlobalOrStdName("puts") or
this.getTarget().hasGlobalOrStdName("printf")
}
}
/** A read of the QUERY_STRING environment variable */
@@ -27,25 +29,19 @@ class QueryString extends EnvironmentRead {
QueryString() { this.getEnvironmentVariable() = "QUERY_STRING" }
}
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asIndirectExpr() instanceof QueryString }
class Configuration extends TaintTrackingConfiguration {
override predicate isSource(Expr source) { source instanceof QueryString }
predicate isSink(DataFlow::Node node) {
exists(PrintStdoutCall call | call.getAnArgument() = [node.asIndirectExpr(), node.asExpr()])
override predicate isSink(Element tainted) {
exists(PrintStdoutCall call | call.getAnArgument() = tainted)
}
predicate isBarrier(DataFlow::Node node) {
isSink(node) and node.asExpr().getUnspecifiedType() instanceof ArithmeticType
or
node.asInstruction().(StoreInstruction).getResultType() instanceof ArithmeticType
override predicate isBarrier(Expr e) {
super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType
}
}
module Flow = TaintTracking::Global<Config>;
from QueryString query, Flow::PathNode sourceNode, Flow::PathNode sinkNode
where
Flow::flowPath(sourceNode, sinkNode) and
query = sourceNode.getNode().asIndirectExpr()
select sinkNode.getNode(), sourceNode, sinkNode, "Cross-site scripting vulnerability due to $@.",
query, "this query data"
from QueryString query, Element printedArg, PathNode sourceNode, PathNode sinkNode
where taintedWithPath(query, printedArg, sourceNode, sinkNode)
select printedArg, sourceNode, sinkNode, "Cross-site scripting vulnerability due to $@.", query,
"this query data"

View File

@@ -82,20 +82,36 @@ module ValidState {
* library will perform, and visit all the places where the size argument is modified.
* 2. Once that dataflow traversal is done, we accumulate the offsets added at each places
* where the offset is modified (see `validStateImpl`).
*
* Because we want to guarantee that each place where we modify the offset has a `PathNode`
* we "flip" a boolean flow state in each `isAdditionalFlowStep`. This ensures that the node
* has a corresponding `PathNode`.
*/
private module ValidStateConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { hasSize(_, source, _) }
private module ValidStateConfig implements DataFlow::StateConfigSig {
class FlowState = boolean;
predicate isSink(DataFlow::Node sink) { isSinkPairImpl(_, _, sink, _, _) }
predicate isSource(DataFlow::Node source, FlowState state) {
hasSize(_, source, _) and
state = false
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
isAdditionalFlowStep2(node1, node2, _)
predicate isSink(DataFlow::Node sink, FlowState state) {
isSinkPairImpl(_, _, sink, _, _) and
state = [false, true]
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
isAdditionalFlowStep2(node1, node2, _) and
state1 = [false, true] and
state2 = state1.booleanNot()
}
predicate includeHiddenNodes() { any() }
}
private import DataFlow::Global<ValidStateConfig>
private import DataFlow::GlobalWithState<ValidStateConfig>
private predicate inLoop(PathNode n) { n.getASuccessor+() = n }

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The number of duplicated dataflow paths reported by queries has been significantly reduced.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
in cases where a non-returning function is called.

View File

@@ -0,0 +1,4 @@
---
category: queryMetadata
---
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.

View File

@@ -0,0 +1,4 @@
---
category: queryMetadata
---
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.

View File

@@ -1,12 +0,0 @@
## 0.8.0
### Query Metadata Changes
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
### Minor Analysis Improvements
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
in cases where a non-returning function is called.
* The number of duplicated dataflow paths reported by queries has been significantly reduced.

View File

@@ -1,7 +0,0 @@
## 0.8.1
### New Queries
* The query `cpp/redundant-null-check-simple` has been promoted to Code Scanning. The query finds cases where a pointer is compared to null after it has already been dereferenced. Such comparisons likely indicate a bug at the place where the pointer is dereferenced, or where the pointer is compared to null.
Note: This query was incorrectly noted as being promoted to Code Scanning in CodeQL version 2.14.6.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.8.1
lastReleaseVersion: 0.7.5

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.8.1
version: 0.8.0-dev
groups:
- cpp
- queries

View File

@@ -1,3 +1,3 @@
failures
astTypeBugs
irTypeBugs
failures

View File

@@ -16,18 +16,18 @@ edges
| test.cpp:91:9:91:16 | fread output argument | test.cpp:93:17:93:24 | filename indirection |
| test.cpp:93:11:93:14 | strncat output argument | test.cpp:94:45:94:48 | path indirection |
| test.cpp:93:17:93:24 | filename indirection | test.cpp:93:11:93:14 | strncat output argument |
| test.cpp:106:20:106:38 | call to getenv | test.cpp:107:33:107:36 | path indirection |
| test.cpp:106:20:106:25 | call to getenv | test.cpp:107:33:107:36 | path indirection |
| test.cpp:106:20:106:38 | call to getenv indirection | test.cpp:107:33:107:36 | path indirection |
| test.cpp:107:31:107:31 | call to operator+ | test.cpp:108:18:108:22 | call to c_str indirection |
| test.cpp:107:33:107:36 | path indirection | test.cpp:107:31:107:31 | call to operator+ |
| test.cpp:113:20:113:38 | call to getenv | test.cpp:114:19:114:22 | path indirection |
| test.cpp:113:20:113:25 | call to getenv | test.cpp:114:19:114:22 | path indirection |
| test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:19:114:22 | path indirection |
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
| test.cpp:114:17:114:17 | call to operator+ | test.cpp:114:10:114:23 | call to operator+ |
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:10:114:23 | call to operator+ |
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | call to operator+ |
| test.cpp:119:20:119:38 | call to getenv | test.cpp:120:19:120:22 | path indirection |
| test.cpp:119:20:119:25 | call to getenv | test.cpp:120:19:120:22 | path indirection |
| test.cpp:119:20:119:38 | call to getenv indirection | test.cpp:120:19:120:22 | path indirection |
| test.cpp:120:17:120:17 | call to operator+ | test.cpp:120:10:120:30 | call to data indirection |
| test.cpp:120:19:120:22 | path indirection | test.cpp:120:17:120:17 | call to operator+ |
@@ -91,12 +91,12 @@ nodes
| test.cpp:93:11:93:14 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:93:17:93:24 | filename indirection | semmle.label | filename indirection |
| test.cpp:94:45:94:48 | path indirection | semmle.label | path indirection |
| test.cpp:106:20:106:38 | call to getenv | semmle.label | call to getenv |
| test.cpp:106:20:106:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:106:20:106:38 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:107:31:107:31 | call to operator+ | semmle.label | call to operator+ |
| test.cpp:107:33:107:36 | path indirection | semmle.label | path indirection |
| test.cpp:108:18:108:22 | call to c_str indirection | semmle.label | call to c_str indirection |
| test.cpp:113:20:113:38 | call to getenv | semmle.label | call to getenv |
| test.cpp:113:20:113:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:113:20:113:38 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:114:10:114:23 | call to operator+ | semmle.label | call to operator+ |
| test.cpp:114:10:114:23 | call to operator+ | semmle.label | call to operator+ |
@@ -104,7 +104,7 @@ nodes
| test.cpp:114:19:114:22 | path indirection | semmle.label | path indirection |
| test.cpp:114:25:114:29 | call to c_str indirection | semmle.label | call to c_str indirection |
| test.cpp:114:25:114:29 | call to c_str indirection | semmle.label | call to c_str indirection |
| test.cpp:119:20:119:38 | call to getenv | semmle.label | call to getenv |
| test.cpp:119:20:119:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:119:20:119:38 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:120:10:120:30 | call to data indirection | semmle.label | call to data indirection |
| test.cpp:120:17:120:17 | call to operator+ | semmle.label | call to operator+ |
@@ -158,13 +158,13 @@ subpaths
| test.cpp:65:10:65:16 | command | test.cpp:62:9:62:16 | fread output argument | test.cpp:65:10:65:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:62:9:62:16 | fread output argument | user input (string read by fread) | test.cpp:64:11:64:17 | strncat output argument | strncat output argument |
| test.cpp:85:32:85:38 | command | test.cpp:82:9:82:16 | fread output argument | test.cpp:85:32:85:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:82:9:82:16 | fread output argument | user input (string read by fread) | test.cpp:84:11:84:17 | strncat output argument | strncat output argument |
| test.cpp:94:45:94:48 | path | test.cpp:91:9:91:16 | fread output argument | test.cpp:94:45:94:48 | path indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:91:9:91:16 | fread output argument | user input (string read by fread) | test.cpp:93:11:93:14 | strncat output argument | strncat output argument |
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:38 | call to getenv | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:106:20:106:38 | call to getenv | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:25 | call to getenv | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:106:20:106:25 | call to getenv | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:38 | call to getenv indirection | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:106:20:106:38 | call to getenv indirection | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | call to operator+ | call to operator+ |
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:25 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:25 | call to getenv | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:25 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:25 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | call to operator+ | call to operator+ |
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv indirection | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv indirection | user input (an environment variable) | test.cpp:114:17:114:17 | call to operator+ | call to operator+ |
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:38 | call to getenv | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:119:20:119:38 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:25 | call to getenv | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:119:20:119:25 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:38 | call to getenv indirection | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:119:20:119:38 | call to getenv indirection | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
| test.cpp:143:10:143:16 | command | test.cpp:140:9:140:11 | fread output argument | test.cpp:143:10:143:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:140:9:140:11 | fread output argument | user input (string read by fread) | test.cpp:142:11:142:17 | sprintf output argument | sprintf output argument |
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:174:9:174:16 | fread output argument | user input (string read by fread) | test.cpp:177:13:177:17 | strncat output argument | strncat output argument |

View File

@@ -1,26 +1,26 @@
edges
| search.c:14:24:14:28 | query indirection | search.c:17:8:17:12 | query indirection |
| search.c:22:24:22:28 | query indirection | search.c:23:39:23:43 | query indirection |
| search.c:55:24:55:28 | query indirection | search.c:62:8:62:17 | query_text indirection |
| search.c:67:21:67:26 | call to getenv indirection | search.c:71:17:71:25 | raw_query indirection |
| search.c:67:21:67:26 | call to getenv indirection | search.c:73:17:73:25 | raw_query indirection |
| search.c:67:21:67:26 | call to getenv indirection | search.c:77:17:77:25 | raw_query indirection |
| search.c:71:17:71:25 | raw_query indirection | search.c:14:24:14:28 | query indirection |
| search.c:73:17:73:25 | raw_query indirection | search.c:22:24:22:28 | query indirection |
| search.c:77:17:77:25 | raw_query indirection | search.c:55:24:55:28 | query indirection |
nodes
| search.c:14:24:14:28 | query indirection | semmle.label | query indirection |
| search.c:17:8:17:12 | query indirection | semmle.label | query indirection |
| search.c:22:24:22:28 | query indirection | semmle.label | query indirection |
| search.c:23:39:23:43 | query indirection | semmle.label | query indirection |
| search.c:55:24:55:28 | query indirection | semmle.label | query indirection |
| search.c:62:8:62:17 | query_text indirection | semmle.label | query_text indirection |
| search.c:67:21:67:26 | call to getenv indirection | semmle.label | call to getenv indirection |
| search.c:71:17:71:25 | raw_query indirection | semmle.label | raw_query indirection |
| search.c:73:17:73:25 | raw_query indirection | semmle.label | raw_query indirection |
| search.c:77:17:77:25 | raw_query indirection | semmle.label | raw_query indirection |
| search.c:14:24:14:28 | query | search.c:17:8:17:12 | query |
| search.c:14:24:14:28 | query | search.c:17:8:17:12 | query |
| search.c:22:24:22:28 | query | search.c:23:39:23:43 | query |
| search.c:22:24:22:28 | query | search.c:23:39:23:43 | query |
| search.c:51:21:51:26 | call to getenv | search.c:55:17:55:25 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:55:17:55:25 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:57:17:57:25 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:57:17:57:25 | raw_query |
| search.c:55:17:55:25 | raw_query | search.c:14:24:14:28 | query |
| search.c:57:17:57:25 | raw_query | search.c:22:24:22:28 | query |
subpaths
nodes
| search.c:14:24:14:28 | query | semmle.label | query |
| search.c:17:8:17:12 | query | semmle.label | query |
| search.c:17:8:17:12 | query | semmle.label | query |
| search.c:22:24:22:28 | query | semmle.label | query |
| search.c:23:39:23:43 | query | semmle.label | query |
| search.c:23:39:23:43 | query | semmle.label | query |
| search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv |
| search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv |
| search.c:55:17:55:25 | raw_query | semmle.label | raw_query |
| search.c:57:17:57:25 | raw_query | semmle.label | raw_query |
#select
| search.c:17:8:17:12 | query indirection | search.c:67:21:67:26 | call to getenv indirection | search.c:17:8:17:12 | query indirection | Cross-site scripting vulnerability due to $@. | search.c:67:21:67:26 | call to getenv | this query data |
| search.c:23:39:23:43 | query indirection | search.c:67:21:67:26 | call to getenv indirection | search.c:23:39:23:43 | query indirection | Cross-site scripting vulnerability due to $@. | search.c:67:21:67:26 | call to getenv | this query data |
| search.c:62:8:62:17 | query_text indirection | search.c:67:21:67:26 | call to getenv indirection | search.c:62:8:62:17 | query_text indirection | Cross-site scripting vulnerability due to $@. | search.c:67:21:67:26 | call to getenv | this query data |
| search.c:17:8:17:12 | query | search.c:51:21:51:26 | call to getenv | search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:51:21:51:26 | call to getenv | this query data |
| search.c:23:39:23:43 | query | search.c:51:21:51:26 | call to getenv | search.c:23:39:23:43 | query | Cross-site scripting vulnerability due to $@. | search.c:51:21:51:26 | call to getenv | this query data |

View File

@@ -47,22 +47,6 @@ void good_server2(char* query) {
printf("\n<p>%i</p>\n", i);
}
typedef unsigned long size_t;
size_t strlen(const char *s);
char *strcpy(char *dst, const char *src);
char *strcat(char *s1, const char *s2);
void bad_server3(char* query) {
char query_text[strlen(query) + 8];
strcpy(query_text, "query: ");
strcat(query_text, query);
puts("<p>Query results for ");
// BAD: Printing out an HTTP parameter with no escaping
puts(query_text);
puts("\n<p>\n");
}
int main(int argc, char** argv) {
char* raw_query = getenv("QUERY_STRING");
if (strcmp("good1", argv[0]) == 0) {
@@ -73,7 +57,5 @@ int main(int argc, char** argv) {
bad_server2(raw_query);
} else if (strcmp("good2", argv[0]) == 0) {
good_server2(raw_query);
} else if (strcmp("bad3", argv[0]) == 0) {
bad_server3(raw_query);
}
}

View File

@@ -5,33 +5,33 @@ edges
| test.cpp:39:27:39:30 | argv indirection | test.cpp:49:32:49:35 | size |
| test.cpp:39:27:39:30 | argv indirection | test.cpp:50:17:50:30 | size |
| test.cpp:39:27:39:30 | argv indirection | test.cpp:53:35:53:60 | ... * ... |
| test.cpp:124:18:124:31 | call to getenv | test.cpp:128:24:128:41 | ... * ... |
| test.cpp:124:18:124:23 | call to getenv | test.cpp:128:24:128:41 | ... * ... |
| test.cpp:124:18:124:31 | call to getenv indirection | test.cpp:128:24:128:41 | ... * ... |
| test.cpp:133:19:133:32 | call to getenv | test.cpp:135:10:135:27 | ... * ... |
| test.cpp:133:19:133:24 | call to getenv | test.cpp:135:10:135:27 | ... * ... |
| test.cpp:133:19:133:32 | call to getenv indirection | test.cpp:135:10:135:27 | ... * ... |
| test.cpp:148:20:148:33 | call to getenv | test.cpp:152:11:152:28 | ... * ... |
| test.cpp:148:20:148:25 | call to getenv | test.cpp:152:11:152:28 | ... * ... |
| test.cpp:148:20:148:33 | call to getenv indirection | test.cpp:152:11:152:28 | ... * ... |
| test.cpp:209:8:209:23 | get_tainted_size indirection | test.cpp:241:9:241:24 | call to get_tainted_size |
| test.cpp:211:14:211:27 | call to getenv | test.cpp:209:8:209:23 | get_tainted_size indirection |
| test.cpp:211:14:211:19 | call to getenv | test.cpp:209:8:209:23 | get_tainted_size indirection |
| test.cpp:211:14:211:27 | call to getenv indirection | test.cpp:209:8:209:23 | get_tainted_size indirection |
| test.cpp:230:21:230:21 | s | test.cpp:231:21:231:21 | s |
| test.cpp:237:24:237:37 | call to getenv | test.cpp:239:9:239:18 | local_size |
| test.cpp:237:24:237:37 | call to getenv | test.cpp:245:11:245:20 | local_size |
| test.cpp:237:24:237:37 | call to getenv | test.cpp:247:10:247:19 | local_size |
| test.cpp:237:24:237:29 | call to getenv | test.cpp:239:9:239:18 | local_size |
| test.cpp:237:24:237:29 | call to getenv | test.cpp:245:11:245:20 | local_size |
| test.cpp:237:24:237:29 | call to getenv | test.cpp:247:10:247:19 | local_size |
| test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:239:9:239:18 | local_size |
| test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:245:11:245:20 | local_size |
| test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:247:10:247:19 | local_size |
| test.cpp:247:10:247:19 | local_size | test.cpp:230:21:230:21 | s |
| test.cpp:250:20:250:27 | out_size | test.cpp:289:17:289:20 | get_size output argument |
| test.cpp:250:20:250:27 | out_size | test.cpp:305:18:305:21 | get_size output argument |
| test.cpp:251:18:251:31 | call to getenv | test.cpp:250:20:250:27 | out_size |
| test.cpp:251:18:251:23 | call to getenv | test.cpp:250:20:250:27 | out_size |
| test.cpp:251:18:251:31 | call to getenv indirection | test.cpp:250:20:250:27 | out_size |
| test.cpp:259:20:259:33 | call to getenv | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:259:20:259:25 | call to getenv | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:259:20:259:33 | call to getenv indirection | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:289:17:289:20 | get_size output argument | test.cpp:291:11:291:28 | ... * ... |
| test.cpp:305:18:305:21 | get_size output argument | test.cpp:308:10:308:27 | ... * ... |
| test.cpp:353:18:353:31 | call to getenv | test.cpp:355:35:355:38 | size |
| test.cpp:353:18:353:31 | call to getenv | test.cpp:356:35:356:38 | size |
| test.cpp:353:18:353:23 | call to getenv | test.cpp:355:35:355:38 | size |
| test.cpp:353:18:353:23 | call to getenv | test.cpp:356:35:356:38 | size |
| test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:355:35:355:38 | size |
| test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:356:35:356:38 | size |
nodes
@@ -42,37 +42,37 @@ nodes
| test.cpp:49:32:49:35 | size | semmle.label | size |
| test.cpp:50:17:50:30 | size | semmle.label | size |
| test.cpp:53:35:53:60 | ... * ... | semmle.label | ... * ... |
| test.cpp:124:18:124:31 | call to getenv | semmle.label | call to getenv |
| test.cpp:124:18:124:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:124:18:124:31 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:128:24:128:41 | ... * ... | semmle.label | ... * ... |
| test.cpp:133:19:133:32 | call to getenv | semmle.label | call to getenv |
| test.cpp:133:19:133:24 | call to getenv | semmle.label | call to getenv |
| test.cpp:133:19:133:32 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:135:10:135:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:148:20:148:33 | call to getenv | semmle.label | call to getenv |
| test.cpp:148:20:148:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:148:20:148:33 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:152:11:152:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:209:8:209:23 | get_tainted_size indirection | semmle.label | get_tainted_size indirection |
| test.cpp:211:14:211:27 | call to getenv | semmle.label | call to getenv |
| test.cpp:211:14:211:19 | call to getenv | semmle.label | call to getenv |
| test.cpp:211:14:211:27 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:230:21:230:21 | s | semmle.label | s |
| test.cpp:231:21:231:21 | s | semmle.label | s |
| test.cpp:237:24:237:37 | call to getenv | semmle.label | call to getenv |
| test.cpp:237:24:237:29 | call to getenv | semmle.label | call to getenv |
| test.cpp:237:24:237:37 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:239:9:239:18 | local_size | semmle.label | local_size |
| test.cpp:241:9:241:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
| test.cpp:245:11:245:20 | local_size | semmle.label | local_size |
| test.cpp:247:10:247:19 | local_size | semmle.label | local_size |
| test.cpp:250:20:250:27 | out_size | semmle.label | out_size |
| test.cpp:251:18:251:31 | call to getenv | semmle.label | call to getenv |
| test.cpp:251:18:251:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:251:18:251:31 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:259:20:259:33 | call to getenv | semmle.label | call to getenv |
| test.cpp:259:20:259:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:259:20:259:33 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:263:11:263:29 | ... * ... | semmle.label | ... * ... |
| test.cpp:289:17:289:20 | get_size output argument | semmle.label | get_size output argument |
| test.cpp:291:11:291:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:305:18:305:21 | get_size output argument | semmle.label | get_size output argument |
| test.cpp:308:10:308:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:353:18:353:31 | call to getenv | semmle.label | call to getenv |
| test.cpp:353:18:353:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:353:18:353:31 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:355:35:355:38 | size | semmle.label | size |
| test.cpp:356:35:356:38 | size | semmle.label | size |
@@ -84,27 +84,27 @@ subpaths
| test.cpp:49:25:49:30 | call to malloc | test.cpp:39:27:39:30 | argv indirection | test.cpp:49:32:49:35 | size | This allocation size is derived from $@ and might overflow. | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |
| test.cpp:50:17:50:30 | new[] | test.cpp:39:27:39:30 | argv indirection | test.cpp:50:17:50:30 | size | This allocation size is derived from $@ and might overflow. | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |
| test.cpp:53:21:53:27 | call to realloc | test.cpp:39:27:39:30 | argv indirection | test.cpp:53:35:53:60 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |
| test.cpp:128:17:128:22 | call to malloc | test.cpp:124:18:124:31 | call to getenv | test.cpp:128:24:128:41 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:124:18:124:31 | call to getenv | user input (an environment variable) |
| test.cpp:128:17:128:22 | call to malloc | test.cpp:124:18:124:23 | call to getenv | test.cpp:128:24:128:41 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:124:18:124:23 | call to getenv | user input (an environment variable) |
| test.cpp:128:17:128:22 | call to malloc | test.cpp:124:18:124:31 | call to getenv indirection | test.cpp:128:24:128:41 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:124:18:124:31 | call to getenv indirection | user input (an environment variable) |
| test.cpp:135:3:135:8 | call to malloc | test.cpp:133:19:133:32 | call to getenv | test.cpp:135:10:135:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:133:19:133:32 | call to getenv | user input (an environment variable) |
| test.cpp:135:3:135:8 | call to malloc | test.cpp:133:19:133:24 | call to getenv | test.cpp:135:10:135:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:133:19:133:24 | call to getenv | user input (an environment variable) |
| test.cpp:135:3:135:8 | call to malloc | test.cpp:133:19:133:32 | call to getenv indirection | test.cpp:135:10:135:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:133:19:133:32 | call to getenv indirection | user input (an environment variable) |
| test.cpp:152:4:152:9 | call to malloc | test.cpp:148:20:148:33 | call to getenv | test.cpp:152:11:152:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:148:20:148:33 | call to getenv | user input (an environment variable) |
| test.cpp:152:4:152:9 | call to malloc | test.cpp:148:20:148:25 | call to getenv | test.cpp:152:11:152:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:148:20:148:25 | call to getenv | user input (an environment variable) |
| test.cpp:152:4:152:9 | call to malloc | test.cpp:148:20:148:33 | call to getenv indirection | test.cpp:152:11:152:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:148:20:148:33 | call to getenv indirection | user input (an environment variable) |
| test.cpp:231:14:231:19 | call to malloc | test.cpp:237:24:237:37 | call to getenv | test.cpp:231:21:231:21 | s | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv | user input (an environment variable) |
| test.cpp:231:14:231:19 | call to malloc | test.cpp:237:24:237:29 | call to getenv | test.cpp:231:21:231:21 | s | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:29 | call to getenv | user input (an environment variable) |
| test.cpp:231:14:231:19 | call to malloc | test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:231:21:231:21 | s | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv indirection | user input (an environment variable) |
| test.cpp:239:2:239:7 | call to malloc | test.cpp:237:24:237:37 | call to getenv | test.cpp:239:9:239:18 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv | user input (an environment variable) |
| test.cpp:239:2:239:7 | call to malloc | test.cpp:237:24:237:29 | call to getenv | test.cpp:239:9:239:18 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:29 | call to getenv | user input (an environment variable) |
| test.cpp:239:2:239:7 | call to malloc | test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:239:9:239:18 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv indirection | user input (an environment variable) |
| test.cpp:241:2:241:7 | call to malloc | test.cpp:211:14:211:27 | call to getenv | test.cpp:241:9:241:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow. | test.cpp:211:14:211:27 | call to getenv | user input (an environment variable) |
| test.cpp:241:2:241:7 | call to malloc | test.cpp:211:14:211:19 | call to getenv | test.cpp:241:9:241:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow. | test.cpp:211:14:211:19 | call to getenv | user input (an environment variable) |
| test.cpp:241:2:241:7 | call to malloc | test.cpp:211:14:211:27 | call to getenv indirection | test.cpp:241:9:241:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow. | test.cpp:211:14:211:27 | call to getenv indirection | user input (an environment variable) |
| test.cpp:245:2:245:9 | call to my_alloc | test.cpp:237:24:237:37 | call to getenv | test.cpp:245:11:245:20 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv | user input (an environment variable) |
| test.cpp:245:2:245:9 | call to my_alloc | test.cpp:237:24:237:29 | call to getenv | test.cpp:245:11:245:20 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:29 | call to getenv | user input (an environment variable) |
| test.cpp:245:2:245:9 | call to my_alloc | test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:245:11:245:20 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv indirection | user input (an environment variable) |
| test.cpp:263:4:263:9 | call to malloc | test.cpp:259:20:259:33 | call to getenv | test.cpp:263:11:263:29 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:259:20:259:33 | call to getenv | user input (an environment variable) |
| test.cpp:263:4:263:9 | call to malloc | test.cpp:259:20:259:25 | call to getenv | test.cpp:263:11:263:29 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:259:20:259:25 | call to getenv | user input (an environment variable) |
| test.cpp:263:4:263:9 | call to malloc | test.cpp:259:20:259:33 | call to getenv indirection | test.cpp:263:11:263:29 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:259:20:259:33 | call to getenv indirection | user input (an environment variable) |
| test.cpp:291:4:291:9 | call to malloc | test.cpp:251:18:251:31 | call to getenv | test.cpp:291:11:291:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv | user input (an environment variable) |
| test.cpp:291:4:291:9 | call to malloc | test.cpp:251:18:251:23 | call to getenv | test.cpp:291:11:291:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:23 | call to getenv | user input (an environment variable) |
| test.cpp:291:4:291:9 | call to malloc | test.cpp:251:18:251:31 | call to getenv indirection | test.cpp:291:11:291:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv indirection | user input (an environment variable) |
| test.cpp:308:3:308:8 | call to malloc | test.cpp:251:18:251:31 | call to getenv | test.cpp:308:10:308:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv | user input (an environment variable) |
| test.cpp:308:3:308:8 | call to malloc | test.cpp:251:18:251:23 | call to getenv | test.cpp:308:10:308:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:23 | call to getenv | user input (an environment variable) |
| test.cpp:308:3:308:8 | call to malloc | test.cpp:251:18:251:31 | call to getenv indirection | test.cpp:308:10:308:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv indirection | user input (an environment variable) |
| test.cpp:355:25:355:33 | call to MyMalloc1 | test.cpp:353:18:353:31 | call to getenv | test.cpp:355:35:355:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv | user input (an environment variable) |
| test.cpp:355:25:355:33 | call to MyMalloc1 | test.cpp:353:18:353:23 | call to getenv | test.cpp:355:35:355:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:23 | call to getenv | user input (an environment variable) |
| test.cpp:355:25:355:33 | call to MyMalloc1 | test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:355:35:355:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv indirection | user input (an environment variable) |
| test.cpp:356:25:356:33 | call to MyMalloc2 | test.cpp:353:18:353:31 | call to getenv | test.cpp:356:35:356:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv | user input (an environment variable) |
| test.cpp:356:25:356:33 | call to MyMalloc2 | test.cpp:353:18:353:23 | call to getenv | test.cpp:356:35:356:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:23 | call to getenv | user input (an environment variable) |
| test.cpp:356:25:356:33 | call to MyMalloc2 | test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:356:35:356:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv indirection | user input (an environment variable) |

View File

@@ -181,12 +181,6 @@ edges
| test.cpp:833:37:833:39 | end | test.cpp:815:52:815:54 | end |
| test.cpp:841:18:841:35 | call to malloc | test.cpp:842:3:842:20 | ... = ... |
| test.cpp:848:20:848:37 | call to malloc | test.cpp:849:5:849:22 | ... = ... |
| test.cpp:856:12:856:35 | call to malloc | test.cpp:857:16:857:29 | ... + ... |
| test.cpp:856:12:856:35 | call to malloc | test.cpp:857:16:857:29 | ... + ... |
| test.cpp:856:12:856:35 | call to malloc | test.cpp:860:5:860:11 | ... = ... |
| test.cpp:857:16:857:29 | ... + ... | test.cpp:857:16:857:29 | ... + ... |
| test.cpp:857:16:857:29 | ... + ... | test.cpp:860:5:860:11 | ... = ... |
| test.cpp:857:16:857:29 | ... + ... | test.cpp:860:5:860:11 | ... = ... |
nodes
| test.cpp:4:15:4:33 | call to malloc | semmle.label | call to malloc |
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
@@ -313,10 +307,6 @@ nodes
| test.cpp:842:3:842:20 | ... = ... | semmle.label | ... = ... |
| test.cpp:848:20:848:37 | call to malloc | semmle.label | call to malloc |
| test.cpp:849:5:849:22 | ... = ... | semmle.label | ... = ... |
| test.cpp:856:12:856:35 | call to malloc | semmle.label | call to malloc |
| test.cpp:857:16:857:29 | ... + ... | semmle.label | ... + ... |
| test.cpp:857:16:857:29 | ... + ... | semmle.label | ... + ... |
| test.cpp:860:5:860:11 | ... = ... | semmle.label | ... = ... |
subpaths
#select
| test.cpp:6:14:6:15 | * ... | test.cpp:4:15:4:33 | call to malloc | test.cpp:6:14:6:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:33 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
@@ -354,4 +344,3 @@ subpaths
| test.cpp:821:7:821:12 | ... = ... | test.cpp:793:14:793:32 | call to malloc | test.cpp:821:7:821:12 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:793:14:793:32 | call to malloc | call to malloc | test.cpp:794:21:794:24 | size | size |
| test.cpp:842:3:842:20 | ... = ... | test.cpp:841:18:841:35 | call to malloc | test.cpp:842:3:842:20 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:841:18:841:35 | call to malloc | call to malloc | test.cpp:842:11:842:15 | index | index |
| test.cpp:849:5:849:22 | ... = ... | test.cpp:848:20:848:37 | call to malloc | test.cpp:849:5:849:22 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:848:20:848:37 | call to malloc | call to malloc | test.cpp:849:13:849:17 | index | index |
| test.cpp:860:5:860:11 | ... = ... | test.cpp:856:12:856:35 | call to malloc | test.cpp:860:5:860:11 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:856:12:856:35 | call to malloc | call to malloc | test.cpp:857:21:857:28 | ... + ... | ... + ... |

View File

@@ -848,15 +848,4 @@ void test16_with_malloc(size_t index) {
int* newname = (int*)malloc(size);
newname[index] = 0; // $ SPURIOUS: alloc=L848 deref=L849 // GOOD [FALSE POSITIVE]
}
}
# define MyMalloc(size) malloc(((size) == 0 ? 1 : (size)))
void test_regression(size_t size) {
int* p = (int*)MyMalloc(size + 1);
int* chend = p + (size + 1); // $ alloc=L856+1
if(p <= chend) {
*p = 42; // $ deref=L860 // BAD
}
}

View File

@@ -1,2 +0,0 @@
description: Exclude @void_type from @value_type
compatibility: full

View File

@@ -1,2 +0,0 @@
description: Add keyset to metadata_handle
compatibility: full

View File

@@ -70,8 +70,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
foreach (var info in assemblyInfoByFileName.Values
.OrderBy(info => info.Name)
.ThenBy(info => info.NetCoreVersion ?? emptyVersion)
.ThenBy(info => info.Version ?? emptyVersion)
.ThenBy(info => info.Filename))
.ThenBy(info => info.Version ?? emptyVersion))
{
foreach (var index in info.IndexStrings)
{

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// <summary>
/// The version number of the .NET Core framework that this assembly targets.
///
///
/// This is extracted from the `TargetFrameworkAttribute` of the assembly, e.g.
/// ```
/// [assembly:TargetFramework(".NETCoreApp,Version=v7.0")]
@@ -160,22 +160,11 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
* loading the same assembly from different locations.
*/
using var pereader = new System.Reflection.PortableExecutable.PEReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read));
if (!pereader.HasMetadata)
{
throw new AssemblyLoadException();
}
using var sha1 = SHA1.Create();
var metadata = pereader.GetMetadata();
unsafe
{
var reader = new MetadataReader(metadata.Pointer, metadata.Length);
if (!reader.IsAssembly)
{
throw new AssemblyLoadException();
}
var def = reader.GetAssemblyDefinition();
// This is how you compute the public key token from the full public key.

View File

@@ -47,12 +47,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
this.progressMonitor = new ProgressMonitor(logger);
this.sourceDir = new DirectoryInfo(srcDir);
packageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName));
tempWorkingDirectory = new TemporaryDirectory(FileUtils.GetTemporaryWorkingDirectory(out cleanupTempWorkingDirectory));
try
{
this.dotnet = DotNet.Make(options, progressMonitor, tempWorkingDirectory);
this.dotnet = DotNet.Make(options, progressMonitor);
}
catch
{
@@ -62,6 +59,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
this.progressMonitor.FindingFiles(srcDir);
packageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName));
tempWorkingDirectory = new TemporaryDirectory(FileUtils.GetTemporaryWorkingDirectory(out cleanupTempWorkingDirectory));
var allFiles = GetAllFiles();
var binaryFileExtensions = new HashSet<string>(new[] { ".dll", ".exe" }); // TODO: add more binary file extensions.
@@ -78,6 +77,21 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
? allFiles.SelectFileNamesByExtension(".dll").ToList()
: options.DllDirs.Select(Path.GetFullPath).ToList();
// Find DLLs in the .Net / Asp.Net Framework
if (options.ScanNetFrameworkDlls)
{
var runtime = new Runtime(dotnet);
var runtimeLocation = runtime.GetRuntime(options.UseSelfContainedDotnet);
progressMonitor.LogInfo($".NET runtime location selected: {runtimeLocation}");
dllDirNames.Add(runtimeLocation);
if (fileContent.UseAspNetDlls && runtime.GetAspRuntime() is string aspRuntime)
{
progressMonitor.LogInfo($"ASP.NET runtime location selected: {aspRuntime}");
dllDirNames.Add(aspRuntime);
}
}
if (options.UseNuGet)
{
dllDirNames.Add(packageDirectory.DirInfo.FullName);
@@ -97,26 +111,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
DownloadMissingPackages(allNonBinaryFiles);
}
var existsNetCoreRefNugetPackage = false;
var existsNetFrameworkRefNugetPackage = false;
// Find DLLs in the .Net / Asp.Net Framework
// This block needs to come after the nuget restore, because the nuget restore might fetch the .NET Core/Framework reference assemblies.
if (options.ScanNetFrameworkDlls)
{
existsNetCoreRefNugetPackage = IsNugetPackageAvailable("microsoft.netcore.app.ref");
existsNetFrameworkRefNugetPackage = IsNugetPackageAvailable("microsoft.netframework.referenceassemblies");
if (existsNetCoreRefNugetPackage || existsNetFrameworkRefNugetPackage)
{
progressMonitor.LogInfo("Found .NET Core/Framework DLLs in NuGet packages. Not adding installation directory.");
}
else
{
AddNetFrameworkDlls(dllDirNames);
}
}
assemblyCache = new AssemblyCache(dllDirNames, progressMonitor);
AnalyseSolutions(solutions);
@@ -125,7 +119,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
UseReference(filename);
}
RemoveUnnecessaryNugetPackages(existsNetCoreRefNugetPackage, existsNetFrameworkRefNugetPackage);
RemoveRuntimeNugetPackageReferences();
ResolveConflicts();
// Output the findings
@@ -160,120 +154,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
DateTime.Now - startTime);
}
private void RemoveUnnecessaryNugetPackages(bool existsNetCoreRefNugetPackage, bool existsNetFrameworkRefNugetPackage)
{
RemoveNugetAnalyzerReferences();
RemoveRuntimeNugetPackageReferences();
if (fileContent.IsNewProjectStructureUsed
&& !fileContent.UseAspNetCoreDlls)
{
// This might have been restored by the CLI even though the project isn't an asp.net core one.
RemoveNugetPackageReference("microsoft.aspnetcore.app.ref");
}
if (existsNetCoreRefNugetPackage && existsNetFrameworkRefNugetPackage)
{
// Multiple packages are available, we keep only one:
RemoveNugetPackageReference("microsoft.netframework.referenceassemblies.");
}
// TODO: There could be multiple `microsoft.netframework.referenceassemblies` packages,
// we could keep the newest one, but this is covered by the conflict resolution logic
// (if the file names match)
}
private void RemoveNugetAnalyzerReferences()
{
if (!options.UseNuGet)
{
return;
}
var packageFolder = packageDirectory.DirInfo.FullName.ToLowerInvariant();
if (packageFolder == null)
{
return;
}
foreach (var filename in usedReferences.Keys)
{
var lowerFilename = filename.ToLowerInvariant();
if (lowerFilename.StartsWith(packageFolder))
{
var firstDirectorySeparatorCharIndex = lowerFilename.IndexOf(Path.DirectorySeparatorChar, packageFolder.Length + 1);
if (firstDirectorySeparatorCharIndex == -1)
{
continue;
}
var secondDirectorySeparatorCharIndex = lowerFilename.IndexOf(Path.DirectorySeparatorChar, firstDirectorySeparatorCharIndex + 1);
if (secondDirectorySeparatorCharIndex == -1)
{
continue;
}
var subFolderIndex = secondDirectorySeparatorCharIndex + 1;
var isInAnalyzersFolder = lowerFilename.IndexOf("analyzers", subFolderIndex) == subFolderIndex;
if (isInAnalyzersFolder)
{
usedReferences.Remove(filename);
progressMonitor.RemovedReference(filename);
}
}
}
}
private void AddNetFrameworkDlls(List<string> dllDirNames)
{
var runtime = new Runtime(dotnet);
string? runtimeLocation = null;
if (options.UseSelfContainedDotnet)
{
runtimeLocation = runtime.ExecutingRuntime;
}
else if (fileContent.IsNewProjectStructureUsed)
{
runtimeLocation = runtime.NetCoreRuntime;
}
else if (fileContent.IsLegacyProjectStructureUsed)
{
runtimeLocation = runtime.DesktopRuntime;
}
runtimeLocation ??= runtime.ExecutingRuntime;
progressMonitor.LogInfo($".NET runtime location selected: {runtimeLocation}");
dllDirNames.Add(runtimeLocation);
if (fileContent.IsNewProjectStructureUsed
&& fileContent.UseAspNetCoreDlls
&& runtime.AspNetCoreRuntime is string aspRuntime)
{
progressMonitor.LogInfo($"ASP.NET runtime location selected: {aspRuntime}");
dllDirNames.Add(aspRuntime);
}
}
private void RemoveRuntimeNugetPackageReferences()
{
var runtimePackagePrefixes = new[]
{
"microsoft.netcore.app.runtime",
"microsoft.aspnetcore.app.runtime",
"microsoft.windowsdesktop.app.runtime",
// legacy runtime packages:
"runtime.linux-x64.microsoft.netcore.app",
"runtime.osx-x64.microsoft.netcore.app",
"runtime.win-x64.microsoft.netcore.app",
// Internal implementation packages not meant for direct consumption:
"runtime."
};
RemoveNugetPackageReference(runtimePackagePrefixes);
}
private void RemoveNugetPackageReference(params string[] packagePrefixes)
{
if (!options.UseNuGet)
{
@@ -281,18 +162,23 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
var packageFolder = packageDirectory.DirInfo.FullName.ToLowerInvariant();
if (packageFolder == null)
var runtimePackageNamePrefixes = new[]
{
return;
}
Path.Combine(packageFolder, "microsoft.netcore.app.runtime"),
Path.Combine(packageFolder, "microsoft.aspnetcore.app.runtime"),
Path.Combine(packageFolder, "microsoft.windowsdesktop.app.runtime"),
var packagePathPrefixes = packagePrefixes.Select(p => Path.Combine(packageFolder, p.ToLowerInvariant()));
// legacy runtime packages:
Path.Combine(packageFolder, "runtime.linux-x64.microsoft.netcore.app"),
Path.Combine(packageFolder, "runtime.osx-x64.microsoft.netcore.app"),
Path.Combine(packageFolder, "runtime.win-x64.microsoft.netcore.app"),
};
foreach (var filename in usedReferences.Keys)
{
var lowerFilename = filename.ToLowerInvariant();
if (packagePathPrefixes.Any(prefix => lowerFilename.StartsWith(prefix)))
if (runtimePackageNamePrefixes.Any(prefix => lowerFilename.StartsWith(prefix)))
{
usedReferences.Remove(filename);
progressMonitor.RemovedReference(filename);
@@ -300,18 +186,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
private bool IsNugetPackageAvailable(string packagePrefix)
{
if (!options.UseNuGet)
{
return false;
}
return new DirectoryInfo(packageDirectory.DirInfo.FullName)
.EnumerateDirectories(packagePrefix + "*", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = false })
.Any();
}
private void GenerateSourceFileFromImplicitUsings()
{
var usings = new HashSet<string>();
@@ -324,7 +198,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
usings.UnionWith(new[] { "System", "System.Collections.Generic", "System.IO", "System.Linq", "System.Net.Http", "System.Threading",
"System.Threading.Tasks" });
if (fileContent.UseAspNetCoreDlls)
if (fileContent.UseAspNetDlls)
{
usings.UnionWith(new[] { "System.Net.Http.Json", "Microsoft.AspNetCore.Builder", "Microsoft.AspNetCore.Hosting",
"Microsoft.AspNetCore.Http", "Microsoft.AspNetCore.Routing", "Microsoft.Extensions.Configuration",
@@ -448,11 +322,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
var emptyVersion = new Version(0, 0);
sortedReferences = sortedReferences
.OrderBy(r => r.NetCoreVersion ?? emptyVersion)
.ThenBy(r => r.Version ?? emptyVersion)
.ThenBy(r => r.Filename)
.ToList();
sortedReferences = sortedReferences.OrderBy(r => r.NetCoreVersion ?? emptyVersion).ThenBy(r => r.Version ?? emptyVersion).ToList();
var finalAssemblyList = new Dictionary<string, AssemblyInfo>();
@@ -587,11 +457,11 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
private bool RestoreProject(string project, bool forceDotnetRefAssemblyFetching, string? pathToNugetConfig = null) =>
dotnet.RestoreProjectToDirectory(project, packageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching, pathToNugetConfig);
private bool RestoreProject(string project, string? pathToNugetConfig = null) =>
dotnet.RestoreProjectToDirectory(project, packageDirectory.DirInfo.FullName, pathToNugetConfig);
private bool RestoreSolution(string solution, out IEnumerable<string> projects) =>
dotnet.RestoreSolutionToDirectory(solution, packageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching: true, out projects);
dotnet.RestoreSolutionToDirectory(solution, packageDirectory.DirInfo.FullName, out projects);
/// <summary>
/// Executes `dotnet restore` on all solution files in solutions.
@@ -617,7 +487,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
{
Parallel.ForEach(projects, new ParallelOptions { MaxDegreeOfParallelism = options.Threads }, project =>
{
RestoreProject(project, forceDotnetRefAssemblyFetching: true);
RestoreProject(project);
});
}
@@ -662,7 +532,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
return;
}
success = RestoreProject(tempDir.DirInfo.FullName, forceDotnetRefAssemblyFetching: false, pathToNugetConfig: nugetConfig);
success = RestoreProject(tempDir.DirInfo.FullName, nugetConfig);
// TODO: the restore might fail, we could retry with a prerelease (*-* instead of *) version of the package.
if (!success)
{
@@ -690,25 +560,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
public void Dispose()
{
try
{
packageDirectory?.Dispose();
}
catch (Exception exc)
{
progressMonitor.LogInfo("Couldn't delete package directory: " + exc.Message);
}
packageDirectory?.Dispose();
if (cleanupTempWorkingDirectory)
{
try
{
tempWorkingDirectory?.Dispose();
}
catch (Exception exc)
{
progressMonitor.LogInfo("Couldn't delete temporary working directory: " + exc.Message);
}
}
tempWorkingDirectory?.Dispose();
}
}
}

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Semmle.Util;
namespace Semmle.Extraction.CSharp.DependencyFetching
{
@@ -14,21 +13,19 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
{
private readonly IDotNetCliInvoker dotnetCliInvoker;
private readonly ProgressMonitor progressMonitor;
private readonly TemporaryDirectory? tempWorkingDirectory;
private DotNet(IDotNetCliInvoker dotnetCliInvoker, ProgressMonitor progressMonitor, TemporaryDirectory? tempWorkingDirectory = null)
private DotNet(IDotNetCliInvoker dotnetCliInvoker, ProgressMonitor progressMonitor)
{
this.progressMonitor = progressMonitor;
this.tempWorkingDirectory = tempWorkingDirectory;
this.dotnetCliInvoker = dotnetCliInvoker;
Info();
}
private DotNet(IDependencyOptions options, ProgressMonitor progressMonitor, TemporaryDirectory tempWorkingDirectory) : this(new DotNetCliInvoker(progressMonitor, Path.Combine(options.DotNetPath ?? string.Empty, "dotnet")), progressMonitor, tempWorkingDirectory) { }
private DotNet(IDependencyOptions options, ProgressMonitor progressMonitor) : this(new DotNetCliInvoker(progressMonitor, Path.Combine(options.DotNetPath ?? string.Empty, "dotnet")), progressMonitor) { }
internal static IDotNet Make(IDotNetCliInvoker dotnetCliInvoker, ProgressMonitor progressMonitor) => new DotNet(dotnetCliInvoker, progressMonitor);
public static IDotNet Make(IDependencyOptions options, ProgressMonitor progressMonitor, TemporaryDirectory tempWorkingDirectory) => new DotNet(options, progressMonitor, tempWorkingDirectory);
public static IDotNet Make(IDependencyOptions options, ProgressMonitor progressMonitor) => new DotNet(options, progressMonitor);
private void Info()
{
@@ -40,29 +37,12 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
private string GetRestoreArgs(string projectOrSolutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching)
private static string GetRestoreArgs(string projectOrSolutionFile, string packageDirectory) =>
$"restore --no-dependencies \"{projectOrSolutionFile}\" --packages \"{packageDirectory}\" /p:DisableImplicitNuGetFallbackFolder=true";
public bool RestoreProjectToDirectory(string projectFile, string packageDirectory, string? pathToNugetConfig = null)
{
var args = $"restore --no-dependencies \"{projectOrSolutionFile}\" --packages \"{packageDirectory}\" /p:DisableImplicitNuGetFallbackFolder=true";
if (forceDotnetRefAssemblyFetching)
{
// Ugly hack: we set the TargetFrameworkRootPath and NetCoreTargetingPackRoot properties to an empty folder:
var path = ".empty";
if (tempWorkingDirectory != null)
{
path = Path.Combine(tempWorkingDirectory.ToString(), "emptyFakeDotnetRoot");
Directory.CreateDirectory(path);
}
args += $" /p:TargetFrameworkRootPath=\"{path}\" /p:NetCoreTargetingPackRoot=\"{path}\"";
}
return args;
}
public bool RestoreProjectToDirectory(string projectFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, string? pathToNugetConfig = null)
{
var args = GetRestoreArgs(projectFile, packageDirectory, forceDotnetRefAssemblyFetching);
var args = GetRestoreArgs(projectFile, packageDirectory);
if (pathToNugetConfig != null)
{
args += $" --configfile \"{pathToNugetConfig}\"";
@@ -71,9 +51,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
return dotnetCliInvoker.RunCommand(args);
}
public bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects)
public bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, out IEnumerable<string> projects)
{
var args = GetRestoreArgs(solutionFile, packageDirectory, forceDotnetRefAssemblyFetching);
var args = GetRestoreArgs(solutionFile, packageDirectory);
args += " --verbosity normal";
if (dotnetCliInvoker.RunCommand(args, out var output))
{

View File

@@ -31,21 +31,21 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
private bool useAspNetCoreDlls = false;
private bool useAspNetDlls = false;
/// <summary>
/// True if any file in the source directory indicates that ASP.NET Core is used.
/// The following heuristic is used to decide, if ASP.NET Core is used:
/// True if any file in the source directory indicates that ASP.NET is used.
/// The following heuristic is used to decide, if ASP.NET is used:
/// If any file in the source directory contains something like (this will most like be a .csproj file)
/// <Project Sdk="Microsoft.NET.Sdk.Web">
/// <FrameworkReference Include="Microsoft.AspNetCore.App"/>
/// </summary>
public bool UseAspNetCoreDlls
public bool UseAspNetDlls
{
get
{
initialize.Run();
return useAspNetCoreDlls;
return useAspNetDlls;
}
}
@@ -60,27 +60,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
private bool isLegacyProjectStructureUsed = false;
public bool IsLegacyProjectStructureUsed
{
get
{
initialize.Run();
return isLegacyProjectStructureUsed;
}
}
private bool isNewProjectStructureUsed = false;
public bool IsNewProjectStructureUsed
{
get
{
initialize.Run();
return isNewProjectStructureUsed;
}
}
public HashSet<string> CustomImplicitUsings
{
get
@@ -162,15 +141,19 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
// Determine if ASP.NET is used.
useAspNetCoreDlls = useAspNetCoreDlls
|| IsGroupMatch(line, ProjectSdk(), "Sdk", "Microsoft.NET.Sdk.Web")
|| IsGroupMatch(line, FrameworkReference(), "Include", "Microsoft.AspNetCore.App");
if (!useAspNetDlls)
{
useAspNetDlls =
IsGroupMatch(line, ProjectSdk(), "Sdk", "Microsoft.NET.Sdk.Web") ||
IsGroupMatch(line, FrameworkReference(), "Include", "Microsoft.AspNetCore.App");
}
// Determine if implicit usings are used.
useImplicitUsings = useImplicitUsings
|| line.Contains("<ImplicitUsings>enable</ImplicitUsings>".AsSpan(), StringComparison.Ordinal)
|| line.Contains("<ImplicitUsings>true</ImplicitUsings>".AsSpan(), StringComparison.Ordinal);
if (!useImplicitUsings)
{
useImplicitUsings = line.Contains("<ImplicitUsings>enable</ImplicitUsings>".AsSpan(), StringComparison.Ordinal) ||
line.Contains("<ImplicitUsings>true</ImplicitUsings>".AsSpan(), StringComparison.Ordinal);
}
// Find all custom implicit usings.
foreach (var valueMatch in CustomImplicitUsingDeclarations().EnumerateMatches(line))
@@ -181,13 +164,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
implicitUsingNamespaces.Add(ns);
}
}
// Determine project structure:
isLegacyProjectStructureUsed = isLegacyProjectStructureUsed || MicrosoftCSharpTargets().IsMatch(line);
isNewProjectStructureUsed = isNewProjectStructureUsed
|| ProjectSdk().IsMatch(line)
|| FrameworkReference().IsMatch(line);
// TODO: we could also check `<Sdk Name="Microsoft.NET.Sdk" />`
}
}
catch (Exception ex)
@@ -208,9 +184,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
[GeneratedRegex("<Using.*\\sInclude=\"(.*?)\".*/?>", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
private static partial Regex CustomImplicitUsingDeclarations();
[GeneratedRegex("<Import.*\\sProject=\".*Microsoft\\.CSharp\\.targets\".*/?>", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
private static partial Regex MicrosoftCSharpTargets();
}
internal interface IUnsafeFileReader

View File

@@ -4,8 +4,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
{
internal interface IDotNet
{
bool RestoreProjectToDirectory(string project, string directory, bool forceDotnetRefAssemblyFetching, string? pathToNugetConfig = null);
bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects);
bool RestoreProjectToDirectory(string project, string directory, string? pathToNugetConfig = null);
bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, out IEnumerable<string> projects);
bool New(string folder);
bool AddPackage(string folder, string package);
IList<string> GetListedRuntimes();

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// </summary>
internal class NugetPackages
{
private readonly string? nugetExe;
private readonly string nugetExe;
private readonly ProgressMonitor progressMonitor;
/// <summary>
@@ -36,18 +36,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
this.packageDirectory = packageDirectory;
this.progressMonitor = progressMonitor;
nugetExe = ResolveNugetExe(sourceDir);
packageFiles = new DirectoryInfo(sourceDir)
.EnumerateFiles("packages.config", SearchOption.AllDirectories)
.ToArray();
if (packageFiles.Length > 0)
{
nugetExe = ResolveNugetExe(sourceDir);
}
else
{
progressMonitor.LogInfo("Found no packages.config file");
}
}
/// <summary>
@@ -119,7 +111,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
string exe, args;
if (Util.Win32.IsWindows())
{
exe = nugetExe!;
exe = nugetExe;
args = string.Format("install -OutputDirectory {0} {1}", packageDirectory, package);
}
else

View File

@@ -55,10 +55,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
LogInfo($"Restoring {package}...");
public void ResolvedReference(string filename) =>
LogInfo($"Resolved reference {filename}");
LogInfo($"Resolved {filename}");
public void RemovedReference(string filename) =>
LogInfo($"Removed reference {filename}");
LogInfo($"Reference {filename} has been removed");
public void Summary(int existingSources, int usedSources, int missingSources,
int references, int unresolvedReferences,

View File

@@ -19,6 +19,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
private readonly IDotNet dotNet;
private readonly Lazy<Dictionary<string, DotNetVersion>> newestRuntimes;
private Dictionary<string, DotNetVersion> NewestRuntimes => newestRuntimes.Value;
private static string ExecutingRuntime => RuntimeEnvironment.GetRuntimeDirectory();
public Runtime(IDotNet dotNet)
{
@@ -69,17 +70,17 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
{
get
{
var monoPath = FileUtils.FindProgramOnPath(Win32.IsWindows() ? "mono.exe" : "mono");
var monoDirs = monoPath is not null
? new[] { monoPath }
: new[] { "/usr/lib/mono", @"C:\Program Files\Mono\lib\mono" };
if (Directory.Exists(@"C:\Windows\Microsoft.NET\Framework64"))
{
return Directory.EnumerateDirectories(@"C:\Windows\Microsoft.NET\Framework64", "v*")
.OrderByDescending(Path.GetFileName);
}
var monoPath = FileUtils.FindProgramOnPath(Win32.IsWindows() ? "mono.exe" : "mono");
var monoDirs = monoPath is not null
? new[] { Path.GetFullPath(Path.Combine(monoPath, "..", "lib", "mono")), monoPath }
: new[] { "/usr/lib/mono", "/usr/local/mono", "/usr/local/bin/mono", @"C:\Program Files\Mono\lib\mono" };
var dir = monoDirs.FirstOrDefault(Directory.Exists);
if (dir is not null)
@@ -106,23 +107,33 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
/// <summary>
/// Gets the Dotnet Core location.
/// Gets the .NET runtime location to use for extraction.
/// </summary>
public string? NetCoreRuntime => GetVersion(netCoreApp);
public string GetRuntime(bool useSelfContained)
{
if (useSelfContained)
{
return ExecutingRuntime;
}
// Location of the newest .NET Core Runtime.
if (GetVersion(netCoreApp) is string path)
{
return path;
}
if (DesktopRuntimes.Any())
{
return DesktopRuntimes.First();
}
// A bad choice if it's the self-contained runtime distributed in codeql dist.
return ExecutingRuntime;
}
/// <summary>
/// Gets the .NET Framework location. Either the installation folder on Windows or Mono
/// Gets the ASP.NET runtime location to use for extraction, if one exists.
/// </summary>
public string? DesktopRuntime => DesktopRuntimes?.FirstOrDefault();
/// <summary>
/// Gets the executing runtime location, this is the self contained runtime shipped in the CodeQL CLI bundle.
/// </summary>
public string ExecutingRuntime => RuntimeEnvironment.GetRuntimeDirectory();
/// <summary>
/// Gets the ASP.NET Core location.
/// </summary>
public string? AspNetCoreRuntime => GetVersion(aspNetCoreApp);
public string? GetAspRuntime() => GetVersion(aspNetCoreApp);
}
}

View File

@@ -8,7 +8,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1822</NoWarn>
</PropertyGroup>
<ItemGroup>

View File

@@ -99,7 +99,7 @@ namespace Semmle.Extraction.Tests
var dotnet = MakeDotnet(dotnetCliInvoker);
// Execute
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages", false);
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages");
// Verify
var lastArgs = dotnetCliInvoker.GetLastArgs();
@@ -114,7 +114,7 @@ namespace Semmle.Extraction.Tests
var dotnet = MakeDotnet(dotnetCliInvoker);
// Execute
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages", false, "myconfig.config");
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages", "myconfig.config");
// Verify
var lastArgs = dotnetCliInvoker.GetLastArgs();
@@ -129,7 +129,7 @@ namespace Semmle.Extraction.Tests
var dotnet = MakeDotnet(dotnetCliInvoker);
// Execute
dotnet.RestoreSolutionToDirectory("mysolution.sln", "mypackages", false, out var projects);
dotnet.RestoreSolutionToDirectory("mysolution.sln", "mypackages", out var projects);
// Verify
var lastArgs = dotnetCliInvoker.GetLastArgs();
@@ -148,7 +148,7 @@ namespace Semmle.Extraction.Tests
dotnetCliInvoker.Success = false;
// Execute
dotnet.RestoreSolutionToDirectory("mysolution.sln", "mypackages", false, out var projects);
dotnet.RestoreSolutionToDirectory("mysolution.sln", "mypackages", out var projects);
// Verify
var lastArgs = dotnetCliInvoker.GetLastArgs();

View File

@@ -1,5 +1,4 @@
using Xunit;
using System;
using System.Collections.Generic;
using Semmle.Extraction.CSharp.DependencyFetching;
@@ -7,9 +6,9 @@ namespace Semmle.Extraction.Tests
{
internal class UnsafeFileReaderStub : IUnsafeFileReader
{
private readonly IEnumerable<string> lines;
private readonly List<string> lines;
public UnsafeFileReaderStub(IEnumerable<string> lines)
public UnsafeFileReaderStub(List<string> lines)
{
this.lines = lines;
}
@@ -25,7 +24,7 @@ namespace Semmle.Extraction.Tests
internal class TestFileContent : FileContent
{
public TestFileContent(IEnumerable<string> lines) : base(new ProgressMonitor(new LoggerStub()),
public TestFileContent(List<string> lines) : base(new ProgressMonitor(new LoggerStub()),
new List<string>() { "test1.cs" },
new UnsafeFileReaderStub(lines))
{ }
@@ -49,7 +48,7 @@ namespace Semmle.Extraction.Tests
// Execute
var allPackages = fileContent.AllPackages;
var useAspNetDlls = fileContent.UseAspNetCoreDlls;
var useAspNetDlls = fileContent.UseAspNetDlls;
// Verify
Assert.False(useAspNetDlls);
@@ -73,7 +72,7 @@ namespace Semmle.Extraction.Tests
var fileContent = new TestFileContent(lines);
// Execute
var useAspNetDlls = fileContent.UseAspNetCoreDlls;
var useAspNetDlls = fileContent.UseAspNetDlls;
var allPackages = fileContent.AllPackages;
// Verify
@@ -137,53 +136,5 @@ namespace Semmle.Extraction.Tests
Assert.Contains("Ns0.Ns1", customImplicitUsings);
Assert.Contains("Ns2", customImplicitUsings);
}
[Fact]
public void TestFileContent_LegacyProjectStructure()
{
// Setup
var input =
"""
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
""";
var lines = input.Split(Environment.NewLine);
var fileContent = new TestFileContent(lines);
// Execute
var isLegacy = fileContent.IsLegacyProjectStructureUsed;
var isNew = fileContent.IsNewProjectStructureUsed;
// Verify
Assert.True(isLegacy);
Assert.False(isNew);
}
[Fact]
public void TestFileContent_NewProjectStructure()
{
// Setup
var input =
"""
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net461;net70</TargetFrameworks>
</PropertyGroup>
</Project>
""";
var lines = input.Split(Environment.NewLine);
var fileContent = new TestFileContent(lines);
// Execute
var isLegacy = fileContent.IsLegacyProjectStructureUsed;
var isNew = fileContent.IsNewProjectStructureUsed;
// Verify
Assert.True(isNew);
Assert.False(isLegacy);
}
}
}

View File

@@ -19,9 +19,9 @@ namespace Semmle.Extraction.Tests
public bool New(string folder) => true;
public bool RestoreProjectToDirectory(string project, string directory, bool forceDotnetRefAssemblyFetching, string? pathToNugetConfig = null) => true;
public bool RestoreProjectToDirectory(string project, string directory, string? pathToNugetConfig = null) => true;
public bool RestoreSolutionToDirectory(string solution, string directory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects)
public bool RestoreSolutionToDirectory(string solution, string directory, out IEnumerable<string> projects)
{
projects = Array.Empty<string>();
return true;

View File

@@ -1,11 +1,3 @@
## 1.7.1
No user-facing changes.
## 1.7.0
No user-facing changes.
## 1.6.5
No user-facing changes.

View File

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

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.1
lastReleaseVersion: 1.6.5

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.7.1
version: 1.7.0-dev
groups:
- csharp
- solorigate

View File

@@ -1,11 +1,3 @@
## 1.7.1
No user-facing changes.
## 1.7.0
No user-facing changes.
## 1.6.5
No user-facing changes.

View File

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

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.1
lastReleaseVersion: 1.6.5

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.7.1
version: 1.7.0-dev
groups:
- csharp
- solorigate

View File

@@ -1,3 +0,0 @@
| Program.cs:0:0:0:0 | Program.cs |
| obj/Debug/net5.0/.NETCoreApp,Version=v5.0.AssemblyAttributes.cs:0:0:0:0 | obj/Debug/net5.0/.NETCoreApp,Version=v5.0.AssemblyAttributes.cs |
| obj/Debug/net5.0/autobuild.AssemblyInfo.cs:0:0:0:0 | obj/Debug/net5.0/autobuild.AssemblyInfo.cs |

View File

@@ -1,5 +0,0 @@
import csharp
from File f
where f.fromSource()
select f

View File

@@ -1 +0,0 @@
var dummy = "dummy";

View File

@@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<Target Name="DeleteBinObjFolders" BeforeTargets="Clean">
<RemoveDir Directories=".\bin" />
<RemoveDir Directories=".\obj" />
</Target>
</Project>

View File

@@ -1,5 +0,0 @@
{
"sdk": {
"version": "5.0.408"
}
}

Some files were not shown because too many files have changed in this diff Show More