Merge branch 'main' into shared-http-client-request

This commit is contained in:
Rasmus Wriedt Larsen
2022-08-22 12:05:37 +02:00
committed by GitHub
192 changed files with 10953 additions and 1801 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Add relation for orphaned local variables
compatibility: full
orphaned_variables.rel: delete

View File

@@ -292,22 +292,20 @@ module SemanticExprConfig {
class Guard = IRGuards::IRGuardCondition;
predicate guard(Guard guard, BasicBlock block) {
block = guard.(IRGuards::IRGuardCondition).getBlock()
}
predicate guard(Guard guard, BasicBlock block) { block = guard.getBlock() }
Expr getGuardAsExpr(Guard guard) { result = guard }
predicate equalityGuard(Guard guard, Expr e1, Expr e2, boolean polarity) {
guard.(IRGuards::IRGuardCondition).comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
guard.comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
}
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock controlled, boolean branch) {
guard.(IRGuards::IRGuardCondition).controls(controlled, branch)
guard.controls(controlled, branch)
}
predicate guardHasBranchEdge(Guard guard, BasicBlock bb1, BasicBlock bb2, boolean branch) {
guard.(IRGuards::IRGuardCondition).controlsEdge(bb1, bb2, branch)
guard.controlsEdge(bb1, bb2, branch)
}
Guard comparisonGuard(Expr e) { result = e }

View File

