mirror of
https://github.com/github/codeql.git
synced 2026-04-18 21:44:02 +02:00
Merge branch 'main' into loc2 and accept new test results.
This commit is contained in:
@@ -128,6 +128,7 @@ use_repo(
|
||||
"kotlin-compiler-1.9.20-Beta",
|
||||
"kotlin-compiler-2.0.0-RC1",
|
||||
"kotlin-compiler-2.0.20-Beta2",
|
||||
"kotlin-compiler-2.1.0-Beta1",
|
||||
"kotlin-compiler-embeddable-1.5.0",
|
||||
"kotlin-compiler-embeddable-1.5.10",
|
||||
"kotlin-compiler-embeddable-1.5.20",
|
||||
@@ -141,6 +142,7 @@ use_repo(
|
||||
"kotlin-compiler-embeddable-1.9.20-Beta",
|
||||
"kotlin-compiler-embeddable-2.0.0-RC1",
|
||||
"kotlin-compiler-embeddable-2.0.20-Beta2",
|
||||
"kotlin-compiler-embeddable-2.1.0-Beta1",
|
||||
"kotlin-stdlib-1.5.0",
|
||||
"kotlin-stdlib-1.5.10",
|
||||
"kotlin-stdlib-1.5.20",
|
||||
@@ -154,6 +156,7 @@ use_repo(
|
||||
"kotlin-stdlib-1.9.20-Beta",
|
||||
"kotlin-stdlib-2.0.0-RC1",
|
||||
"kotlin-stdlib-2.0.20-Beta2",
|
||||
"kotlin-stdlib-2.1.0-Beta1",
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
|
||||
@@ -57,10 +57,6 @@
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - CaptureModels": [
|
||||
"java/ql/src/utils/modelgenerator/internal/CaptureModels.qll",
|
||||
"csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll"
|
||||
],
|
||||
"Sign Java/C#": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 2.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
3
cpp/ql/lib/change-notes/released/2.0.1.md
Normal file
3
cpp/ql/lib/change-notes/released/2.0.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 2.0.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.0.0
|
||||
lastReleaseVersion: 2.0.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 2.0.1-dev
|
||||
version: 2.0.2-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -651,7 +651,8 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
|
||||
|
||||
/**
|
||||
* Holds if this declaration is an implicit function declaration, that is,
|
||||
* where a function is used before it is declared (under older C standards).
|
||||
* where a function is used before it is declared (under older C standards,
|
||||
* or when there were parse errors).
|
||||
*/
|
||||
predicate isImplicit() { fun_implicit(underlyingElement(this)) }
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ class Type extends Locatable, @type {
|
||||
|
||||
/**
|
||||
* Gets a specifier of this type, recursively looking through `typedef` and
|
||||
* `decltype`. For example, in the context of `typedef const int *restrict
|
||||
* t`, the type `volatile t` has specifiers `volatile` and `restrict` but not
|
||||
* `decltype`. For example, in the context of `typedef const int *restrict t`,
|
||||
* the type `volatile t` has specifiers `volatile` and `restrict` but not
|
||||
* `const` since the `const` is attached to the type being pointed to rather
|
||||
* than the pointer itself.
|
||||
*/
|
||||
|
||||
@@ -118,19 +118,34 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
|
||||
|
||||
/**
|
||||
* Gets the position of the first format argument, corresponding with
|
||||
* the first format specifier in the format string.
|
||||
* the first format specifier in the format string. We ignore all
|
||||
* implicit function definitions.
|
||||
*/
|
||||
int getFirstFormatArgumentIndex() {
|
||||
result = this.getNumberOfParameters() and
|
||||
// the formatting function either has a definition in the snapshot, or all
|
||||
// The formatting function either has a definition in the snapshot, or all
|
||||
// `DeclarationEntry`s agree on the number of parameters (otherwise we don't
|
||||
// really know the correct number)
|
||||
(
|
||||
this.hasDefinition()
|
||||
or
|
||||
forall(FunctionDeclarationEntry fde | fde = this.getADeclarationEntry() |
|
||||
result = fde.getNumberOfParameters()
|
||||
)
|
||||
if this.hasDefinition()
|
||||
then result = this.getDefinition().getNumberOfParameters()
|
||||
else result = this.getNumberOfExplicitParameters()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-implicit function declaration entry.
|
||||
*/
|
||||
private FunctionDeclarationEntry getAnExplicitDeclarationEntry() {
|
||||
result = this.getADeclarationEntry() and
|
||||
not result.isImplicit()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of parameters, excluding any parameters that have been defined
|
||||
* from implicit function declarations. If there is some inconsistency in the number
|
||||
* of parameters, then don't return anything.
|
||||
*/
|
||||
private int getNumberOfExplicitParameters() {
|
||||
forex(FunctionDeclarationEntry fde | fde = this.getAnExplicitDeclarationEntry() |
|
||||
result = fde.getNumberOfParameters()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ module FlowFromFree<FlowFromFreeParamSig P> {
|
||||
|
||||
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, _, state, _) }
|
||||
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
exists(Expr e, DataFlow::Node source, DeallocationExpr dealloc |
|
||||
P::isSink(sink, e) and
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
## 1.2.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed false positives in the `cpp/wrong-number-format-arguments` ("Too few arguments to formatting function") query when the formatting function has been declared implicitly.
|
||||
|
||||
## 1.2.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Removed false positives caused by buffer accesses in unreachable code.
|
||||
* Removed false positives caused by inconsistent type checking.
|
||||
* Removed false positives caused by buffer accesses in unreachable code
|
||||
* Removed false positives caused by inconsistent type checking
|
||||
* Add modeling of C functions that don't throw, thereby increasing the precision of the `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query. The query now produces additional true positives.
|
||||
|
||||
## 1.2.2
|
||||
|
||||
@@ -13,23 +13,85 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
class WideCharPointerType extends PointerType {
|
||||
WideCharPointerType() { this.getBaseType() instanceof WideCharType }
|
||||
}
|
||||
|
||||
/**
|
||||
* Given type `t`, recurses through and returns all
|
||||
* intermediate base types, including `t`.
|
||||
*/
|
||||
Type getABaseType(Type t) {
|
||||
result = t
|
||||
or
|
||||
result = getABaseType(t.(DerivedType).getBaseType())
|
||||
or
|
||||
result = getABaseType(t.(TypedefType).getBaseType())
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that may also be `CharPointerType`, but that are likely used as arbitrary buffers.
|
||||
*/
|
||||
class UnlikelyToBeAStringType extends Type {
|
||||
UnlikelyToBeAStringType() {
|
||||
this.(PointerType).getBaseType().(CharType).isUnsigned() or
|
||||
this.(PointerType).getBaseType().getName().toLowerCase().matches("%byte") or
|
||||
this.getName().toLowerCase().matches("%byte") or
|
||||
this.(PointerType).getBaseType().hasName("uint8_t")
|
||||
exists(Type targ | getABaseType(this) = targ |
|
||||
// NOTE: not using CharType isUnsigned, but rather look for any explicitly declared unsigned
|
||||
// char types. Assuming these are used for buffers, not strings.
|
||||
targ.(CharType).getName().toLowerCase().matches("unsigned%") or
|
||||
targ.getName().toLowerCase().matches(["uint8_t", "%byte%"])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Types that can be wide depending on the UNICODE macro
|
||||
// see https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
class UnicodeMacroDependentWidthType extends Type {
|
||||
UnicodeMacroDependentWidthType() {
|
||||
exists(Type targ | getABaseType(this) = targ |
|
||||
targ.getName() in [
|
||||
"LPCTSTR",
|
||||
"LPTSTR",
|
||||
"PCTSTR",
|
||||
"PTSTR",
|
||||
"TBYTE",
|
||||
"TCHAR"
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class UnicodeMacro extends Macro {
|
||||
UnicodeMacro() { this.getName().toLowerCase().matches("%unicode%") }
|
||||
}
|
||||
|
||||
class UnicodeMacroInvocation extends MacroInvocation {
|
||||
UnicodeMacroInvocation() { this.getMacro() instanceof UnicodeMacro }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds when a expression whose type is UnicodeMacroDependentWidthType and
|
||||
* is observed to be guarded by a check involving a bitwise-and operation
|
||||
* with a UnicodeMacroInvocation.
|
||||
* Such expressions are assumed to be checked dynamically, i.e.,
|
||||
* the flag would indicate if UNICODE typing is set correctly to allow
|
||||
* or disallow a widening cast.
|
||||
*/
|
||||
predicate isLikelyDynamicallyChecked(Expr e) {
|
||||
e.getType() instanceof UnicodeMacroDependentWidthType and
|
||||
exists(GuardCondition gc, BitwiseAndExpr bai, UnicodeMacroInvocation umi |
|
||||
bai.getAnOperand() = umi.getExpr()
|
||||
|
|
||||
// bai == 0 is false when reaching `e.getBasicBlock()`.
|
||||
// That is, bai != 0 when reaching `e.getBasicBlock()`.
|
||||
gc.ensuresEq(bai, 0, e.getBasicBlock(), false)
|
||||
or
|
||||
// bai == k and k != 0 is true when reaching `e.getBasicBlock()`.
|
||||
gc.ensuresEq(bai, any(int k | k != 0), e.getBasicBlock(), true)
|
||||
)
|
||||
}
|
||||
|
||||
from Expr e1, Cast e2
|
||||
where
|
||||
e2 = e1.getConversion() and
|
||||
@@ -42,7 +104,11 @@ where
|
||||
not e1.getType() instanceof UnlikelyToBeAStringType and
|
||||
// Avoid castings from 'new' expressions as typically these will be safe
|
||||
// Example: `__Type* ret = reinterpret_cast<__Type*>(New(m_pmo) char[num * sizeof(__Type)]);`
|
||||
not exists(NewOrNewArrayExpr newExpr | newExpr.getAChild*() = e1)
|
||||
not exists(NewOrNewArrayExpr newExpr | newExpr.getAChild*() = e1) and
|
||||
// Avoid cases where the cast is guarded by a check to determine if
|
||||
// unicode encoding is enabled in such a way to disallow the dangerous cast
|
||||
// at runtime.
|
||||
not isLikelyDynamicallyChecked(e1)
|
||||
select e1,
|
||||
"Conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
|
||||
". Use of invalid string can lead to undefined behavior."
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to detect byte arrays.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to recognize dynamic checks prior to possible dangerous widening.
|
||||
5
cpp/ql/src/change-notes/released/1.2.4.md
Normal file
5
cpp/ql/src/change-notes/released/1.2.4.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 1.2.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed false positives in the `cpp/wrong-number-format-arguments` ("Too few arguments to formatting function") query when the formatting function has been declared implicitly.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.2.3
|
||||
lastReleaseVersion: 1.2.4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.2.4-dev
|
||||
version: 1.2.5-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -2,25 +2,168 @@
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | false |
|
||||
| file://:0:0:0:0 | __super | false |
|
||||
| file://:0:0:0:0 | __va_list_tag | false |
|
||||
| file://:0:0:0:0 | decltype([...](...){...}) | false |
|
||||
| file://:0:0:0:0 | operator= | false |
|
||||
| file://:0:0:0:0 | operator= | false |
|
||||
| test.cpp:0:0:0:0 | test.cpp | false |
|
||||
| test.cpp:2:1:2:61 | #define FOO class S{int i; void f(void) { int j; return; } }; | false |
|
||||
| test.cpp:2:1:2:68 | #define CLASS_DECL class S{int i; void f(void) { int j; return; } }; | false |
|
||||
| test.cpp:4:1:4:1 | S | false |
|
||||
| test.cpp:4:1:4:1 | declaration of S | false |
|
||||
| test.cpp:4:1:4:1 | declaration of operator= | false |
|
||||
| test.cpp:4:1:4:1 | declaration of operator= | false |
|
||||
| test.cpp:4:1:4:1 | operator= | false |
|
||||
| test.cpp:4:1:4:1 | operator= | false |
|
||||
| test.cpp:4:1:4:3 | FOO | false |
|
||||
| test.cpp:4:1:4:3 | S | false |
|
||||
| test.cpp:4:1:4:3 | declaration | true |
|
||||
| test.cpp:4:1:4:3 | definition of S | true |
|
||||
| test.cpp:4:1:4:3 | definition of f | true |
|
||||
| test.cpp:4:1:4:3 | definition of i | true |
|
||||
| test.cpp:4:1:4:3 | definition of j | true |
|
||||
| test.cpp:4:1:4:3 | f | false |
|
||||
| test.cpp:4:1:4:3 | i | false |
|
||||
| test.cpp:4:1:4:3 | j | true |
|
||||
| test.cpp:4:1:4:3 | return ... | true |
|
||||
| test.cpp:4:1:4:3 | { ... } | true |
|
||||
| test.cpp:4:1:4:10 | CLASS_DECL | false |
|
||||
| test.cpp:4:1:4:10 | S | false |
|
||||
| test.cpp:4:1:4:10 | declaration | true |
|
||||
| test.cpp:4:1:4:10 | definition of S | true |
|
||||
| test.cpp:4:1:4:10 | definition of f | true |
|
||||
| test.cpp:4:1:4:10 | definition of i | true |
|
||||
| test.cpp:4:1:4:10 | definition of j | true |
|
||||
| test.cpp:4:1:4:10 | f | false |
|
||||
| test.cpp:4:1:4:10 | i | false |
|
||||
| test.cpp:4:1:4:10 | j | true |
|
||||
| test.cpp:4:1:4:10 | return ... | true |
|
||||
| test.cpp:4:1:4:10 | { ... } | true |
|
||||
| test.cpp:6:1:6:42 | #define FUNCTION_DECL void f1() { int k; } | false |
|
||||
| test.cpp:8:1:8:13 | FUNCTION_DECL | false |
|
||||
| test.cpp:8:1:8:13 | declaration | true |
|
||||
| test.cpp:8:1:8:13 | definition of f1 | true |
|
||||
| test.cpp:8:1:8:13 | definition of k | true |
|
||||
| test.cpp:8:1:8:13 | f1 | false |
|
||||
| test.cpp:8:1:8:13 | k | true |
|
||||
| test.cpp:8:1:8:13 | return ... | true |
|
||||
| test.cpp:8:1:8:13 | { ... } | true |
|
||||
| test.cpp:10:1:10:33 | #define VARIABLE_DECL int v1 = 1; | false |
|
||||
| test.cpp:12:1:12:13 | 1 | true |
|
||||
| test.cpp:12:1:12:13 | VARIABLE_DECL | false |
|
||||
| test.cpp:12:1:12:13 | definition of v1 | true |
|
||||
| test.cpp:12:1:12:13 | initializer for v1 | true |
|
||||
| test.cpp:12:1:12:13 | v1 | true |
|
||||
| test.cpp:14:1:14:35 | #define TYPE_DECL_1 typedef int t1; | false |
|
||||
| test.cpp:16:1:16:11 | TYPE_DECL_1 | false |
|
||||
| test.cpp:16:1:16:11 | declaration of t1 | true |
|
||||
| test.cpp:16:1:16:11 | t1 | false |
|
||||
| test.cpp:18:1:18:35 | #define TYPE_DECL_2 using t2 = int; | false |
|
||||
| test.cpp:20:1:20:11 | TYPE_DECL_2 | false |
|
||||
| test.cpp:20:1:20:11 | declaration of t2 | true |
|
||||
| test.cpp:20:1:20:11 | t2 | false |
|
||||
| test.cpp:22:1:22:47 | #define NAMESPACE_DECL namespace ns { int v2; } | false |
|
||||
| test.cpp:24:1:24:14 | NAMESPACE_DECL | false |
|
||||
| test.cpp:24:1:24:14 | definition of v2 | true |
|
||||
| test.cpp:24:1:24:14 | ns | false |
|
||||
| test.cpp:24:1:24:14 | ns | false |
|
||||
| test.cpp:24:1:24:14 | v2 | true |
|
||||
| test.cpp:26:1:26:43 | #define USING_NAMESPACE using namespace ns; | false |
|
||||
| test.cpp:28:1:28:34 | #define ENUM_CONSTANT enum_element | false |
|
||||
| test.cpp:30:12:30:21 | definition of enum_class | false |
|
||||
| test.cpp:30:12:30:21 | enum_class | false |
|
||||
| test.cpp:30:25:30:37 | ENUM_CONSTANT | false |
|
||||
| test.cpp:30:25:30:37 | enum_element | false |
|
||||
| test.cpp:32:1:32:41 | #define USING_ENUM using enum enum_class; | false |
|
||||
| test.cpp:34:1:34:10 | USING_ENUM | false |
|
||||
| test.cpp:34:1:34:10 | using enum enum_class | false |
|
||||
| test.cpp:36:1:36:48 | #define STATIC_ASSERT static_assert(1 == 1, ""); | false |
|
||||
| test.cpp:38:1:38:13 | 1 | true |
|
||||
| test.cpp:38:1:38:13 | 1 | true |
|
||||
| test.cpp:38:1:38:13 | ... == ... | true |
|
||||
| test.cpp:38:1:38:13 | STATIC_ASSERT | false |
|
||||
| test.cpp:38:1:38:13 | static_assert(..., "") | false |
|
||||
| test.cpp:40:1:40:42 | #define ATTRIBUTE [[nodiscard("reason1")]] | false |
|
||||
| test.cpp:42:1:42:9 | ATTRIBUTE | false |
|
||||
| test.cpp:42:1:42:9 | nodiscard | false |
|
||||
| test.cpp:42:1:42:9 | reason1 | false |
|
||||
| test.cpp:42:1:42:9 | reason1 | true |
|
||||
| test.cpp:43:5:43:6 | declaration of f2 | false |
|
||||
| test.cpp:43:5:43:6 | f2 | false |
|
||||
| test.cpp:45:1:45:31 | #define ATTRIBUTE_ARG "reason2" | false |
|
||||
| test.cpp:47:3:47:11 | nodiscard | false |
|
||||
| test.cpp:47:13:47:25 | ATTRIBUTE_ARG | false |
|
||||
| test.cpp:47:13:47:25 | reason2 | false |
|
||||
| test.cpp:47:13:47:25 | reason2 | true |
|
||||
| test.cpp:48:5:48:6 | declaration of f3 | false |
|
||||
| test.cpp:48:5:48:6 | f3 | false |
|
||||
| test.cpp:50:1:50:16 | #define TYPE int | false |
|
||||
| test.cpp:52:1:52:4 | TYPE | false |
|
||||
| test.cpp:52:6:52:7 | definition of v3 | true |
|
||||
| test.cpp:52:6:52:7 | v3 | true |
|
||||
| test.cpp:52:11:52:11 | 1 | false |
|
||||
| test.cpp:52:11:52:11 | initializer for v3 | false |
|
||||
| test.cpp:54:1:54:29 | #define DERIVATION : public S | false |
|
||||
| test.cpp:56:7:56:7 | T | false |
|
||||
| test.cpp:56:7:56:7 | T | false |
|
||||
| test.cpp:56:7:56:7 | declaration of T | false |
|
||||
| test.cpp:56:7:56:7 | declaration of operator= | false |
|
||||
| test.cpp:56:7:56:7 | declaration of operator= | false |
|
||||
| test.cpp:56:7:56:7 | definition of T | false |
|
||||
| test.cpp:56:7:56:7 | operator= | false |
|
||||
| test.cpp:56:7:56:7 | operator= | false |
|
||||
| test.cpp:56:9:56:18 | DERIVATION | false |
|
||||
| test.cpp:56:9:56:18 | derivation | false |
|
||||
| test.cpp:58:1:58:31 | #define FRIEND friend int f3(); | false |
|
||||
| test.cpp:60:7:60:7 | U | false |
|
||||
| test.cpp:60:7:60:7 | declaration of operator= | false |
|
||||
| test.cpp:60:7:60:7 | declaration of operator= | false |
|
||||
| test.cpp:60:7:60:7 | definition of U | false |
|
||||
| test.cpp:60:7:60:7 | operator= | false |
|
||||
| test.cpp:60:7:60:7 | operator= | false |
|
||||
| test.cpp:61:3:61:8 | FRIEND | false |
|
||||
| test.cpp:61:3:61:8 | U's friend | false |
|
||||
| test.cpp:64:1:64:24 | #define NAME_QUAL_1 ns:: | false |
|
||||
| test.cpp:66:1:66:22 | #define NAME_QUAL_2 ns | false |
|
||||
| test.cpp:68:1:68:19 | #define LOCAL_VAR m | false |
|
||||
| test.cpp:70:6:70:7 | definition of f4 | false |
|
||||
| test.cpp:70:6:70:7 | f4 | false |
|
||||
| test.cpp:70:11:76:1 | { ... } | false |
|
||||
| test.cpp:71:5:71:8 | ns:: | false |
|
||||
| test.cpp:71:5:71:15 | NAME_QUAL_1 | false |
|
||||
| test.cpp:71:5:71:18 | v2 | false |
|
||||
| test.cpp:71:5:71:19 | ExprStmt | false |
|
||||
| test.cpp:72:5:72:8 | ns:: | false |
|
||||
| test.cpp:72:5:72:15 | NAME_QUAL_2 | false |
|
||||
| test.cpp:72:5:72:21 | v2 | false |
|
||||
| test.cpp:72:5:72:22 | ExprStmt | false |
|
||||
| test.cpp:73:5:73:23 | declaration | false |
|
||||
| test.cpp:73:9:73:17 | LOCAL_VAR | false |
|
||||
| test.cpp:73:9:73:17 | definition of m | true |
|
||||
| test.cpp:73:9:73:17 | m | true |
|
||||
| test.cpp:73:20:73:22 | 42 | false |
|
||||
| test.cpp:73:20:73:22 | initializer for m | false |
|
||||
| test.cpp:74:5:74:41 | declaration | false |
|
||||
| test.cpp:74:10:74:10 | definition of l | false |
|
||||
| test.cpp:74:10:74:10 | l | false |
|
||||
| test.cpp:74:13:74:40 | [...](...){...} | false |
|
||||
| test.cpp:74:13:74:40 | initializer for l | false |
|
||||
| test.cpp:74:13:74:40 | {...} | false |
|
||||
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | declaration of (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | declaration of (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | definition of (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | definition of operator= | false |
|
||||
| test.cpp:74:14:74:14 | operator= | false |
|
||||
| test.cpp:74:15:74:15 | definition of m | false |
|
||||
| test.cpp:74:15:74:15 | m | false |
|
||||
| test.cpp:74:15:74:15 | m | false |
|
||||
| test.cpp:74:15:74:23 | LOCAL_VAR | false |
|
||||
| test.cpp:74:15:74:23 | m | true |
|
||||
| test.cpp:74:25:74:25 | definition of operator() | false |
|
||||
| test.cpp:74:25:74:25 | operator() | false |
|
||||
| test.cpp:74:28:74:40 | { ... } | false |
|
||||
| test.cpp:74:30:74:38 | return ... | false |
|
||||
| test.cpp:74:37:74:37 | (int)... | false |
|
||||
| test.cpp:75:5:75:5 | (const lambda [] type at line 74, col. 14)... | false |
|
||||
| test.cpp:75:5:75:5 | l | false |
|
||||
| test.cpp:75:5:75:8 | ExprStmt | false |
|
||||
| test.cpp:75:6:75:6 | call to operator() | false |
|
||||
| test.cpp:76:1:76:1 | return ... | false |
|
||||
| test.cpp:78:1:78:15 | #define ID(x) x | false |
|
||||
| test.cpp:79:1:79:23 | #define NESTED(x) ID(x) | false |
|
||||
| test.cpp:80:5:80:6 | definition of v4 | false |
|
||||
| test.cpp:80:5:80:6 | v4 | false |
|
||||
| test.cpp:80:10:80:18 | ID(x) | false |
|
||||
| test.cpp:80:10:80:18 | NESTED(x) | false |
|
||||
| test.cpp:80:17:80:17 | 1 | true |
|
||||
| test.cpp:80:17:80:17 | initializer for v4 | true |
|
||||
| test.cpp:82:1:82:39 | // semmle-extractor-options: -std=c++20 | false |
|
||||
|
||||
@@ -1,5 +1,82 @@
|
||||
|
||||
#define FOO class S{int i; void f(void) { int j; return; } };
|
||||
#define CLASS_DECL class S{int i; void f(void) { int j; return; } };
|
||||
|
||||
FOO
|
||||
CLASS_DECL
|
||||
|
||||
#define FUNCTION_DECL void f1() { int k; }
|
||||
|
||||
FUNCTION_DECL
|
||||
|
||||
#define VARIABLE_DECL int v1 = 1;
|
||||
|
||||
VARIABLE_DECL
|
||||
|
||||
#define TYPE_DECL_1 typedef int t1;
|
||||
|
||||
TYPE_DECL_1
|
||||
|
||||
#define TYPE_DECL_2 using t2 = int;
|
||||
|
||||
TYPE_DECL_2
|
||||
|
||||
#define NAMESPACE_DECL namespace ns { int v2; }
|
||||
|
||||
NAMESPACE_DECL
|
||||
|
||||
#define USING_NAMESPACE using namespace ns;
|
||||
|
||||
#define ENUM_CONSTANT enum_element
|
||||
|
||||
enum class enum_class { ENUM_CONSTANT };
|
||||
|
||||
#define USING_ENUM using enum enum_class;
|
||||
|
||||
USING_ENUM
|
||||
|
||||
#define STATIC_ASSERT static_assert(1 == 1, "");
|
||||
|
||||
STATIC_ASSERT
|
||||
|
||||
#define ATTRIBUTE [[nodiscard("reason1")]]
|
||||
|
||||
ATTRIBUTE
|
||||
int f2();
|
||||
|
||||
#define ATTRIBUTE_ARG "reason2"
|
||||
|
||||
[[nodiscard(ATTRIBUTE_ARG)]]
|
||||
int f3();
|
||||
|
||||
#define TYPE int
|
||||
|
||||
TYPE v3 = 1;
|
||||
|
||||
#define DERIVATION : public S
|
||||
|
||||
class T DERIVATION {};
|
||||
|
||||
#define FRIEND friend int f3();
|
||||
|
||||
class U {
|
||||
FRIEND
|
||||
};
|
||||
|
||||
#define NAME_QUAL_1 ns::
|
||||
|
||||
#define NAME_QUAL_2 ns
|
||||
|
||||
#define LOCAL_VAR m
|
||||
|
||||
void f4() {
|
||||
NAME_QUAL_1 v2;
|
||||
NAME_QUAL_2 :: v2;
|
||||
int LOCAL_VAR = 42;
|
||||
auto l = [LOCAL_VAR]() { return m; };
|
||||
l();
|
||||
}
|
||||
|
||||
#define ID(x) x
|
||||
#define NESTED(x) ID(x)
|
||||
int v4 = NESTED(1);
|
||||
|
||||
// semmle-extractor-options: -std=c++20
|
||||
|
||||
@@ -10,3 +10,4 @@
|
||||
| test.c:15:2:15:7 | call to printf | Format for printf expects 3 arguments but given 2 |
|
||||
| test.c:19:2:19:7 | call to printf | Format for printf expects 2 arguments but given 1 |
|
||||
| test.c:29:3:29:8 | call to printf | Format for printf expects 2 arguments but given 1 |
|
||||
| test.c:53:2:53:10 | call to my_logger | Format for my_logger expects 3 arguments but given 2 |
|
||||
|
||||
@@ -44,3 +44,6 @@ void test_custom_printf2()
|
||||
printf("", "%i %i", 100, 200); // GOOD
|
||||
printf("%i %i", "" ); // GOOD
|
||||
}
|
||||
|
||||
extern "C" void my_logger(int param, char *fmt, ...) __attribute__((format(printf, 2, 3))) {}
|
||||
|
||||
|
||||
@@ -46,4 +46,12 @@ void test(int i, const char *str)
|
||||
printf("%Y", 1, 2); // GOOD (unknown format character, this might be correct)
|
||||
printf("%1.1Y", 1, 2); // GOOD (unknown format character, this might be correct)
|
||||
printf("%*.*Y", 1, 2); // GOOD (unknown format character, this might be correct)
|
||||
|
||||
// Implicit logger function declaration
|
||||
my_logger(0, "%i %i %i %i %i %i\n", 1, 2, 3, 4, 5, 6); // GOOD
|
||||
my_logger(0, "%i %i %i\n", 1, 2, 3); // GOOD
|
||||
my_logger(0, "%i %i %i\n", 1, 2); // BAD (too few format arguments)
|
||||
}
|
||||
|
||||
// A spurious definition of my_logger
|
||||
extern void my_logger(int param, char *fmt, int, int, int, int, int);
|
||||
|
||||
@@ -53,4 +53,59 @@ void NonStringFalsePositiveTest2(unsigned char* buffer)
|
||||
{
|
||||
wchar_t *lpWchar = NULL;
|
||||
lpWchar = (LPWSTR)buffer; // Possible False Positive
|
||||
}
|
||||
}
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
using FOO = BYTE*;
|
||||
|
||||
void NonStringFalsePositiveTest3(FOO buffer)
|
||||
{
|
||||
wchar_t *lpWchar = NULL;
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
}
|
||||
|
||||
#define UNICODE 0x8
|
||||
|
||||
// assume EMPTY_MACRO is tied to if UNICODE is enabled
|
||||
#ifdef EMPTY_MACRO
|
||||
typedef WCHAR* LPTSTR;
|
||||
#else
|
||||
typedef char* LPTSTR;
|
||||
#endif
|
||||
|
||||
void CheckedConversionFalsePositiveTest3(unsigned short flags, LPTSTR buffer)
|
||||
{
|
||||
wchar_t *lpWchar = NULL;
|
||||
if(flags & UNICODE)
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) == 0x8)
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) != 0x8)
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
|
||||
// Bad operator precedence
|
||||
if(flags & UNICODE == 0x8)
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) != 0)
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) == 0)
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
}
|
||||
|
||||
@@ -3,3 +3,11 @@
|
||||
| WcharCharConversion.cpp:24:22:24:27 | lpChar | Conversion from char * to wchar_t *. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:26:23:26:28 | lpChar | Conversion from char * to LPCWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:27:17:27:22 | lpChar | Conversion from char * to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:82:21:82:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:87:21:87:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:90:21:90:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:96:21:96:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:98:21:98:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:103:21:103:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:106:21:106:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:110:20:110:25 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Context.ExtractionError($"Couldn't read file: {originalPath}. {exc.Message}", null, null, exc.StackTrace);
|
||||
Context.ExtractionError($"Couldn't read file: {originalPath}. {exc.Message}", null, null, exc.StackTrace, Semmle.Util.Logging.Severity.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.25
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.25
|
||||
lastReleaseVersion: 1.7.26
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.26-dev
|
||||
version: 1.7.27-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.25
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.25
|
||||
lastReleaseVersion: 1.7.26
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.26-dev
|
||||
version: 1.7.27-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -61,8 +61,3 @@ query predicate preBasicBlockConsistency(ControlFlowElement cfe1, ControlFlowEle
|
||||
bbIntraSuccInconsistency(cfe1, cfe2) and
|
||||
s = "intra succ inconsistency"
|
||||
}
|
||||
|
||||
query predicate multipleToString(Node n, string s) {
|
||||
s = strictconcat(n.toString(), ",") and
|
||||
strictcount(n.toString()) > 1
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
## 3.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* C#: Add support for MaD directly on properties and indexers using *attributes*. Using `Attribute.Getter` or `Attribute.Setter` in the model `ext` field applies the model to the getter or setter for properties and indexers. Prior to this change `Attribute` models unintentionally worked for property setters (if the property is decorated with the matching attribute). That is, a model that uses the `Attribute` feature directly on a property for a property setter needs to be changed to `Attribute.Setter`.
|
||||
* C#: Remove all CIL tables and related QL library functionality.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The class `ThreatModelFlowSource` has been renamed to `ActiveThreatModelSource` to more clearly reflect it only contains the currently active threat model sources. `ThreatModelFlowSource` has been marked as deprecated.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `DataFlow::Node` instances are no longer created for library methods and fields that are not callable (either statically or dynamically) or otherwise referred to from source code. This may affect third-party queries that use these nodes to identify library methods or fields that are present in DLL files where those methods or fields are unreferenced. If this presents a problem, consider using `Callable` and other non-dataflow classes to identify such library entities.
|
||||
* C#: Add extractor support for attributes on indexers.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* C#: Add support for MaD directly on properties and indexers using *attributes*. Using `Attribute.Getter` or `Attribute.Setter` in the model `ext` field applies the model to the getter or setter for properties and indexers. Prior to this change `Attribute` models unintentionally worked for property setters (if the property is decorated with the matching attribute). That is, a model that uses the `Attribute` feature directly on a property for a property setter needs to be changed to `Attribute.Setter`.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* C#: Remove all CIL tables and related QL library functionality.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C#: Add extractor support for attributes on indexers.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* `DataFlow::Node` instances are no longer created for library methods and fields that are not callable (either statically or dynamically) or otherwise referred to from source code. This may affect third-party queries that use these nodes to identify library methods or fields that are present in DLL files where those methods or fields are unreferenced. If this presents a problem, consider using `Callable` and other non-dataflow classes to identify such library entities.
|
||||
15
csharp/ql/lib/change-notes/released/3.0.0.md
Normal file
15
csharp/ql/lib/change-notes/released/3.0.0.md
Normal file
@@ -0,0 +1,15 @@
|
||||
## 3.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* C#: Add support for MaD directly on properties and indexers using *attributes*. Using `Attribute.Getter` or `Attribute.Setter` in the model `ext` field applies the model to the getter or setter for properties and indexers. Prior to this change `Attribute` models unintentionally worked for property setters (if the property is decorated with the matching attribute). That is, a model that uses the `Attribute` feature directly on a property for a property setter needs to be changed to `Attribute.Setter`.
|
||||
* C#: Remove all CIL tables and related QL library functionality.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The class `ThreatModelFlowSource` has been renamed to `ActiveThreatModelSource` to more clearly reflect it only contains the currently active threat model sources. `ThreatModelFlowSource` has been marked as deprecated.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `DataFlow::Node` instances are no longer created for library methods and fields that are not callable (either statically or dynamically) or otherwise referred to from source code. This may affect third-party queries that use these nodes to identify library methods or fields that are present in DLL files where those methods or fields are unreferenced. If this presents a problem, consider using `Callable` and other non-dataflow classes to identify such library entities.
|
||||
* C#: Add extractor support for attributes on indexers.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.0.0
|
||||
lastReleaseVersion: 3.0.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 2.0.1-dev
|
||||
version: 3.0.1-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -15,11 +15,19 @@ class CfgScope extends Element, @top_level_exprorstmt_parent {
|
||||
CfgScope() {
|
||||
this.getFile().fromSource() and
|
||||
(
|
||||
this instanceof Callable
|
||||
this =
|
||||
any(Callable c |
|
||||
c.(Constructor).hasInitializer()
|
||||
or
|
||||
InitializerSplitting::constructorInitializes(c, _)
|
||||
or
|
||||
c.hasBody()
|
||||
)
|
||||
or
|
||||
// For now, static initializer values have their own scope. Eventually, they
|
||||
// should be treated like instance initializers.
|
||||
this.(Assignable).(Modifiable).isStatic()
|
||||
this.(Assignable).(Modifiable).isStatic() and
|
||||
expr_parent_top_level_adjusted2(_, _, this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ private predicate elementSpec(
|
||||
or
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _)
|
||||
or
|
||||
neutralModel(namespace, type, name, signature, _, _) and ext = "" and subtypes = false
|
||||
neutralModel(namespace, type, name, signature, _, _) and ext = "" and subtypes = true
|
||||
}
|
||||
|
||||
private predicate elementSpec(
|
||||
@@ -602,7 +602,7 @@ private predicate interpretSummary(
|
||||
predicate interpretNeutral(UnboundCallable c, string kind, string provenance) {
|
||||
exists(string namespace, string type, string name, string signature |
|
||||
neutralModel(namespace, type, name, signature, kind, provenance) and
|
||||
c = interpretElement(namespace, type, false, name, signature, "")
|
||||
c = interpretElement(namespace, type, true, name, signature, "")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ private predicate needsChecks(ActionMethod m) { m.isEdit() and not m.isAdmin() }
|
||||
* that may indicate that it's used as the ID for some resource
|
||||
*/
|
||||
private predicate hasIdParameter(ActionMethod m) {
|
||||
exists(ThreatModelFlowSource src | src.getEnclosingCallable() = m |
|
||||
exists(ActiveThreatModelSource src | src.getEnclosingCallable() = m |
|
||||
src.asParameter().getName().toLowerCase().matches(["%id", "%idx"])
|
||||
or
|
||||
// handle cases like `Request.QueryString["Id"]`
|
||||
|
||||
@@ -55,7 +55,7 @@ deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource
|
||||
deprecated class LocalSource extends DataFlow::Node instanceof LocalFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ module CommandInjection = TaintTracking::Global<CommandInjectionConfig>;
|
||||
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/** Command Injection sinks defined through Models as Data. */
|
||||
private class ExternalCommandInjectionExprSink extends Sink {
|
||||
|
||||
@@ -54,7 +54,7 @@ module ConditionalBypass = TaintTracking::Global<ConditionalBypassConfig>;
|
||||
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/** The result of a reverse dns may be user-controlled. */
|
||||
class ReverseDnsSource extends Source {
|
||||
|
||||
@@ -73,14 +73,14 @@ class ExternalApiDataNode extends DataFlow::Node {
|
||||
}
|
||||
}
|
||||
|
||||
/** A configuration for tracking flow from `ThreatModelFlowSource`s to `ExternalApiDataNode`s. */
|
||||
/** A configuration for tracking flow from `ActiveThreatModelSource`s to `ExternalApiDataNode`s. */
|
||||
private module RemoteSourceToExternalApiConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||
}
|
||||
|
||||
/** A module for tracking flow from `ThreatModelFlowSource`s to `ExternalApiDataNode`s. */
|
||||
/** A module for tracking flow from `ActiveThreatModelSource`s to `ExternalApiDataNode`s. */
|
||||
module RemoteSourceToExternalApi = TaintTracking::Global<RemoteSourceToExternalApiConfig>;
|
||||
|
||||
/** A node representing untrusted data being passed to an external API. */
|
||||
|
||||
@@ -60,7 +60,7 @@ module LdapInjection = TaintTracking::Global<LdapInjectionConfig>;
|
||||
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/** LDAP sinks defined through Models as Data. */
|
||||
private class ExternalLdapExprSink extends Sink {
|
||||
|
||||
@@ -43,7 +43,7 @@ private module LogForgingConfig implements DataFlow::ConfigSig {
|
||||
module LogForging = TaintTracking::Global<LogForgingConfig>;
|
||||
|
||||
/** A source of remote user input. */
|
||||
private class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
private class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
private class HtmlSanitizer extends Sanitizer {
|
||||
HtmlSanitizer() { this.asExpr() instanceof HtmlSanitizedExpr }
|
||||
|
||||
@@ -48,7 +48,7 @@ private module MissingXmlValidationConfig implements DataFlow::ConfigSig {
|
||||
module MissingXmlValidation = TaintTracking::Global<MissingXmlValidationConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ThreatModelFlowSource` instead.
|
||||
* DEPRECATED: Use `ActiveThreatModelSource` instead.
|
||||
*
|
||||
* A source of remote user input.
|
||||
*/
|
||||
@@ -57,7 +57,7 @@ deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource
|
||||
/**
|
||||
* A source supported by the current threat model.
|
||||
*/
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/**
|
||||
* The input argument to a call to `XmlReader.Create` where the input will not be validated against
|
||||
|
||||
@@ -49,7 +49,7 @@ module ReDoS = TaintTracking::Global<ReDoSConfig>;
|
||||
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/**
|
||||
* An expression that represents a regular expression with potential exponential behavior.
|
||||
|
||||
@@ -48,7 +48,7 @@ module RegexInjection = TaintTracking::Global<RegexInjectionConfig>;
|
||||
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/**
|
||||
* A `pattern` argument to a construction of a `Regex`.
|
||||
|
||||
@@ -54,7 +54,7 @@ deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource
|
||||
deprecated class LocalSource extends DataFlow::Node instanceof LocalFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/** An argument to the `ConnectionString` property on a data connection class. */
|
||||
class SqlConnectionStringSink extends Sink {
|
||||
|
||||
@@ -65,7 +65,7 @@ deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource
|
||||
deprecated class LocalSource extends DataFlow::Node instanceof LocalFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/** An SQL expression passed to an API call that executes SQL. */
|
||||
class SqlInjectionExprSink extends Sink {
|
||||
|
||||
@@ -50,7 +50,7 @@ module TaintedPath = TaintTracking::Global<TaintedPathConfig>;
|
||||
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/**
|
||||
* A path argument to a `File` method call.
|
||||
|
||||
@@ -49,7 +49,7 @@ abstract private class ConstructorOrStaticMethodSink extends Sink { }
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
private class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
private class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/**
|
||||
* User input to object method call deserialization flow tracking configuration.
|
||||
|
||||
@@ -52,7 +52,7 @@ module UrlRedirect = TaintTracking::Global<UrlRedirectConfig>;
|
||||
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/** URL Redirection sinks defined through Models as Data. */
|
||||
private class ExternalUrlRedirectExprSink extends Sink {
|
||||
|
||||
@@ -15,7 +15,7 @@ private import semmle.code.csharp.security.Sanitizers
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
private class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
private class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/**
|
||||
* A data flow sink for untrusted user input used in XML processing.
|
||||
|
||||
@@ -58,7 +58,7 @@ module XpathInjection = TaintTracking::Global<XpathInjectionConfig>;
|
||||
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/** The `xpath` argument to an `XPathExpression.Compile(..)` call. */
|
||||
class XPathExpressionCompileSink extends Sink {
|
||||
|
||||
@@ -165,7 +165,7 @@ module XssTrackingConfig implements DataFlow::ConfigSig {
|
||||
module XssTracking = TaintTracking::Global<XssTrackingConfig>;
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
private class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
private class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
|
||||
|
||||
|
||||
@@ -56,10 +56,9 @@ class HtmlTextWriterSink extends HtmlSink {
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that is used as an argument to an HTML sink method on
|
||||
* `AttributeCollection`.
|
||||
* DEPRECATED: Attribute collections are no longer considered HTML sinks.
|
||||
*/
|
||||
class AttributeCollectionSink extends HtmlSink {
|
||||
deprecated class AttributeCollectionSink extends DataFlow::ExprNode {
|
||||
AttributeCollectionSink() {
|
||||
exists(SystemWebUIAttributeCollectionClass ac, Parameter p |
|
||||
p = ac.getAddMethod().getParameter(1) or
|
||||
|
||||
@@ -20,11 +20,18 @@ abstract class SourceNode extends DataFlow::Node {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ActiveThreatModelSource` instead.
|
||||
*
|
||||
* A class of data flow sources that respects the
|
||||
* current threat model configuration.
|
||||
*/
|
||||
class ThreatModelFlowSource extends DataFlow::Node {
|
||||
ThreatModelFlowSource() {
|
||||
deprecated class ThreatModelFlowSource = ActiveThreatModelSource;
|
||||
|
||||
/**
|
||||
* A data flow source that is enabled in the current threat model configuration.
|
||||
*/
|
||||
class ActiveThreatModelSource extends DataFlow::Node {
|
||||
ActiveThreatModelSource() {
|
||||
exists(string kind |
|
||||
// Specific threat model.
|
||||
currentThreatModel(kind) and
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 1.0.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* C#: The indexer and `Add` method on `System.Web.UI.AttributeCollection` is no longer considered an HTML sink.
|
||||
|
||||
## 1.0.8
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -20,7 +20,7 @@ import XmlInjection::PathGraph
|
||||
* A taint-tracking configuration for untrusted user input used in XML.
|
||||
*/
|
||||
module XmlInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
|
||||
@@ -21,7 +21,7 @@ import AssemblyPathInjection::PathGraph
|
||||
* A taint-tracking configuration for untrusted user input used to load a DLL.
|
||||
*/
|
||||
module AssemblyPathInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc, string name, int arg |
|
||||
|
||||
@@ -17,7 +17,7 @@ import semmle.code.csharp.frameworks.Format
|
||||
import FormatString::PathGraph
|
||||
|
||||
module FormatStringConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(FormatCall call | call.hasInsertions()).getFormatExpr()
|
||||
|
||||
5
csharp/ql/src/change-notes/released/1.0.9.md
Normal file
5
csharp/ql/src/change-notes/released/1.0.9.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 1.0.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* C#: The indexer and `Add` method on `System.Web.UI.AttributeCollection` is no longer considered an HTML sink.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.8
|
||||
lastReleaseVersion: 1.0.9
|
||||
|
||||
@@ -61,7 +61,7 @@ module TaintedWebClient = TaintTracking::Global<TaintedWebClientConfig>;
|
||||
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
|
||||
|
||||
/** A source supported by the current threat model. */
|
||||
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/**
|
||||
* A path argument to a `WebClient` method call that has an address argument.
|
||||
|
||||
@@ -60,7 +60,7 @@ module RequestForgery {
|
||||
/**
|
||||
* A dataflow source for Server Side Request Forgery(SSRF) Vulnerabilities.
|
||||
*/
|
||||
private class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
|
||||
private class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
/**
|
||||
* An url argument to a `HttpRequestMessage` constructor call
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 1.0.9-dev
|
||||
version: 1.0.10-dev
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
import internal.CaptureModels
|
||||
|
||||
from DataFlowSummaryTargetApi api, string flow
|
||||
where flow = captureContentFlow(api)
|
||||
where flow = ContentSensitive::captureFlow(api, _)
|
||||
select flow order by flow
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @name Capture mixed neutral models.
|
||||
* @description Finds neutral models to be used by other queries.
|
||||
* @kind diagnostic
|
||||
* @id cs/utils/modelgenerator/mixed-neutral-models
|
||||
* @tags modelgenerator
|
||||
*/
|
||||
|
||||
import internal.CaptureModels
|
||||
|
||||
from DataFlowSummaryTargetApi api, string noflow
|
||||
where noflow = captureMixedNeutral(api)
|
||||
select noflow order by noflow
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @name Capture mixed summary models.
|
||||
* @description Finds applicable summary models to be used by other queries.
|
||||
* @kind diagnostic
|
||||
* @id cs/utils/modelgenerator/mixed-summary-models
|
||||
* @tags modelgenerator
|
||||
*/
|
||||
|
||||
import internal.CaptureModels
|
||||
|
||||
from DataFlowSummaryTargetApi api, string flow
|
||||
where flow = captureMixedFlow(api, _)
|
||||
select flow order by flow
|
||||
@@ -6,9 +6,7 @@
|
||||
* @tags modelgenerator
|
||||
*/
|
||||
|
||||
import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
import internal.CaptureModels
|
||||
import internal.CaptureSummaryFlowQuery
|
||||
|
||||
from DataFlowSummaryTargetApi api, string noflow
|
||||
where noflow = captureNoFlow(api)
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
* @tags modelgenerator
|
||||
*/
|
||||
|
||||
import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
import internal.CaptureModels
|
||||
import internal.CaptureSummaryFlowQuery
|
||||
|
||||
from DataFlowSummaryTargetApi api, string flow
|
||||
where flow = captureFlow(api)
|
||||
|
||||
@@ -1,635 +1,354 @@
|
||||
/**
|
||||
* Provides classes and predicates related to capturing summary, source,
|
||||
* and sink models of the Standard or a 3rd party library.
|
||||
*/
|
||||
private import csharp as CS
|
||||
private import semmle.code.csharp.commons.Util as Util
|
||||
private import semmle.code.csharp.commons.Collections as Collections
|
||||
private import semmle.code.csharp.commons.QualifiedName as QualifiedName
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate as TaintTrackingPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.Location
|
||||
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
|
||||
|
||||
private import CaptureModelsSpecific
|
||||
private import CaptureModelsPrinting
|
||||
module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CsharpDataFlow> {
|
||||
class Type = CS::Type;
|
||||
|
||||
/**
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
|
||||
*/
|
||||
private class ReturnNodeExt extends DataFlow::Node {
|
||||
private DataFlowImplCommon::ReturnKindExt kind;
|
||||
class Parameter = CS::Parameter;
|
||||
|
||||
ReturnNodeExt() {
|
||||
kind = DataFlowImplCommon::getValueReturnPosition(this).getKind() or
|
||||
kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind()
|
||||
class Callable = CS::Callable;
|
||||
|
||||
class NodeExtended extends CS::DataFlow::Node {
|
||||
Callable getAsExprEnclosingCallable() { result = this.asExpr().getEnclosingCallable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of the return node.
|
||||
* Holds if any of the parameters of `api` are `System.Func<>`.
|
||||
*/
|
||||
DataFlowImplCommon::ReturnKindExt getKind() { result = kind }
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
private signature string printCallableParamSig(Callable c, ParameterPosition p);
|
||||
|
||||
private module PrintReturnNodeExt<printCallableParamSig/2 printCallableParam> {
|
||||
string getOutput(ReturnNodeExt node) {
|
||||
node.getKind() instanceof DataFlowImplCommon::ValueReturnKind and
|
||||
result = "ReturnValue"
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
|
||||
result = printCallableParam(returnNodeEnclosingCallable(node), pos)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
string getOutput(ReturnNodeExt node) {
|
||||
result = PrintReturnNodeExt<paramReturnNodeAsOutput/2>::getOutput(node)
|
||||
}
|
||||
|
||||
string getContentOutput(ReturnNodeExt node) {
|
||||
result = PrintReturnNodeExt<paramReturnNodeAsContentOutput/2>::getOutput(node)
|
||||
}
|
||||
|
||||
class DataFlowSummaryTargetApi extends SummaryTargetApi {
|
||||
DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) }
|
||||
}
|
||||
|
||||
class DataFlowSourceTargetApi = SourceTargetApi;
|
||||
|
||||
class DataFlowSinkTargetApi = SinkTargetApi;
|
||||
|
||||
private module ModelPrintingInput implements ModelPrintingSig {
|
||||
class SummaryApi = DataFlowSummaryTargetApi;
|
||||
|
||||
class SourceOrSinkApi = SourceOrSinkTargetApi;
|
||||
|
||||
string getProvenance() { result = "df-generated" }
|
||||
}
|
||||
|
||||
module Printing = ModelPrinting<ModelPrintingInput>;
|
||||
|
||||
/**
|
||||
* Holds if `c` is a relevant content kind, where the underlying type is relevant.
|
||||
*/
|
||||
private predicate isRelevantTypeInContent(DataFlow::ContentSet c) {
|
||||
isRelevantType(getUnderlyingContentType(c))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`.
|
||||
*/
|
||||
private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(DataFlow::ContentSet f |
|
||||
DataFlowPrivate::readStep(node1, f, node2) and
|
||||
// Partially restrict the content types used for intermediate steps.
|
||||
(not exists(getUnderlyingContentType(f)) or isRelevantTypeInContent(f))
|
||||
)
|
||||
or
|
||||
exists(DataFlow::ContentSet f | DataFlowPrivate::storeStep(node1, f, node2) | containerContent(f))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if content `c` is either a field, a synthetic field or language specific
|
||||
* content of a relevant type or a container like content.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate isRelevantContent0(DataFlow::ContentSet c) {
|
||||
isRelevantTypeInContent(c) or
|
||||
containerContent(c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of the parameter node `p`.
|
||||
*/
|
||||
string parameterNodeAsInput(DataFlow::ParameterNode p) {
|
||||
result = parameterAccess(p.asParameter())
|
||||
or
|
||||
result = qualifierString() and p instanceof InstanceParameterNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of the parameter `p`
|
||||
* when used in content flow.
|
||||
*/
|
||||
string parameterNodeAsContentInput(DataFlow::ParameterNode p) {
|
||||
result = parameterContentAccess(p.asParameter())
|
||||
or
|
||||
result = qualifierString() and p instanceof InstanceParameterNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD input string representation of `source`.
|
||||
*/
|
||||
string asInputArgument(DataFlow::Node source) { result = asInputArgumentSpecific(source) }
|
||||
|
||||
/**
|
||||
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
|
||||
*/
|
||||
string captureQualifierFlow(DataFlowSummaryTargetApi api) {
|
||||
exists(ReturnNodeExt ret |
|
||||
api = returnNodeEnclosingCallable(ret) and
|
||||
isOwnInstanceAccessNode(ret)
|
||||
) and
|
||||
result = Printing::asLiftedValueModel(api, qualifierString(), "ReturnValue")
|
||||
}
|
||||
|
||||
private int accessPathLimit0() { result = 2 }
|
||||
|
||||
private newtype TTaintState =
|
||||
TTaintRead(int n) { n in [0 .. accessPathLimit0()] } or
|
||||
TTaintStore(int n) { n in [1 .. accessPathLimit0()] }
|
||||
|
||||
abstract private class TaintState extends TTaintState {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A FlowState representing a tainted read.
|
||||
*/
|
||||
private class TaintRead extends TaintState, TTaintRead {
|
||||
private int step;
|
||||
|
||||
TaintRead() { this = TTaintRead(step) }
|
||||
|
||||
/**
|
||||
* Gets the flow state step number.
|
||||
*/
|
||||
int getStep() { result = step }
|
||||
|
||||
override string toString() { result = "TaintRead(" + step + ")" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A FlowState representing a tainted write.
|
||||
*/
|
||||
private class TaintStore extends TaintState, TTaintStore {
|
||||
private int step;
|
||||
|
||||
TaintStore() { this = TTaintStore(step) }
|
||||
|
||||
/**
|
||||
* Gets the flow state step number.
|
||||
*/
|
||||
int getStep() { result = step }
|
||||
|
||||
override string toString() { result = "TaintStore(" + step + ")" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow configuration for tracking flow through APIs.
|
||||
* The sources are the parameters of an API and the sinks are the return values (excluding `this`) and parameters.
|
||||
*
|
||||
* This can be used to generate Flow summaries for APIs from parameter to return.
|
||||
*/
|
||||
module PropagateFlowConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState = TaintState;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source instanceof DataFlow::ParameterNode and
|
||||
source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi and
|
||||
state.(TaintRead).getStep() = 0
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
sink instanceof ReturnNodeExt and
|
||||
not isOwnInstanceAccessNode(sink) and
|
||||
not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable())) and
|
||||
(state instanceof TaintRead or state instanceof TaintStore)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
exists(DataFlow::ContentSet c |
|
||||
DataFlowImplCommon::store(node1, c.getAStoreContent(), node2, _, _) and
|
||||
isRelevantContent0(c) and
|
||||
(
|
||||
state1 instanceof TaintRead and state2.(TaintStore).getStep() = 1
|
||||
or
|
||||
state1.(TaintStore).getStep() + 1 = state2.(TaintStore).getStep()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(DataFlow::ContentSet c |
|
||||
DataFlowPrivate::readStep(node1, c, node2) and
|
||||
isRelevantContent0(c) and
|
||||
state1.(TaintRead).getStep() + 1 = state2.(TaintRead).getStep()
|
||||
private predicate isHigherOrder(Callable api) {
|
||||
exists(Type t | t = api.getAParameter().getType().getUnboundDeclaration() |
|
||||
t instanceof SystemLinqExpressions::DelegateExtType
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) {
|
||||
exists(Type t | t = n.getType() and not isRelevantType(t))
|
||||
private predicate irrelevantAccessor(CS::Accessor a) {
|
||||
a.getDeclaration().(CS::Property).isReadWrite()
|
||||
}
|
||||
|
||||
DataFlow::FlowFeature getAFeature() {
|
||||
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
|
||||
}
|
||||
}
|
||||
|
||||
module PropagateFlow = TaintTracking::GlobalWithState<PropagateFlowConfig>;
|
||||
|
||||
/**
|
||||
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
|
||||
*/
|
||||
string captureThroughFlow0(
|
||||
DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt
|
||||
) {
|
||||
exists(string input, string output |
|
||||
p.getEnclosingCallable() = api and
|
||||
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
|
||||
input = parameterNodeAsInput(p) and
|
||||
output = getOutput(returnNodeExt) and
|
||||
input != output and
|
||||
result = Printing::asLiftedTaintModel(api, input, output)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
|
||||
*/
|
||||
string captureThroughFlow(DataFlowSummaryTargetApi api) {
|
||||
exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt |
|
||||
PropagateFlow::flow(p, returnNodeExt) and
|
||||
result = captureThroughFlow0(api, p, returnNodeExt)
|
||||
)
|
||||
}
|
||||
|
||||
private module PropagateContentFlowConfig implements ContentDataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof DataFlow::ParameterNode and
|
||||
source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof ReturnNodeExt and
|
||||
sink.getEnclosingCallable() instanceof DataFlowSummaryTargetApi
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep = isAdditionalContentFlowStep/2;
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) {
|
||||
exists(Type t | t = n.getType() and not isRelevantType(t))
|
||||
}
|
||||
|
||||
int accessPathLimit() { result = 2 }
|
||||
|
||||
predicate isRelevantContent(DataFlow::ContentSet s) { isRelevantContent0(s) }
|
||||
|
||||
DataFlow::FlowFeature getAFeature() {
|
||||
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
|
||||
}
|
||||
}
|
||||
|
||||
private module PropagateContentFlow = ContentDataFlow::Global<PropagateContentFlowConfig>;
|
||||
|
||||
private string getContent(PropagateContentFlow::AccessPath ap, int i) {
|
||||
exists(ContentSet head, PropagateContentFlow::AccessPath tail |
|
||||
head = ap.getHead() and
|
||||
tail = ap.getTail()
|
||||
|
|
||||
i = 0 and
|
||||
result = "." + printContent(head)
|
||||
private predicate isUninterestingForModels(Callable api) {
|
||||
api.getDeclaringType().getNamespace().getFullName() = ""
|
||||
or
|
||||
i > 0 and result = getContent(tail, i - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of a store step access path.
|
||||
*/
|
||||
private string printStoreAccessPath(PropagateContentFlow::AccessPath ap) {
|
||||
result = concat(int i | | getContent(ap, i), "" order by i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of a read step access path.
|
||||
*/
|
||||
private string printReadAccessPath(PropagateContentFlow::AccessPath ap) {
|
||||
result = concat(int i | | getContent(ap, i), "" order by i desc)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the access path `ap` contains a field or synthetic field access.
|
||||
*/
|
||||
private predicate mentionsField(PropagateContentFlow::AccessPath ap) {
|
||||
exists(ContentSet head, PropagateContentFlow::AccessPath tail |
|
||||
head = ap.getHead() and
|
||||
tail = ap.getTail()
|
||||
|
|
||||
mentionsField(tail) or isField(head)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate apiFlow(
|
||||
DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, PropagateContentFlow::AccessPath reads,
|
||||
ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath stores, boolean preservesValue
|
||||
) {
|
||||
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
|
||||
returnNodeExt.getEnclosingCallable() = api and
|
||||
p.getEnclosingCallable() = api
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of APIs relevant for modeling using content flow.
|
||||
* The following heuristic is applied:
|
||||
* Content flow is only relevant for an API, if
|
||||
* #content flow <= 2 * #parameters + 3
|
||||
* If an API produces more content flow, it is likely that
|
||||
* 1. Types are not sufficiently constrained leading to a combinatorial
|
||||
* explosion in dispatch and thus in the generated summaries.
|
||||
* 2. It is a reasonable approximation to use the non-content based flow
|
||||
* detection instead, as reads and stores would use a significant
|
||||
* part of an objects internal state.
|
||||
*/
|
||||
private class ContentDataFlowSummaryTargetApi extends DataFlowSummaryTargetApi {
|
||||
ContentDataFlowSummaryTargetApi() {
|
||||
count(string input, string output |
|
||||
exists(
|
||||
DataFlow::ParameterNode p, PropagateContentFlow::AccessPath reads,
|
||||
ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath stores
|
||||
|
|
||||
apiFlow(this, p, reads, returnNodeExt, stores, _) and
|
||||
input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and
|
||||
output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores)
|
||||
)
|
||||
) <= 2 * this.getNumberOfParameters() + 3
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate apiContentFlow(
|
||||
ContentDataFlowSummaryTargetApi api, DataFlow::ParameterNode p,
|
||||
PropagateContentFlow::AccessPath reads, ReturnNodeExt returnNodeExt,
|
||||
PropagateContentFlow::AccessPath stores, boolean preservesValue
|
||||
) {
|
||||
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
|
||||
returnNodeExt.getEnclosingCallable() = api and
|
||||
p.getEnclosingCallable() = api
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any of the content sets in `path` translates into a synthetic field.
|
||||
*/
|
||||
private predicate hasSyntheticContent(PropagateContentFlow::AccessPath path) {
|
||||
exists(PropagateContentFlow::AccessPath tail, ContentSet head |
|
||||
head = path.getHead() and
|
||||
tail = path.getTail()
|
||||
|
|
||||
exists(getSyntheticName(head)) or
|
||||
hasSyntheticContent(tail)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A module containing predicates for validating access paths containing content sets
|
||||
* that translates into synthetic fields, when used for generated summary models.
|
||||
*/
|
||||
private module AccessPathSyntheticValidation {
|
||||
/**
|
||||
* Holds if there exists an API that has content flow from `read` (on type `t1`)
|
||||
* to `store` (on type `t2`).
|
||||
*/
|
||||
private predicate step(
|
||||
Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store
|
||||
) {
|
||||
exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt |
|
||||
p.getType() = t1 and
|
||||
returnNodeExt.getType() = t2 and
|
||||
apiContentFlow(_, p, read, returnNodeExt, store, _)
|
||||
api instanceof CS::ConversionOperator
|
||||
or
|
||||
api instanceof Util::MainMethod
|
||||
or
|
||||
api instanceof CS::Destructor
|
||||
or
|
||||
api instanceof CS::AnonymousFunctionExpr
|
||||
or
|
||||
api.(CS::Constructor).isParameterless()
|
||||
or
|
||||
exists(Type decl | decl = api.getDeclaringType() |
|
||||
decl instanceof SystemObjectClass or
|
||||
decl instanceof SystemValueTypeClass
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists an API that has content flow from `read` (on type `t1`)
|
||||
* to `store` (on type `t2`), where `read` does not have synthetic content and `store` does.
|
||||
*
|
||||
* Step A -> Synth.
|
||||
*/
|
||||
private predicate synthPathEntry(
|
||||
Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store
|
||||
) {
|
||||
not hasSyntheticContent(read) and
|
||||
hasSyntheticContent(store) and
|
||||
step(t1, read, t2, store)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists an API that has content flow from `read` (on type `t1`)
|
||||
* to `store` (on type `t2`), where `read` has synthetic content
|
||||
* and `store` does not.
|
||||
*
|
||||
* Step Synth -> A.
|
||||
*/
|
||||
private predicate synthPathExit(
|
||||
Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store
|
||||
) {
|
||||
hasSyntheticContent(read) and
|
||||
not hasSyntheticContent(store) and
|
||||
step(t1, read, t2, store)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a path of steps from `read` to an exit.
|
||||
*
|
||||
* read ->* Synth -> A
|
||||
*/
|
||||
private predicate reachesSynthExit(Type t, PropagateContentFlow::AccessPath read) {
|
||||
synthPathExit(t, read, _, _)
|
||||
or
|
||||
hasSyntheticContent(read) and
|
||||
exists(PropagateContentFlow::AccessPath mid, Type midType |
|
||||
hasSyntheticContent(mid) and
|
||||
step(t, read, midType, mid) and
|
||||
reachesSynthExit(midType, mid.reverse())
|
||||
)
|
||||
// Disregard properties that have both a get and a set accessor,
|
||||
// which implicitly means auto implemented properties.
|
||||
irrelevantAccessor(api)
|
||||
}
|
||||
|
||||
private predicate relevant(Callable api) {
|
||||
[api.(CS::Modifiable), api.(CS::Accessor).getDeclaration()].isEffectivelyPublic() and
|
||||
api.fromSource() and
|
||||
api.isUnboundDeclaration() and
|
||||
not isUninterestingForModels(api)
|
||||
}
|
||||
|
||||
private Callable getARelevantOverrideeOrImplementee(Overridable m) {
|
||||
m.overridesOrImplements(result) and relevant(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a path of steps from an entry to `store`.
|
||||
*
|
||||
* A -> Synth ->* store
|
||||
* Gets the super implementation of `api` if it is relevant.
|
||||
* If such a super implementation does not exist, returns `api` if it is relevant.
|
||||
*/
|
||||
private predicate synthEntryReaches(Type t, PropagateContentFlow::AccessPath store) {
|
||||
synthPathEntry(_, _, t, store)
|
||||
or
|
||||
hasSyntheticContent(store) and
|
||||
exists(PropagateContentFlow::AccessPath mid, Type midType |
|
||||
hasSyntheticContent(mid) and
|
||||
step(midType, mid, t, store) and
|
||||
synthEntryReaches(midType, mid.reverse())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if at least one of the access paths `read` (on type `t1`) and `store` (on type `t2`)
|
||||
* contain content that will be translated into a synthetic field, when being used in
|
||||
* a MaD summary model, and if there is a range of APIs, such that
|
||||
* when chaining their flow access paths, there exists access paths `A` and `B` where
|
||||
* A ->* read -> store ->* B and where `A` and `B` do not contain content that will
|
||||
* be translated into a synthetic field.
|
||||
*
|
||||
* This is needed because we don't want to include summaries that reads from or
|
||||
* stores into a "dead" synthetic field.
|
||||
*
|
||||
* Example:
|
||||
* Assume we have a type `t` (in this case `t1` = `t2`) with methods `getX` and
|
||||
* `setX`, which gets and sets a private field `X` on `t`.
|
||||
* This would lead to the following content flows
|
||||
* getX : Argument[this].SyntheticField[t.X] -> ReturnValue.
|
||||
* setX : Argument[0] -> Argument[this].SyntheticField[t.X]
|
||||
* As the reads and stores are on synthetic fields we should only make summaries
|
||||
* if both of these methods exist.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate acceptReadStore(
|
||||
Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store
|
||||
) {
|
||||
synthPathEntry(t1, read, t2, store) and reachesSynthExit(t2, store.reverse())
|
||||
or
|
||||
exists(PropagateContentFlow::AccessPath store0 | store0.reverse() = read |
|
||||
synthEntryReaches(t1, store0) and synthPathExit(t1, read, t2, store)
|
||||
private Callable liftedImpl(Callable api) {
|
||||
(
|
||||
result = getARelevantOverrideeOrImplementee(api)
|
||||
or
|
||||
synthEntryReaches(t1, store0) and
|
||||
step(t1, read, t2, store) and
|
||||
reachesSynthExit(t2, store.reverse())
|
||||
)
|
||||
result = api and relevant(api)
|
||||
) and
|
||||
not exists(getARelevantOverrideeOrImplementee(result))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds, if the API `api` has relevant flow from `read` on `p` to `store` on `returnNodeExt`.
|
||||
* Flow is considered relevant,
|
||||
* 1. If `read` or `store` do not contain a content set that translates into a synthetic field.
|
||||
* 2. If `read` or `store` contain a content set that translates into a synthetic field, and if
|
||||
* the synthetic content is "live" on the relevant declaring type.
|
||||
*/
|
||||
private predicate apiRelevantContentFlow(
|
||||
ContentDataFlowSummaryTargetApi api, DataFlow::ParameterNode p,
|
||||
PropagateContentFlow::AccessPath read, ReturnNodeExt returnNodeExt,
|
||||
PropagateContentFlow::AccessPath store, boolean preservesValue
|
||||
) {
|
||||
apiContentFlow(api, p, read, returnNodeExt, store, preservesValue) and
|
||||
(
|
||||
not hasSyntheticContent(read) and not hasSyntheticContent(store)
|
||||
or
|
||||
AccessPathSyntheticValidation::acceptReadStore(p.getType(), read, returnNodeExt.getType(), store)
|
||||
)
|
||||
}
|
||||
private predicate hasManualSummaryModel(Callable api) {
|
||||
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate captureContentFlow0(
|
||||
ContentDataFlowSummaryTargetApi api, string input, string output, boolean preservesValue,
|
||||
boolean lift
|
||||
) {
|
||||
exists(
|
||||
DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath reads,
|
||||
PropagateContentFlow::AccessPath stores
|
||||
|
|
||||
apiRelevantContentFlow(api, p, reads, returnNodeExt, stores, preservesValue) and
|
||||
input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and
|
||||
output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and
|
||||
input != output and
|
||||
(if mentionsField(reads) or mentionsField(stores) then lift = false else lift = true)
|
||||
)
|
||||
}
|
||||
private predicate hasManualSourceModel(Callable api) {
|
||||
api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content based summary model(s) of the API `api` (if there is flow from a parameter to
|
||||
* the return value or a parameter).
|
||||
*
|
||||
* Models are lifted to the best type in case the read and store access paths do not
|
||||
* contain a field or synthetic field access.
|
||||
*/
|
||||
string captureContentFlow(ContentDataFlowSummaryTargetApi api) {
|
||||
exists(string input, string output, boolean lift, boolean preservesValue |
|
||||
captureContentFlow0(api, input, output, _, lift) and
|
||||
preservesValue = max(boolean p | captureContentFlow0(api, input, output, p, lift)) and
|
||||
result = Printing::asModel(api, input, output, preservesValue, lift)
|
||||
)
|
||||
}
|
||||
private predicate hasManualSinkModel(Callable api) {
|
||||
api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel())
|
||||
}
|
||||
|
||||
/**
|
||||
* A dataflow configuration used for finding new sources.
|
||||
* The sources are the already known existing sources and the sinks are the API return nodes.
|
||||
*
|
||||
* This can be used to generate Source summaries for an API, if the API expose an already known source
|
||||
* via its return (then the API itself becomes a source).
|
||||
*/
|
||||
module PropagateFromSourceConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(string kind |
|
||||
isRelevantSourceKind(kind) and
|
||||
ExternalFlow::sourceNode(source, kind)
|
||||
predicate isUninterestingForDataFlowModels(Callable api) { isHigherOrder(api) }
|
||||
|
||||
class SourceOrSinkTargetApi extends Callable {
|
||||
SourceOrSinkTargetApi() { relevant(this) }
|
||||
}
|
||||
|
||||
class SinkTargetApi extends SourceOrSinkTargetApi {
|
||||
SinkTargetApi() { not hasManualSinkModel(this) }
|
||||
}
|
||||
|
||||
class SourceTargetApi extends SourceOrSinkTargetApi {
|
||||
SourceTargetApi() {
|
||||
not hasManualSourceModel(this) and
|
||||
// Do not generate source models for overridable callables
|
||||
// as virtual dispatch implies that too many methods
|
||||
// will be considered sources.
|
||||
not this.(Overridable).overridesOrImplements(_)
|
||||
}
|
||||
}
|
||||
|
||||
class SummaryTargetApi extends Callable {
|
||||
private Callable lift;
|
||||
|
||||
SummaryTargetApi() {
|
||||
lift = liftedImpl(this) and
|
||||
not hasManualSummaryModel(lift)
|
||||
}
|
||||
|
||||
Callable lift() { result = lift }
|
||||
|
||||
predicate isRelevant() {
|
||||
relevant(this) and
|
||||
not hasManualSummaryModel(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `t` is a type that is generally used for bulk data in collection types.
|
||||
* Eg. char[] is roughly equivalent to string and thus a highly
|
||||
* relevant type for model generation.
|
||||
*/
|
||||
private predicate isPrimitiveTypeUsedForBulkData(CS::Type t) {
|
||||
t instanceof CS::ByteType or
|
||||
t instanceof CS::CharType
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the collection type `ct` is irrelevant for model generation.
|
||||
* Collection types where the type of the elements are
|
||||
* (1) unknown - are considered relevant.
|
||||
* (2) known - at least one the child types should be relevant (a non-simple type
|
||||
* or a type used for bulk data)
|
||||
*/
|
||||
private predicate irrelevantCollectionType(CS::Type ct) {
|
||||
Collections::isCollectionType(ct) and
|
||||
forex(CS::Type child | child = ct.getAChild() |
|
||||
child instanceof CS::SimpleType and
|
||||
not isPrimitiveTypeUsedForBulkData(child)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof ReturnNodeExt and
|
||||
sink.getEnclosingCallable() instanceof DataFlowSourceTargetApi
|
||||
predicate isRelevantType(CS::Type t) {
|
||||
not t instanceof CS::SimpleType and
|
||||
not t instanceof CS::Enum and
|
||||
not t instanceof SystemDateTimeStruct and
|
||||
not t instanceof SystemTypeClass and
|
||||
not irrelevantCollectionType(t)
|
||||
}
|
||||
|
||||
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSinkCallContext }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) {
|
||||
exists(Type t | t = n.getType() and not isRelevantType(t))
|
||||
/**
|
||||
* Gets the underlying type of the content `c`.
|
||||
*/
|
||||
private CS::Type getUnderlyingContType(DataFlow::Content c) {
|
||||
result = c.(DataFlow::FieldContent).getField().getType() or
|
||||
result = c.(DataFlow::SyntheticFieldContent).getField().getType()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
isRelevantTaintStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
private module PropagateFromSource = TaintTracking::Global<PropagateFromSourceConfig>;
|
||||
|
||||
/**
|
||||
* Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`.
|
||||
*/
|
||||
string captureSource(DataFlowSourceTargetApi api) {
|
||||
exists(DataFlow::Node source, ReturnNodeExt sink, string kind |
|
||||
PropagateFromSource::flow(source, sink) and
|
||||
ExternalFlow::sourceNode(source, kind) and
|
||||
api = sink.getEnclosingCallable() and
|
||||
not irrelevantSourceSinkApi(source.getEnclosingCallable(), api) and
|
||||
result = Printing::asSourceModel(api, getOutput(sink), kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A dataflow configuration used for finding new sinks.
|
||||
* The sources are the parameters of the API and the fields of the enclosing type.
|
||||
*
|
||||
* This can be used to generate Sink summaries for APIs, if the API propagates a parameter (or enclosing type field)
|
||||
* into an existing known sink (then the API itself becomes a sink).
|
||||
*/
|
||||
module PropagateToSinkConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
apiSource(source) and source.getEnclosingCallable() instanceof DataFlowSinkTargetApi
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(string kind | isRelevantSinkKind(kind) and ExternalFlow::sinkNode(sink, kind))
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(Type t | t = node.getType() and not isRelevantType(t))
|
||||
Type getUnderlyingContentType(DataFlow::ContentSet c) {
|
||||
exists(DataFlow::Content cont |
|
||||
c.isSingleton(cont) and
|
||||
result = getUnderlyingContType(cont)
|
||||
)
|
||||
or
|
||||
sinkModelSanitizer(node)
|
||||
exists(CS::Property p |
|
||||
c.isProperty(p) and
|
||||
result = p.getType()
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
|
||||
string qualifierString() { result = "Argument[this]" }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
isRelevantTaintStep(node1, node2)
|
||||
string parameterAccess(CS::Parameter p) {
|
||||
if Collections::isCollectionType(p.getType())
|
||||
then result = "Argument[" + p.getPosition() + "].Element"
|
||||
else result = "Argument[" + p.getPosition() + "]"
|
||||
}
|
||||
|
||||
string parameterContentAccess(CS::Parameter p) { result = "Argument[" + p.getPosition() + "]" }
|
||||
|
||||
class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode;
|
||||
|
||||
private signature string parameterAccessSig(Parameter p);
|
||||
|
||||
private module ParamReturnNodeAsOutput<parameterAccessSig/1 getParamAccess> {
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
|
||||
result = getParamAccess(c.getParameter(pos.getPosition()))
|
||||
or
|
||||
pos.isThisParameter() and
|
||||
result = qualifierString()
|
||||
}
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
|
||||
result = ParamReturnNodeAsOutput<parameterAccess/1>::paramReturnNodeAsOutput(c, pos)
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) {
|
||||
result = ParamReturnNodeAsOutput<parameterContentAccess/1>::paramReturnNodeAsOutput(c, pos)
|
||||
}
|
||||
|
||||
Callable returnNodeEnclosingCallable(DataFlow::Node ret) {
|
||||
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable(_)
|
||||
}
|
||||
|
||||
predicate isOwnInstanceAccessNode(DataFlowPrivate::ReturnNode node) {
|
||||
node.asExpr() instanceof CS::ThisAccess
|
||||
}
|
||||
|
||||
private predicate isRelevantMemberAccess(DataFlow::Node node) {
|
||||
exists(CS::MemberAccess access | access = node.asExpr() |
|
||||
access.hasThisQualifier() and
|
||||
access.getTarget().isEffectivelyPublic() and
|
||||
(
|
||||
access instanceof CS::FieldAccess
|
||||
or
|
||||
access.getTarget().(CS::Property).getSetter().isPublic()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate sinkModelSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
predicate apiSource(DataFlow::Node source) {
|
||||
isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode
|
||||
}
|
||||
|
||||
private predicate uniquelyCalls(DataFlowCallable dc1, DataFlowCallable dc2) {
|
||||
exists(DataFlowCall call |
|
||||
dc1 = call.getEnclosingCallable() and
|
||||
dc2 = unique(DataFlowCallable dc0 | dc0 = viableCallable(call) | dc0)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[dc1, dc2]
|
||||
private predicate uniquelyCallsPlus(DataFlowCallable dc1, DataFlowCallable dc2) =
|
||||
fastTC(uniquelyCalls/2)(dc1, dc2)
|
||||
|
||||
bindingset[sourceEnclosing, api]
|
||||
predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) {
|
||||
not exists(DataFlowCallable dc1, DataFlowCallable dc2 |
|
||||
uniquelyCallsPlus(dc1, dc2) or dc1 = dc2
|
||||
|
|
||||
dc1.getUnderlyingCallable() = api and
|
||||
dc2.getUnderlyingCallable() = sourceEnclosing
|
||||
)
|
||||
}
|
||||
|
||||
string getInputArgument(DataFlow::Node source) {
|
||||
exists(int pos |
|
||||
pos = source.(DataFlow::ParameterNode).getParameter().getPosition() and
|
||||
result = "Argument[" + pos + "]"
|
||||
)
|
||||
or
|
||||
source.asExpr() instanceof DataFlowPrivate::FieldOrPropertyAccess and
|
||||
result = qualifierString()
|
||||
}
|
||||
|
||||
bindingset[kind]
|
||||
predicate isRelevantSinkKind(string kind) { any() }
|
||||
|
||||
bindingset[kind]
|
||||
predicate isRelevantSourceKind(string kind) { any() }
|
||||
|
||||
predicate containerContent(DataFlow::ContentSet c) { c.isElement() }
|
||||
|
||||
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
TaintTrackingPrivate::defaultAdditionalTaintStep(nodeFrom, nodeTo, _) and
|
||||
not nodeTo.asExpr() instanceof CS::ElementAccess and
|
||||
not exists(DataFlow::ContentSet c |
|
||||
DataFlowPrivate::readStep(nodeFrom, c, nodeTo) and containerContent(c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[d]
|
||||
private string getFullyQualifiedName(Declaration d) {
|
||||
exists(string qualifier, string name |
|
||||
d.hasFullyQualifiedName(qualifier, name) and
|
||||
result = QualifiedName::getQualifiedName(qualifier, name)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isField(DataFlow::ContentSet c) {
|
||||
c.isField(_) or c.isSyntheticField(_) or c.isProperty(_)
|
||||
}
|
||||
|
||||
string getSyntheticName(DataFlow::ContentSet c) {
|
||||
exists(CS::Field f |
|
||||
not f.isEffectivelyPublic() and
|
||||
c.isField(f) and
|
||||
result = getFullyQualifiedName(f)
|
||||
)
|
||||
or
|
||||
exists(CS::Property p |
|
||||
not p.isEffectivelyPublic() and
|
||||
c.isProperty(p) and
|
||||
result = getFullyQualifiedName(p)
|
||||
)
|
||||
or
|
||||
c.isSyntheticField(result)
|
||||
}
|
||||
|
||||
string printContent(DataFlow::ContentSet c) {
|
||||
exists(CS::Field f, string name | name = getFullyQualifiedName(f) |
|
||||
c.isField(f) and
|
||||
f.isEffectivelyPublic() and
|
||||
result = "Field[" + name + "]"
|
||||
)
|
||||
or
|
||||
exists(CS::Property p, string name | name = getFullyQualifiedName(p) |
|
||||
c.isProperty(p) and
|
||||
p.isEffectivelyPublic() and
|
||||
result = "Property[" + name + "]"
|
||||
)
|
||||
or
|
||||
result = "SyntheticField[" + getSyntheticName(c) + "]"
|
||||
or
|
||||
c.isElement() and
|
||||
result = "Element"
|
||||
}
|
||||
|
||||
predicate partialModel = ExternalFlow::partialModel/6;
|
||||
|
||||
predicate sourceNode = ExternalFlow::sourceNode/2;
|
||||
|
||||
predicate sinkNode = ExternalFlow::sinkNode/2;
|
||||
}
|
||||
|
||||
private module PropagateToSink = TaintTracking::Global<PropagateToSinkConfig>;
|
||||
|
||||
/**
|
||||
* Gets the sink model(s) of `api`, if there is flow from a parameter to an existing known sink.
|
||||
*/
|
||||
string captureSink(DataFlowSinkTargetApi api) {
|
||||
exists(DataFlow::Node src, DataFlow::Node sink, string kind |
|
||||
PropagateToSink::flow(src, sink) and
|
||||
ExternalFlow::sinkNode(sink, kind) and
|
||||
api = src.getEnclosingCallable() and
|
||||
result = Printing::asSinkModel(api, asInputArgument(src), kind)
|
||||
)
|
||||
}
|
||||
import MakeModelGenerator<Location, CsharpDataFlow, CsharpTaintTracking, ModelGeneratorInput>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
private import csharp as CS
|
||||
private import codeql.mad.modelgenerator.ModelPrinting
|
||||
private import codeql.mad.modelgenerator.internal.ModelPrinting
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
|
||||
|
||||
private module ModelPrintingLang implements ModelPrintingLangSig {
|
||||
|
||||
@@ -1,436 +0,0 @@
|
||||
/**
|
||||
* Provides predicates related to capturing summary models of the Standard or a 3rd party library.
|
||||
*/
|
||||
|
||||
private import csharp as CS
|
||||
private import semmle.code.csharp.commons.Util as Util
|
||||
private import semmle.code.csharp.commons.Collections as Collections
|
||||
private import semmle.code.csharp.commons.QualifiedName as QualifiedName
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate as TaintTrackingPrivate
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.ContentDataFlow as ContentDataFlow
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||
|
||||
module DataFlow = CS::DataFlow;
|
||||
|
||||
module TaintTracking = CS::TaintTracking;
|
||||
|
||||
class Type = CS::Type;
|
||||
|
||||
class Callable = CS::Callable;
|
||||
|
||||
class ContentSet = DataFlow::ContentSet;
|
||||
|
||||
/**
|
||||
* Holds if any of the parameters of `api` are `System.Func<>`.
|
||||
*/
|
||||
private predicate isHigherOrder(Callable api) {
|
||||
exists(Type t | t = api.getAParameter().getType().getUnboundDeclaration() |
|
||||
t instanceof SystemLinqExpressions::DelegateExtType
|
||||
)
|
||||
}
|
||||
|
||||
private predicate irrelevantAccessor(CS::Accessor a) {
|
||||
a.getDeclaration().(CS::Property).isReadWrite()
|
||||
}
|
||||
|
||||
private predicate isUninterestingForModels(Callable api) {
|
||||
api.getDeclaringType().getNamespace().getFullName() = ""
|
||||
or
|
||||
api instanceof CS::ConversionOperator
|
||||
or
|
||||
api instanceof Util::MainMethod
|
||||
or
|
||||
api instanceof CS::Destructor
|
||||
or
|
||||
api instanceof CS::AnonymousFunctionExpr
|
||||
or
|
||||
api.(CS::Constructor).isParameterless()
|
||||
or
|
||||
exists(Type decl | decl = api.getDeclaringType() |
|
||||
decl instanceof SystemObjectClass or
|
||||
decl instanceof SystemValueTypeClass
|
||||
)
|
||||
or
|
||||
// Disregard properties that have both a get and a set accessor,
|
||||
// which implicitly means auto implemented properties.
|
||||
irrelevantAccessor(api)
|
||||
}
|
||||
|
||||
private predicate relevant(Callable api) {
|
||||
[api.(CS::Modifiable), api.(CS::Accessor).getDeclaration()].isEffectivelyPublic() and
|
||||
api.fromSource() and
|
||||
api.isUnboundDeclaration() and
|
||||
not isUninterestingForModels(api)
|
||||
}
|
||||
|
||||
private Callable getARelevantOverrideeOrImplementee(Overridable m) {
|
||||
m.overridesOrImplements(result) and relevant(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the super implementation of `api` if it is relevant.
|
||||
* If such a super implementation does not exist, returns `api` if it is relevant.
|
||||
*/
|
||||
private Callable liftedImpl(Callable api) {
|
||||
(
|
||||
result = getARelevantOverrideeOrImplementee(api)
|
||||
or
|
||||
result = api and relevant(api)
|
||||
) and
|
||||
not exists(getARelevantOverrideeOrImplementee(result))
|
||||
}
|
||||
|
||||
private predicate hasManualSummaryModel(Callable api) {
|
||||
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
|
||||
}
|
||||
|
||||
private predicate hasManualSourceModel(Callable api) {
|
||||
api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel())
|
||||
}
|
||||
|
||||
private predicate hasManualSinkModel(Callable api) {
|
||||
api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if it is irrelevant to generate models for `api` based on data flow analysis.
|
||||
*
|
||||
* This serves as an extra filter for the `relevant` predicate.
|
||||
*/
|
||||
predicate isUninterestingForDataFlowModels(CS::Callable api) { isHigherOrder(api) }
|
||||
|
||||
/**
|
||||
* Holds if it is irrelevant to generate models for `api` based on type-based analysis.
|
||||
*
|
||||
* This serves as an extra filter for the `relevant` predicate.
|
||||
*/
|
||||
predicate isUninterestingForTypeBasedFlowModels(CS::Callable api) { none() }
|
||||
|
||||
/**
|
||||
* A class of callables that are potentially relevant for generating source or
|
||||
* sink models.
|
||||
*/
|
||||
class SourceOrSinkTargetApi extends Callable {
|
||||
SourceOrSinkTargetApi() { relevant(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of callables that are potentially relevant for generating sink models.
|
||||
*/
|
||||
class SinkTargetApi extends SourceOrSinkTargetApi {
|
||||
SinkTargetApi() { not hasManualSinkModel(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of callables that are potentially relevant for generating source models.
|
||||
*/
|
||||
class SourceTargetApi extends SourceOrSinkTargetApi {
|
||||
SourceTargetApi() {
|
||||
not hasManualSourceModel(this) and
|
||||
// Do not generate source models for overridable callables
|
||||
// as virtual dispatch implies that too many methods
|
||||
// will be considered sources.
|
||||
not this.(Overridable).overridesOrImplements(_)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of callables that are potentially relevant for generating summary or
|
||||
* neutral models.
|
||||
*
|
||||
* In the Standard library and 3rd party libraries it is the callables (or callables that have a
|
||||
* super implementation) that can be called from outside the library itself.
|
||||
*/
|
||||
class SummaryTargetApi extends Callable {
|
||||
private Callable lift;
|
||||
|
||||
SummaryTargetApi() {
|
||||
lift = liftedImpl(this) and
|
||||
not hasManualSummaryModel(lift)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the callable that a model will be lifted to.
|
||||
*
|
||||
* The lifted callable is relevant in terms of model
|
||||
* generation (this is ensured by `liftedImpl`).
|
||||
*/
|
||||
Callable lift() { result = lift }
|
||||
|
||||
/**
|
||||
* Holds if `this` is relevant in terms of model generation.
|
||||
*/
|
||||
predicate isRelevant() { relevant(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `t` is a type that is generally used for bulk data in collection types.
|
||||
* Eg. char[] is roughly equivalent to string and thus a highly
|
||||
* relevant type for model generation.
|
||||
*/
|
||||
private predicate isPrimitiveTypeUsedForBulkData(CS::Type t) {
|
||||
t instanceof CS::ByteType or
|
||||
t instanceof CS::CharType
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the collection type `ct` is irrelevant for model generation.
|
||||
* Collection types where the type of the elements are
|
||||
* (1) unknown - are considered relevant.
|
||||
* (2) known - at least one the child types should be relevant (a non-simple type
|
||||
* or a type used for bulk data)
|
||||
*/
|
||||
private predicate irrelevantCollectionType(CS::Type ct) {
|
||||
Collections::isCollectionType(ct) and
|
||||
forex(CS::Type child | child = ct.getAChild() |
|
||||
child instanceof CS::SimpleType and
|
||||
not isPrimitiveTypeUsedForBulkData(child)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for type `t` for fields that are relevant as an intermediate
|
||||
* read or write step in the data flow analysis.
|
||||
* That is, flow through any data-flow node that does not have a relevant type
|
||||
* will be excluded.
|
||||
*/
|
||||
predicate isRelevantType(CS::Type t) {
|
||||
not t instanceof CS::SimpleType and
|
||||
not t instanceof CS::Enum and
|
||||
not t instanceof SystemDateTimeStruct and
|
||||
not t instanceof SystemTypeClass and
|
||||
not irrelevantCollectionType(t)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying type of the content `c`.
|
||||
*/
|
||||
private CS::Type getUnderlyingContType(DataFlow::Content c) {
|
||||
result = c.(DataFlow::FieldContent).getField().getType() or
|
||||
result = c.(DataFlow::SyntheticFieldContent).getField().getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying type of the content `c`.
|
||||
*/
|
||||
CS::Type getUnderlyingContentType(DataFlow::ContentSet c) {
|
||||
exists(DataFlow::Content cont |
|
||||
c.isSingleton(cont) and
|
||||
result = getUnderlyingContType(cont)
|
||||
)
|
||||
or
|
||||
exists(CS::Property p |
|
||||
c.isProperty(p) and
|
||||
result = p.getType()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of the qualifier.
|
||||
*/
|
||||
string qualifierString() { result = "Argument[this]" }
|
||||
|
||||
string parameterAccess(CS::Parameter p) {
|
||||
if Collections::isCollectionType(p.getType())
|
||||
then result = "Argument[" + p.getPosition() + "].Element"
|
||||
else result = "Argument[" + p.getPosition() + "]"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of the parameter `p`
|
||||
* when used in content flow.
|
||||
*/
|
||||
string parameterContentAccess(CS::Parameter p) { result = "Argument[" + p.getPosition() + "]" }
|
||||
|
||||
class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode;
|
||||
|
||||
class ParameterPosition = DataFlowDispatch::ParameterPosition;
|
||||
|
||||
private signature string parameterAccessSig(Parameter p);
|
||||
|
||||
module ParamReturnNodeAsOutput<parameterAccessSig/1 getParamAccess> {
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
|
||||
result = getParamAccess(c.getParameter(pos.getPosition()))
|
||||
or
|
||||
pos.isThisParameter() and
|
||||
result = qualifierString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of return through parameter at position
|
||||
* `pos` of callable `c`.
|
||||
*/
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
|
||||
result = ParamReturnNodeAsOutput<parameterAccess/1>::paramReturnNodeAsOutput(c, pos)
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) {
|
||||
result = ParamReturnNodeAsOutput<parameterContentAccess/1>::paramReturnNodeAsOutput(c, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `ret`.
|
||||
*/
|
||||
Callable returnNodeEnclosingCallable(DataFlow::Node ret) {
|
||||
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is an own instance access.
|
||||
*/
|
||||
predicate isOwnInstanceAccessNode(DataFlowPrivate::ReturnNode node) {
|
||||
node.asExpr() instanceof CS::ThisAccess
|
||||
}
|
||||
|
||||
private predicate isRelevantMemberAccess(DataFlow::Node node) {
|
||||
exists(CS::MemberAccess access | access = node.asExpr() |
|
||||
access.hasThisQualifier() and
|
||||
access.getTarget().isEffectivelyPublic() and
|
||||
(
|
||||
access instanceof CS::FieldAccess
|
||||
or
|
||||
access.getTarget().(CS::Property).getSetter().isPublic()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate sinkModelSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is an api entrypoint relevant for creating sink models.
|
||||
*/
|
||||
predicate apiSource(DataFlow::Node source) {
|
||||
isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode
|
||||
}
|
||||
|
||||
private predicate uniquelyCalls(DataFlowCallable dc1, DataFlowCallable dc2) {
|
||||
exists(DataFlowCall call |
|
||||
dc1 = call.getEnclosingCallable() and
|
||||
dc2 = unique(DataFlowCallable dc0 | dc0 = viableCallable(call) | dc0)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[dc1, dc2]
|
||||
private predicate uniquelyCallsPlus(DataFlowCallable dc1, DataFlowCallable dc2) =
|
||||
fastTC(uniquelyCalls/2)(dc1, dc2)
|
||||
|
||||
/**
|
||||
* Holds if it is not relevant to generate a source model for `api`, even
|
||||
* if flow is detected from a node within `source` to a sink within `api`.
|
||||
*/
|
||||
bindingset[sourceEnclosing, api]
|
||||
predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) {
|
||||
not exists(DataFlowCallable dc1, DataFlowCallable dc2 | uniquelyCallsPlus(dc1, dc2) or dc1 = dc2 |
|
||||
dc1.getUnderlyingCallable() = api and
|
||||
dc2.getUnderlyingCallable() = sourceEnclosing
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD input string representation of `source`.
|
||||
*/
|
||||
string asInputArgumentSpecific(DataFlow::Node source) {
|
||||
exists(int pos |
|
||||
pos = source.(DataFlow::ParameterNode).getParameter().getPosition() and
|
||||
result = "Argument[" + pos + "]"
|
||||
)
|
||||
or
|
||||
source.asExpr() instanceof DataFlowPrivate::FieldOrPropertyAccess and
|
||||
result = qualifierString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `kind` is a relevant sink kind for creating sink models.
|
||||
*/
|
||||
bindingset[kind]
|
||||
predicate isRelevantSinkKind(string kind) { any() }
|
||||
|
||||
/**
|
||||
* Holds if `kind` is a relevant source kind for creating source models.
|
||||
*/
|
||||
bindingset[kind]
|
||||
predicate isRelevantSourceKind(string kind) { any() }
|
||||
|
||||
/**
|
||||
* Holds if the the content `c` is a container.
|
||||
*/
|
||||
predicate containerContent(DataFlow::ContentSet c) { c.isElement() }
|
||||
|
||||
/**
|
||||
* Holds if there is a taint step from `node1` to `node2` in content flow.
|
||||
*/
|
||||
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
TaintTrackingPrivate::defaultAdditionalTaintStep(nodeFrom, nodeTo, _) and
|
||||
not nodeTo.asExpr() instanceof CS::ElementAccess and
|
||||
not exists(DataFlow::ContentSet c |
|
||||
DataFlowPrivate::readStep(nodeFrom, c, nodeTo) and containerContent(c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[d]
|
||||
private string getFullyQualifiedName(Declaration d) {
|
||||
exists(string qualifier, string name |
|
||||
d.hasFullyQualifiedName(qualifier, name) and
|
||||
result = QualifiedName::getQualifiedName(qualifier, name)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the content set `c` is a field, property or synthetic field.
|
||||
*/
|
||||
predicate isField(ContentSet c) { c.isField(_) or c.isSyntheticField(_) or c.isProperty(_) }
|
||||
|
||||
/**
|
||||
* Gets the MaD synthetic name string representation for the content set `c`, if any.
|
||||
*/
|
||||
string getSyntheticName(DataFlow::ContentSet c) {
|
||||
exists(CS::Field f |
|
||||
not f.isEffectivelyPublic() and
|
||||
c.isField(f) and
|
||||
result = getFullyQualifiedName(f)
|
||||
)
|
||||
or
|
||||
exists(CS::Property p |
|
||||
not p.isEffectivelyPublic() and
|
||||
c.isProperty(p) and
|
||||
result = getFullyQualifiedName(p)
|
||||
)
|
||||
or
|
||||
c.isSyntheticField(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of the content set `c`.
|
||||
*/
|
||||
string printContent(DataFlow::ContentSet c) {
|
||||
exists(CS::Field f, string name | name = getFullyQualifiedName(f) |
|
||||
c.isField(f) and
|
||||
f.isEffectivelyPublic() and
|
||||
result = "Field[" + name + "]"
|
||||
)
|
||||
or
|
||||
exists(CS::Property p, string name | name = getFullyQualifiedName(p) |
|
||||
c.isProperty(p) and
|
||||
p.isEffectivelyPublic() and
|
||||
result = "Property[" + name + "]"
|
||||
)
|
||||
or
|
||||
result = "SyntheticField[" + getSyntheticName(c) + "]"
|
||||
or
|
||||
c.isElement() and
|
||||
result = "Element"
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
private import CaptureModels
|
||||
|
||||
/**
|
||||
* Capture fluent APIs that return `this`.
|
||||
* Example of a fluent API:
|
||||
* ```csharp
|
||||
* public class BasicFlow {
|
||||
* public BasicFlow ReturnThis(object input)
|
||||
* {
|
||||
* // some side effect
|
||||
* return this;
|
||||
* }
|
||||
* ```
|
||||
* Captured Model:
|
||||
* ```Summaries;BasicFlow;false;ReturnThis;(System.Object);Argument[this];ReturnValue;value;df-generated```
|
||||
* Capture APIs that transfer taint from an input parameter to an output return
|
||||
* value or parameter.
|
||||
* Allows a sequence of read steps followed by a sequence of store steps.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ```csharp
|
||||
* public class BasicFlow {
|
||||
* private string tainted;
|
||||
*
|
||||
* public String ReturnField()
|
||||
* {
|
||||
* return tainted;
|
||||
* }
|
||||
*
|
||||
* public void AssignFieldToArray(object[] target)
|
||||
* {
|
||||
* target[0] = tainted;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* Captured Models:
|
||||
* ```
|
||||
* Summaries;BasicFlow;false;ReturnField;();Argument[this];ReturnValue;taint;df-generated |
|
||||
* Summaries;BasicFlow;false;AssignFieldToArray;(System.Object[]);Argument[this];Argument[0].Element;taint;df-generated
|
||||
* ```
|
||||
*
|
||||
* ```csharp
|
||||
* public class BasicFlow {
|
||||
* private string tainted;
|
||||
*
|
||||
* public void SetField(string s)
|
||||
* {
|
||||
* tainted = s;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* Captured Model:
|
||||
* ```Summaries;BasicFlow;false;SetField;(System.String);Argument[0];Argument[this];taint;df-generated```
|
||||
*
|
||||
* ```csharp
|
||||
* public class BasicFlow {
|
||||
* public void ReturnSubstring(string s)
|
||||
* {
|
||||
* return s.Substring(0, 1);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* Captured Model:
|
||||
* ```Summaries;BasicFlow;false;ReturnSubstring;(System.String);Argument[0];ReturnValue;taint;df-generated```
|
||||
*
|
||||
* ```csharp
|
||||
* public class BasicFlow {
|
||||
* public void AssignToArray(int data, int[] target)
|
||||
* {
|
||||
* target[0] = data;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* Captured Model:
|
||||
* ```Summaries;BasicFlow;false;AssignToArray;(System.Int32,System.Int32[]);Argument[0];Argument[1].Element;taint;df-generated```
|
||||
*/
|
||||
string captureFlow(DataFlowSummaryTargetApi api) {
|
||||
result = captureQualifierFlow(api) or
|
||||
result = captureThroughFlow(api)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the neutral summary model for `api`, if any.
|
||||
* A neutral summary model is generated, if we are not generating
|
||||
* a summary model that applies to `api` and if it relevant to generate
|
||||
* a model for `api`.
|
||||
*/
|
||||
string captureNoFlow(DataFlowSummaryTargetApi api) {
|
||||
not exists(DataFlowSummaryTargetApi api0 | exists(captureFlow(api0)) and api0.lift() = api.lift()) and
|
||||
api.isRelevant() and
|
||||
result = Printing::asNeutralSummaryModel(api)
|
||||
}
|
||||
@@ -2,7 +2,7 @@ private import csharp
|
||||
private import semmle.code.csharp.frameworks.system.collections.Generic as GenericCollections
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
private import CaptureModelsSpecific as Specific
|
||||
private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput
|
||||
private import CaptureModelsPrinting
|
||||
|
||||
/**
|
||||
@@ -38,7 +38,7 @@ private predicate localTypeParameter(Callable callable, TypeParameter tp) {
|
||||
*/
|
||||
private predicate parameter(Callable callable, string input, TypeParameter tp) {
|
||||
exists(Parameter p |
|
||||
input = Specific::parameterAccess(p) and
|
||||
input = ModelGeneratorInput::parameterAccess(p) and
|
||||
p = callable.getAParameter() and
|
||||
(
|
||||
// Parameter of type tp
|
||||
@@ -69,7 +69,7 @@ private string implicit(Callable callable, TypeParameter tp) {
|
||||
then access = ".Element"
|
||||
else access = getSyntheticField(tp)
|
||||
|
|
||||
result = Specific::qualifierString() + access
|
||||
result = ModelGeneratorInput::qualifierString() + access
|
||||
)
|
||||
}
|
||||
|
||||
@@ -191,9 +191,7 @@ private module Printing = ModelPrinting<ModelPrintingInput>;
|
||||
* A class of callables that are relevant generating summaries for based
|
||||
* on the Theorems for Free approach.
|
||||
*/
|
||||
class TypeBasedFlowTargetApi extends Specific::SummaryTargetApi {
|
||||
TypeBasedFlowTargetApi() { not Specific::isUninterestingForTypeBasedFlowModels(this) }
|
||||
|
||||
class TypeBasedFlowTargetApi extends ModelGeneratorInput::SummaryTargetApi {
|
||||
/**
|
||||
* Gets the string representation of all type based summaries for `this`
|
||||
* inspired by the Theorems for Free approach.
|
||||
|
||||
@@ -293,7 +293,8 @@ namespace My.Qltest
|
||||
}
|
||||
|
||||
// Test synthetic fields
|
||||
public class K {
|
||||
public class K
|
||||
{
|
||||
|
||||
public object MyField;
|
||||
|
||||
@@ -309,19 +310,22 @@ namespace My.Qltest
|
||||
|
||||
public object GetMyFieldOnSyntheticField() => throw null;
|
||||
|
||||
public void M1() {
|
||||
public void M1()
|
||||
{
|
||||
var o = new object();
|
||||
SetMySyntheticField(o);
|
||||
Sink(GetMySyntheticField());
|
||||
}
|
||||
|
||||
public void M2() {
|
||||
public void M2()
|
||||
{
|
||||
var o = new object();
|
||||
SetMyNestedSyntheticField(o);
|
||||
Sink(GetMyNestedSyntheticField());
|
||||
}
|
||||
|
||||
public void M3() {
|
||||
public void M3()
|
||||
{
|
||||
var o = new object();
|
||||
SetMyFieldOnSyntheticField(o);
|
||||
Sink(GetMyFieldOnSyntheticField());
|
||||
@@ -329,4 +333,19 @@ namespace My.Qltest
|
||||
|
||||
static void Sink(object o) { }
|
||||
}
|
||||
|
||||
// Test content data flow provenance.
|
||||
public class L
|
||||
{
|
||||
public void M1()
|
||||
{
|
||||
var l = new Library();
|
||||
var o = new object();
|
||||
l.SetValue(o);
|
||||
Sink(l.GetValue());
|
||||
}
|
||||
|
||||
static void Sink(object o) { }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,5 +13,9 @@ namespace My.Qltest
|
||||
public static object StepArgReturnGenerated(object x) => throw null;
|
||||
|
||||
public static object StepArgReturnGeneratedIgnored(object x) => throw null;
|
||||
|
||||
public void SetValue(object o) => throw null;
|
||||
|
||||
public object GetValue() => throw null;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -30,6 +30,8 @@ models
|
||||
| 29 | Summary: My.Qltest; K; false; GetMyNestedSyntheticField; (); ; Argument[this].SyntheticField[My.Qltest.K.MySyntheticField1].SyntheticField[MySyntheticField1.MyNestedSyntheticField]; ReturnValue; value; manual |
|
||||
| 30 | Summary: My.Qltest; K; false; SetMyFieldOnSyntheticField; (System.Object); ; Argument[0]; Argument[this].SyntheticField[My.Qltest.K.MySyntheticField2].Field[My.Qltest.K.MyField]; value; manual |
|
||||
| 31 | Summary: My.Qltest; K; false; GetMyFieldOnSyntheticField; (); ; Argument[this].SyntheticField[My.Qltest.K.MySyntheticField2].Field[My.Qltest.K.MyField]; ReturnValue; value; manual |
|
||||
| 32 | Summary: My.Qltest; Library; false; SetValue; (System.Object); ; Argument[0]; Argument[this].SyntheticField[X]; value; dfc-generated |
|
||||
| 33 | Summary: My.Qltest; Library; false; GetValue; (); ; Argument[this].SyntheticField[X]; ReturnValue; value; dfc-generated |
|
||||
edges
|
||||
| ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | provenance | |
|
||||
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | provenance | |
|
||||
@@ -127,21 +129,26 @@ edges
|
||||
| ExternalFlow.cs:279:13:279:23 | [post] this access : J | ExternalFlow.cs:281:18:281:21 | this access : J | provenance | |
|
||||
| ExternalFlow.cs:279:22:279:22 | access to local variable j : Object | ExternalFlow.cs:279:13:279:23 | [post] this access : J | provenance | MaD:25 |
|
||||
| ExternalFlow.cs:281:18:281:21 | this access : J | ExternalFlow.cs:281:18:281:27 | access to property Prop1 | provenance | MaD:24 |
|
||||
| ExternalFlow.cs:313:17:313:17 | access to local variable o : Object | ExternalFlow.cs:314:33:314:33 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:313:21:313:32 | object creation of type Object : Object | ExternalFlow.cs:313:17:313:17 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:314:13:314:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | ExternalFlow.cs:315:18:315:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | provenance | |
|
||||
| ExternalFlow.cs:314:33:314:33 | access to local variable o : Object | ExternalFlow.cs:314:13:314:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | provenance | MaD:26 |
|
||||
| ExternalFlow.cs:315:18:315:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | ExternalFlow.cs:315:18:315:38 | call to method GetMySyntheticField | provenance | MaD:27 |
|
||||
| ExternalFlow.cs:319:17:319:17 | access to local variable o : Object | ExternalFlow.cs:320:39:320:39 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:319:21:319:32 | object creation of type Object : Object | ExternalFlow.cs:319:17:319:17 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:320:13:320:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | ExternalFlow.cs:321:18:321:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | provenance | |
|
||||
| ExternalFlow.cs:320:39:320:39 | access to local variable o : Object | ExternalFlow.cs:320:13:320:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | provenance | MaD:28 |
|
||||
| ExternalFlow.cs:321:18:321:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | ExternalFlow.cs:321:18:321:44 | call to method GetMyNestedSyntheticField | provenance | MaD:29 |
|
||||
| ExternalFlow.cs:325:17:325:17 | access to local variable o : Object | ExternalFlow.cs:326:40:326:40 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:325:21:325:32 | object creation of type Object : Object | ExternalFlow.cs:325:17:325:17 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:326:13:326:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | ExternalFlow.cs:327:18:327:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | provenance | |
|
||||
| ExternalFlow.cs:326:40:326:40 | access to local variable o : Object | ExternalFlow.cs:326:13:326:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | provenance | MaD:30 |
|
||||
| ExternalFlow.cs:327:18:327:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | ExternalFlow.cs:327:18:327:45 | call to method GetMyFieldOnSyntheticField | provenance | MaD:31 |
|
||||
| ExternalFlow.cs:315:17:315:17 | access to local variable o : Object | ExternalFlow.cs:316:33:316:33 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:315:21:315:32 | object creation of type Object : Object | ExternalFlow.cs:315:17:315:17 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:316:13:316:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | ExternalFlow.cs:317:18:317:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | provenance | |
|
||||
| ExternalFlow.cs:316:33:316:33 | access to local variable o : Object | ExternalFlow.cs:316:13:316:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | provenance | MaD:26 |
|
||||
| ExternalFlow.cs:317:18:317:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | ExternalFlow.cs:317:18:317:38 | call to method GetMySyntheticField | provenance | MaD:27 |
|
||||
| ExternalFlow.cs:322:17:322:17 | access to local variable o : Object | ExternalFlow.cs:323:39:323:39 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:322:21:322:32 | object creation of type Object : Object | ExternalFlow.cs:322:17:322:17 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:323:13:323:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | ExternalFlow.cs:324:18:324:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | provenance | |
|
||||
| ExternalFlow.cs:323:39:323:39 | access to local variable o : Object | ExternalFlow.cs:323:13:323:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | provenance | MaD:28 |
|
||||
| ExternalFlow.cs:324:18:324:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | ExternalFlow.cs:324:18:324:44 | call to method GetMyNestedSyntheticField | provenance | MaD:29 |
|
||||
| ExternalFlow.cs:329:17:329:17 | access to local variable o : Object | ExternalFlow.cs:330:40:330:40 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:329:21:329:32 | object creation of type Object : Object | ExternalFlow.cs:329:17:329:17 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:330:13:330:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | ExternalFlow.cs:331:18:331:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | provenance | |
|
||||
| ExternalFlow.cs:330:40:330:40 | access to local variable o : Object | ExternalFlow.cs:330:13:330:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | provenance | MaD:30 |
|
||||
| ExternalFlow.cs:331:18:331:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | ExternalFlow.cs:331:18:331:45 | call to method GetMyFieldOnSyntheticField | provenance | MaD:31 |
|
||||
| ExternalFlow.cs:343:17:343:17 | access to local variable o : Object | ExternalFlow.cs:344:24:344:24 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:343:21:343:32 | object creation of type Object : Object | ExternalFlow.cs:343:17:343:17 | access to local variable o : Object | provenance | |
|
||||
| ExternalFlow.cs:344:13:344:13 | [post] access to local variable l : Library [synthetic X] : Object | ExternalFlow.cs:345:18:345:18 | access to local variable l : Library [synthetic X] : Object | provenance | |
|
||||
| ExternalFlow.cs:344:24:344:24 | access to local variable o : Object | ExternalFlow.cs:344:13:344:13 | [post] access to local variable l : Library [synthetic X] : Object | provenance | MaD:32 |
|
||||
| ExternalFlow.cs:345:18:345:18 | access to local variable l : Library [synthetic X] : Object | ExternalFlow.cs:345:18:345:29 | call to method GetValue | provenance | MaD:33 |
|
||||
nodes
|
||||
| ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | semmle.label | access to local variable arg1 : Object |
|
||||
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
@@ -261,24 +268,30 @@ nodes
|
||||
| ExternalFlow.cs:279:22:279:22 | access to local variable j : Object | semmle.label | access to local variable j : Object |
|
||||
| ExternalFlow.cs:281:18:281:21 | this access : J | semmle.label | this access : J |
|
||||
| ExternalFlow.cs:281:18:281:27 | access to property Prop1 | semmle.label | access to property Prop1 |
|
||||
| ExternalFlow.cs:313:17:313:17 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:313:21:313:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:314:13:314:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object |
|
||||
| ExternalFlow.cs:314:33:314:33 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:315:18:315:38 | call to method GetMySyntheticField | semmle.label | call to method GetMySyntheticField |
|
||||
| ExternalFlow.cs:315:18:315:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object |
|
||||
| ExternalFlow.cs:319:17:319:17 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:319:21:319:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:320:13:320:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object |
|
||||
| ExternalFlow.cs:320:39:320:39 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:321:18:321:44 | call to method GetMyNestedSyntheticField | semmle.label | call to method GetMyNestedSyntheticField |
|
||||
| ExternalFlow.cs:321:18:321:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object |
|
||||
| ExternalFlow.cs:325:17:325:17 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:325:21:325:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:326:13:326:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object |
|
||||
| ExternalFlow.cs:326:40:326:40 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:327:18:327:45 | call to method GetMyFieldOnSyntheticField | semmle.label | call to method GetMyFieldOnSyntheticField |
|
||||
| ExternalFlow.cs:327:18:327:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object |
|
||||
| ExternalFlow.cs:315:17:315:17 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:315:21:315:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:316:13:316:34 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField] : Object |
|
||||
| ExternalFlow.cs:316:33:316:33 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:317:18:317:38 | call to method GetMySyntheticField | semmle.label | call to method GetMySyntheticField |
|
||||
| ExternalFlow.cs:317:18:317:38 | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField] : Object |
|
||||
| ExternalFlow.cs:322:17:322:17 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:322:21:322:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:323:13:323:40 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object |
|
||||
| ExternalFlow.cs:323:39:323:39 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:324:18:324:44 | call to method GetMyNestedSyntheticField | semmle.label | call to method GetMyNestedSyntheticField |
|
||||
| ExternalFlow.cs:324:18:324:44 | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField1, synthetic MySyntheticField1.MyNestedSyntheticField] : Object |
|
||||
| ExternalFlow.cs:329:17:329:17 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:329:21:329:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:330:13:330:41 | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | semmle.label | [post] this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object |
|
||||
| ExternalFlow.cs:330:40:330:40 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:331:18:331:45 | call to method GetMyFieldOnSyntheticField | semmle.label | call to method GetMyFieldOnSyntheticField |
|
||||
| ExternalFlow.cs:331:18:331:45 | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object | semmle.label | this access : K [synthetic My.Qltest.K.MySyntheticField2, field MyField] : Object |
|
||||
| ExternalFlow.cs:343:17:343:17 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:343:21:343:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:344:13:344:13 | [post] access to local variable l : Library [synthetic X] : Object | semmle.label | [post] access to local variable l : Library [synthetic X] : Object |
|
||||
| ExternalFlow.cs:344:24:344:24 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| ExternalFlow.cs:345:18:345:18 | access to local variable l : Library [synthetic X] : Object | semmle.label | access to local variable l : Library [synthetic X] : Object |
|
||||
| ExternalFlow.cs:345:18:345:29 | call to method GetValue | semmle.label | call to method GetValue |
|
||||
subpaths
|
||||
| ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | ExternalFlow.cs:84:35:84:35 | o : Object | ExternalFlow.cs:84:40:84:40 | access to parameter o : Object | ExternalFlow.cs:84:25:84:41 | call to method Map<Object,Object> : T[] [element] : Object |
|
||||
invalidModelRow
|
||||
@@ -308,6 +321,7 @@ invalidModelRow
|
||||
| ExternalFlow.cs:240:18:240:18 | access to local variable o | ExternalFlow.cs:238:21:238:28 | object creation of type HC : HC | ExternalFlow.cs:240:18:240:18 | access to local variable o | $@ | ExternalFlow.cs:238:21:238:28 | object creation of type HC : HC | object creation of type HC : HC |
|
||||
| ExternalFlow.cs:258:18:258:18 | access to local variable b | ExternalFlow.cs:256:20:256:31 | object creation of type Object : Object | ExternalFlow.cs:258:18:258:18 | access to local variable b | $@ | ExternalFlow.cs:256:20:256:31 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:281:18:281:27 | access to property Prop1 | ExternalFlow.cs:278:21:278:32 | object creation of type Object : Object | ExternalFlow.cs:281:18:281:27 | access to property Prop1 | $@ | ExternalFlow.cs:278:21:278:32 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:315:18:315:38 | call to method GetMySyntheticField | ExternalFlow.cs:313:21:313:32 | object creation of type Object : Object | ExternalFlow.cs:315:18:315:38 | call to method GetMySyntheticField | $@ | ExternalFlow.cs:313:21:313:32 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:321:18:321:44 | call to method GetMyNestedSyntheticField | ExternalFlow.cs:319:21:319:32 | object creation of type Object : Object | ExternalFlow.cs:321:18:321:44 | call to method GetMyNestedSyntheticField | $@ | ExternalFlow.cs:319:21:319:32 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:327:18:327:45 | call to method GetMyFieldOnSyntheticField | ExternalFlow.cs:325:21:325:32 | object creation of type Object : Object | ExternalFlow.cs:327:18:327:45 | call to method GetMyFieldOnSyntheticField | $@ | ExternalFlow.cs:325:21:325:32 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:317:18:317:38 | call to method GetMySyntheticField | ExternalFlow.cs:315:21:315:32 | object creation of type Object : Object | ExternalFlow.cs:317:18:317:38 | call to method GetMySyntheticField | $@ | ExternalFlow.cs:315:21:315:32 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:324:18:324:44 | call to method GetMyNestedSyntheticField | ExternalFlow.cs:322:21:322:32 | object creation of type Object : Object | ExternalFlow.cs:324:18:324:44 | call to method GetMyNestedSyntheticField | $@ | ExternalFlow.cs:322:21:322:32 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:331:18:331:45 | call to method GetMyFieldOnSyntheticField | ExternalFlow.cs:329:21:329:32 | object creation of type Object : Object | ExternalFlow.cs:331:18:331:45 | call to method GetMyFieldOnSyntheticField | $@ | ExternalFlow.cs:329:21:329:32 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:345:18:345:29 | call to method GetValue | ExternalFlow.cs:343:21:343:32 | object creation of type Object : Object | ExternalFlow.cs:345:18:345:29 | call to method GetValue | $@ | ExternalFlow.cs:343:21:343:32 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
|
||||
@@ -43,6 +43,8 @@ extensions:
|
||||
- ["My.Qltest", "K", false, "GetMyNestedSyntheticField", "()", "", "Argument[this].SyntheticField[My.Qltest.K.MySyntheticField1].SyntheticField[MySyntheticField1.MyNestedSyntheticField]", "ReturnValue", "value", "manual"]
|
||||
- ["My.Qltest", "K", false, "SetMyFieldOnSyntheticField", "(System.Object)", "", "Argument[0]", "Argument[this].SyntheticField[My.Qltest.K.MySyntheticField2].Field[My.Qltest.K.MyField]", "value", "manual"]
|
||||
- ["My.Qltest", "K", false, "GetMyFieldOnSyntheticField", "()", "", "Argument[this].SyntheticField[My.Qltest.K.MySyntheticField2].Field[My.Qltest.K.MyField]", "ReturnValue", "value", "manual"]
|
||||
- ["My.Qltest", "Library", false, "SetValue", "(System.Object)", "", "Argument[0]", "Argument[this].SyntheticField[X]", "value", "dfc-generated"]
|
||||
- ["My.Qltest", "Library", false, "GetValue", "()", "", "Argument[this].SyntheticField[X]", "ReturnValue", "value", "dfc-generated"]
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
|
||||
@@ -2,5 +2,5 @@ import csharp
|
||||
import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
|
||||
from DataFlow::Node source
|
||||
where source instanceof ThreatModelFlowSource
|
||||
where source instanceof ActiveThreatModelSource
|
||||
select source
|
||||
|
||||
@@ -2,7 +2,7 @@ import csharp
|
||||
import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
|
||||
module CommandLineFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc | mc.getTarget().hasName("Sink") | sink.asExpr() = mc.getArgument(0))
|
||||
|
||||
@@ -2,5 +2,5 @@ import csharp
|
||||
import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
|
||||
from DataFlow::Node source
|
||||
where source instanceof ThreatModelFlowSource
|
||||
where source instanceof ActiveThreatModelSource
|
||||
select source, source.(SourceNode).getThreatModel()
|
||||
|
||||
@@ -4,7 +4,7 @@ import TestUtilities.InlineFlowTest
|
||||
import TaintFlowTest<DatabaseConfig>
|
||||
|
||||
module DatabaseConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc | mc.getTarget().hasName("Sink") | sink.asExpr() = mc.getArgument(0))
|
||||
|
||||
@@ -4,7 +4,7 @@ import TestUtilities.InlineFlowTest
|
||||
import TaintFlowTest<FilesConfig>
|
||||
|
||||
module FilesConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc | mc.getTarget().hasName("Sink") | sink.asExpr() = mc.getArgument(0))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
|
||||
private module ThreatModelConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sinkNode(sink, _) }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
| script.aspx:4:1:4:23 | <%= ... %> | XSS.cs:115:16:115:29 | someJavascript |
|
||||
| script.aspx:8:1:8:12 | <%= ... %> | XSS.cs:122:24:122:28 | Field |
|
||||
| script.aspx:4:1:4:23 | <%= ... %> | XSS.cs:120:16:120:29 | someJavascript |
|
||||
| script.aspx:8:1:8:12 | <%= ... %> | XSS.cs:127:24:127:28 | Field |
|
||||
| script.aspx:12:1:12:14 | <%= ... %> | <outside test directory> | Request |
|
||||
| script.aspx:16:1:16:34 | <%= ... %> | <outside test directory> | QueryString |
|
||||
| script.aspx:20:1:20:41 | <%= ... %> | <outside test directory> | QueryString |
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Test
|
||||
Table table;
|
||||
Label label;
|
||||
string connectionString;
|
||||
public Button button;
|
||||
|
||||
public void WebUIXSS()
|
||||
{
|
||||
@@ -100,6 +101,10 @@ namespace Test
|
||||
// GOOD: HTML encoding
|
||||
string name = context.Request.QueryString["name"];
|
||||
new StringContent(HttpUtility.HtmlEncode(name));
|
||||
|
||||
// GOOD: Implicit HTML encoding
|
||||
string html = context.Request.QueryString["html"];
|
||||
button.Attributes.Add("data-href", html);
|
||||
}
|
||||
|
||||
public void UrlEncoded(HttpContextBase context)
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
#select
|
||||
| XSS.cs:26:32:26:51 | call to method ToString | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:26:32:26:51 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | User-provided value |
|
||||
| XSS.cs:27:29:27:48 | call to method ToString | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:27:29:27:48 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | User-provided value |
|
||||
| XSS.cs:28:26:28:45 | call to method ToString | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:28:26:28:45 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | User-provided value |
|
||||
| XSS.cs:38:36:38:39 | access to local variable name | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:38:36:38:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:59:22:59:25 | access to local variable name | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:59:22:59:25 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:76:36:76:39 | access to local variable name | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:76:36:76:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:79:36:79:40 | access to local variable name2 | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | XSS.cs:79:36:79:40 | access to local variable name2 | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | User-provided value |
|
||||
| XSS.cs:86:28:86:31 | access to local variable name | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:86:28:86:31 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:87:31:87:34 | access to local variable name | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:87:31:87:34 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:95:31:95:34 | access to local variable name | XSS.cs:94:27:94:53 | access to property QueryString : NameValueCollection | XSS.cs:95:31:95:34 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:94:27:94:53 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:135:20:135:33 | access to property RawUrl | XSS.cs:135:20:135:33 | access to property RawUrl | XSS.cs:135:20:135:33 | access to property RawUrl | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:135:20:135:33 | access to property RawUrl | User-provided value |
|
||||
| XSS.cs:27:32:27:51 | call to method ToString | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | XSS.cs:27:32:27:51 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | User-provided value |
|
||||
| XSS.cs:28:29:28:48 | call to method ToString | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | XSS.cs:28:29:28:48 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | User-provided value |
|
||||
| XSS.cs:29:26:29:45 | call to method ToString | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | XSS.cs:29:26:29:45 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | User-provided value |
|
||||
| XSS.cs:39:36:39:39 | access to local variable name | XSS.cs:38:27:38:53 | access to property QueryString : NameValueCollection | XSS.cs:39:36:39:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:38:27:38:53 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:60:22:60:25 | access to local variable name | XSS.cs:58:27:58:65 | access to property QueryString : NameValueCollection | XSS.cs:60:22:60:25 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:58:27:58:65 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:77:36:77:39 | access to local variable name | XSS.cs:76:27:76:53 | access to property QueryString : NameValueCollection | XSS.cs:77:36:77:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:76:27:76:53 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:80:36:80:40 | access to local variable name2 | XSS.cs:79:28:79:42 | access to property Request : HttpRequestBase | XSS.cs:80:36:80:40 | access to local variable name2 | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:79:28:79:42 | access to property Request : HttpRequestBase | User-provided value |
|
||||
| XSS.cs:87:28:87:31 | access to local variable name | XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | XSS.cs:87:28:87:31 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:88:31:88:34 | access to local variable name | XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | XSS.cs:88:31:88:34 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:96:31:96:34 | access to local variable name | XSS.cs:95:27:95:53 | access to property QueryString : NameValueCollection | XSS.cs:96:31:96:34 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:95:27:95:53 | access to property QueryString : NameValueCollection | User-provided value |
|
||||
| XSS.cs:140:20:140:33 | access to property RawUrl | XSS.cs:140:20:140:33 | access to property RawUrl | XSS.cs:140:20:140:33 | access to property RawUrl | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:140:20:140:33 | access to property RawUrl | User-provided value |
|
||||
| script.aspx:12:1:12:14 | <%= ... %> | script.aspx:12:1:12:14 | <%= ... %> | script.aspx:12:1:12:14 | <%= ... %> | $@ flows to here and is a remote source accessed inline in an ASPX page. | script.aspx:12:1:12:14 | <%= ... %> | User-provided value |
|
||||
| script.aspx:16:1:16:34 | <%= ... %> | script.aspx:16:1:16:34 | <%= ... %> | script.aspx:16:1:16:34 | <%= ... %> | $@ flows to here and is a remote source accessed inline in an ASPX page. | script.aspx:16:1:16:34 | <%= ... %> | User-provided value |
|
||||
| script.aspx:20:1:20:41 | <%= ... %> | script.aspx:20:1:20:41 | <%= ... %> | script.aspx:20:1:20:41 | <%= ... %> | $@ flows to here and is a remote source accessed inline in an ASPX page. | script.aspx:20:1:20:41 | <%= ... %> | User-provided value |
|
||||
edges
|
||||
| XSS.cs:25:13:25:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:26:32:26:40 | access to local variable userInput : StringBuilder | provenance | |
|
||||
| XSS.cs:25:13:25:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:27:29:27:37 | access to local variable userInput : StringBuilder | provenance | |
|
||||
| XSS.cs:25:13:25:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:28:26:28:34 | access to local variable userInput : StringBuilder | provenance | |
|
||||
| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:25:48:25:67 | access to property Text : String | provenance | MaD:4 |
|
||||
| XSS.cs:25:48:25:67 | access to property Text : String | XSS.cs:25:13:25:21 | [post] access to local variable userInput : StringBuilder | provenance | MaD:2 |
|
||||
| XSS.cs:26:32:26:40 | access to local variable userInput : StringBuilder | XSS.cs:26:32:26:51 | call to method ToString | provenance | MaD:3 |
|
||||
| XSS.cs:27:29:27:37 | access to local variable userInput : StringBuilder | XSS.cs:27:29:27:48 | call to method ToString | provenance | MaD:3 |
|
||||
| XSS.cs:28:26:28:34 | access to local variable userInput : StringBuilder | XSS.cs:28:26:28:45 | call to method ToString | provenance | MaD:3 |
|
||||
| XSS.cs:37:20:37:23 | access to local variable name : String | XSS.cs:38:36:38:39 | access to local variable name | provenance | Sink:MaD:5 |
|
||||
| XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:37:20:37:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:37:27:37:61 | access to indexer : String | provenance | MaD:6 |
|
||||
| XSS.cs:37:27:37:61 | access to indexer : String | XSS.cs:37:20:37:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:57:20:57:23 | access to local variable name : String | XSS.cs:59:22:59:25 | access to local variable name | provenance | |
|
||||
| XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:57:20:57:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:57:27:57:73 | access to indexer : String | provenance | MaD:6 |
|
||||
| XSS.cs:57:27:57:73 | access to indexer : String | XSS.cs:57:20:57:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:75:20:75:23 | access to local variable name : String | XSS.cs:76:36:76:39 | access to local variable name | provenance | |
|
||||
| XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:75:20:75:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:75:27:75:61 | access to indexer : String | provenance | MaD:6 |
|
||||
| XSS.cs:75:27:75:61 | access to indexer : String | XSS.cs:75:20:75:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:78:20:78:24 | access to local variable name2 : String | XSS.cs:79:36:79:40 | access to local variable name2 | provenance | |
|
||||
| XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | XSS.cs:78:20:78:24 | access to local variable name2 : String | provenance | |
|
||||
| XSS.cs:85:20:85:23 | access to local variable name : String | XSS.cs:86:28:86:31 | access to local variable name | provenance | |
|
||||
| XSS.cs:85:20:85:23 | access to local variable name : String | XSS.cs:87:31:87:34 | access to local variable name | provenance | |
|
||||
| XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:85:20:85:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:85:27:85:61 | access to indexer : String | provenance | MaD:6 |
|
||||
| XSS.cs:85:27:85:61 | access to indexer : String | XSS.cs:85:20:85:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:94:20:94:23 | access to local variable name : String | XSS.cs:95:31:95:34 | access to local variable name | provenance | Sink:MaD:1 |
|
||||
| XSS.cs:94:27:94:53 | access to property QueryString : NameValueCollection | XSS.cs:94:20:94:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:94:27:94:53 | access to property QueryString : NameValueCollection | XSS.cs:94:27:94:61 | access to indexer : String | provenance | MaD:6 |
|
||||
| XSS.cs:94:27:94:61 | access to indexer : String | XSS.cs:94:20:94:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:26:13:26:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:27:32:27:40 | access to local variable userInput : StringBuilder | provenance | |
|
||||
| XSS.cs:26:13:26:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:28:29:28:37 | access to local variable userInput : StringBuilder | provenance | |
|
||||
| XSS.cs:26:13:26:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:29:26:29:34 | access to local variable userInput : StringBuilder | provenance | |
|
||||
| XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | XSS.cs:26:48:26:67 | access to property Text : String | provenance | MaD:4 |
|
||||
| XSS.cs:26:48:26:67 | access to property Text : String | XSS.cs:26:13:26:21 | [post] access to local variable userInput : StringBuilder | provenance | MaD:2 |
|
||||
| XSS.cs:27:32:27:40 | access to local variable userInput : StringBuilder | XSS.cs:27:32:27:51 | call to method ToString | provenance | MaD:3 |
|
||||
| XSS.cs:28:29:28:37 | access to local variable userInput : StringBuilder | XSS.cs:28:29:28:48 | call to method ToString | provenance | MaD:3 |
|
||||
| XSS.cs:29:26:29:34 | access to local variable userInput : StringBuilder | XSS.cs:29:26:29:45 | call to method ToString | provenance | MaD:3 |
|
||||
| XSS.cs:38:20:38:23 | access to local variable name : String | XSS.cs:39:36:39:39 | access to local variable name | provenance | Sink:MaD:5 |
|
||||
| XSS.cs:38:27:38:53 | access to property QueryString : NameValueCollection | XSS.cs:38:20:38:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:38:27:38:53 | access to property QueryString : NameValueCollection | XSS.cs:38:27:38:61 | access to indexer : String | provenance | MaD:6 |
|
||||
| XSS.cs:38:27:38:61 | access to indexer : String | XSS.cs:38:20:38:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:58:20:58:23 | access to local variable name : String | XSS.cs:60:22:60:25 | access to local variable name | provenance | |
|
||||
| XSS.cs:58:27:58:65 | access to property QueryString : NameValueCollection | XSS.cs:58:20:58:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:58:27:58:65 | access to property QueryString : NameValueCollection | XSS.cs:58:27:58:73 | access to indexer : String | provenance | MaD:6 |
|
||||
| XSS.cs:58:27:58:73 | access to indexer : String | XSS.cs:58:20:58:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:76:20:76:23 | access to local variable name : String | XSS.cs:77:36:77:39 | access to local variable name | provenance | |
|
||||
| XSS.cs:76:27:76:53 | access to property QueryString : NameValueCollection | XSS.cs:76:20:76:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:76:27:76:53 | access to property QueryString : NameValueCollection | XSS.cs:76:27:76:61 | access to indexer : String | provenance | MaD:6 |
|
||||
| XSS.cs:76:27:76:61 | access to indexer : String | XSS.cs:76:20:76:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:79:20:79:24 | access to local variable name2 : String | XSS.cs:80:36:80:40 | access to local variable name2 | provenance | |
|
||||
| XSS.cs:79:28:79:42 | access to property Request : HttpRequestBase | XSS.cs:79:20:79:24 | access to local variable name2 : String | provenance | |
|
||||
| XSS.cs:86:20:86:23 | access to local variable name : String | XSS.cs:87:28:87:31 | access to local variable name | provenance | |
|
||||
| XSS.cs:86:20:86:23 | access to local variable name : String | XSS.cs:88:31:88:34 | access to local variable name | provenance | |
|
||||
| XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | XSS.cs:86:20:86:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | XSS.cs:86:27:86:61 | access to indexer : String | provenance | MaD:6 |
|
||||
| XSS.cs:86:27:86:61 | access to indexer : String | XSS.cs:86:20:86:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:95:20:95:23 | access to local variable name : String | XSS.cs:96:31:96:34 | access to local variable name | provenance | Sink:MaD:1 |
|
||||
| XSS.cs:95:27:95:53 | access to property QueryString : NameValueCollection | XSS.cs:95:20:95:23 | access to local variable name : String | provenance | |
|
||||
| XSS.cs:95:27:95:53 | access to property QueryString : NameValueCollection | XSS.cs:95:27:95:61 | access to indexer : String | provenance | MaD:6 |
|
||||
| XSS.cs:95:27:95:61 | access to indexer : String | XSS.cs:95:20:95:23 | access to local variable name : String | provenance | |
|
||||
| script.aspx:12:1:12:14 | <%= ... %> | script.aspx:12:1:12:14 | <%= ... %> | provenance | |
|
||||
| script.aspx:16:1:16:34 | <%= ... %> | script.aspx:16:1:16:34 | <%= ... %> | provenance | |
|
||||
| script.aspx:20:1:20:41 | <%= ... %> | script.aspx:20:1:20:41 | <%= ... %> | provenance | |
|
||||
@@ -56,40 +56,40 @@ models
|
||||
| 5 | Sink: System.Web; HttpResponse; false; Write; ; ; Argument[0]; html-injection; manual |
|
||||
| 6 | Summary: System.Collections.Specialized; NameValueCollection; false; get_Item; (System.String); ; Argument[this]; ReturnValue; taint; df-generated |
|
||||
nodes
|
||||
| XSS.cs:25:13:25:21 | [post] access to local variable userInput : StringBuilder | semmle.label | [post] access to local variable userInput : StringBuilder |
|
||||
| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox |
|
||||
| XSS.cs:25:48:25:67 | access to property Text : String | semmle.label | access to property Text : String |
|
||||
| XSS.cs:26:32:26:40 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder |
|
||||
| XSS.cs:26:32:26:51 | call to method ToString | semmle.label | call to method ToString |
|
||||
| XSS.cs:27:29:27:37 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder |
|
||||
| XSS.cs:27:29:27:48 | call to method ToString | semmle.label | call to method ToString |
|
||||
| XSS.cs:28:26:28:34 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder |
|
||||
| XSS.cs:28:26:28:45 | call to method ToString | semmle.label | call to method ToString |
|
||||
| XSS.cs:37:20:37:23 | access to local variable name : String | semmle.label | access to local variable name : String |
|
||||
| XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSS.cs:37:27:37:61 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSS.cs:38:36:38:39 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:57:20:57:23 | access to local variable name : String | semmle.label | access to local variable name : String |
|
||||
| XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSS.cs:57:27:57:73 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSS.cs:59:22:59:25 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:75:20:75:23 | access to local variable name : String | semmle.label | access to local variable name : String |
|
||||
| XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSS.cs:75:27:75:61 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSS.cs:76:36:76:39 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:78:20:78:24 | access to local variable name2 : String | semmle.label | access to local variable name2 : String |
|
||||
| XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | semmle.label | access to property Request : HttpRequestBase |
|
||||
| XSS.cs:79:36:79:40 | access to local variable name2 | semmle.label | access to local variable name2 |
|
||||
| XSS.cs:85:20:85:23 | access to local variable name : String | semmle.label | access to local variable name : String |
|
||||
| XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSS.cs:85:27:85:61 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSS.cs:86:28:86:31 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:87:31:87:34 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:94:20:94:23 | access to local variable name : String | semmle.label | access to local variable name : String |
|
||||
| XSS.cs:94:27:94:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSS.cs:94:27:94:61 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSS.cs:95:31:95:34 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:135:20:135:33 | access to property RawUrl | semmle.label | access to property RawUrl |
|
||||
| XSS.cs:26:13:26:21 | [post] access to local variable userInput : StringBuilder | semmle.label | [post] access to local variable userInput : StringBuilder |
|
||||
| XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox |
|
||||
| XSS.cs:26:48:26:67 | access to property Text : String | semmle.label | access to property Text : String |
|
||||
| XSS.cs:27:32:27:40 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder |
|
||||
| XSS.cs:27:32:27:51 | call to method ToString | semmle.label | call to method ToString |
|
||||
| XSS.cs:28:29:28:37 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder |
|
||||
| XSS.cs:28:29:28:48 | call to method ToString | semmle.label | call to method ToString |
|
||||
| XSS.cs:29:26:29:34 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder |
|
||||
| XSS.cs:29:26:29:45 | call to method ToString | semmle.label | call to method ToString |
|
||||
| XSS.cs:38:20:38:23 | access to local variable name : String | semmle.label | access to local variable name : String |
|
||||
| XSS.cs:38:27:38:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSS.cs:38:27:38:61 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSS.cs:39:36:39:39 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:58:20:58:23 | access to local variable name : String | semmle.label | access to local variable name : String |
|
||||
| XSS.cs:58:27:58:65 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSS.cs:58:27:58:73 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSS.cs:60:22:60:25 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:76:20:76:23 | access to local variable name : String | semmle.label | access to local variable name : String |
|
||||
| XSS.cs:76:27:76:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSS.cs:76:27:76:61 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSS.cs:77:36:77:39 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:79:20:79:24 | access to local variable name2 : String | semmle.label | access to local variable name2 : String |
|
||||
| XSS.cs:79:28:79:42 | access to property Request : HttpRequestBase | semmle.label | access to property Request : HttpRequestBase |
|
||||
| XSS.cs:80:36:80:40 | access to local variable name2 | semmle.label | access to local variable name2 |
|
||||
| XSS.cs:86:20:86:23 | access to local variable name : String | semmle.label | access to local variable name : String |
|
||||
| XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSS.cs:86:27:86:61 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSS.cs:87:28:87:31 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:88:31:88:34 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:95:20:95:23 | access to local variable name : String | semmle.label | access to local variable name : String |
|
||||
| XSS.cs:95:27:95:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
|
||||
| XSS.cs:95:27:95:61 | access to indexer : String | semmle.label | access to indexer : String |
|
||||
| XSS.cs:96:31:96:34 | access to local variable name | semmle.label | access to local variable name |
|
||||
| XSS.cs:140:20:140:33 | access to property RawUrl | semmle.label | access to property RawUrl |
|
||||
| script.aspx:12:1:12:14 | <%= ... %> | semmle.label | <%= ... %> |
|
||||
| script.aspx:16:1:16:34 | <%= ... %> | semmle.label | <%= ... %> |
|
||||
| script.aspx:20:1:20:41 | <%= ... %> | semmle.label | <%= ... %> |
|
||||
|
||||
@@ -3,7 +3,7 @@ import utils.modelgenerator.internal.CaptureModels
|
||||
import TestUtilities.InlineMadTest
|
||||
|
||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||
string getCapturedModel(Callable c) { result = captureContentFlow(c) }
|
||||
string getCapturedModel(Callable c) { result = ContentSensitive::captureFlow(c, _) }
|
||||
|
||||
string getKind() { result = "contentbased-summary" }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import csharp
|
||||
import utils.modelgenerator.internal.CaptureSummaryFlowQuery
|
||||
import utils.modelgenerator.internal.CaptureModels
|
||||
import TestUtilities.InlineMadTest
|
||||
|
||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import csharp
|
||||
import utils.modelgenerator.internal.CaptureSummaryFlowQuery
|
||||
import utils.modelgenerator.internal.CaptureModels
|
||||
import TestUtilities.InlineMadTest
|
||||
|
||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user