mirror of
https://github.com/github/codeql.git
synced 2026-07-20 10:48:17 +02:00
Merge remote-tracking branch 'upstream/master' into detect-conflated-memory
Conflicts: cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected cpp/ql/test/library-tests/ir/ir/raw_sanity.expected cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected
This commit is contained in:
@@ -21,6 +21,7 @@ The following changes in version 1.24 affect C# analysis in all applications.
|
||||
| Potentially dangerous use of non-short-circuit logic (`cs/non-short-circuit`) | Fewer false positive results | Results have been removed when the expression contains an `out` parameter. |
|
||||
| Dereferenced variable may be null (`cs/dereferenced-value-may-be-null`) | More results | Results are reported from parameters with a default value of `null`. |
|
||||
| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the value assigned is an (implicitly or explicitly) cast default-like value. For example, `var s = (string)null` and `string s = default`. |
|
||||
| XPath injection (`cs/xml/xpath-injection`) | More results | The query now recognizes calls to methods on `System.Xml.XPath.XPathNavigator` objects. |
|
||||
|
||||
## Removal of old queries
|
||||
|
||||
|
||||
@@ -6,16 +6,18 @@
|
||||
|
||||
* Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`).
|
||||
|
||||
* Imports with the `.js` extension can now be resolved to a TypeScript file,
|
||||
* Resolution of imports has improved, leading to more results from the security queries:
|
||||
- Imports with the `.js` extension can now be resolved to a TypeScript file,
|
||||
when the import refers to a file generated by TypeScript.
|
||||
- Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved.
|
||||
- Export declarations of the form `export * as ns from "x"` are now analyzed more precisely.
|
||||
|
||||
* Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved.
|
||||
* The analysis of sanitizers has improved, leading to more accurate results from the security queries.
|
||||
In particular:
|
||||
- Sanitizer guards now act across function boundaries in more cases.
|
||||
- Sanitizers can now better distinguish between a tainted value and an object _containing_ a tainted value.
|
||||
|
||||
* Export declarations of the form `export * as ns from "x"` are now analyzed more precisely.
|
||||
|
||||
* The analysis of sanitizer guards has improved, leading to fewer false-positive results from the security queries.
|
||||
|
||||
* The call graph construction has been improved, leading to more results from the security queries:
|
||||
* Call graph construction has been improved, leading to more results from the security queries:
|
||||
- Calls can now be resolved to indirectly-defined class members in more cases.
|
||||
- Calls through partial invocations such as `.bind` can now be resolved in more cases.
|
||||
|
||||
@@ -80,8 +82,14 @@
|
||||
| Use of password hash with insufficient computational effort (`js/insufficient-password-hash`) | Fewer false positive results | This query now recognizes additional cases that do not require secure hashing. |
|
||||
| Useless regular-expression character escape (`js/useless-regexp-character-escape`) | Fewer false positive results | This query now distinguishes escapes in strings and regular expression literals. |
|
||||
| Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. |
|
||||
| Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. |
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* The predicates `RegExpTerm.getSuccessor` and `RegExpTerm.getPredecessor` have been changed to reflect textual, not operational, matching order. This only makes a difference in lookbehind assertions, which are operationally matched backwards. Previously, `getSuccessor` would mimick this, so in an assertion `(?<=ab)` the term `b` would be considered the predecessor, not the successor, of `a`. Textually, however, `a` is still matched before `b`, and this is the order we now follow.
|
||||
* An extensible model of the `EventEmitter` pattern has been implemented.
|
||||
* Taint-tracking configurations now interact differently with the `data` flow label, which may affect queries
|
||||
that combine taint-tracking and flow labels.
|
||||
- Sources added by the 1-argument `isSource` predicate are associated with the `taint` label now, instead of the `data` label.
|
||||
- Sanitizers now only block the `taint` label. As a result, sanitizers no longer block the flow of tainted values wrapped inside a property of an object.
|
||||
To retain the old behavior, instead use a barrier, or block the `data` flow label using a labeled sanitizer.
|
||||
|
||||
@@ -4,6 +4,8 @@ The following changes in version 1.24 affect Python analysis in all applications
|
||||
|
||||
## General improvements
|
||||
|
||||
Support for Django version 2.x and 3.x
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
@@ -13,6 +15,7 @@ The following changes in version 1.24 affect Python analysis in all applications
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
| Uncontrolled command line (`py/command-line-injection`) | More results | We now model the `fabric` and `invoke` pacakges for command execution. |
|
||||
|
||||
### Web framework support
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -243,7 +243,7 @@ private module Cached {
|
||||
* - Types are checked using the `compatibleTypes()` relation.
|
||||
*/
|
||||
cached
|
||||
module Final {
|
||||
private module Final {
|
||||
/**
|
||||
* Holds if `p` can flow to `node` in the same callable using only
|
||||
* value-preserving steps, not taking call contexts into account.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,22 @@ abstract class BuiltInOperation extends Expr {
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperation" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ built-in operation that is used to support functions with variable numbers of arguments.
|
||||
* This includes `va_start`, `va_end`, `va_copy`, and `va_arg`.
|
||||
*/
|
||||
class VarArgsExpr extends BuiltInOperation {
|
||||
VarArgsExpr() {
|
||||
this instanceof BuiltInVarArgsStart
|
||||
or
|
||||
this instanceof BuiltInVarArgsEnd
|
||||
or
|
||||
this instanceof BuiltInVarArg
|
||||
or
|
||||
this instanceof BuiltInVarArgCopy
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ `__builtin_va_start` built-in operation (used by some
|
||||
* implementations of `va_start`).
|
||||
@@ -20,6 +36,16 @@ class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr {
|
||||
override string toString() { result = "__builtin_va_start" }
|
||||
|
||||
override string getCanonicalQLClass() { result = "BuiltInVarArgsStart" }
|
||||
|
||||
/**
|
||||
* Gets the `va_list` argument.
|
||||
*/
|
||||
final Expr getVAList() { result = getChild(0) }
|
||||
|
||||
/**
|
||||
* Gets the argument that specifies the last named parameter before the ellipsis.
|
||||
*/
|
||||
final VariableAccess getLastNamedParameter() { result = getChild(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,6 +61,11 @@ class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr {
|
||||
override string toString() { result = "__builtin_va_end" }
|
||||
|
||||
override string getCanonicalQLClass() { result = "BuiltInVarArgsEnd" }
|
||||
|
||||
/**
|
||||
* Gets the `va_list` argument.
|
||||
*/
|
||||
final Expr getVAList() { result = getChild(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,6 +79,11 @@ class BuiltInVarArg extends BuiltInOperation, @vaargexpr {
|
||||
override string toString() { result = "__builtin_va_arg" }
|
||||
|
||||
override string getCanonicalQLClass() { result = "BuiltInVarArg" }
|
||||
|
||||
/**
|
||||
* Gets the `va_list` argument.
|
||||
*/
|
||||
final Expr getVAList() { result = getChild(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,6 +99,16 @@ class BuiltInVarArgCopy extends BuiltInOperation, @vacopyexpr {
|
||||
override string toString() { result = "__builtin_va_copy" }
|
||||
|
||||
override string getCanonicalQLClass() { result = "BuiltInVarArgCopy" }
|
||||
|
||||
/**
|
||||
* Gets the destination `va_list` argument.
|
||||
*/
|
||||
final Expr getDestinationVAList() { result = getChild(0) }
|
||||
|
||||
/**
|
||||
* Gets the the source `va_list` argument.
|
||||
*/
|
||||
final Expr getSourceVAList() { result = getChild(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -243,7 +243,7 @@ private module Cached {
|
||||
* - Types are checked using the `compatibleTypes()` relation.
|
||||
*/
|
||||
cached
|
||||
module Final {
|
||||
private module Final {
|
||||
/**
|
||||
* Holds if `p` can flow to `node` in the same callable using only
|
||||
* value-preserving steps, not taking call contexts into account.
|
||||
|
||||
@@ -70,7 +70,7 @@ private newtype TOpcode =
|
||||
TVarArgsStart() or
|
||||
TVarArgsEnd() or
|
||||
TVarArg() or
|
||||
TVarArgCopy() or
|
||||
TNextVarArg() or
|
||||
TCallSideEffect() or
|
||||
TCallReadSideEffect() or
|
||||
TIndirectReadSideEffect() or
|
||||
@@ -629,20 +629,20 @@ module Opcode {
|
||||
final override string toString() { result = "BuiltIn" }
|
||||
}
|
||||
|
||||
class VarArgsStart extends BuiltInOperationOpcode, TVarArgsStart {
|
||||
class VarArgsStart extends UnaryOpcode, TVarArgsStart {
|
||||
final override string toString() { result = "VarArgsStart" }
|
||||
}
|
||||
|
||||
class VarArgsEnd extends BuiltInOperationOpcode, TVarArgsEnd {
|
||||
class VarArgsEnd extends UnaryOpcode, TVarArgsEnd {
|
||||
final override string toString() { result = "VarArgsEnd" }
|
||||
}
|
||||
|
||||
class VarArg extends BuiltInOperationOpcode, TVarArg {
|
||||
class VarArg extends UnaryOpcode, TVarArg {
|
||||
final override string toString() { result = "VarArg" }
|
||||
}
|
||||
|
||||
class VarArgCopy extends BuiltInOperationOpcode, TVarArgCopy {
|
||||
final override string toString() { result = "VarArgCopy" }
|
||||
class NextVarArg extends UnaryOpcode, TNextVarArg {
|
||||
final override string toString() { result = "NextVarArg" }
|
||||
}
|
||||
|
||||
class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode,
|
||||
|
||||
@@ -5,6 +5,7 @@ import IRTypeSanity // module is in IRType.qll
|
||||
module InstructionSanity {
|
||||
private import internal.InstructionImports as Imports
|
||||
private import Imports::OperandTag
|
||||
private import Imports::Overlap
|
||||
private import internal.IRInternal
|
||||
|
||||
/**
|
||||
@@ -302,4 +303,18 @@ module InstructionSanity {
|
||||
instr.isResultConflated() and
|
||||
not shouldBeConflated(instr)
|
||||
}
|
||||
|
||||
query predicate invalidOverlap(
|
||||
MemoryOperand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(Overlap overlap |
|
||||
overlap = useOperand.getDefinitionOverlap() and
|
||||
overlap instanceof MayPartiallyOverlap and
|
||||
message =
|
||||
"MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" +
|
||||
overlap.toString() + "'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,6 +384,8 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
override string toString() { result = "SideEffect" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,3 +3,4 @@ import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
|
||||
@@ -107,14 +107,15 @@ private module Cached {
|
||||
oldOperand instanceof OldIR::NonPhiMemoryOperand and
|
||||
exists(
|
||||
OldBlock useBlock, int useRank, Alias::MemoryLocation useLocation,
|
||||
Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset
|
||||
Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset,
|
||||
Alias::MemoryLocation actualDefLocation
|
||||
|
|
||||
useLocation = Alias::getOperandMemoryLocation(oldOperand) and
|
||||
hasUseAtRank(useLocation, useBlock, useRank, oldInstruction) and
|
||||
definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank) and
|
||||
hasDefinitionAtRank(useLocation, defLocation, defBlock, defRank, defOffset) and
|
||||
instr = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, _) and
|
||||
overlap = Alias::getOverlap(defLocation, useLocation)
|
||||
instr = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import IRTypeSanity // module is in IRType.qll
|
||||
module InstructionSanity {
|
||||
private import internal.InstructionImports as Imports
|
||||
private import Imports::OperandTag
|
||||
private import Imports::Overlap
|
||||
private import internal.IRInternal
|
||||
|
||||
/**
|
||||
@@ -302,4 +303,18 @@ module InstructionSanity {
|
||||
instr.isResultConflated() and
|
||||
not shouldBeConflated(instr)
|
||||
}
|
||||
|
||||
query predicate invalidOverlap(
|
||||
MemoryOperand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(Overlap overlap |
|
||||
overlap = useOperand.getDefinitionOverlap() and
|
||||
overlap instanceof MayPartiallyOverlap and
|
||||
message =
|
||||
"MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" +
|
||||
overlap.toString() + "'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,6 +384,8 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
override string toString() { result = "SideEffect" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,3 +3,4 @@ import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
|
||||
@@ -64,6 +64,13 @@ newtype TInstructionTag =
|
||||
InitializerElementAddressTag() or
|
||||
InitializerElementDefaultValueTag() or
|
||||
InitializerElementDefaultValueStoreTag() or
|
||||
VarArgsStartEllipsisAddressTag() or
|
||||
VarArgsStartTag() or
|
||||
VarArgsVAListLoadTag() or
|
||||
VarArgsArgAddressTag() or
|
||||
VarArgsArgLoadTag() or
|
||||
VarArgsMoveNextTag() or
|
||||
VarArgsVAListStoreTag() or
|
||||
AsmTag() or
|
||||
AsmInputTag(int elementIndex) { exists(AsmStmt asm | exists(asm.getChild(elementIndex))) }
|
||||
|
||||
@@ -188,6 +195,20 @@ string getInstructionTagId(TInstructionTag tag) {
|
||||
or
|
||||
tag = InitializerElementDefaultValueStoreTag() and result = "InitElemDefValStore"
|
||||
or
|
||||
tag = VarArgsStartEllipsisAddressTag() and result = "VarArgsStartEllipsisAddr"
|
||||
or
|
||||
tag = VarArgsStartTag() and result = "VarArgsStart"
|
||||
or
|
||||
tag = VarArgsVAListLoadTag() and result = "VarArgsVAListLoad"
|
||||
or
|
||||
tag = VarArgsArgAddressTag() and result = "VarArgsArgAddr"
|
||||
or
|
||||
tag = VarArgsArgLoadTag() and result = "VaArgsArgLoad"
|
||||
or
|
||||
tag = VarArgsMoveNextTag() and result = "VarArgsMoveNext"
|
||||
or
|
||||
tag = VarArgsVAListStoreTag() and result = "VarArgsVAListStore"
|
||||
or
|
||||
tag = AsmTag() and result = "Asm"
|
||||
or
|
||||
exists(int index | tag = AsmInputTag(index) and result = "AsmInputTag(" + index + ")")
|
||||
|
||||
@@ -83,6 +83,10 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
exists(DeleteExpr deleteExpr | deleteExpr.getAllocatorCall() = expr)
|
||||
or
|
||||
exists(DeleteArrayExpr deleteArrayExpr | deleteArrayExpr.getAllocatorCall() = expr)
|
||||
or
|
||||
exists(BuiltInVarArgsStart vaStartExpr |
|
||||
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2020,7 +2020,12 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
||||
override BuiltInOperation expr;
|
||||
|
||||
TranslatedBuiltInOperation() {
|
||||
not expr instanceof BuiltInOperationBuiltInAddressOf // Handled specially
|
||||
// The following expressions are handled specially.
|
||||
not expr instanceof BuiltInOperationBuiltInAddressOf and
|
||||
not expr instanceof BuiltInVarArgsStart and
|
||||
not expr instanceof BuiltInVarArg and
|
||||
not expr instanceof BuiltInVarArgsEnd and
|
||||
not expr instanceof BuiltInVarArgCopy
|
||||
}
|
||||
|
||||
final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
|
||||
@@ -2075,39 +2080,318 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a `BuiltInVarArgsStart` expression.
|
||||
* Holds if the expression `expr` is one of the `va_list` operands to a `va_*` macro.
|
||||
*/
|
||||
class TranslatedVarArgsStart extends TranslatedBuiltInOperation {
|
||||
override BuiltInVarArgsStart expr;
|
||||
|
||||
final override Opcode getOpcode() { result instanceof Opcode::VarArgsStart }
|
||||
private predicate isVAListExpr(Expr expr) {
|
||||
exists(VarArgsExpr parent, Expr originalExpr |
|
||||
(
|
||||
originalExpr = parent.(BuiltInVarArgsStart).getVAList()
|
||||
or
|
||||
originalExpr = parent.(BuiltInVarArgsEnd).getVAList()
|
||||
or
|
||||
originalExpr = parent.(BuiltInVarArg).getVAList()
|
||||
or
|
||||
originalExpr = parent.(BuiltInVarArgCopy).getSourceVAList()
|
||||
or
|
||||
originalExpr = parent.(BuiltInVarArgCopy).getDestinationVAList()
|
||||
) and
|
||||
expr = originalExpr.getFullyConverted()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a `BuiltInVarArgsEnd` expression.
|
||||
* Gets the type of the `va_list` being accessed by `expr`, where `expr` is a `va_list` operand of a
|
||||
* `va_*` macro.
|
||||
*
|
||||
* In the Unix ABI, `va_list` is declared as `typedef struct __va_list_tag va_list[1];`. When used
|
||||
* as the type of a local variable, this gets an implicit array-to-pointer conversion, so that the
|
||||
* actual argument to the `va_*` macro is a prvalue of type `__va_list_tag*`. When used as the type
|
||||
* of a function parameter, the parameter's type decays to `__va_list_tag*`, so that the argument
|
||||
* to the `va_*` macro is still a prvalue of type `__va_list_tag*`, with no implicit conversion
|
||||
* necessary. In either case, we treat `__va_list_tag` as the representative type of the `va_list`.
|
||||
*
|
||||
* In the Windows ABI, `va_list` is declared as a pointer type (usually `char*`). Whether used as
|
||||
* the type of a local variable or of a parameter, this means that the argument to the `va_*` macro
|
||||
* is always an _lvalue_ of type `char*`. We treat `char*` as the representative type of the
|
||||
* `va_list`.
|
||||
*/
|
||||
class TranslatedVarArgsEnd extends TranslatedBuiltInOperation {
|
||||
override BuiltInVarArgsEnd expr;
|
||||
private Type getVAListType(Expr expr) {
|
||||
isVAListExpr(expr) and
|
||||
if expr.isPRValueCategory()
|
||||
then
|
||||
// In the Unix ABI, this will be a prvalue of type `__va_list_tag*`. We want the `__va_list_tag`
|
||||
// type.
|
||||
result = expr.getType().getUnderlyingType().(PointerType).getBaseType()
|
||||
else
|
||||
// In the Windows ABI, this will be an lvalue of some pointer type. We want that pointer type.
|
||||
result = expr.getType()
|
||||
}
|
||||
|
||||
final override Opcode getOpcode() { result instanceof Opcode::VarArgsEnd }
|
||||
/**
|
||||
* The IR translation of a `BuiltInVarArgsStart` expression.
|
||||
*/
|
||||
class TranslatedVarArgsStart extends TranslatedNonConstantExpr {
|
||||
override BuiltInVarArgsStart expr;
|
||||
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = VarArgsStartEllipsisAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getEllipsisVariableGLValueType()
|
||||
or
|
||||
tag = VarArgsStartTag() and
|
||||
opcode instanceof Opcode::VarArgsStart and
|
||||
resultType = getTypeForPRValue(getVAListType(expr.getVAList().getFullyConverted()))
|
||||
or
|
||||
tag = VarArgsVAListStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getTypeForPRValue(getVAListType(expr.getVAList().getFullyConverted()))
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() {
|
||||
result = getInstruction(VarArgsStartEllipsisAddressTag())
|
||||
}
|
||||
|
||||
final override Instruction getResult() { none() }
|
||||
|
||||
final override TranslatedElement getChild(int id) { id = 0 and result = getVAList() }
|
||||
|
||||
private TranslatedExpr getVAList() {
|
||||
result = getTranslatedExpr(expr.getVAList().getFullyConverted())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = VarArgsStartEllipsisAddressTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getInstruction(VarArgsStartTag())
|
||||
or
|
||||
tag = VarArgsStartTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getVAList().getFirstInstruction()
|
||||
or
|
||||
tag = VarArgsVAListStoreTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getVAList() and
|
||||
result = getInstruction(VarArgsVAListStoreTag())
|
||||
}
|
||||
|
||||
final override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = VarArgsStartEllipsisAddressTag() and
|
||||
result = getEnclosingFunction().getEllipsisVariable()
|
||||
}
|
||||
|
||||
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = VarArgsStartTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getInstruction(VarArgsStartEllipsisAddressTag())
|
||||
or
|
||||
tag = VarArgsVAListStoreTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and result = getVAList().getResult()
|
||||
or
|
||||
operandTag instanceof StoreValueOperandTag and result = getInstruction(VarArgsStartTag())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a `BuiltInVarArg` expression.
|
||||
*/
|
||||
class TranslatedVarArg extends TranslatedBuiltInOperation {
|
||||
class TranslatedVarArg extends TranslatedNonConstantExpr {
|
||||
override BuiltInVarArg expr;
|
||||
|
||||
final override Opcode getOpcode() { result instanceof Opcode::VarArg }
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = VarArgsVAListLoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getTypeForPRValue(getVAListType(expr.getVAList().getFullyConverted()))
|
||||
or
|
||||
tag = VarArgsArgAddressTag() and
|
||||
opcode instanceof Opcode::VarArg and
|
||||
resultType = getResultType()
|
||||
or
|
||||
tag = VarArgsMoveNextTag() and
|
||||
opcode instanceof Opcode::NextVarArg and
|
||||
resultType = getTypeForPRValue(getVAListType(expr.getVAList().getFullyConverted()))
|
||||
or
|
||||
tag = VarArgsVAListStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getTypeForPRValue(getVAListType(expr.getVAList().getFullyConverted()))
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getVAList().getFirstInstruction() }
|
||||
|
||||
final override Instruction getResult() { result = getInstruction(VarArgsArgAddressTag()) }
|
||||
|
||||
final override TranslatedElement getChild(int id) { id = 0 and result = getVAList() }
|
||||
|
||||
private TranslatedExpr getVAList() {
|
||||
result = getTranslatedExpr(expr.getVAList().getFullyConverted())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = VarArgsVAListLoadTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getInstruction(VarArgsArgAddressTag())
|
||||
or
|
||||
tag = VarArgsArgAddressTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getInstruction(VarArgsMoveNextTag())
|
||||
or
|
||||
tag = VarArgsMoveNextTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getInstruction(VarArgsVAListStoreTag())
|
||||
or
|
||||
tag = VarArgsVAListStoreTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getVAList() and
|
||||
result = getInstruction(VarArgsVAListLoadTag())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = VarArgsVAListLoadTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getVAList().getResult()
|
||||
or
|
||||
operandTag instanceof LoadOperandTag and
|
||||
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
or
|
||||
tag = VarArgsArgAddressTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getInstruction(VarArgsVAListLoadTag())
|
||||
or
|
||||
tag = VarArgsMoveNextTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getInstruction(VarArgsVAListLoadTag())
|
||||
or
|
||||
tag = VarArgsVAListStoreTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and result = getVAList().getResult()
|
||||
or
|
||||
operandTag instanceof StoreValueOperandTag and result = getInstruction(VarArgsMoveNextTag())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a `BuiltInVarArgsEnd` expression.
|
||||
*/
|
||||
class TranslatedVarArgsEnd extends TranslatedNonConstantExpr {
|
||||
override BuiltInVarArgsEnd expr;
|
||||
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::VarArgsEnd and
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getVAList().getFirstInstruction() }
|
||||
|
||||
final override Instruction getResult() { none() }
|
||||
|
||||
final override TranslatedElement getChild(int id) { id = 0 and result = getVAList() }
|
||||
|
||||
private TranslatedExpr getVAList() {
|
||||
result = getTranslatedExpr(expr.getVAList().getFullyConverted())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getVAList() and
|
||||
result = getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getVAList().getResult()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a `BuiltInVarArgCopy` expression.
|
||||
*/
|
||||
class TranslatedVarArgCopy extends TranslatedBuiltInOperation {
|
||||
class TranslatedVarArgCopy extends TranslatedNonConstantExpr {
|
||||
override BuiltInVarArgCopy expr;
|
||||
|
||||
final override Opcode getOpcode() { result instanceof Opcode::VarArgCopy }
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = VarArgsVAListLoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getTypeForPRValue(getVAListType(expr.getSourceVAList().getFullyConverted()))
|
||||
or
|
||||
tag = VarArgsVAListStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getTypeForPRValue(getVAListType(expr.getDestinationVAList().getFullyConverted()))
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() {
|
||||
result = getSourceVAList().getFirstInstruction()
|
||||
}
|
||||
|
||||
final override Instruction getResult() { result = getInstruction(VarArgsVAListStoreTag()) }
|
||||
|
||||
final override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getDestinationVAList()
|
||||
or
|
||||
id = 1 and result = getSourceVAList()
|
||||
}
|
||||
|
||||
private TranslatedExpr getDestinationVAList() {
|
||||
result = getTranslatedExpr(expr.getDestinationVAList().getFullyConverted())
|
||||
}
|
||||
|
||||
private TranslatedExpr getSourceVAList() {
|
||||
result = getTranslatedExpr(expr.getSourceVAList().getFullyConverted())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = VarArgsVAListLoadTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getDestinationVAList().getFirstInstruction()
|
||||
or
|
||||
tag = VarArgsVAListStoreTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getSourceVAList() and
|
||||
result = getInstruction(VarArgsVAListLoadTag())
|
||||
or
|
||||
child = getDestinationVAList() and
|
||||
result = getInstruction(VarArgsVAListStoreTag())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = VarArgsVAListLoadTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getSourceVAList().getResult()
|
||||
or
|
||||
operandTag instanceof LoadOperandTag and
|
||||
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
or
|
||||
tag = VarArgsVAListStoreTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and result = getDestinationVAList().getResult()
|
||||
or
|
||||
operandTag instanceof StoreValueOperandTag and result = getInstruction(VarArgsVAListLoadTag())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,6 +43,12 @@ private int getEllipsisVariableByteSize() {
|
||||
)
|
||||
}
|
||||
|
||||
CppType getEllipsisVariablePRValueType() {
|
||||
result = getUnknownOpaqueType(getEllipsisVariableByteSize())
|
||||
}
|
||||
|
||||
CppType getEllipsisVariableGLValueType() { result = getTypeForGLValue(any(UnknownType t)) }
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a function. This is the root elements for
|
||||
* all other elements associated with this function.
|
||||
@@ -280,7 +286,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
or
|
||||
tag = EllipsisTempVar() and
|
||||
func.isVarargs() and
|
||||
type = getUnknownOpaqueType(getEllipsisVariableByteSize())
|
||||
type = getEllipsisVariablePRValueType()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,6 +304,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
result = getIRTempVariable(func, ReturnValueTempVar())
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variable that represents the `...` parameter, if any.
|
||||
*/
|
||||
final IREllipsisVariable getEllipsisVariable() { result.getEnclosingFunction() = func }
|
||||
|
||||
/**
|
||||
* Holds if the function has a non-`void` return type.
|
||||
*/
|
||||
@@ -512,13 +523,13 @@ class TranslatedEllipsisParameter extends TranslatedParameter, TTranslatedEllips
|
||||
|
||||
final override predicate hasIndirection() { any() }
|
||||
|
||||
final override CppType getGLValueType() { result = getTypeForGLValue(any(UnknownType t)) }
|
||||
final override CppType getGLValueType() { result = getEllipsisVariableGLValueType() }
|
||||
|
||||
final override CppType getPRValueType() {
|
||||
result = getUnknownOpaqueType(getEllipsisVariableByteSize())
|
||||
final override CppType getPRValueType() { result = getEllipsisVariablePRValueType() }
|
||||
|
||||
final override IREllipsisVariable getIRVariable() {
|
||||
result = getTranslatedFunction(func).getEllipsisVariable()
|
||||
}
|
||||
|
||||
final override IREllipsisVariable getIRVariable() { result.getEnclosingFunction() = func }
|
||||
}
|
||||
|
||||
private TranslatedConstructorInitList getTranslatedConstructorInitList(Function func) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import IRTypeSanity // module is in IRType.qll
|
||||
module InstructionSanity {
|
||||
private import internal.InstructionImports as Imports
|
||||
private import Imports::OperandTag
|
||||
private import Imports::Overlap
|
||||
private import internal.IRInternal
|
||||
|
||||
/**
|
||||
@@ -302,4 +303,18 @@ module InstructionSanity {
|
||||
instr.isResultConflated() and
|
||||
not shouldBeConflated(instr)
|
||||
}
|
||||
|
||||
query predicate invalidOverlap(
|
||||
MemoryOperand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(Overlap overlap |
|
||||
overlap = useOperand.getDefinitionOverlap() and
|
||||
overlap instanceof MayPartiallyOverlap and
|
||||
message =
|
||||
"MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" +
|
||||
overlap.toString() + "'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,6 +384,8 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
override string toString() { result = "SideEffect" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,3 +3,4 @@ import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
|
||||
@@ -107,14 +107,15 @@ private module Cached {
|
||||
oldOperand instanceof OldIR::NonPhiMemoryOperand and
|
||||
exists(
|
||||
OldBlock useBlock, int useRank, Alias::MemoryLocation useLocation,
|
||||
Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset
|
||||
Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset,
|
||||
Alias::MemoryLocation actualDefLocation
|
||||
|
|
||||
useLocation = Alias::getOperandMemoryLocation(oldOperand) and
|
||||
hasUseAtRank(useLocation, useBlock, useRank, oldInstruction) and
|
||||
definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank) and
|
||||
hasDefinitionAtRank(useLocation, defLocation, defBlock, defRank, defOffset) and
|
||||
instr = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, _) and
|
||||
overlap = Alias::getOverlap(defLocation, useLocation)
|
||||
instr = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -22,6 +22,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -885,15 +885,24 @@ void FuncPtrConversions(int(*pfn)(int), void* p) {
|
||||
pfn = (int(*)(int))p;
|
||||
}
|
||||
|
||||
void VAListUsage(int x, __builtin_va_list args) {
|
||||
__builtin_va_list args2;
|
||||
__builtin_va_copy(args2, args);
|
||||
double d = __builtin_va_arg(args, double);
|
||||
float f = __builtin_va_arg(args, int);
|
||||
__builtin_va_end(args2);
|
||||
}
|
||||
|
||||
void VarArgUsage(int x, ...) {
|
||||
__builtin_va_list args;
|
||||
|
||||
__builtin_va_start(args, x);
|
||||
__builtin_va_list args2;
|
||||
__builtin_va_start(args2, args);
|
||||
__builtin_va_copy(args2, args);
|
||||
double d = __builtin_va_arg(args, double);
|
||||
float f = __builtin_va_arg(args, float);
|
||||
float f = __builtin_va_arg(args, int);
|
||||
__builtin_va_end(args);
|
||||
VAListUsage(x, args2);
|
||||
__builtin_va_end(args2);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -22,6 +22,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -22,6 +22,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -459,7 +459,7 @@ ssa.cpp:
|
||||
# 112| m112_12(Point) = Chi : total:m112_7, partial:m112_11
|
||||
# 113| r113_1(glval<Point>) = VariableAddress[b] :
|
||||
# 113| r113_2(glval<Point>) = VariableAddress[a] :
|
||||
# 113| r113_3(Point) = Load : &:r113_2, ~m112_12
|
||||
# 113| r113_3(Point) = Load : &:r113_2, m112_12
|
||||
# 113| m113_4(Point) = Store : &:r113_1, r113_3
|
||||
# 114| v114_1(void) = NoOp :
|
||||
# 111| v111_10(void) = ReturnVoid :
|
||||
|
||||
@@ -457,7 +457,7 @@ ssa.cpp:
|
||||
# 112| m112_12(Point) = Chi : total:m112_7, partial:m112_11
|
||||
# 113| r113_1(glval<Point>) = VariableAddress[b] :
|
||||
# 113| r113_2(glval<Point>) = VariableAddress[a] :
|
||||
# 113| r113_3(Point) = Load : &:r113_2, ~m112_12
|
||||
# 113| r113_3(Point) = Load : &:r113_2, m112_12
|
||||
# 113| m113_4(Point) = Store : &:r113_1, r113_3
|
||||
# 114| v114_1(void) = NoOp :
|
||||
# 111| v111_10(void) = ReturnVoid :
|
||||
@@ -490,7 +490,7 @@ ssa.cpp:
|
||||
# 117| m117_12(Point) = Chi : total:m117_7, partial:m117_11
|
||||
# 118| r118_1(glval<Point>) = VariableAddress[b] :
|
||||
# 118| r118_2(glval<Point>) = VariableAddress[a] :
|
||||
# 118| r118_3(Point) = Load : &:r118_2, ~m117_12
|
||||
# 118| r118_3(Point) = Load : &:r118_2, m117_12
|
||||
# 118| m118_4(Point) = Store : &:r118_1, r118_3
|
||||
# 119| r119_1(glval<unknown>) = FunctionAddress[Escape] :
|
||||
# 119| r119_2(glval<Point>) = VariableAddress[a] :
|
||||
@@ -941,7 +941,7 @@ ssa.cpp:
|
||||
# 209| m209_12(int) = Chi : total:m208_2, partial:m209_11
|
||||
# 210| r210_1(glval<int>) = VariableAddress[#return] :
|
||||
# 210| r210_2(glval<int>) = VariableAddress[y] :
|
||||
# 210| r210_3(int) = Load : &:r210_2, ~m209_12
|
||||
# 210| r210_3(int) = Load : &:r210_2, m209_12
|
||||
# 210| m210_4(int) = Store : &:r210_1, r210_3
|
||||
# 207| r207_8(glval<int>) = VariableAddress[#return] :
|
||||
# 207| v207_9(void) = ReturnValue : &:r207_8, m210_4
|
||||
@@ -1179,7 +1179,7 @@ ssa.cpp:
|
||||
# 251| r251_2(glval<char *>) = VariableAddress[dst] :
|
||||
# 251| r251_3(char *) = Load : &:r251_2, m248_12
|
||||
# 251| m251_4(char *) = Store : &:r251_1, r251_3
|
||||
# 247| v247_12(void) = ReturnIndirection : &:r247_8, ~m249_6
|
||||
# 247| v247_12(void) = ReturnIndirection : &:r247_8, m249_6
|
||||
# 247| r247_13(glval<char *>) = VariableAddress[#return] :
|
||||
# 247| v247_14(void) = ReturnValue : &:r247_13, m251_4
|
||||
# 247| v247_15(void) = UnmodeledUse : mu*
|
||||
|
||||
@@ -18,6 +18,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -18,6 +18,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -18,6 +18,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -18,6 +18,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -570,6 +570,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -633,6 +633,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -579,6 +579,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -52,16 +52,12 @@
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | * ... | test.cpp:56:31:56:34 | * ... | AST only |
|
||||
| test.cpp:56:13:56:16 | * ... | test.cpp:59:9:59:12 | * ... | AST only |
|
||||
| test.cpp:56:21:56:24 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
|
||||
| test.cpp:56:21:56:24 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
|
||||
| test.cpp:56:30:56:43 | (...) | test.cpp:56:30:56:43 | (...) | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | * ... | test.cpp:56:13:56:16 | * ... | AST only |
|
||||
| test.cpp:56:31:56:34 | * ... | test.cpp:59:9:59:12 | * ... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
@@ -72,8 +68,6 @@
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | * ... | test.cpp:56:13:56:16 | * ... | AST only |
|
||||
| test.cpp:59:9:59:12 | * ... | test.cpp:56:31:56:34 | * ... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
@@ -125,9 +119,7 @@
|
||||
| test.cpp:128:7:128:7 | x | test.cpp:126:15:126:15 | x | AST only |
|
||||
| test.cpp:128:11:128:11 | n | test.cpp:129:15:129:15 | x | IR only |
|
||||
| test.cpp:129:15:129:15 | x | test.cpp:128:11:128:11 | n | IR only |
|
||||
| test.cpp:136:21:136:21 | x | test.cpp:137:21:137:21 | x | AST only |
|
||||
| test.cpp:136:21:136:21 | x | test.cpp:139:13:139:13 | x | AST only |
|
||||
| test.cpp:137:21:137:21 | x | test.cpp:136:21:136:21 | x | AST only |
|
||||
| test.cpp:137:21:137:21 | x | test.cpp:139:13:139:13 | x | AST only |
|
||||
| test.cpp:139:3:139:24 | ... = ... | test.cpp:139:3:139:24 | ... = ... | AST only |
|
||||
| test.cpp:139:13:139:13 | x | test.cpp:136:21:136:21 | x | AST only |
|
||||
@@ -137,6 +129,4 @@
|
||||
| test.cpp:147:3:147:18 | ... = ... | test.cpp:147:3:147:18 | ... = ... | AST only |
|
||||
| test.cpp:147:7:147:7 | y | test.cpp:145:15:145:15 | y | AST only |
|
||||
| test.cpp:149:15:149:15 | x | test.cpp:144:15:144:15 | x | IR only |
|
||||
| test.cpp:153:21:153:21 | x | test.cpp:154:21:154:21 | x | AST only |
|
||||
| test.cpp:154:21:154:21 | x | test.cpp:153:21:153:21 | x | AST only |
|
||||
| test.cpp:156:3:156:17 | ... = ... | test.cpp:156:3:156:17 | ... = ... | AST only |
|
||||
|
||||
@@ -355,7 +355,7 @@ test.cpp:
|
||||
# 46| m46_4(int) = Store : &:r46_3, r46_2
|
||||
# 46| valnum = m43_10, m45_10, m46_4, r43_8, r45_8, r46_2
|
||||
# 47| v47_1(void) = NoOp :
|
||||
# 39| v39_14(void) = ReturnIndirection : &:r39_12, ~m44_6
|
||||
# 39| v39_14(void) = ReturnIndirection : &:r39_12, m44_6
|
||||
# 39| r39_15(glval<int>) = VariableAddress[#return] :
|
||||
# 39| valnum = unique
|
||||
# 39| v39_16(void) = ReturnValue : &:r39_15
|
||||
@@ -440,9 +440,9 @@ test.cpp:
|
||||
# 56| r56_3(char *) = Load : &:r56_2, m56_1
|
||||
# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
|
||||
# 56| r56_4(char) = Load : &:r56_3, ~m49_4
|
||||
# 56| valnum = unique
|
||||
# 56| valnum = r56_14, r56_4, r59_3
|
||||
# 56| r56_5(int) = Convert : r56_4
|
||||
# 56| valnum = unique
|
||||
# 56| valnum = r56_15, r56_5, r59_4
|
||||
# 56| r56_6(glval<char *>) = VariableAddress[str] :
|
||||
# 56| valnum = r49_6, r53_2, r56_6
|
||||
# 56| r56_7(char *) = Load : &:r56_6, m49_7
|
||||
@@ -463,9 +463,9 @@ test.cpp:
|
||||
# 56| r56_13(char *) = Load : &:r56_12, m56_1
|
||||
# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
|
||||
# 56| r56_14(char) = Load : &:r56_13, ~m49_4
|
||||
# 56| valnum = unique
|
||||
# 56| valnum = r56_14, r56_4, r59_3
|
||||
# 56| r56_15(int) = Convert : r56_14
|
||||
# 56| valnum = unique
|
||||
# 56| valnum = r56_15, r56_5, r59_4
|
||||
# 56| r56_16(int) = Constant[0] :
|
||||
# 56| valnum = r53_6, r56_16, r59_5
|
||||
# 56| r56_17(bool) = CompareNE : r56_15, r56_16
|
||||
@@ -493,9 +493,9 @@ test.cpp:
|
||||
# 59| r59_2(char *) = Load : &:r59_1, m56_1
|
||||
# 59| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
|
||||
# 59| r59_3(char) = Load : &:r59_2, ~m49_4
|
||||
# 59| valnum = unique
|
||||
# 59| valnum = r56_14, r56_4, r59_3
|
||||
# 59| r59_4(int) = Convert : r59_3
|
||||
# 59| valnum = unique
|
||||
# 59| valnum = r56_15, r56_5, r59_4
|
||||
# 59| r59_5(int) = Constant[0] :
|
||||
# 59| valnum = r53_6, r56_16, r59_5
|
||||
# 59| r59_6(bool) = CompareEQ : r59_4, r59_5
|
||||
@@ -925,7 +925,7 @@ test.cpp:
|
||||
# 129| m129_6(int) = Store : &:r129_1, r129_5
|
||||
# 129| valnum = m124_11, m128_6, m129_6, r128_2, r129_5
|
||||
# 130| v130_1(void) = NoOp :
|
||||
# 124| v124_12(void) = ReturnIndirection : &:r124_8, ~m128_7
|
||||
# 124| v124_12(void) = ReturnIndirection : &:r124_8, m128_7
|
||||
# 124| v124_13(void) = ReturnVoid :
|
||||
# 124| v124_14(void) = UnmodeledUse : mu*
|
||||
# 124| v124_15(void) = AliasedUse : m124_3
|
||||
@@ -951,9 +951,9 @@ test.cpp:
|
||||
# 136| r136_4(glval<int>) = FieldAddress[x] : r136_3
|
||||
# 136| valnum = r136_4, r137_4, r139_5
|
||||
# 136| r136_5(int) = Load : &:r136_4, ~m135_4
|
||||
# 136| valnum = m136_6, r136_5
|
||||
# 136| valnum = m136_6, m137_6, r136_5, r137_5
|
||||
# 136| m136_6(int) = Store : &:r136_1, r136_5
|
||||
# 136| valnum = m136_6, r136_5
|
||||
# 136| valnum = m136_6, m137_6, r136_5, r137_5
|
||||
# 137| r137_1(glval<int>) = VariableAddress[c] :
|
||||
# 137| valnum = unique
|
||||
# 137| r137_2(glval<A *>) = VariableAddress[global_a] :
|
||||
@@ -963,9 +963,9 @@ test.cpp:
|
||||
# 137| r137_4(glval<int>) = FieldAddress[x] : r137_3
|
||||
# 137| valnum = r136_4, r137_4, r139_5
|
||||
# 137| r137_5(int) = Load : &:r137_4, ~m135_4
|
||||
# 137| valnum = m137_6, r137_5
|
||||
# 137| valnum = m136_6, m137_6, r136_5, r137_5
|
||||
# 137| m137_6(int) = Store : &:r137_1, r137_5
|
||||
# 137| valnum = m137_6, r137_5
|
||||
# 137| valnum = m136_6, m137_6, r136_5, r137_5
|
||||
# 139| r139_1(glval<int>) = VariableAddress[global_n] :
|
||||
# 139| valnum = unique
|
||||
# 139| r139_2(int) = Load : &:r139_1, ~m135_3
|
||||
@@ -1068,7 +1068,7 @@ test.cpp:
|
||||
# 149| m149_6(int) = Store : &:r149_1, r149_5
|
||||
# 149| valnum = m144_6, m149_6, r144_5, r149_5
|
||||
# 150| v150_1(void) = NoOp :
|
||||
# 143| v143_10(void) = ReturnIndirection : &:r143_8, ~m147_7
|
||||
# 143| v143_10(void) = ReturnIndirection : &:r143_8, m147_7
|
||||
# 143| v143_11(void) = ReturnVoid :
|
||||
# 143| v143_12(void) = UnmodeledUse : mu*
|
||||
# 143| v143_13(void) = AliasedUse : m143_3
|
||||
@@ -1098,9 +1098,9 @@ test.cpp:
|
||||
# 153| r153_4(glval<int>) = FieldAddress[x] : r153_3
|
||||
# 153| valnum = r153_4, r154_4
|
||||
# 153| r153_5(int) = Load : &:r153_4, ~m152_4
|
||||
# 153| valnum = m153_6, r153_5
|
||||
# 153| valnum = m153_6, m154_6, r153_5, r154_5
|
||||
# 153| m153_6(int) = Store : &:r153_1, r153_5
|
||||
# 153| valnum = m153_6, r153_5
|
||||
# 153| valnum = m153_6, m154_6, r153_5, r154_5
|
||||
# 154| r154_1(glval<int>) = VariableAddress[c] :
|
||||
# 154| valnum = unique
|
||||
# 154| r154_2(glval<A *>) = VariableAddress[global_a] :
|
||||
@@ -1110,9 +1110,9 @@ test.cpp:
|
||||
# 154| r154_4(glval<int>) = FieldAddress[x] : r154_3
|
||||
# 154| valnum = r153_4, r154_4
|
||||
# 154| r154_5(int) = Load : &:r154_4, ~m152_4
|
||||
# 154| valnum = m154_6, r154_5
|
||||
# 154| valnum = m153_6, m154_6, r153_5, r154_5
|
||||
# 154| m154_6(int) = Store : &:r154_1, r154_5
|
||||
# 154| valnum = m154_6, r154_5
|
||||
# 154| valnum = m153_6, m154_6, r153_5, r154_5
|
||||
# 156| r156_1(glval<int>) = VariableAddress[n] :
|
||||
# 156| valnum = r152_6, r156_1
|
||||
# 156| r156_2(int) = Load : &:r156_1, m152_7
|
||||
|
||||
@@ -12,5 +12,7 @@
|
||||
| test.cpp:46:2:46:9 | call to strcpy_s | Potentially unsafe call to strcpy_s; second argument should be size of destination. |
|
||||
| test.cpp:47:2:47:9 | call to strcpy_s | Potentially unsafe call to strcpy_s; second argument should be size of destination. |
|
||||
| test.cpp:60:3:60:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:63:3:63:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:68:2:68:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:79:3:79:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:82:3:82:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -243,7 +243,7 @@ private module Cached {
|
||||
* - Types are checked using the `compatibleTypes()` relation.
|
||||
*/
|
||||
cached
|
||||
module Final {
|
||||
private module Final {
|
||||
/**
|
||||
* Holds if `p` can flow to `node` in the same callable using only
|
||||
* value-preserving steps, not taking call contexts into account.
|
||||
|
||||
@@ -21,4 +21,23 @@ module SystemXmlXPath {
|
||||
class XPathExpression extends Class {
|
||||
XPathExpression() { this.hasName("XPathExpression") }
|
||||
}
|
||||
|
||||
/** The `System.Xml.XPath.XPathNavigator` class. */
|
||||
class XPathNavigator extends Class {
|
||||
XPathNavigator() { this.hasName("XPathNavigator") }
|
||||
|
||||
/** Gets a method that selects nodes. */
|
||||
csharp::Method getASelectMethod() {
|
||||
result = this.getAMethod() and result.getName().matches("Select%")
|
||||
}
|
||||
|
||||
/** Gets the `Compile` method. */
|
||||
csharp::Method getCompileMethod() { result = this.getAMethod("Compile") }
|
||||
|
||||
/** Gets an `Evaluate` method. */
|
||||
csharp::Method getAnEvaluateMethod() { result = this.getAMethod("Evaluate") }
|
||||
|
||||
/** Gets a `Matches` method. */
|
||||
csharp::Method getAMatchesMethod() { result = this.getAMethod("Matches") }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ private newtype TOpcode =
|
||||
TVarArgsStart() or
|
||||
TVarArgsEnd() or
|
||||
TVarArg() or
|
||||
TVarArgCopy() or
|
||||
TNextVarArg() or
|
||||
TCallSideEffect() or
|
||||
TCallReadSideEffect() or
|
||||
TIndirectReadSideEffect() or
|
||||
@@ -629,20 +629,20 @@ module Opcode {
|
||||
final override string toString() { result = "BuiltIn" }
|
||||
}
|
||||
|
||||
class VarArgsStart extends BuiltInOperationOpcode, TVarArgsStart {
|
||||
class VarArgsStart extends UnaryOpcode, TVarArgsStart {
|
||||
final override string toString() { result = "VarArgsStart" }
|
||||
}
|
||||
|
||||
class VarArgsEnd extends BuiltInOperationOpcode, TVarArgsEnd {
|
||||
class VarArgsEnd extends UnaryOpcode, TVarArgsEnd {
|
||||
final override string toString() { result = "VarArgsEnd" }
|
||||
}
|
||||
|
||||
class VarArg extends BuiltInOperationOpcode, TVarArg {
|
||||
class VarArg extends UnaryOpcode, TVarArg {
|
||||
final override string toString() { result = "VarArg" }
|
||||
}
|
||||
|
||||
class VarArgCopy extends BuiltInOperationOpcode, TVarArgCopy {
|
||||
final override string toString() { result = "VarArgCopy" }
|
||||
class NextVarArg extends UnaryOpcode, TNextVarArg {
|
||||
final override string toString() { result = "NextVarArg" }
|
||||
}
|
||||
|
||||
class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode,
|
||||
|
||||
@@ -5,6 +5,7 @@ import IRTypeSanity // module is in IRType.qll
|
||||
module InstructionSanity {
|
||||
private import internal.InstructionImports as Imports
|
||||
private import Imports::OperandTag
|
||||
private import Imports::Overlap
|
||||
private import internal.IRInternal
|
||||
|
||||
/**
|
||||
@@ -302,4 +303,18 @@ module InstructionSanity {
|
||||
instr.isResultConflated() and
|
||||
not shouldBeConflated(instr)
|
||||
}
|
||||
|
||||
query predicate invalidOverlap(
|
||||
MemoryOperand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(Overlap overlap |
|
||||
overlap = useOperand.getDefinitionOverlap() and
|
||||
overlap instanceof MayPartiallyOverlap and
|
||||
message =
|
||||
"MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" +
|
||||
overlap.toString() + "'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,6 +384,8 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
override string toString() { result = "SideEffect" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,3 +3,4 @@ import semmle.code.csharp.ir.implementation.IRType as IRType
|
||||
import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.csharp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.csharp.ir.internal.Overlap as Overlap
|
||||
|
||||
@@ -5,6 +5,7 @@ import IRTypeSanity // module is in IRType.qll
|
||||
module InstructionSanity {
|
||||
private import internal.InstructionImports as Imports
|
||||
private import Imports::OperandTag
|
||||
private import Imports::Overlap
|
||||
private import internal.IRInternal
|
||||
|
||||
/**
|
||||
@@ -302,4 +303,18 @@ module InstructionSanity {
|
||||
instr.isResultConflated() and
|
||||
not shouldBeConflated(instr)
|
||||
}
|
||||
|
||||
query predicate invalidOverlap(
|
||||
MemoryOperand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(Overlap overlap |
|
||||
overlap = useOperand.getDefinitionOverlap() and
|
||||
overlap instanceof MayPartiallyOverlap and
|
||||
message =
|
||||
"MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" +
|
||||
overlap.toString() + "'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,6 +384,8 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
|
||||
class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
override string toString() { result = "SideEffect" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,3 +3,4 @@ import semmle.code.csharp.ir.implementation.IRType as IRType
|
||||
import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.csharp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.csharp.ir.internal.Overlap as Overlap
|
||||
|
||||
@@ -107,14 +107,15 @@ private module Cached {
|
||||
oldOperand instanceof OldIR::NonPhiMemoryOperand and
|
||||
exists(
|
||||
OldBlock useBlock, int useRank, Alias::MemoryLocation useLocation,
|
||||
Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset
|
||||
Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset,
|
||||
Alias::MemoryLocation actualDefLocation
|
||||
|
|
||||
useLocation = Alias::getOperandMemoryLocation(oldOperand) and
|
||||
hasUseAtRank(useLocation, useBlock, useRank, oldInstruction) and
|
||||
definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank) and
|
||||
hasDefinitionAtRank(useLocation, defLocation, defBlock, defRank, defOffset) and
|
||||
instr = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, _) and
|
||||
overlap = Alias::getOverlap(defLocation, useLocation)
|
||||
instr = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,20 @@ module XPathInjection {
|
||||
}
|
||||
}
|
||||
|
||||
/** The `xpath` argument to an `XPathNavigator` call. */
|
||||
class XmlNavigatorSink extends Sink {
|
||||
XmlNavigatorSink() {
|
||||
exists(SystemXmlXPath::XPathNavigator xmlNav, Method m |
|
||||
this.getExpr() = m.getACall().getArgumentForName("xpath")
|
||||
|
|
||||
m = xmlNav.getASelectMethod() or
|
||||
m = xmlNav.getCompileMethod() or
|
||||
m = xmlNav.getAnEvaluateMethod() or
|
||||
m = xmlNav.getAMatchesMethod()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
|
||||
|
||||
private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
|
||||
|
||||
@@ -39,11 +39,7 @@ edges
|
||||
| A.cs:105:23:105:23 | access to local variable b : B | A.cs:105:17:105:29 | object creation of type D [b] : B |
|
||||
| A.cs:106:14:106:14 | access to local variable d [b] : B | A.cs:106:14:106:16 | access to field b |
|
||||
| A.cs:107:14:107:14 | access to local variable d [b, c] | A.cs:107:14:107:16 | access to field b [c] : C |
|
||||
| A.cs:107:14:107:14 | access to local variable d [b, c] | A.cs:107:14:107:16 | access to field b [c] : C1 |
|
||||
| A.cs:107:14:107:14 | access to local variable d [b, c] | A.cs:107:14:107:16 | access to field b [c] : C2 |
|
||||
| A.cs:107:14:107:16 | access to field b [c] : C | A.cs:107:14:107:18 | access to field c |
|
||||
| A.cs:107:14:107:16 | access to field b [c] : C1 | A.cs:107:14:107:18 | access to field c |
|
||||
| A.cs:107:14:107:16 | access to field b [c] : C2 | A.cs:107:14:107:18 | access to field c |
|
||||
| A.cs:108:14:108:14 | access to local variable b [c] : C | A.cs:108:14:108:16 | access to field c |
|
||||
| A.cs:113:17:113:23 | object creation of type B : B | A.cs:114:29:114:29 | access to local variable b : B |
|
||||
| A.cs:114:18:114:54 | object creation of type MyList [head] : B | A.cs:115:35:115:36 | access to local variable l1 [head] : B |
|
||||
@@ -254,8 +250,6 @@ nodes
|
||||
| A.cs:106:14:106:16 | access to field b | semmle.label | access to field b |
|
||||
| A.cs:107:14:107:14 | access to local variable d [b, c] | semmle.label | access to local variable d [b, c] |
|
||||
| A.cs:107:14:107:16 | access to field b [c] : C | semmle.label | access to field b [c] : C |
|
||||
| A.cs:107:14:107:16 | access to field b [c] : C1 | semmle.label | access to field b [c] : C1 |
|
||||
| A.cs:107:14:107:16 | access to field b [c] : C2 | semmle.label | access to field b [c] : C2 |
|
||||
| A.cs:107:14:107:18 | access to field c | semmle.label | access to field c |
|
||||
| A.cs:108:14:108:14 | access to local variable b [c] : C | semmle.label | access to local variable b [c] : C |
|
||||
| A.cs:108:14:108:16 | access to field c | semmle.label | access to field c |
|
||||
|
||||
@@ -18,6 +18,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -18,6 +18,7 @@ useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Web.cs /r:System.Collections.Specialized.dll ${testdir}/../../../resources/stubs/System.Data.cs /r:System.Private.Xml.dll /r:System.Xml.XPath.dll /r:System.Data.Common.dll
|
||||
// semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Web.cs /r:System.Collections.Specialized.dll ${testdir}/../../../resources/stubs/System.Data.cs /r:System.Private.Xml.dll /r:System.Xml.XPath.dll /r:System.Data.Common.dll /r:System.Runtime.Extensions.dll
|
||||
|
||||
using System;
|
||||
using System.Web;
|
||||
@@ -12,14 +12,49 @@ public class XPathInjectionHandler : IHttpHandler
|
||||
string userName = ctx.Request.QueryString["userName"];
|
||||
string password = ctx.Request.QueryString["password"];
|
||||
|
||||
var s = "//users/user[login/text()='" + userName + "' and password/text() = '" + password + "']/home_dir/text()";
|
||||
|
||||
// BAD: User input used directly in an XPath expression
|
||||
XPathExpression.Compile("//users/user[login/text()='" + userName + "' and password/text() = '" + password + "']/home_dir/text()");
|
||||
XPathExpression.Compile(s);
|
||||
XmlNode xmlNode = null;
|
||||
// BAD: User input used directly in an XPath expression to SelectNodes
|
||||
xmlNode.SelectNodes("//users/user[login/text()='" + userName + "' and password/text() = '" + password + "']/home_dir/text()");
|
||||
xmlNode.SelectNodes(s);
|
||||
|
||||
// GOOD: Uses parameters to avoid including user input directly in XPath expression
|
||||
XPathExpression.Compile("//users/user[login/text()=$username]/home_dir/text()");
|
||||
var expr = XPathExpression.Compile("//users/user[login/text()=$username]/home_dir/text()");
|
||||
|
||||
var doc = new XPathDocument("");
|
||||
var nav = doc.CreateNavigator();
|
||||
|
||||
// BAD
|
||||
nav.Select(s);
|
||||
|
||||
// GOOD
|
||||
nav.Select(expr);
|
||||
|
||||
// BAD
|
||||
nav.SelectSingleNode(s);
|
||||
|
||||
// GOOD
|
||||
nav.SelectSingleNode(expr);
|
||||
|
||||
// BAD
|
||||
nav.Compile(s);
|
||||
|
||||
// GOOD
|
||||
nav.Compile("//users/user[login/text()=$username]/home_dir/text()");
|
||||
|
||||
// BAD
|
||||
nav.Evaluate(s);
|
||||
|
||||
// Good
|
||||
nav.Evaluate(expr);
|
||||
|
||||
// BAD
|
||||
nav.Matches(s);
|
||||
|
||||
// GOOD
|
||||
nav.Matches(expr);
|
||||
}
|
||||
|
||||
public bool IsReusable
|
||||
|
||||
@@ -1,15 +1,40 @@
|
||||
edges
|
||||
| XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:16:33:16:136 | ... + ... |
|
||||
| XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:19:29:19:132 | ... + ... |
|
||||
| XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:16:33:16:136 | ... + ... |
|
||||
| XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:19:29:19:132 | ... + ... |
|
||||
| XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:18:33:18:33 | access to local variable s |
|
||||
| XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:21:29:21:29 | access to local variable s |
|
||||
| XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:30:20:30:20 | access to local variable s |
|
||||
| XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:36:30:36:30 | access to local variable s |
|
||||
| XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:42:21:42:21 | access to local variable s |
|
||||
| XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:48:22:48:22 | access to local variable s |
|
||||
| XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:54:21:54:21 | access to local variable s |
|
||||
| XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:18:33:18:33 | access to local variable s |
|
||||
| XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:21:29:21:29 | access to local variable s |
|
||||
| XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:30:20:30:20 | access to local variable s |
|
||||
| XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:36:30:36:30 | access to local variable s |
|
||||
| XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:42:21:42:21 | access to local variable s |
|
||||
| XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:48:22:48:22 | access to local variable s |
|
||||
| XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:54:21:54:21 | access to local variable s |
|
||||
nodes
|
||||
| XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XPathInjection.cs:16:33:16:136 | ... + ... | semmle.label | ... + ... |
|
||||
| XPathInjection.cs:19:29:19:132 | ... + ... | semmle.label | ... + ... |
|
||||
| XPathInjection.cs:18:33:18:33 | access to local variable s | semmle.label | access to local variable s |
|
||||
| XPathInjection.cs:21:29:21:29 | access to local variable s | semmle.label | access to local variable s |
|
||||
| XPathInjection.cs:30:20:30:20 | access to local variable s | semmle.label | access to local variable s |
|
||||
| XPathInjection.cs:36:30:36:30 | access to local variable s | semmle.label | access to local variable s |
|
||||
| XPathInjection.cs:42:21:42:21 | access to local variable s | semmle.label | access to local variable s |
|
||||
| XPathInjection.cs:48:22:48:22 | access to local variable s | semmle.label | access to local variable s |
|
||||
| XPathInjection.cs:54:21:54:21 | access to local variable s | semmle.label | access to local variable s |
|
||||
#select
|
||||
| XPathInjection.cs:16:33:16:136 | ... + ... | XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:16:33:16:136 | ... + ... | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:12:27:12:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:16:33:16:136 | ... + ... | XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:16:33:16:136 | ... + ... | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:13:27:13:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:19:29:19:132 | ... + ... | XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:19:29:19:132 | ... + ... | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:12:27:12:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:19:29:19:132 | ... + ... | XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:19:29:19:132 | ... + ... | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:13:27:13:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:18:33:18:33 | access to local variable s | XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:18:33:18:33 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:12:27:12:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:18:33:18:33 | access to local variable s | XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:18:33:18:33 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:13:27:13:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:21:29:21:29 | access to local variable s | XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:21:29:21:29 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:12:27:12:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:21:29:21:29 | access to local variable s | XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:21:29:21:29 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:13:27:13:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:30:20:30:20 | access to local variable s | XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:30:20:30:20 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:12:27:12:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:30:20:30:20 | access to local variable s | XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:30:20:30:20 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:13:27:13:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:36:30:36:30 | access to local variable s | XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:36:30:36:30 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:12:27:12:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:36:30:36:30 | access to local variable s | XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:36:30:36:30 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:13:27:13:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:42:21:42:21 | access to local variable s | XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:42:21:42:21 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:12:27:12:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:42:21:42:21 | access to local variable s | XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:42:21:42:21 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:13:27:13:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:48:22:48:22 | access to local variable s | XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:48:22:48:22 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:12:27:12:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:48:22:48:22 | access to local variable s | XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:48:22:48:22 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:13:27:13:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:54:21:54:21 | access to local variable s | XPathInjection.cs:12:27:12:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:54:21:54:21 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:12:27:12:49 | access to property QueryString | User-provided value |
|
||||
| XPathInjection.cs:54:21:54:21 | access to local variable s | XPathInjection.cs:13:27:13:49 | access to property QueryString : NameValueCollection | XPathInjection.cs:54:21:54:21 | access to local variable s | $@ flows to here and is used in an XPath expression. | XPathInjection.cs:13:27:13:49 | access to property QueryString | User-provided value |
|
||||
|
||||
@@ -1016,7 +1016,7 @@ class LambdaExpr extends FunctionalExpr, @lambdaexpr {
|
||||
}
|
||||
|
||||
/** Gets the body of this lambda expression, if it is a statement. */
|
||||
Stmt getStmtBody() { hasStmtBody() and result = asMethod().getBody() }
|
||||
Block getStmtBody() { hasStmtBody() and result = asMethod().getBody() }
|
||||
|
||||
/** Gets a printable representation of this expression. */
|
||||
override string toString() { result = "...->..." }
|
||||
|
||||
@@ -481,13 +481,13 @@ class GetterMethod extends Method {
|
||||
|
||||
/**
|
||||
* A finalizer method, with name `finalize`,
|
||||
* return type `void` and modifier `protected`.
|
||||
* return type `void` and no parameters.
|
||||
*/
|
||||
class FinalizeMethod extends Method {
|
||||
FinalizeMethod() {
|
||||
this.hasName("finalize") and
|
||||
this.getReturnType().hasName("void") and
|
||||
this.isProtected()
|
||||
this.hasNoParameters()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -243,7 +243,7 @@ private module Cached {
|
||||
* - Types are checked using the `compatibleTypes()` relation.
|
||||
*/
|
||||
cached
|
||||
module Final {
|
||||
private module Final {
|
||||
/**
|
||||
* Holds if `p` can flow to `node` in the same callable using only
|
||||
* value-preserving steps, not taking call contexts into account.
|
||||
|
||||
@@ -445,6 +445,13 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
|
||||
method.getName() = "wrap" and arg = 0
|
||||
)
|
||||
or
|
||||
method.getDeclaringType().hasQualifiedName("org.apache.commons.codec.binary", "Base64") and
|
||||
(
|
||||
method.getName() = "decodeBase64" and arg = 0
|
||||
or
|
||||
method.getName().matches("encodeBase64%") and arg = 0
|
||||
)
|
||||
or
|
||||
method.getDeclaringType().hasQualifiedName("org.apache.commons.io", "IOUtils") and
|
||||
(
|
||||
method.getName() = "buffer" and arg = 0
|
||||
@@ -466,6 +473,10 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
|
||||
method.getName() = "toString" and arg = 0
|
||||
)
|
||||
or
|
||||
method.getDeclaringType().hasQualifiedName("java.net", "URLDecoder") and
|
||||
method.hasName("decode") and
|
||||
arg = 0
|
||||
or
|
||||
// A URI created from a tainted string is still tainted.
|
||||
method.getDeclaringType().hasQualifiedName("java.net", "URI") and
|
||||
method.hasName("create") and
|
||||
|
||||
46
javascript/ql/src/experimental/SockJS/SockJS.qll
Normal file
46
javascript/ql/src/experimental/SockJS/SockJS.qll
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Provides classes for working with [SockJS](http://sockjs.org).
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* A model of the `SockJS` websocket data handler (https://sockjs.org).
|
||||
*/
|
||||
module SockJS {
|
||||
/**
|
||||
* Access to user-controlled data object received from websocket
|
||||
* For example:
|
||||
* ```
|
||||
* server.on('connection', function(conn) {
|
||||
* conn.on('data', function(message) {
|
||||
* ...
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
class SourceFromSocketJS extends RemoteFlowSource {
|
||||
SourceFromSocketJS() {
|
||||
exists(
|
||||
DataFlow::CallNode createServer, DataFlow::CallNode connNode,
|
||||
DataFlow::CallNode dataHandlerNode
|
||||
|
|
||||
createServer = appCreation() and
|
||||
connNode = createServer.getAMethodCall("on") and
|
||||
connNode.getArgument(0).getStringValue() = "connection" and
|
||||
dataHandlerNode = connNode.getCallback(1).getParameter(0).getAMethodCall("on") and
|
||||
dataHandlerNode.getArgument(0).getStringValue() = "data" and
|
||||
this = dataHandlerNode.getCallback(1).getParameter(0)
|
||||
)
|
||||
}
|
||||
|
||||
override string getSourceType() { result = "input from SockJS WebSocket" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a new SockJS server.
|
||||
*/
|
||||
private DataFlow::CallNode appCreation() {
|
||||
result = DataFlow::moduleImport("sockjs").getAMemberCall("createServer")
|
||||
}
|
||||
}
|
||||
16
javascript/ql/src/experimental/SockJS/examples/server.js
Normal file
16
javascript/ql/src/experimental/SockJS/examples/server.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const express = require('express');
|
||||
const http = require('http');
|
||||
const sockjs = require('sockjs');
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
const sockjs_echo = sockjs.createServer({});
|
||||
sockjs_echo.on('connection', function(conn) {
|
||||
conn.on('data', function(message) {
|
||||
var data = JSON.parse(message);
|
||||
conn.write(JSON.stringify(eval(data.test)));
|
||||
});
|
||||
});
|
||||
|
||||
sockjs_echo.installHandlers(server, {prefix:'/echo'});
|
||||
server.listen(9090, '127.0.0.1');
|
||||
@@ -117,7 +117,14 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
|
||||
ArgumentsVariable getArgumentsVariable() { result.getFunction() = this }
|
||||
|
||||
/** Holds if the body of this function refers to the function's `arguments` variable. */
|
||||
predicate usesArgumentsObject() { exists(getArgumentsVariable().getAnAccess()) }
|
||||
predicate usesArgumentsObject() {
|
||||
exists(getArgumentsVariable().getAnAccess())
|
||||
or
|
||||
exists(PropAccess read |
|
||||
read.getBase() = getVariable().getAnAccess() and
|
||||
read.getPropertyName() = "arguments"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this function declares a parameter or local variable named `arguments`.
|
||||
|
||||
@@ -167,6 +167,7 @@ module PromiseTypeTracking {
|
||||
* Gets the result from a single step through a promise, from `pred` to `result` summarized by `summary`.
|
||||
* This can be loading a resolved value from a promise, storing a value in a promise, or copying a resolved value from one promise to another.
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlow::SourceNode promiseStep(DataFlow::SourceNode pred, StepSummary summary) {
|
||||
exists(PromiseFlowStep step, string field | field = Promises::valueProp() |
|
||||
summary = LoadStep(field) and
|
||||
@@ -184,6 +185,7 @@ module PromiseTypeTracking {
|
||||
* Gets the result from a single step through a promise, from `pred` with tracker `t2` to `result` with tracker `t`.
|
||||
* This can be loading a resolved value from a promise, storing a value in a promise, or copying a resolved value from one promise to another.
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlow::SourceNode promiseStep(
|
||||
DataFlow::SourceNode pred, DataFlow::TypeTracker t, DataFlow::TypeTracker t2
|
||||
) {
|
||||
|
||||
@@ -98,6 +98,17 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Gets the flow label to associate with sources added by the 1-argument `isSource` predicate.
|
||||
*
|
||||
* For taint-tracking configurations, this defaults to `taint` and for other data-flow configurations
|
||||
* it defaults to `data`.
|
||||
*
|
||||
* Overriding this predicate is rarely needed, and overriding the 2-argument `isSource` predicate
|
||||
* should be preferred when possible.
|
||||
*/
|
||||
FlowLabel getDefaultSourceLabel() { result = FlowLabel::data() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a source of flow labeled with `lbl` that is relevant
|
||||
* for this configuration.
|
||||
@@ -256,9 +267,11 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* A label describing the kind of information tracked by a flow configuration.
|
||||
*
|
||||
* There are two standard labels "data" and "taint", the former describing values
|
||||
* that directly originate from a flow source, the latter values that are derived
|
||||
* from a flow source via one or more transformations (such as string operations).
|
||||
* There are two standard labels "data" and "taint".
|
||||
* - "data" only propagates along value-preserving data flow, such as assignments
|
||||
* and parameter-passing, and is the default flow source for a `DataFlow::Configuration`.
|
||||
* - "taint" additionally permits flow through transformations such as string operations,
|
||||
* and is the default flow source for a `TaintTracking::Configuration`.
|
||||
*/
|
||||
abstract class FlowLabel extends string {
|
||||
bindingset[this]
|
||||
@@ -666,7 +679,7 @@ private predicate exploratoryFlowStep(
|
||||
*/
|
||||
private predicate isSource(DataFlow::Node nd, DataFlow::Configuration cfg, FlowLabel lbl) {
|
||||
(cfg.isSource(nd) or nd.(AdditionalSource).isSourceFor(cfg)) and
|
||||
lbl = FlowLabel::data()
|
||||
lbl = cfg.getDefaultSourceLabel()
|
||||
or
|
||||
nd.(AdditionalSource).isSourceFor(cfg, lbl)
|
||||
or
|
||||
@@ -945,18 +958,31 @@ private predicate reachableFromStoreBase(
|
||||
s2.getEndLabel())
|
||||
)
|
||||
or
|
||||
exists(DataFlow::Node mid, PathSummary oldSummary, PathSummary newSummary |
|
||||
reachableFromStoreBase(prop, rhs, mid, cfg, oldSummary) and
|
||||
(
|
||||
flowStep(mid, cfg, nd, newSummary)
|
||||
or
|
||||
isAdditionalLoadStoreStep(mid, nd, prop, cfg) and
|
||||
newSummary = PathSummary::level()
|
||||
) and
|
||||
exists(PathSummary oldSummary, PathSummary newSummary |
|
||||
reachableFromStoreBaseStep(prop, rhs, nd, cfg, oldSummary, newSummary) and
|
||||
summary = oldSummary.appendValuePreserving(newSummary)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `rhs` is the right-hand side of a write to property `prop`, and `nd` is reachable
|
||||
* from the base of that write under configuration `cfg` (possibly through callees) along a
|
||||
* path whose last step is summarized by `newSummary`, and the previous steps are summarized
|
||||
* by `oldSummary`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate reachableFromStoreBaseStep(
|
||||
string prop, DataFlow::Node rhs, DataFlow::Node nd, DataFlow::Configuration cfg,
|
||||
PathSummary oldSummary, PathSummary newSummary
|
||||
) {
|
||||
exists(DataFlow::Node mid | reachableFromStoreBase(prop, rhs, mid, cfg, oldSummary) |
|
||||
flowStep(mid, cfg, nd, newSummary)
|
||||
or
|
||||
isAdditionalLoadStoreStep(mid, nd, prop, cfg) and
|
||||
newSummary = PathSummary::level()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `pred` is written to a property of some base object, and that base
|
||||
* object may flow into the base of property read `succ` under configuration `cfg` along
|
||||
@@ -968,13 +994,29 @@ pragma[noinline]
|
||||
private predicate flowThroughProperty(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::Configuration cfg, PathSummary summary
|
||||
) {
|
||||
exists(string prop, DataFlow::Node base, PathSummary oldSummary, PathSummary newSummary |
|
||||
reachableFromStoreBase(prop, pred, base, cfg, oldSummary) and
|
||||
loadStep(base, succ, prop, cfg, newSummary) and
|
||||
exists(PathSummary oldSummary, PathSummary newSummary |
|
||||
storeToLoad(pred, succ, cfg, oldSummary, newSummary) and
|
||||
summary = oldSummary.append(newSummary)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `pred` is written to a property of some base object, and that base
|
||||
* object may flow into the base of property read `succ` under configuration `cfg` along
|
||||
* a path whose last step is summarized by `newSummary`, and the previous steps are summarized
|
||||
* by `oldSummary`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate storeToLoad(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::Configuration cfg, PathSummary oldSummary,
|
||||
PathSummary newSummary
|
||||
) {
|
||||
exists(string prop, DataFlow::Node base |
|
||||
reachableFromStoreBase(prop, pred, base, cfg, oldSummary) and
|
||||
loadStep(base, succ, prop, cfg, newSummary)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` and `cb` are passed as arguments to a function which in turn
|
||||
* invokes `cb`, passing `arg` as its `i`th argument.
|
||||
|
||||
@@ -157,12 +157,12 @@ class InvokeNode extends DataFlow::SourceNode {
|
||||
* `name` is set to `result`.
|
||||
*/
|
||||
DataFlow::ValueNode getOptionArgument(int i, string name) {
|
||||
exists(ObjectLiteralNode obj |
|
||||
obj.flowsTo(getArgument(i)) and
|
||||
obj.hasPropertyWrite(name, result)
|
||||
)
|
||||
getOptionsArgument(i).hasPropertyWrite(name, result)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private ObjectLiteralNode getOptionsArgument(int i) { result.flowsTo(getArgument(i)) }
|
||||
|
||||
/** Gets an abstract value representing possible callees of this call site. */
|
||||
final AbstractValue getACalleeValue() { result = getCalleeNode().analyze().getAValue() }
|
||||
|
||||
|
||||
@@ -48,7 +48,16 @@ module TaintTracking {
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink) { super.isSink(sink) }
|
||||
|
||||
/** Holds if the intermediate node `node` is a taint sanitizer. */
|
||||
/**
|
||||
* Holds if the intermediate node `node` is a taint sanitizer, that is,
|
||||
* tainted values can not flow into or out of `node`.
|
||||
*
|
||||
* Note that this only blocks flow through nodes that operate directly on the tainted value.
|
||||
* An object _containing_ a tainted value in a property can still flow into and out of `node`.
|
||||
* To block such objects, override `isBarrier` or use a labeled sanitizer to block the `data` flow label.
|
||||
*
|
||||
* For operations that _check_ if a value is tainted or safe, use `isSanitizerGuard` instead.
|
||||
*/
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
@@ -84,25 +93,35 @@ module TaintTracking {
|
||||
* For example, if `guard` is the comparison expression in
|
||||
* `if(x == 'some-constant'){ ... x ... }`, it could sanitize flow of
|
||||
* `x` into the "then" branch.
|
||||
*
|
||||
* Node that this only handles checks that operate directly on the tainted value.
|
||||
* Objects that _contain_ a tainted value in a property may still flow across the check.
|
||||
* To block such objects, use a labeled sanitizer guard to block the `data` label.
|
||||
*/
|
||||
predicate isSanitizerGuard(SanitizerGuardNode guard) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
super.isBarrier(node) or
|
||||
isSanitizer(node) or
|
||||
node instanceof DataFlow::VarAccessBarrier
|
||||
override predicate isLabeledBarrier(DataFlow::Node node, DataFlow::FlowLabel lbl) {
|
||||
super.isLabeledBarrier(node, lbl)
|
||||
or
|
||||
isSanitizer(node) and lbl.isTaint()
|
||||
}
|
||||
|
||||
final override predicate isBarrierEdge(DataFlow::Node source, DataFlow::Node sink) {
|
||||
super.isBarrierEdge(source, sink) or
|
||||
isSanitizerEdge(source, sink)
|
||||
override predicate isBarrier(DataFlow::Node node) {
|
||||
super.isBarrier(node)
|
||||
or
|
||||
// For variable accesses we block both the data and taint label, as a falsy value
|
||||
// can't be an object, and thus can't have any tainted properties.
|
||||
node instanceof DataFlow::VarAccessBarrier
|
||||
}
|
||||
|
||||
final override predicate isBarrierEdge(
|
||||
DataFlow::Node source, DataFlow::Node sink, DataFlow::FlowLabel lbl
|
||||
) {
|
||||
super.isBarrierEdge(source, sink, lbl) or
|
||||
super.isBarrierEdge(source, sink, lbl)
|
||||
or
|
||||
isSanitizerEdge(source, sink, lbl)
|
||||
or
|
||||
isSanitizerEdge(source, sink) and lbl.isTaint()
|
||||
}
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) {
|
||||
@@ -127,6 +146,8 @@ module TaintTracking {
|
||||
) {
|
||||
isAdditionalFlowStep(pred, succ) and valuePreserving = false
|
||||
}
|
||||
|
||||
override DataFlow::FlowLabel getDefaultSourceLabel() { result.isTaint() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,7 +178,7 @@ module TaintTracking {
|
||||
* them.
|
||||
*/
|
||||
abstract class SanitizerGuardNode extends DataFlow::BarrierGuardNode {
|
||||
override predicate blocks(boolean outcome, Expr e) { sanitizes(outcome, e) }
|
||||
override predicate blocks(boolean outcome, Expr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if this node sanitizes expression `e`, provided it evaluates
|
||||
@@ -166,6 +187,8 @@ module TaintTracking {
|
||||
abstract predicate sanitizes(boolean outcome, Expr e);
|
||||
|
||||
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel label) {
|
||||
sanitizes(outcome, e) and label.isTaint()
|
||||
or
|
||||
sanitizes(outcome, e, label)
|
||||
}
|
||||
|
||||
@@ -180,10 +203,6 @@ module TaintTracking {
|
||||
* A sanitizer guard node that only blocks specific flow labels.
|
||||
*/
|
||||
abstract class LabeledSanitizerGuardNode extends SanitizerGuardNode, DataFlow::BarrierGuardNode {
|
||||
final override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel label) {
|
||||
sanitizes(outcome, e, label)
|
||||
}
|
||||
|
||||
override predicate sanitizes(boolean outcome, Expr e) { none() }
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,18 @@ private class RecursiveReadDir extends FileSystemAccess, FileNameProducer, DataF
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getAFileName() { result = getCallback([1 .. 2]).getParameter(1) }
|
||||
override DataFlow::Node getAFileName() { result = trackFileSource(DataFlow::TypeTracker::end()) }
|
||||
|
||||
private DataFlow::SourceNode trackFileSource(DataFlow::TypeTracker t) {
|
||||
t.start() and result = getCallback([1 .. 2]).getParameter(1)
|
||||
or
|
||||
t.startInPromise() and not exists(getCallback([1 .. 2])) and result = this
|
||||
or
|
||||
// Tracking out of a promise
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
result = PromiseTypeTracking::promiseStep(trackFileSource(t2), t, t2)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,10 +231,24 @@ private module JSONFile {
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
this.getCalleeName() = "readFile" and result = getCallback([1 .. 2]).getParameter(1)
|
||||
override DataFlow::Node getADataNode() { result = trackRead(DataFlow::TypeTracker::end()) }
|
||||
|
||||
private DataFlow::SourceNode trackRead(DataFlow::TypeTracker t) {
|
||||
this.getCalleeName() = "readFile" and
|
||||
(
|
||||
t.start() and result = getCallback([1 .. 2]).getParameter(1)
|
||||
or
|
||||
t.startInPromise() and not exists(getCallback([1 .. 2])) and result = this
|
||||
)
|
||||
or
|
||||
this.getCalleeName() = "readFileSync" and result = this
|
||||
t.start() and
|
||||
this.getCalleeName() = "readFileSync" and
|
||||
result = this
|
||||
or
|
||||
// Tracking out of a promise
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
result = PromiseTypeTracking::promiseStep(trackRead(t2), t, t2)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +268,122 @@ private module JSONFile {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the library `load-json-file`.
|
||||
*/
|
||||
private class LoadJsonFile extends FileSystemReadAccess, DataFlow::CallNode {
|
||||
LoadJsonFile() {
|
||||
this = DataFlow::moduleImport("load-json-file").getACall()
|
||||
or
|
||||
this = DataFlow::moduleMember("load-json-file", "sync").getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getADataNode() { result = trackRead(DataFlow::TypeTracker::end()) }
|
||||
|
||||
private DataFlow::SourceNode trackRead(DataFlow::TypeTracker t) {
|
||||
this.getCalleeName() = "sync" and t.start() and result = this
|
||||
or
|
||||
not this.getCalleeName() = "sync" and t.startInPromise() and result = this
|
||||
or
|
||||
// Tracking out of a promise
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
result = PromiseTypeTracking::promiseStep(trackRead(t2), t, t2)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the library `write-json-file`.
|
||||
*/
|
||||
private class WriteJsonFile extends FileSystemWriteAccess, DataFlow::CallNode {
|
||||
WriteJsonFile() {
|
||||
this = DataFlow::moduleImport("write-json-file").getACall()
|
||||
or
|
||||
this = DataFlow::moduleMember("write-json-file", "sync").getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getADataNode() { result = getArgument(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the library `walkdir`.
|
||||
*/
|
||||
private class WalkDir extends FileNameProducer, FileSystemAccess, DataFlow::CallNode {
|
||||
WalkDir() {
|
||||
this = DataFlow::moduleImport("walkdir").getACall()
|
||||
or
|
||||
this = DataFlow::moduleMember("walkdir", "sync").getACall()
|
||||
or
|
||||
this = DataFlow::moduleMember("walkdir", "async").getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getAFileName() { result = trackFileSource(DataFlow::TypeTracker::end()) }
|
||||
|
||||
private DataFlow::SourceNode trackFileSource(DataFlow::TypeTracker t) {
|
||||
not this.getCalleeName() = any(string s | s = "sync" or s = "async") and
|
||||
t.start() and
|
||||
(
|
||||
result = getCallback(getNumArgument() - 1).getParameter(0)
|
||||
or
|
||||
result = getAMethodCall(EventEmitter::on()).getCallback(1).getParameter(0)
|
||||
)
|
||||
or
|
||||
t.start() and this.getCalleeName() = "sync" and result = this
|
||||
or
|
||||
t.startInPromise() and this.getCalleeName() = "async" and result = this
|
||||
or
|
||||
// Tracking out of a promise
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
result = PromiseTypeTracking::promiseStep(trackFileSource(t2), t, t2)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the library `globule`.
|
||||
*/
|
||||
private class Globule extends FileNameProducer, FileSystemAccess, DataFlow::CallNode {
|
||||
Globule() {
|
||||
this = DataFlow::moduleMember("globule", "find").getACall()
|
||||
or
|
||||
this = DataFlow::moduleMember("globule", "match").getACall()
|
||||
or
|
||||
this = DataFlow::moduleMember("globule", "isMatch").getACall()
|
||||
or
|
||||
this = DataFlow::moduleMember("globule", "mapping").getACall()
|
||||
or
|
||||
this = DataFlow::moduleMember("globule", "findMapping").getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() {
|
||||
(this.getCalleeName() = "match" or this.getCalleeName() = "isMatch") and
|
||||
result = getArgument(1)
|
||||
or
|
||||
this.getCalleeName() = "mapping" and
|
||||
(
|
||||
result = getAnArgument() and not exists(result.getALocalSource().getAPropertyWrite("src"))
|
||||
or
|
||||
result = getAnArgument().getALocalSource().getAPropertyWrite("src").getRhs()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAFileName() {
|
||||
result = this and
|
||||
(
|
||||
this.getCalleeName() = "find" or
|
||||
this.getCalleeName() = "match" or
|
||||
this.getCalleeName() = "findMapping" or
|
||||
this.getCalleeName() = "mapping"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A file system access made by a NodeJS library.
|
||||
* This class models multiple NodeJS libraries that access files.
|
||||
@@ -257,6 +398,10 @@ private class LibraryAccess extends FileSystemAccess, DataFlow::InvokeNode {
|
||||
or
|
||||
this = DataFlow::moduleImport("rimraf").getACall()
|
||||
or
|
||||
this = DataFlow::moduleImport("readdirp").getACall()
|
||||
or
|
||||
this = DataFlow::moduleImport("walker").getACall()
|
||||
or
|
||||
this =
|
||||
DataFlow::moduleMember("node-dir",
|
||||
any(string s |
|
||||
|
||||
@@ -23,7 +23,7 @@ module CleartextLogging {
|
||||
* A data flow sink for clear-text logging of sensitive information.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node {
|
||||
DataFlow::FlowLabel getLabel() { result.isDataOrTaint() }
|
||||
DataFlow::FlowLabel getLabel() { result.isTaint() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +127,7 @@ module CleartextLogging {
|
||||
|
||||
override string describe() { result = "an access to " + name }
|
||||
|
||||
override DataFlow::FlowLabel getLabel() { result.isData() }
|
||||
override DataFlow::FlowLabel getLabel() { result.isTaint() }
|
||||
}
|
||||
|
||||
/** An access to a variable or property that might contain a password. */
|
||||
@@ -153,7 +153,7 @@ module CleartextLogging {
|
||||
|
||||
override string describe() { result = "an access to " + name }
|
||||
|
||||
override DataFlow::FlowLabel getLabel() { result.isData() }
|
||||
override DataFlow::FlowLabel getLabel() { result.isTaint() }
|
||||
}
|
||||
|
||||
/** A call that might return a password. */
|
||||
@@ -167,7 +167,7 @@ module CleartextLogging {
|
||||
|
||||
override string describe() { result = "a call to " + name }
|
||||
|
||||
override DataFlow::FlowLabel getLabel() { result.isData() }
|
||||
override DataFlow::FlowLabel getLabel() { result.isTaint() }
|
||||
}
|
||||
|
||||
/** An access to the sensitive object `process.env`. */
|
||||
@@ -177,7 +177,7 @@ module CleartextLogging {
|
||||
override string describe() { result = "process environment" }
|
||||
|
||||
override DataFlow::FlowLabel getLabel() {
|
||||
result.isData() or
|
||||
result.isTaint() or
|
||||
result instanceof PartiallySensitiveMap
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ module PrototypePollution {
|
||||
private class RemoteFlowAsSource extends Source {
|
||||
RemoteFlowAsSource() { this instanceof RemoteFlowSource }
|
||||
|
||||
override DataFlow::FlowLabel getAFlowLabel() { result.isData() }
|
||||
override DataFlow::FlowLabel getAFlowLabel() { result.isTaint() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,7 +53,7 @@ module UnsafeDynamicMethodAccess {
|
||||
hasUnsafeMethods(read.getBase().getALocalSource()) and
|
||||
src = read.getPropertyNameExpr().flow() and
|
||||
dst = read and
|
||||
(srclabel = data() or srclabel = taint()) and
|
||||
srclabel.isTaint() and
|
||||
dstlabel = unsafeFunction()
|
||||
)
|
||||
or
|
||||
@@ -62,7 +62,7 @@ module UnsafeDynamicMethodAccess {
|
||||
not PropertyInjection::isPrototypeLessObject(proj.getObject().getALocalSource()) and
|
||||
src = proj.getASelector() and
|
||||
dst = proj and
|
||||
(srclabel = data() or srclabel = taint()) and
|
||||
srclabel.isTaint() and
|
||||
dstlabel = unsafeFunction()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ module UnsafeDynamicMethodAccess {
|
||||
/**
|
||||
* Gets the flow label relevant for this source.
|
||||
*/
|
||||
DataFlow::FlowLabel getFlowLabel() { result = data() }
|
||||
DataFlow::FlowLabel getFlowLabel() { result = taint() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,7 +40,7 @@ module UnvalidatedDynamicMethodCall {
|
||||
exists(DataFlow::PropRead read |
|
||||
src = read.getPropertyNameExpr().flow() and
|
||||
dst = read and
|
||||
(srclabel = data() or srclabel = taint()) and
|
||||
srclabel.isTaint() and
|
||||
(
|
||||
dstlabel instanceof MaybeNonFunction
|
||||
or
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user