@@ -218,8 +218,6 @@ class Folder extends Container, @folder {
class File extends Container, @file {
override string getAbsolutePath() { files(underlyingElement(this), result) }
override string toString() { result = Container.super.toString() }
override string getAPrimaryQlClass() { result = "File" }
override Location getLocation() {

View File

@@ -398,6 +398,8 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
exists(DeclStmt s | s.getADeclaration() = this and s.getEnclosingFunction() = result)
or
exists(ConditionDeclExpr e | e.getVariable() = this and e.getEnclosingFunction() = result)
or
orphaned_variables(underlyingElement(this), unresolveElement(result))
}
}

View File

@@ -523,6 +523,11 @@ autoderivation(
int derivation_type: @type ref
);
orphaned_variables(
int var: @localvariable ref,
int function: @function ref
)
enumconstants(
unique int id: @enumconstant,
int parent: @usertype ref,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add relation for orphaned local variables
compatibility: partial

View File

@@ -106,6 +106,26 @@ predicate inheritanceConversionTypes(
toType = convert.getResultType()
}
private signature class ConversionInstruction extends UnaryInstruction;
module Conversion<ConversionInstruction I> {
signature predicate hasTypes(I instr, Type fromType, Type toType);
module Using<hasTypes/3 project> {
pragma[nomagic]
predicate hasOperandAndTypes(I convert, Instruction unary, Type fromType, Type toType) {
project(convert, fromType, toType) and
unary = convert.getUnary()
}
}
}
pragma[nomagic]
predicate hasObjectAndField(FieldAddressInstruction fai, Instruction object, Field f) {
fai.getObjectAddress() = object and
fai.getField() = f
}
/** Gets the HashCons value of an address computed by `instr`, if any. */
TGlobalAddress globalAddress(Instruction instr) {
result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable())
@@ -117,25 +137,27 @@ TGlobalAddress globalAddress(Instruction instr) {
result = TLoad(globalAddress(load.getSourceAddress()))
)
or
exists(ConvertInstruction convert, Type fromType, Type toType | instr = convert |
uncheckedConversionTypes(convert, fromType, toType) and
result = TConversion("unchecked", globalAddress(convert.getUnary()), fromType, toType)
exists(Type fromType, Type toType, Instruction unary |
Conversion<ConvertInstruction>::Using<uncheckedConversionTypes/3>::hasOperandAndTypes(instr,
unary, fromType, toType) and
result = TConversion("unchecked", globalAddress(unary), fromType, toType)
)
or
exists(CheckedConvertOrNullInstruction convert, Type fromType, Type toType | instr = convert |
checkedConversionTypes(convert, fromType, toType) and
result = TConversion("checked", globalAddress(convert.getUnary()), fromType, toType)
exists(Type fromType, Type toType, Instruction unary |
Conversion<CheckedConvertOrNullInstruction>::Using<checkedConversionTypes/3>::hasOperandAndTypes(instr,
unary, fromType, toType) and
result = TConversion("checked", globalAddress(unary), fromType, toType)
)
or
exists(InheritanceConversionInstruction convert, Type fromType, Type toType | instr = convert |
inheritanceConversionTypes(convert, fromType, toType) and
result = TConversion("inheritance", globalAddress(convert.getUnary()), fromType, toType)
exists(Type fromType, Type toType, Instruction unary |
Conversion<InheritanceConversionInstruction>::Using<inheritanceConversionTypes/3>::hasOperandAndTypes(instr,
unary, fromType, toType) and
result = TConversion("inheritance", globalAddress(unary), fromType, toType)
)
or
exists(FieldAddressInstruction fai | instr = fai |
result =
TFieldAddress(globalAddress(pragma[only_bind_into](fai.getObjectAddress())),
pragma[only_bind_out](fai.getField()))
exists(FieldAddressInstruction fai, Instruction object, Field f | instr = fai |
hasObjectAndField(fai, object, f) and
result = TFieldAddress(globalAddress(object), f)
)
or
result = globalAddress(instr.(PointerOffsetInstruction).getLeft())
@@ -268,7 +290,11 @@ class PathElement extends TPathElement {
predicate isSink(IRBlock block) { exists(this.asSink(block)) }
string toString() {
result = [asStore().toString(), asCall(_).toString(), asMid().toString(), asSink(_).toString()]
result =
[
this.asStore().toString(), this.asCall(_).toString(), this.asMid().toString(),
this.asSink(_).toString()
]
}
predicate hasLocationInfo(

View File

@@ -19,6 +19,7 @@ import semmle.code.cpp.security.Security
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.dataflow.TaintTracking2
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.models.implementations.Strcat
import DataFlow::PathGraph
@@ -83,6 +84,32 @@ class ExecState extends DataFlow::FlowState {
DataFlow::Node getFstNode() { result = fst }
DataFlow::Node getSndNode() { result = snd }
/** Holds if this is a possible `ExecState` for `sink`. */
predicate isFeasibleForSink(DataFlow::Node sink) {
any(ExecStateConfiguration conf).hasFlow(snd, sink)
}
}
/**
* A `TaintTracking` configuration that's used to find the relevant `ExecState`s for a
* given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
* `ExecTaintConfiguration::isSink`.
*/
class ExecStateConfiguration extends TaintTracking2::Configuration {
ExecStateConfiguration() { this = "ExecStateConfiguration" }
override predicate isSource(DataFlow::Node source) {
exists(ExecState state | state.getSndNode() = source)
}
override predicate isSink(DataFlow::Node sink) {
shellCommand(sinkAsArgumentIndirection(sink), _)
}
override predicate isSanitizerOut(DataFlow::Node node) {
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
}
}
class ExecTaintConfiguration extends TaintTracking::Configuration {
@@ -94,8 +121,8 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
shellCommand(sinkAsArgumentIndirection(sink), _) and
state instanceof ExecState
any(ExecStateConfiguration conf).isSink(sink) and
state.(ExecState).isFeasibleForSink(sink)
}
override predicate isAdditionalTaintStep(

View File

@@ -67,7 +67,7 @@ predicate findUseCharacterConversion(Expr exp, string msg) {
exists(FunctionCall fc |
fc = exp and
(
exists(Loop lptmp | lptmp = fc.getEnclosingStmt().getParentStmt*()) and
fc.getEnclosingStmt().getParentStmt*() instanceof Loop and
fc.getTarget().hasName(["mbtowc", "mbrtowc", "_mbtowc_l"]) and
not fc.getArgument(0).isConstant() and
not fc.getArgument(1).isConstant() and

View File

@@ -44,11 +44,8 @@ predicate conversionDoneLate(MulExpr mexp) {
mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and
e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize()
or
e0.(FunctionCall)
.getTarget()
.getParameter(argumentPosition(e0.(FunctionCall), mexp, _))
.getType()
.getSize() = mexp.getConversion().getConversion().getType().getSize()
e0.(FunctionCall).getTarget().getParameter(argumentPosition(e0, mexp, _)).getType().getSize() =
mexp.getConversion().getConversion().getType().getSize()
)
)
}
@@ -75,7 +72,7 @@ predicate signSmallerWithEqualSizes(MulExpr mexp) {
ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and
ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and
(
not exists(DivExpr de | mexp.getParent*() = de)
not mexp.getParent*() instanceof DivExpr
or
exists(DivExpr de, Expr ec |
e2.isConstant() and

View File

@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
override Location getLocation() { result = comment.getLocation() }
}
private predicate onSameLine(ValidExpectation a, ActualResult b) {
exists(string fname, int line, Location la, Location lb |
// Join order intent:
// Take the locations of ActualResults,
// join with locations in the same file / on the same line,
// then match those against ValidExpectations.
la = a.getLocation() and
pragma[only_bind_into](lb) = b.getLocation() and
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
lb.hasLocationInfo(fname, line, _, _, _)
)
}
private class ValidExpectation extends Expectation, TValidExpectation {
string tag;
string value;
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
string getKnownFailure() { result = knownFailure }
predicate matchesActualResult(ActualResult actualResult) {
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
getLocation().getFile() = actualResult.getLocation().getFile() and
onSameLine(pragma[only_bind_into](this), actualResult) and
getTag() = actualResult.getTag() and
getValue() = actualResult.getValue()
}

View File

@@ -14137,6 +14137,30 @@ ir.cpp:
# 1845| Type = [Struct] B
# 1845| ValueCategory = lvalue
# 1846| getStmt(2): [ReturnStmt] return ...
# 1849| [TopLevelFunction] void magicvars()
# 1849| <params>:
# 1849| getEntryPoint(): [BlockStmt] { ... }
# 1850| getStmt(0): [DeclStmt] declaration
# 1850| getDeclarationEntry(0): [VariableDeclarationEntry] definition of pf
# 1850| Type = [PointerType] const char *
# 1850| getVariable().getInitializer(): [Initializer] initializer for pf
# 1850| getExpr(): [VariableAccess] __PRETTY_FUNCTION__
# 1850| Type = [ArrayType] const char[17]
# 1850| ValueCategory = lvalue
# 1850| getExpr().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 1850| Type = [PointerType] const char *
# 1850| ValueCategory = prvalue
# 1851| getStmt(1): [DeclStmt] declaration
# 1851| getDeclarationEntry(0): [VariableDeclarationEntry] definition of strfunc
# 1851| Type = [PointerType] const char *
# 1851| getVariable().getInitializer(): [Initializer] initializer for strfunc
# 1851| getExpr(): [VariableAccess] __func__
# 1851| Type = [ArrayType] const char[10]
# 1851| ValueCategory = lvalue
# 1851| getExpr().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 1851| Type = [PointerType] const char *
# 1851| ValueCategory = prvalue
# 1852| getStmt(2): [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

View File

@@ -1846,4 +1846,9 @@ namespace block_assignment {
}
}
void magicvars() {
const char *pf = __PRETTY_FUNCTION__;
const char *strfunc = __func__;
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -8641,6 +8641,15 @@
| ir.cpp:1845:13:1845:13 | SideEffect | ~m1845_9 |
| ir.cpp:1845:13:1845:13 | SideEffect | ~m1845_12 |
| ir.cpp:1845:13:1845:13 | Unary | r1845_3 |
| ir.cpp:1849:6:1849:14 | ChiPartial | partial:m1849_3 |
| ir.cpp:1849:6:1849:14 | ChiTotal | total:m1849_2 |
| ir.cpp:1849:6:1849:14 | SideEffect | m1849_3 |
| ir.cpp:1850:17:1850:18 | Address | &:r1850_1 |
| ir.cpp:1850:22:1850:40 | StoreValue | r1850_3 |
| ir.cpp:1850:22:1850:40 | Unary | r1850_2 |
| ir.cpp:1851:17:1851:23 | Address | &:r1851_1 |
| ir.cpp:1851:27:1851:34 | StoreValue | r1851_3 |
| ir.cpp:1851:27:1851:34 | Unary | r1851_2 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |

View File

@@ -9914,6 +9914,24 @@ ir.cpp:
# 1843| v1843_5(void) = AliasedUse : ~m?
# 1843| v1843_6(void) = ExitFunction :
# 1849| void magicvars()
# 1849| Block 0
# 1849| v1849_1(void) = EnterFunction :
# 1849| mu1849_2(unknown) = AliasedDefinition :
# 1849| mu1849_3(unknown) = InitializeNonLocal :
# 1850| r1850_1(glval<char *>) = VariableAddress[pf] :
# 1850| r1850_2(glval<char[17]>) = VariableAddress[__PRETTY_FUNCTION__] :
# 1850| r1850_3(char *) = Convert : r1850_2
# 1850| mu1850_4(char *) = Store[pf] : &:r1850_1, r1850_3
# 1851| r1851_1(glval<char *>) = VariableAddress[strfunc] :
# 1851| r1851_2(glval<char[10]>) = VariableAddress[__func__] :
# 1851| r1851_3(char *) = Convert : r1851_2
# 1851| mu1851_4(char *) = Store[strfunc] : &:r1851_1, r1851_3
# 1852| v1852_1(void) = NoOp :
# 1849| v1849_4(void) = ReturnVoid :
# 1849| v1849_5(void) = AliasedUse : ~m?
# 1849| v1849_6(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -99,8 +99,6 @@ thisArgumentIsNonPointer
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
nonUniqueIRVariable
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -149,8 +149,6 @@ thisArgumentIsNonPointer
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
nonUniqueIRVariable
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -99,8 +99,6 @@ thisArgumentIsNonPointer
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
nonUniqueIRVariable
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -309,8 +309,6 @@ class FunctionPointerType extends Type, CustomModifierReceiver, Parameterizable,
/** Gets the calling convention. */
int getCallingConvention() { cil_function_pointer_calling_conventions(this, result) }
override string toString() { result = Type.super.toString() }
/** Holds if the return type is `void`. */
predicate returnsVoid() { this.getReturnType() instanceof VoidType }

View File

@@ -215,11 +215,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
/** Gets a `Call` that has this callable as a target. */
Call getACall() { this = result.getTarget() }
override Parameter getParameter(int n) { result = Parameterizable.super.getParameter(n) }
override Parameter getAParameter() { result = Parameterizable.super.getAParameter() }
override int getNumberOfParameters() { result = Parameterizable.super.getNumberOfParameters() }
}
/**
@@ -276,8 +272,6 @@ class Method extends Callable, Virtualizable, Attributable, @method {
predicate hasParams() { exists(this.getParamsType()) }
// Remove when `Callable.isOverridden()` is removed
override predicate isOverridden() { Virtualizable.super.isOverridden() }
override predicate fromSource() {
Callable.super.fromSource() and
not this.isCompilerGenerated()
@@ -472,8 +466,6 @@ class RecordCloneMethod extends Method, DotNet::RecordCloneCallable {
override Constructor getConstructor() {
result = DotNet::RecordCloneCallable.super.getConstructor()
}
override string toString() { result = Method.super.toString() }
}
/**

View File

@@ -116,10 +116,6 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac
override Location getALocation() { result = this.getADeclaration().getALocation() }
override string toString() { result = DotNet::Namespace.super.toString() }
override predicate hasQualifiedName(string a, string b) {
DotNet::Namespace.super.hasQualifiedName(a, b)
}
}
/**

View File

@@ -42,8 +42,6 @@ class DeclarationWithAccessors extends AssignableMember, Virtualizable, Attribut
}
override Type getType() { none() }
override string toString() { result = AssignableMember.super.toString() }
}
/**

View File

@@ -163,10 +163,6 @@ module Ssa {
* (`ImplicitDefinition`), or a phi node (`PhiNode`).
*/
class Definition extends SsaImpl::Definition {
final override SourceVariable getSourceVariable() {
result = SsaImpl::Definition.super.getSourceVariable()
}
/**
* Gets the control flow node of this SSA definition, if any. Phi nodes are
* examples of SSA definitions without a control flow node, as they are

View File

@@ -105,15 +105,12 @@ class DataFlowSummarizedCallable instanceof FlowSummary::SummarizedCallable {
private module Cached {
/**
* The following heuristic is used to rank when to use source code or when to use summaries for DataFlowCallables.
* 1. Use hand written summaries.
* 2. Use source code.
* 3. Use auto generated summaries.
* 1. Use hand written summaries or source code.
* 2. Use auto generated summaries.
*/
cached
newtype TDataFlowCallable =
TDotNetCallable(DotNet::Callable c) {
c.isUnboundDeclaration() and not c instanceof DataFlowSummarizedCallable
} or
TDotNetCallable(DotNet::Callable c) { c.isUnboundDeclaration() } or
TSummarizedCallable(DataFlowSummarizedCallable sc)
cached
@@ -370,7 +367,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
result.asCallable() = cfn.getEnclosingCallable()
}
override string toString() { result = cfn.toString() }
@@ -400,7 +397,7 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
result.asCallable() = cfn.getEnclosingCallable()
}
override string toString() { result = cfn.toString() }
@@ -419,14 +416,14 @@ class TransitiveCapturedDataFlowCall extends DataFlowCall, TTransitiveCapturedCa
TransitiveCapturedDataFlowCall() { this = TTransitiveCapturedCall(cfn, target) }
override DataFlowCallable getARuntimeTarget() { result.getUnderlyingCallable() = target }
override DataFlowCallable getARuntimeTarget() { result.asCallable() = target }
override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
override DataFlow::ExprNode getNode() { none() }
override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
result.asCallable() = cfn.getEnclosingCallable()
}
override string toString() { result = "[transitive] " + cfn.toString() }
@@ -450,7 +447,7 @@ class CilDataFlowCall extends DataFlowCall, TCilCall {
override DataFlow::ExprNode getNode() { result.getExpr() = call }
override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = call.getEnclosingCallable()
result.asCallable() = call.getEnclosingCallable()
}
override string toString() { result = call.toString() }

View File

@@ -65,9 +65,11 @@ abstract class NodeImpl extends Node {
private class ExprNodeImpl extends ExprNode, NodeImpl {
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = this.getExpr().(CIL::Expr).getEnclosingCallable()
or
result.getUnderlyingCallable() = this.getControlFlowNodeImpl().getEnclosingCallable()
result.asCallable() =
[
this.getExpr().(CIL::Expr).getEnclosingCallable().(DotNet::Callable),
this.getControlFlowNodeImpl().getEnclosingCallable()
]
}
override DotNet::Type getTypeImpl() {
@@ -852,7 +854,7 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
Ssa::Definition getDefinition() { result = def }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = def.getEnclosingCallable()
result.asCallable() = def.getEnclosingCallable()
}
override Type getTypeImpl() { result = def.getSourceVariable().getType() }
@@ -914,9 +916,7 @@ private module ParameterNodes {
callable = c.asCallable() and pos.isThisParameter()
}
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = callable
}
override DataFlowCallable getEnclosingCallableImpl() { result.asCallable() = callable }
override Type getTypeImpl() { result = callable.getDeclaringType() }
@@ -963,7 +963,7 @@ private module ParameterNodes {
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
pos.isImplicitCapturedParameterPosition(def.getSourceVariable().getAssignable()) and
c.getUnderlyingCallable() = this.getEnclosingCallable()
c.asCallable() = this.getEnclosingCallable()
}
}
@@ -1078,7 +1078,7 @@ private module ArgumentNodes {
}
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
result.asCallable() = cfn.getEnclosingCallable()
}
override Type getTypeImpl() { result = v.getType() }
@@ -1107,7 +1107,7 @@ private module ArgumentNodes {
override ControlFlow::Node getControlFlowNodeImpl() { result = cfn }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
result.asCallable() = cfn.getEnclosingCallable()
}
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
@@ -1146,7 +1146,7 @@ private module ArgumentNodes {
}
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = callCfn.getEnclosingCallable()
result.asCallable() = callCfn.getEnclosingCallable()
}
override Type getTypeImpl() { result = this.getParameter().getType() }
@@ -1227,7 +1227,7 @@ private module ReturnNodes {
override NormalReturnKind getKind() { any() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = yrs.getEnclosingCallable()
result.asCallable() = yrs.getEnclosingCallable()
}
override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() }
@@ -1253,7 +1253,7 @@ private module ReturnNodes {
override NormalReturnKind getKind() { any() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = expr.getEnclosingCallable()
result.asCallable() = expr.getEnclosingCallable()
}
override Type getTypeImpl() { result = expr.getEnclosingCallable().getReturnType() }
@@ -1330,9 +1330,10 @@ private module ReturnNodes {
* In this case we adjust it to instead be a return node.
*/
private predicate summaryPostUpdateNodeIsOutOrRef(SummaryNode n, Parameter p) {
exists(ParameterNode pn |
exists(ParameterNodeImpl pn, DataFlowCallable c, ParameterPosition pos |
FlowSummaryImpl::Private::summaryPostUpdateNode(n, pn) and
pn.getParameter() = p and
pn.isParameterOf(c, pos) and
p = c.asSummarizedCallable().getParameter(pos.getPosition()) and
p.isOutOrRef()
)
}
@@ -1903,7 +1904,7 @@ private module PostUpdateNodes {
}
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
result.asCallable() = cfn.getEnclosingCallable()
}
override DotNet::Type getTypeImpl() { result = oc.getType() }
@@ -1923,7 +1924,7 @@ private module PostUpdateNodes {
override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
result.asCallable() = cfn.getEnclosingCallable()
}
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
@@ -2012,12 +2013,11 @@ class LambdaCallKind = Unit;
/** Holds if `creation` is an expression that creates a delegate for `c`. */
predicate lambdaCreation(ExprNode creation, LambdaCallKind kind, DataFlowCallable c) {
exists(Expr e | e = creation.getExpr() |
c.getUnderlyingCallable() = e.(AnonymousFunctionExpr)
or
c.getUnderlyingCallable() = e.(CallableAccess).getTarget().getUnboundDeclaration()
or
c.getUnderlyingCallable() =
e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
c.asCallable() =
[
e.(AnonymousFunctionExpr), e.(CallableAccess).getTarget().getUnboundDeclaration(),
e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
]
) and
kind = TMkUnit()
}

View File

@@ -41,7 +41,7 @@ class Node extends TNode {
/** Gets the enclosing callable of this node. */
final Callable getEnclosingCallable() {
result = this.(NodeImpl).getEnclosingCallableImpl().getUnderlyingCallable()
result = this.(NodeImpl).getEnclosingCallableImpl().asCallable()
}
/** Gets the control flow node corresponding to this node, if any. */
@@ -103,7 +103,7 @@ class ParameterNode extends Node instanceof ParameterNodeImpl {
DotNet::Parameter getParameter() {
exists(DataFlowCallable c, ParameterPosition ppos |
super.isParameterOf(c, ppos) and
result = c.getUnderlyingCallable().getParameter(ppos.getPosition())
result = c.asCallable().getParameter(ppos.getPosition())
)
}

View File

@@ -553,7 +553,7 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ {
final override Callable getARuntimeTarget() {
exists(ExplicitDelegateLikeDataFlowCall call |
this = call.getCall() and
result = viableCallableLambda(call, _).getUnderlyingCallable()
result = viableCallableLambda(call, _).asCallable()
)
}

View File

@@ -357,3 +357,36 @@ class MicrosoftAspNetCoreHttpHtmlString extends Class {
this.hasQualifiedName("Microsoft.AspNetCore.Html", "HtmlString")
}
}
/**
* The `Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions` class.
*/
class MicrosoftAspNetCoreBuilderEndpointRouteBuilderExtensions extends Class {
MicrosoftAspNetCoreBuilderEndpointRouteBuilderExtensions() {
this.hasQualifiedName("Microsoft.AspNetCore.Builder", "EndpointRouteBuilderExtensions")
}
/** Gets the `Map` extension method. */
Method getMapMethod() { result = this.getAMethod("Map") }
/** Gets the `MapGet` extension method. */
Method getMapGetMethod() { result = this.getAMethod("MapGet") }
/** Gets the `MapPost` extension method. */
Method getMapPostMethod() { result = this.getAMethod("MapPost") }
/** Gets the `MapPut` extension method. */
Method getMapPutMethod() { result = this.getAMethod("MapPut") }
/** Gets the `MapDelete` extension method. */
Method getMapDeleteMethod() { result = this.getAMethod("MapDelete") }
/** Get a `Map` like extenion methods. */
Method getAMapMethod() {
result =
[
this.getMapMethod(), this.getMapGetMethod(), this.getMapPostMethod(),
this.getMapPutMethod(), this.getMapDeleteMethod()
]
}
}

View File

@@ -171,6 +171,35 @@ class ActionMethodParameter extends RemoteFlowSource, DataFlow::ParameterNode {
/** A data flow source of remote user input (ASP.NET Core). */
abstract class AspNetCoreRemoteFlowSource extends RemoteFlowSource { }
private predicate reachesMapGetArg(DataFlow::Node n) {
exists(MethodCall mc |
mc.getTarget() = any(MicrosoftAspNetCoreBuilderEndpointRouteBuilderExtensions c).getAMapMethod() and
n.asExpr() = mc.getArgument(2)
)
or
exists(DataFlow::Node mid | reachesMapGetArg(mid) |
DataFlow::localFlowStep(n, mid) or
n.asExpr() = mid.asExpr().(DelegateCreation).getArgument()
)
}
/** A parameter to a routing method delegate. */
class AspNetCoreRoutingMethodParameter extends AspNetCoreRemoteFlowSource, DataFlow::ParameterNode {
AspNetCoreRoutingMethodParameter() {
exists(DataFlow::Node n, Callable c |
reachesMapGetArg(n) and
c.getAParameter() = this.asParameter() and
c.isSourceDeclaration()
|
n.asExpr() = c
or
n.asExpr().(CallableAccess).getTarget().getUnboundDeclaration() = c
)
}
override string getSourceType() { result = "ASP.NET Core routing endpoint." }
}
/**
* Data flow for ASP.NET Core.
*

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Parameters of delegates passed to routing endpoint calls like `MapGet` in ASP.NET Core are now considered remote flow sources.

View File

@@ -817,10 +817,6 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
else result = this.getInstruction(AddressTag())
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
result = TranslatedVariableAccess.super.getInstructionOperand(tag, operandTag)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) {
TranslatedVariableAccess.super.hasInstruction(opcode, tag, resultType)
or

View File

@@ -21,10 +21,6 @@ abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDecla
result = "compiler generated declaration (" + generatedBy.toString() + ")"
}
override TranslatedElement getChild(int id) {
result = LocalVariableDeclarationBase.super.getChild(id)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getInitialization() and result = getInstruction(InitializerStoreTag())
}

View File

@@ -112,7 +112,7 @@ string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
* Gets the enclosing callable of `ret`.
*/
CS::Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) {
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).getUnderlyingCallable()
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable()
}
/**

View File

@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
override Location getLocation() { result = comment.getLocation() }
}
private predicate onSameLine(ValidExpectation a, ActualResult b) {
exists(string fname, int line, Location la, Location lb |
// Join order intent:
// Take the locations of ActualResults,
// join with locations in the same file / on the same line,
// then match those against ValidExpectations.
la = a.getLocation() and
pragma[only_bind_into](lb) = b.getLocation() and
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
lb.hasLocationInfo(fname, line, _, _, _)
)
}
private class ValidExpectation extends Expectation, TValidExpectation {
string tag;
string value;
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
string getKnownFailure() { result = knownFailure }
predicate matchesActualResult(ActualResult actualResult) {
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
getLocation().getFile() = actualResult.getLocation().getFile() and
onSameLine(pragma[only_bind_into](this), actualResult) and
getTag() = actualResult.getTag() and
getValue() = actualResult.getValue()
}

View File

@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using System;
namespace Testing
{
@@ -20,4 +22,40 @@ namespace Testing
throw null;
}
}
public class Item
{
public string Tainted { get; set; }
}
public class AspRoutingEndpoints
{
public delegate void MapGetHandler(string param);
public void HandlerMethod(string param) { }
public void M1(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// The delegate parameters are considered flow sources.
app.MapGet("/api/redirect/{newUrl}", (string newUrl) => { });
app.MapGet("/{myApi}/redirect/{myUrl}", (string myApi, string myUrl) => { });
Action<string> handler = (string lambdaParam) => { };
app.MapGet("/api/redirect/{lambdaParam}", handler);
MapGetHandler handler2 = HandlerMethod;
app.MapGet("/api/redirect/{mapGetParam}", handler2);
app.MapPost("/api/redirect/{mapPostParam}", (string mapPostParam) => { });
app.MapPut("/api/redirect/{mapPutParam}", (string mapPutParam) => { });
app.MapDelete("/api/redirect/{mapDeleteParam}", (string mapDeleteParam) => { });
app.MapPost("/items", (Item item) => { });
app.Run();
}
}
}

View File

@@ -1,4 +1,14 @@
remoteFlowSourceMembers
| AspRemoteFlowSource.cs:8:23:8:31 | RequestId |
| AspRemoteFlowSource.cs:10:23:10:31 | RequestId |
| AspRemoteFlowSource.cs:28:23:28:29 | Tainted |
remoteFlowSources
| AspRemoteFlowSource.cs:18:42:18:50 | viewModel |
| AspRemoteFlowSource.cs:20:42:20:50 | viewModel |
| AspRemoteFlowSource.cs:35:42:35:46 | param |
| AspRemoteFlowSource.cs:43:58:43:63 | newUrl |
| AspRemoteFlowSource.cs:44:61:44:65 | myApi |
| AspRemoteFlowSource.cs:44:75:44:79 | myUrl |
| AspRemoteFlowSource.cs:46:46:46:56 | lambdaParam |
| AspRemoteFlowSource.cs:52:65:52:76 | mapPostParam |
| AspRemoteFlowSource.cs:53:63:53:73 | mapPutParam |
| AspRemoteFlowSource.cs:54:69:54:82 | mapDeleteParam |
| AspRemoteFlowSource.cs:56:41:56:44 | item |

View File

@@ -0,0 +1 @@
// empty

View File

@@ -0,0 +1,62 @@
// A hand-written test file that mimics the output of compiling a `.cshtml` file
#pragma checksum "Index.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "c4ae76542f1958092cebd8f57beef899d20fc548"
// <auto-generated/>
#pragma warning disable 1591
[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(dotnetweb.Pages.Pages_Index), @"mvc.1.0.razor-page", @"Index.cshtml")]
namespace dotnetweb.Pages
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#nullable restore
using dotnetweb;
#line default
#line hidden
#nullable disable
[global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"c4ae76542f1958092cebd8f57beef899d20fc548", @"Index.cshtml")]
// [global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"c13da96c2597d5ddb7d415fb4892c644a268f50b", @"/Pages/_ViewImports.cshtml")]
public class Pages_Index : global::Microsoft.AspNetCore.Mvc.RazorPages.Page
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
#nullable restore
#line 3 "Index.cshtml"
ViewData["Title"] = "ASP.NET Core";
var message = Request.Query["m"];
#line default
#line hidden
#nullable disable
WriteLiteral("<div class=\"cli\">\n <div class=\"cli-example\"> \n");
#nullable restore
#line 14 "Index.cshtml"
Write(Html.Raw(message)); // BAD
#line default
#line hidden
#nullable disable
WriteLiteral("\n </div>\n</div>\n\n\n");
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<string> Html { get; private set; }
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<string> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<string>)PageContext?.ViewData;
}
}
#pragma warning restore 1591

View File

@@ -1,4 +1,5 @@
edges
| Index.cshtml:5:19:5:31 | access to property Query : IQueryCollection | Index.cshtml:14:16:14:22 | call to operator implicit conversion |
| XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:19:25:19:52 | access to indexer : String |
| XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:26:30:26:34 | access to local variable sayHi |
| XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:36:40:36:44 | access to local variable sayHi |
@@ -14,6 +15,8 @@ edges
| XSSAspNetCore.cs:61:44:61:63 | access to indexer : StringValues | XSSAspNetCore.cs:61:44:61:66 | access to indexer |
| XSSAspNetCore.cs:72:51:72:65 | access to property Headers : IHeaderDictionary | XSSAspNetCore.cs:72:51:72:72 | call to operator implicit conversion |
nodes
| Index.cshtml:5:19:5:31 | access to property Query : IQueryCollection | semmle.label | access to property Query : IQueryCollection |
| Index.cshtml:14:16:14:22 | call to operator implicit conversion | semmle.label | call to operator implicit conversion |
| XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
| XSSAspNet.cs:19:25:19:52 | access to indexer : String | semmle.label | access to indexer : String |
| XSSAspNet.cs:26:30:26:34 | access to local variable sayHi | semmle.label | access to local variable sayHi |
@@ -36,6 +39,7 @@ nodes
| XSSAspNetCore.cs:72:51:72:72 | call to operator implicit conversion | semmle.label | call to operator implicit conversion |
subpaths
#select
| Index.cshtml:14:16:14:22 | call to operator implicit conversion | Index.cshtml:5:19:5:31 | access to property Query : IQueryCollection | Index.cshtml:14:16:14:22 | call to operator implicit conversion | $@ flows to here and is written to HTML or JavaScript: Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.Raw() method. | Index.cshtml:5:19:5:31 | access to property Query : IQueryCollection | User-provided value |
| XSSAspNet.cs:26:30:26:34 | access to local variable sayHi | XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:26:30:26:34 | access to local variable sayHi | $@ flows to here and is written to HTML or JavaScript: System.Web.WebPages.WebPage.WriteLiteral() method. | XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | User-provided value |
| XSSAspNet.cs:36:40:36:44 | access to local variable sayHi | XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:36:40:36:44 | access to local variable sayHi | $@ flows to here and is written to HTML or JavaScript: System.Web.WebPages.WebPage.WriteLiteralTo() method. | XSSAspNet.cs:19:25:19:43 | access to property QueryString : NameValueCollection | User-provided value |
| XSSAspNet.cs:43:28:43:55 | access to indexer | XSSAspNet.cs:43:28:43:46 | access to property QueryString : NameValueCollection | XSSAspNet.cs:43:28:43:55 | access to indexer | $@ flows to here and is written to HTML or JavaScript. | XSSAspNet.cs:43:28:43:46 | access to property QueryString : NameValueCollection | User-provided value |

View File

@@ -46,5 +46,3 @@ namespace ASP
}
}
}
// source-extractor-options: /r:${testdir}/../../../../../packages/Microsoft.AspNet.WebPages.3.2.3/lib/net45/System.Web.WebPages.dll /r:${testdir}/../../../../../packages/Microsoft.AspNet.Mvc.5.2.3/lib/net45/System.Web.Mvc.dll /r:System.Dynamic.Runtime.dll /r:System.Runtime.Extensions.dll /r:System.Linq.Expressions.dll /r:System.Web.dll /r:C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.dll /r:System.Collections.Specialized.dll

View File

@@ -75,5 +75,3 @@ namespace Testing.Controllers
}
}
}
// initial-extractor-options: /r:netstandard.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Mvc.1.1.3/lib/net451/Microsoft.AspNetCore.Mvc.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Mvc.Core.1.1.3/lib/net451/Microsoft.AspNetCore.Mvc.Core.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Antiforgery.1.1.2/lib/net451/Microsoft.AspNetCore.Antiforgery.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Mvc.ViewFeatures.1.1.3/lib/net451/Microsoft.AspNetCore.Mvc.ViewFeatures.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Mvc.Abstractions.1.1.3/lib/net451/Microsoft.AspNetCore.Mvc.Abstractions.dll /r:${testdir}/../../../../../packages\Microsoft.AspNetCore.Http.Abstractions.1.1.2\lib\net451\Microsoft.AspNetCore.Http.Abstractions.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Html.Abstractions.1.1.2/lib/netstandard1.0/Microsoft.AspNetCore.Html.Abstractions.dll /r:${testdir}/../../../../../packages/Microsoft.AspNetCore.Http.Features.1.1.2\lib\net451\Microsoft.AspNetCore.Http.Features.dll /r:${testdir}/../../../../../packages\Microsoft.Extensions.Primitives.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll /r:System.Linq.dll /r:System.Linq.Expressions.dll /r:System.Linq.Queryable.dll

View File

@@ -30,7 +30,7 @@
.. [1] C++20 support is currently in beta. Supported for GCC on Linux only. Modules are *not* supported.
.. [2] Support for the clang-cl compiler is preliminary.
.. [3] Support for the Arm Compiler (armcc) is preliminary.
.. [4] Builds that execute on Java 7 to 18 can be analyzed. The analysis understands Java 18 standard language features.
.. [4] Builds that execute on Java 7 to 19 can be analyzed. The analysis understands Java 19 standard language features.
.. [5] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin.
.. [6] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files.
.. [7] Requires glibc 2.17.

View File

@@ -28,12 +28,12 @@ class AstNode extends @node, Locatable {
/**
* Gets a child node of this node.
*/
AstNode getAChild() { result = getChild(_) }
AstNode getAChild() { result = this.getChild(_) }
/**
* Gets the number of child nodes of this node.
*/
int getNumChild() { result = count(getAChild()) }
int getNumChild() { result = count(this.getAChild()) }
/**
* Gets a child with the given index and of the given kind, if one exists.
@@ -63,7 +63,7 @@ class AstNode extends @node, Locatable {
AstNode getUniquelyNumberedChild(int index) {
result =
rank[index + 1](AstNode child, string kind, int i |
child = getChildOfKind(kind, i)
child = this.getChildOfKind(kind, i)
|
child order by kind, i
)
@@ -74,17 +74,17 @@ class AstNode extends @node, Locatable {
/** Gets the parent node of this AST node, but without crossing function boundaries. */
private AstNode parentInSameFunction() {
result = getParent() and
result = this.getParent() and
not this instanceof FuncDef
}
/** Gets the innermost function definition to which this AST node belongs, if any. */
FuncDef getEnclosingFunction() { result = getParent().parentInSameFunction*() }
FuncDef getEnclosingFunction() { result = this.getParent().parentInSameFunction*() }
/**
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
*/
final string getPrimaryQlClasses() { result = concat(getAPrimaryQlClass(), ",") }
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
/**
* Gets the name of a primary CodeQL class to which this node belongs.
@@ -116,12 +116,12 @@ class ExprParent extends @exprparent, AstNode {
/**
* Gets an expression that is a child node of this node in the AST.
*/
Expr getAChildExpr() { result = getChildExpr(_) }
Expr getAChildExpr() { result = this.getChildExpr(_) }
/**
* Gets the number of child expressions of this node.
*/
int getNumChildExpr() { result = count(getAChildExpr()) }
int getNumChildExpr() { result = count(this.getAChildExpr()) }
}
/**
@@ -139,12 +139,12 @@ class GoModExprParent extends @modexprparent, AstNode {
/**
* Gets an expression that is a child node of this node in the AST.
*/
GoModExpr getAChildGoModExpr() { result = getChildGoModExpr(_) }
GoModExpr getAChildGoModExpr() { result = this.getChildGoModExpr(_) }
/**
* Gets the number of child expressions of this node.
*/
int getNumChildGoModExpr() { result = count(getAChildGoModExpr()) }
int getNumChildGoModExpr() { result = count(this.getAChildGoModExpr()) }
}
/**
@@ -162,12 +162,12 @@ class StmtParent extends @stmtparent, AstNode {
/**
* Gets a statement that is a child node of this node in the AST.
*/
Stmt getAChildStmt() { result = getChildStmt(_) }
Stmt getAChildStmt() { result = this.getChildStmt(_) }
/**
* Gets the number of child statements of this node.
*/
int getNumChildStmt() { result = count(getAChildStmt()) }
int getNumChildStmt() { result = count(this.getAChildStmt()) }
}
/**
@@ -185,12 +185,12 @@ class DeclParent extends @declparent, AstNode {
/**
* Gets a child declaration of this node in the AST.
*/
Decl getADecl() { result = getDecl(_) }
Decl getADecl() { result = this.getDecl(_) }
/**
* Gets the number of child declarations of this node.
*/
int getNumDecl() { result = count(getADecl()) }
int getNumDecl() { result = count(this.getADecl()) }
}
/**
@@ -208,12 +208,12 @@ class FieldParent extends @fieldparent, AstNode {
/**
* Gets a child field of this node in the AST.
*/
FieldBase getAField() { result = getField(_) }
FieldBase getAField() { result = this.getField(_) }
/**
* Gets the number of child fields of this node.
*/
int getNumFields() { result = count(getAField()) }
int getNumFields() { result = count(this.getAField()) }
}
/**

View File

@@ -787,7 +787,7 @@ class InterfaceType extends @interfacetype, CompositeType {
* Note that the indexes are not contiguous.
*/
TypeSetLiteralType getDirectlyEmbeddedTypeSetLiteral(int index) {
hasDirectlyEmbeddedType(index, result)
this.hasDirectlyEmbeddedType(index, result)
}
/**
@@ -798,7 +798,7 @@ class InterfaceType extends @interfacetype, CompositeType {
TypeSetLiteralType getAnEmbeddedTypeSetLiteral() {
result = this.getDirectlyEmbeddedTypeSetLiteral(_) or
result =
getADirectlyEmbeddedInterface()
this.getADirectlyEmbeddedInterface()
.getUnderlyingType()
.(InterfaceType)
.getAnEmbeddedTypeSetLiteral()

View File

@@ -166,21 +166,11 @@ module ControlFlow {
)
}
/**
* Holds if this node writes `rhs` to `channel`.
*/
predicate writesToChannel(DataFlow::ExprNode channel, DataFlow::ExprNode rhs) {
exists(SendStmt send |
send.getChannel() = channel.asExpr() and
send.getValue() = rhs.asExpr()
)
}
/**
* Holds if this node sets any field or element of `base` to `rhs`.
*/
predicate writesComponent(DataFlow::Node base, DataFlow::Node rhs) {
writesElement(base, _, rhs) or writesField(base, _, rhs) or writesToChannel(base, rhs)
writesElement(base, _, rhs) or writesField(base, _, rhs)
}
}

View File

@@ -24,7 +24,9 @@ predicate containerStoreStep(Node node1, Node node2, Content c) {
)
or
c instanceof CollectionContent and
exists(Write w | w.writesToChannel(node2, node1))
exists(SendStmt send |
send.getChannel() = node2.(ExprNode).asExpr() and send.getValue() = node1.(ExprNode).asExpr()
)
or
c instanceof MapKeyContent and
node2.getType() instanceof MapType and

View File

@@ -634,7 +634,10 @@ module Public {
predicate isReceiverOf(MethodDecl m) { parm.isReceiverOf(m) }
}
private Node getADirectlyWrittenNode() { exists(Write w | w.writesComponent(result, _)) }
private Node getADirectlyWrittenNode() {
exists(Write w | w.writesComponent(result, _)) or
result = DataFlow::exprNode(any(SendStmt s).getChannel())
}
private DataFlow::Node getAccessPathPredecessor(DataFlow::Node node) {
result = node.(PointerDereferenceNode).getOperand()

View File

@@ -3,7 +3,6 @@
*/
import go
private import semmle.go.StringOps
/**
* Provides classes for working with concepts relating to the [github.com/elazarl/goproxy](https://pkg.go.dev/github.com/elazarl/goproxy) package.

View File

@@ -4,7 +4,6 @@
*/
import go
private import semmle.go.StringOps
/**
* Provides models of commonly used functions in the `github.com/golang/glog` packages and its

View File

@@ -1,7 +1,6 @@
/** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */
import go
private import semmle.go.StringOps
/** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */
module Logrus {

View File

@@ -3,7 +3,6 @@
*/
import go
private import semmle.go.StringOps
/**
* Provides models of commonly used functions in the `github.com/davecgh/go-spew/spew` package.

View File

@@ -3,7 +3,6 @@
*/
import go
private import semmle.go.StringOps
/**
* Provides models of commonly used functions in the `go.uber.org/zap` package.

View File

@@ -3,7 +3,6 @@
*/
import go
private import semmle.go.StringOps
/** Provides models of commonly used functions in the `fmt` package. */
module Fmt {

View File

@@ -3,7 +3,6 @@
*/
import go
private import semmle.go.StringOps
/** Provides models of commonly used functions in the `log` package. */
module Log {

View File

@@ -4,7 +4,6 @@
*/
import go
private import semmle.go.StringOps
/**
* Provides extension points for customizing the data-flow tracking configuration for reasoning

View File

@@ -9,7 +9,6 @@
*/
import go
import semmle.go.frameworks.SQL
from DataFlow::MethodCallNode call
where

View File

@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
override Location getLocation() { result = comment.getLocation() }
}
private predicate onSameLine(ValidExpectation a, ActualResult b) {
exists(string fname, int line, Location la, Location lb |
// Join order intent:
// Take the locations of ActualResults,
// join with locations in the same file / on the same line,
// then match those against ValidExpectations.
la = a.getLocation() and
pragma[only_bind_into](lb) = b.getLocation() and
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
lb.hasLocationInfo(fname, line, _, _, _)
)
}
private class ValidExpectation extends Expectation, TValidExpectation {
string tag;
string value;
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
string getKnownFailure() { result = knownFailure }
predicate matchesActualResult(ActualResult actualResult) {
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
getLocation().getFile() = actualResult.getLocation().getFile() and
onSameLine(pragma[only_bind_into](this), actualResult) and
getTag() = actualResult.getTag() and
getValue() = actualResult.getValue()
}

View File

@@ -0,0 +1,22 @@
edges
| test.go:9:9:9:11 | selection of c [collection] : string | test.go:9:7:9:11 | <-... |
| test.go:13:16:13:16 | definition of s [pointer, c, collection] : string | test.go:16:2:16:2 | s [pointer, c, collection] : string |
| test.go:15:10:15:17 | call to source : string | test.go:16:9:16:12 | data : string |
| test.go:16:2:16:2 | implicit dereference [c, collection] : string | test.go:13:16:13:16 | definition of s [pointer, c, collection] : string |
| test.go:16:2:16:2 | implicit dereference [c, collection] : string | test.go:16:2:16:4 | selection of c [collection] : string |
| test.go:16:2:16:2 | s [pointer, c, collection] : string | test.go:16:2:16:2 | implicit dereference [c, collection] : string |
| test.go:16:2:16:4 | selection of c [collection] : string | test.go:9:9:9:11 | selection of c [collection] : string |
| test.go:16:2:16:4 | selection of c [collection] : string | test.go:16:2:16:2 | implicit dereference [c, collection] : string |
| test.go:16:9:16:12 | data : string | test.go:16:2:16:4 | selection of c [collection] : string |
nodes
| test.go:9:7:9:11 | <-... | semmle.label | <-... |
| test.go:9:9:9:11 | selection of c [collection] : string | semmle.label | selection of c [collection] : string |
| test.go:13:16:13:16 | definition of s [pointer, c, collection] : string | semmle.label | definition of s [pointer, c, collection] : string |
| test.go:15:10:15:17 | call to source : string | semmle.label | call to source : string |
| test.go:16:2:16:2 | implicit dereference [c, collection] : string | semmle.label | implicit dereference [c, collection] : string |
| test.go:16:2:16:2 | s [pointer, c, collection] : string | semmle.label | s [pointer, c, collection] : string |
| test.go:16:2:16:4 | selection of c [collection] : string | semmle.label | selection of c [collection] : string |
| test.go:16:9:16:12 | data : string | semmle.label | data : string |
subpaths
#select
| test.go:15:10:15:17 | call to source : string | test.go:15:10:15:17 | call to source : string | test.go:9:7:9:11 | <-... | path |

View File

@@ -0,0 +1,26 @@
package test
type State struct {
c chan string
}
func handler(s *State) {
sink(<-s.c)
}
func requester(s *State) {
data := source()
s.c <- data
}
func source() string {
return "tainted"
}
func sink(s string) {}

View File

@@ -0,0 +1,18 @@
import go
import DataFlow::PathGraph
class TestConfig extends DataFlow::Configuration {
TestConfig() { this = "test config" }
override predicate isSource(DataFlow::Node source) {
source.(DataFlow::CallNode).getTarget().getName() = "source"
}
override predicate isSink(DataFlow::Node sink) {
sink = any(DataFlow::CallNode c | c.getTarget().getName() = "sink").getAnArgument()
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, TestConfig c
where c.hasFlowPath(source, sink)
select source, source, sink, "path"

View File

@@ -3,7 +3,6 @@
*/
import go
import semmle.go.dataflow.DataFlow
import semmle.go.dataflow.ExternalFlow
import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import CsvValidation

View File

@@ -1,5 +1,4 @@
import go
import semmle.go.dataflow.DataFlow
import semmle.go.dataflow.ExternalFlow
import CsvValidation

View File

@@ -1,5 +1,4 @@
import go
import semmle.go.dataflow.DataFlow
import semmle.go.dataflow.ExternalFlow
import CsvValidation

View File

@@ -1,5 +1,4 @@
import go
import semmle.go.dataflow.DataFlow
import semmle.go.dataflow.ExternalFlow
import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import CsvValidation

View File

@@ -1,5 +1,4 @@
import go
import semmle.go.frameworks.WebSocket
from WebSocketReader r, DataFlow::Node nd
where nd = r.getAnOutput().getNode(r.getACall())

View File

@@ -30,9 +30,22 @@ sourceSets {
// change the excludes for building with other versions.
// Currently 1.7.0 is configured:
excludes = [
"utils/versions/v_1_4_32/*.kt",
"utils/versions/v_1_5_21/Descriptors.kt",
"utils/versions/v_1_6_10/Descriptors.kt",
// For 1.7.20-Beta, the below two files should be included, and the corresponding v_1_7_20-Beta ones should be excluded from this list.
//"utils/versions/v_1_4_32/allOverriddenIncludingSelf.kt",
//"utils/versions/v_1_4_32/createImplicitParameterDeclarationWithWrappedDescriptor.kt",
"utils/versions/v_1_4_32/Descriptors.kt",
"utils/versions/v_1_4_32/FileEntry.kt",
"utils/versions/v_1_4_32/Functions.kt",
"utils/versions/v_1_4_32/IsUnderscoreParameter.kt",
"utils/versions/v_1_4_32/Psi2Ir.kt",
"utils/versions/v_1_4_32/Types.kt",
"utils/versions/v_1_4_32/withHasQuestionMark.kt",
"utils/versions/v_1_5_20/Descriptors.kt",
"utils/versions/v_1_6_0/Descriptors.kt",
"utils/versions/v_1_7_20-Beta/createImplicitParameterDeclarationWithWrappedDescriptor.kt",
"utils/versions/v_1_7_20-Beta/allOverriddenIncludingSelf.kt",
]
}
}

View File

@@ -25,7 +25,7 @@ def version_string_to_tuple(version):
ci_version = '1.7.0'
# Version numbers in the list need to be in semantically increasing order
many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.21', '1.5.31', '1.6.10', '1.6.20', '1.7.0' ]
many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.20', '1.5.30', '1.6.0', '1.6.20', '1.7.0', '1.7.20-Beta' ]
many_versions_tuples = [version_string_to_tuple(v) for v in many_versions]

View File

@@ -4150,7 +4150,12 @@ open class KotlinFileExtractor(
startIndex: Int = 0,
reverse: Boolean = false
) {
extractTypeArguments((0 until c.typeArgumentsCount).map { c.getTypeArgument(it)!! }, tw.getLocation(c), parentExpr, enclosingCallable, enclosingStmt, startIndex, reverse)
val typeArguments = (0 until c.typeArgumentsCount).map { c.getTypeArgument(it) }.requireNoNullsOrNull()
if (typeArguments == null) {
logger.errorElement("Found a null type argument for a member access expression", c)
} else {
extractTypeArguments(typeArguments, tw.getLocation(c), parentExpr, enclosingCallable, enclosingStmt, startIndex, reverse)
}
}
private fun extractArrayCreationWithInitializer(

View File

@@ -5,12 +5,10 @@ import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
import com.github.codeql.utils.versions.isRawType
import com.semmle.extractor.java.OdasaOutput
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.allOverridden
import org.jetbrains.kotlin.backend.common.ir.isFinalClass
import org.jetbrains.kotlin.backend.common.ir.*
import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
@@ -26,7 +24,6 @@ import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.types.Variance

View File

@@ -1,6 +1,6 @@
package com.github.codeql.utils
import org.jetbrains.kotlin.backend.common.ir.allOverridden
import com.github.codeql.utils.versions.allOverriddenIncludingSelf
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
import org.jetbrains.kotlin.ir.declarations.IrClass
@@ -59,7 +59,7 @@ private val specialFunctionShortNames = specialFunctions.keys.map { it.functionN
private fun getSpecialJvmName(f: IrFunction): String? {
if (specialFunctionShortNames.contains(f.name) && f is IrSimpleFunction) {
f.allOverridden(true).forEach { overriddenFunc ->
f.allOverriddenIncludingSelf().forEach { overriddenFunc ->
overriddenFunc.parentClassOrNull?.fqNameWhenAvailable?.let { parentFqName ->
specialFunctions[MethodKey(parentFqName, f.name)]?.let {
return it

View File

@@ -3,8 +3,8 @@ package com.github.codeql.utils
import com.github.codeql.KotlinUsesExtractor
import com.github.codeql.getJavaEquivalentClassId
import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.classId
import org.jetbrains.kotlin.ir.util.constructedClassType
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance

View File

@@ -0,0 +1,6 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.backend.common.ir.allOverridden
fun IrSimpleFunction.allOverriddenIncludingSelf() = this.allOverridden(includeSelf = true)

View File

@@ -0,0 +1,6 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
fun IrClass.createImplicitParameterDeclarationWithWrappedDescriptor() = this.createImplicitParameterDeclarationWithWrappedDescriptor()

View File

@@ -0,0 +1,6 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.allOverridden
fun IrSimpleFunction.allOverriddenIncludingSelf() = this.allOverridden(includeSelf = true)

View File

@@ -0,0 +1,6 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.util.createImplicitParameterDeclarationWithWrappedDescriptor
fun IrClass.createImplicitParameterDeclarationWithWrappedDescriptor() = this.createImplicitParameterDeclarationWithWrappedDescriptor()

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Java 19 builds can now be extracted. There are no non-preview new language features in this release, so the only user-visible change is that the CodeQL extractor will now correctly trace compilations using the JDK 19 release of `javac`.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Classes and methods that are seen with several different paths during the extraction process (for example, packaged into different JAR files) now report an arbitrarily selected location via their `getLocation` and `hasLocationInfo` predicates, rather than reporting all of them. This may lead to reduced alert duplication.

View File

@@ -205,5 +205,19 @@ cached
private predicate fixedHasLocation(Top l, Location loc, File f) {
hasSourceLocation(l, loc, f)
or
hasLocation(l, loc) and not hasSourceLocation(l, _, _) and locations_default(loc, f, _, _, _, _)
// When an entity has more than one location, as it might due to
// e.g. a parameterized generic being seen and extracted in several
// different directories or JAR files, select an arbitrary representative
// location to avoid needlessly duplicating alerts.
//
// Don't do this when the relevant location is in a source file, because
// that is much more unusual and we would rather notice the bug than mask it here.
loc =
min(Location candidateLoc |
hasLocation(l, candidateLoc)
|
candidateLoc order by candidateLoc.getFile().toString()
) and
not hasSourceLocation(l, _, _) and
locations_default(loc, f, _, _, _, _)
}

View File

@@ -9,21 +9,23 @@ private import semmle.code.java.frameworks.android.Android
* The class `android.database.sqlite.SQLiteDatabase`.
*/
class TypeSQLiteDatabase extends Class {
TypeSQLiteDatabase() { hasQualifiedName("android.database.sqlite", "SQLiteDatabase") }
TypeSQLiteDatabase() { this.hasQualifiedName("android.database.sqlite", "SQLiteDatabase") }
}
/**
* The class `android.database.sqlite.SQLiteQueryBuilder`.
*/
class TypeSQLiteQueryBuilder extends Class {
TypeSQLiteQueryBuilder() { hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder") }
TypeSQLiteQueryBuilder() {
this.hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder")
}
}
/**
* The class `android.database.DatabaseUtils`.
*/
class TypeDatabaseUtils extends Class {
TypeDatabaseUtils() { hasQualifiedName("android.database", "DatabaseUtils") }
TypeDatabaseUtils() { this.hasQualifiedName("android.database", "DatabaseUtils") }
}
/**

View File

@@ -53,7 +53,7 @@ private class FileSetRedableMethodAccess extends MethodAccess {
private predicate isCallToSecondArgumentWithValue(boolean value) {
this.getMethod().getNumberOfParameters() = 1 and value = true
or
isCallWithArgument(1, value)
this.isCallWithArgument(1, value)
}
private predicate isCallWithArgument(int index, boolean arg) {

View File

@@ -23,7 +23,8 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr()
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr() and
sink.asExpr() instanceof VarAccess
}
override predicate isSanitizer(DataFlow::Node node) {
@@ -31,18 +32,17 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration {
castCheck(node.asExpr()) or
node.getType() instanceof SmallType or
smallExpr(node.asExpr()) or
node.getEnclosingCallable() instanceof HashCodeMethod
node.getEnclosingCallable() instanceof HashCodeMethod or
exists(RightShiftOp e | e.getShiftedVariable().getAnAccess() = node.asExpr())
}
}
from
DataFlow::PathNode source, DataFlow::PathNode sink, NumericNarrowingCastExpr exp,
VarAccess tainted, NumericCastFlowConfig conf
NumericCastFlowConfig conf
where
exp.getExpr() = tainted and
sink.getNode().asExpr() = tainted and
conf.hasFlowPath(source, sink) and
not exists(RightShiftOp e | e.getShiftedVariable() = tainted.getVariable())
sink.getNode().asExpr() = exp.getExpr() and
conf.hasFlowPath(source, sink)
select exp, source, sink,
"$@ flows to here and is cast to a narrower type, potentially causing truncation.",
source.getNode(), "User-provided value"

View File

@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
override Location getLocation() { result = comment.getLocation() }
}
private predicate onSameLine(ValidExpectation a, ActualResult b) {
exists(string fname, int line, Location la, Location lb |
// Join order intent:
// Take the locations of ActualResults,
// join with locations in the same file / on the same line,
// then match those against ValidExpectations.
la = a.getLocation() and
pragma[only_bind_into](lb) = b.getLocation() and
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
lb.hasLocationInfo(fname, line, _, _, _)
)
}
private class ValidExpectation extends Expectation, TValidExpectation {
string tag;
string value;
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
string getKnownFailure() { result = knownFailure }
predicate matchesActualResult(ActualResult actualResult) {
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
getLocation().getFile() = actualResult.getLocation().getFile() and
onSameLine(pragma[only_bind_into](this), actualResult) and
getTag() = actualResult.getTag() and
getValue() = actualResult.getValue()
}

View File

@@ -1,2 +1 @@
| A.kt:4:21:4:29 | someFun(...) | file:///!unknown-binary-location/OC$C.class:0:0:0:0 | someFun | file:///!unknown-binary-location/OC$C.class:0:0:0:0 | C<D1,D2,E1,E2> | OC.class:0:0:0:0 | OC<F1,F2> |
| A.kt:4:21:4:29 | someFun(...) | file:///!unknown-binary-location/OC$C.class:0:0:0:0 | someFun | file:///!unknown-binary-location/OC$C.class:0:0:0:0 | C<D1,D2,E1,E2> | file:///!unknown-binary-location/OC.class:0:0:0:0 | OC<F1,F2> |

View File

@@ -234,8 +234,6 @@ class File extends Container, @file {
/** Gets a toplevel piece of JavaScript code in this file. */
TopLevel getATopLevel() { result.getFile() = this }
override string toString() { result = Container.super.toString() }
/** Gets the URL of this file. */
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }

View File

@@ -147,30 +147,22 @@ private string getASrcFolderName() { result = ["ts", "js", "src", "lib"] }
*/
class MainModulePath extends PathExpr, @json_string {
PackageJson pkg;
string relativePath;
MainModulePath() {
relativePath = "." and
this = pkg.getPropValue(["main", "module"])
or
// { "exports": "path" } is sugar for { "exports": { ".": "path" }}
relativePath = "." and
this = pkg.getPropValue("exports")
or
exists(JsonValue val | val = pkg.getPropValue("exports").getPropValue(relativePath) |
// Either specified directly as a string: { "./path": "./path.js" }
this = val
or
// Or by module type: { "./path": { "require": "./path.cjs", ... }}
this = val.getPropValue(_)
)
this = getAPartOfExportsSection(pkg)
}
/** Gets the `package.json` file in which this path occurs. */
PackageJson getPackageJson() { result = pkg }
/** Gets the relative path under which this is exported, usually starting with a `.`. */
string getRelativePath() { result = relativePath }
string getRelativePath() {
result = getExportRelativePath(this)
or
not exists(getExportRelativePath(this)) and result = "."
}
/** DEPRECATED: Alias for getPackageJson */
deprecated PackageJSON getPackageJSON() { result = getPackageJson() }
@@ -183,6 +175,29 @@ class MainModulePath extends PathExpr, @json_string {
}
}
private JsonValue getAPartOfExportsSection(PackageJson pkg) {
result = pkg.getPropValue("exports")
or
result = getAPartOfExportsSection(pkg).getPropValue(_)
}
/** Gets the text of one of the conditions or paths enclosing the given `part` of an `exports` section. */
private string getAnEnclosingExportProperty(JsonValue part) {
exists(JsonObject parent, string prop |
parent = getAPartOfExportsSection(_) and
part = parent.getPropValue(prop)
|
result = prop
or
result = getAnEnclosingExportProperty(parent)
)
}
private string getExportRelativePath(JsonValue part) {
result = getAnEnclosingExportProperty(part) and
result.matches(".%")
}
module MainModulePath {
/** Gets the path to the main entry point of `pkg`. */
MainModulePath of(PackageJson pkg) { result = of(pkg, ".") }

View File

@@ -43,8 +43,6 @@ abstract private class BracketedListOfExpressions extends Expr {
* An array expression viewed as a bracketed list of expressions.
*/
private class ArrayExprIsABracketedListOfExpressions extends ArrayExpr, BracketedListOfExpressions {
override predicate isImpure() { ArrayExpr.super.isImpure() }
/** Gets the `i`th element of this array literal. */
override Expr getElement(int i) { result = ArrayExpr.super.getElement(i) }
}

View File

@@ -17,4 +17,4 @@
"peerDependencies": {
"tea": "2.x"
}
}
}

View File

@@ -2,8 +2,6 @@ import semmle.javascript.frameworks.Testing
class MyTest extends Test, CallExpr {
MyTest() { getCallee().(VarAccess).getName() = "mytest" }
override string toString() { result = CallExpr.super.toString() }
}
from Test t

View File

@@ -68,8 +68,6 @@ class ListComp extends ListComp_, Comp {
override Expr getIterable() { result = ListComp_.super.getIterable() }
override string toString() { result = ListComp_.super.toString() }
override Expr getElt() { result = Comp.super.getElt() }
}

View File

@@ -616,6 +616,9 @@ private string non_byte_prefix() {
not result.charAt(_) in ["b", "B"]
}
/** A string constant. This is a placeholder class -- use `StrConst` instead. */
class Str = StrConst;
/** A string constant. */
class StrConst extends Str_, ImmutableLiteral {
/* syntax: "hello" */

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