Skip to content

Commit cd9538d

Browse files
committed
Merge remote-tracking branch 'upstream/master' into dataflow/precise-field-types
2 parents 2c243ad + 5787871 commit cd9538d

File tree

202 files changed

+9076
-3991
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

202 files changed

+9076
-3991
lines changed

change-notes/1.25/analysis-cpp.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Improvements to C/C++ analysis
2+
3+
The following changes in version 1.25 affect C/C++ analysis in all applications.
4+
5+
## General improvements
6+
7+
## New queries
8+
9+
| **Query** | **Tags** | **Purpose** |
10+
|-----------------------------|-----------|--------------------------------------------------------------------|
11+
12+
## Changes to existing queries
13+
14+
| **Query** | **Expected impact** | **Change** |
15+
|----------------------------|------------------------|------------------------------------------------------------------|
16+
17+
## Changes to libraries
18+
19+
* The data-flow library has been improved, which affects most security queries by potentially
20+
adding more results. Flow through functions now takes nested field reads/writes into account.
21+
For example, the library is able to track flow from `taint()` to `sink()` via the method
22+
`getf2f1()` in
23+
```c
24+
struct C {
25+
int f1;
26+
};
27+
28+
struct C2
29+
{
30+
C f2;
31+
32+
int getf2f1() {
33+
return f2.f1; // Nested field read
34+
}
35+
36+
void m() {
37+
f2.f1 = taint();
38+
sink(getf2f1()); // NEW: taint() reaches here
39+
}
40+
};
41+
```

change-notes/1.25/analysis-csharp.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,28 @@ The following changes in version 1.25 affect C# analysis in all applications.
2424
have type parameters. This means that non-generic nested types inside construced types,
2525
such as `A<int>.B`, no longer are considered unbound generics. (Such nested types do,
2626
however, still have relevant `.getSourceDeclaration()`s, for example `A<>.B`.)
27+
* The data-flow library has been improved, which affects most security queries by potentially
28+
adding more results. Flow through methods now takes nested field reads/writes into account.
29+
For example, the library is able to track flow from `"taint"` to `Sink()` via the method
30+
`GetF2F1()` in
31+
```csharp
32+
class C1
33+
{
34+
string F1;
35+
}
36+
37+
class C2
38+
{
39+
C1 F2;
40+
41+
string GetF2F1() => F2.F1; // Nested field read
42+
43+
void M()
44+
{
45+
F2 = new C1() { F1 = "taint" };
46+
Sink(GetF2F1()); // NEW: "taint" reaches here
47+
}
48+
}
49+
```
2750

2851
## Changes to autobuilder

change-notes/1.25/analysis-java.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Improvements to Java analysis
2+
3+
The following changes in version 1.25 affect Java analysis in all applications.
4+
5+
## General improvements
6+
7+
## New queries
8+
9+
| **Query** | **Tags** | **Purpose** |
10+
|-----------------------------|-----------|--------------------------------------------------------------------|
11+
12+
13+
## Changes to existing queries
14+
15+
| **Query** | **Expected impact** | **Change** |
16+
|------------------------------|------------------------|-----------------------------------|
17+
18+
19+
## Changes to libraries
20+
21+
* The data-flow library has been improved, which affects most security queries by potentially
22+
adding more results. Flow through methods now takes nested field reads/writes into account.
23+
For example, the library is able to track flow from `"taint"` to `sink()` via the method
24+
`getF2F1()` in
25+
```java
26+
class C1 {
27+
String f1;
28+
C1(String f1) { this.f1 = f1; }
29+
}
30+
31+
class C2 {
32+
C1 f2;
33+
String getF2F1() {
34+
return this.f2.f1; // Nested field read
35+
}
36+
void m() {
37+
this.f2 = new C1("taint");
38+
sink(this.getF2F1()); // NEW: "taint" reaches here
39+
}
40+
}
41+
```

change-notes/1.25/analysis-javascript.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66
- [fstream](https://www.npmjs.com/package/fstream)
77
- [jGrowl](https://github.com/stanlemon/jGrowl)
88
- [jQuery](https://jquery.com/)
9+
- [marsdb](https://www.npmjs.com/package/marsdb)
10+
- [minimongo](https://www.npmjs.com/package/minimongo/)
911

1012
## New queries
1113

1214
| **Query** | **Tags** | **Purpose** |
1315
|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
1416
| Cross-site scripting through DOM (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are not shown on LGTM by default. |
1517
| Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. |
18+
| Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. |
1619

1720
## Changes to existing queries
1821

@@ -23,7 +26,10 @@
2326
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. |
2427
| Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. |
2528
| Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. |
29+
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. |
30+
| Zip Slip (`js/zipslip`) | More results | This query now recognizes zip-slip vulnerabilities involving links. |
2631

2732
## Changes to libraries
2833

34+
* A library `semmle.javascript.explore.CallGraph` has been added to help write queries for exploring the call graph.
2935
* Added data flow for `Map` and `Set`, and added matching type-tracking steps that can accessed using the `CollectionsTypeTracking` module.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* This library proves that a subset of pointer dereferences in a program are
3+
* safe, i.e. in-bounds.
4+
* It does so by first defining what a pointer dereference is (on the IR
5+
* `Instruction` level), and then using the array length analysis and the range
6+
* analysis together to prove that some of these pointer dereferences are safe.
7+
*
8+
* The analysis is soundy, i.e. it is sound if no undefined behaviour is present
9+
* in the program.
10+
* Furthermore, it crucially depends on the soundiness of the range analysis and
11+
* the array length analysis.
12+
*/
13+
14+
import cpp
15+
private import experimental.semmle.code.cpp.rangeanalysis.ArrayLengthAnalysis
16+
private import semmle.code.cpp.rangeanalysis.RangeAnalysis
17+
18+
/**
19+
* Gets the instruction that computes the address of memory that `i` accesses.
20+
* Only holds if `i` dereferences a pointer, not when the computation of the
21+
* memory address is constant, or if the address of a local variable is loaded/stored to.
22+
*/
23+
private Instruction getMemoryAddressInstruction(Instruction i) {
24+
(
25+
result = i.(FieldAddressInstruction).getObjectAddress() or
26+
result = i.(LoadInstruction).getSourceAddress() or
27+
result = i.(StoreInstruction).getDestinationAddress()
28+
) and
29+
not result instanceof FieldAddressInstruction and
30+
not result instanceof VariableAddressInstruction and
31+
not result instanceof ConstantValueInstruction
32+
}
33+
34+
/**
35+
* All instructions that dereference a pointer.
36+
*/
37+
class PointerDereferenceInstruction extends Instruction {
38+
PointerDereferenceInstruction() { exists(getMemoryAddressInstruction(this)) }
39+
40+
Instruction getAddress() { result = getMemoryAddressInstruction(this) }
41+
}
42+
43+
/**
44+
* Holds if `ptrDeref` can be proven to always access allocated memory.
45+
*/
46+
predicate inBounds(PointerDereferenceInstruction ptrDeref) {
47+
exists(Length length, int lengthDelta, Offset offset, int offsetDelta |
48+
knownArrayLength(ptrDeref.getAddress(), length, lengthDelta, offset, offsetDelta) and
49+
// lower bound - note that we treat a pointer that accesses an array of
50+
// length 0 as on upper-bound violation, but not as a lower-bound violation
51+
(
52+
offset instanceof ZeroOffset and
53+
offsetDelta >= 0
54+
or
55+
offset instanceof OpOffset and
56+
exists(int lowerBoundDelta |
57+
boundedOperand(offset.(OpOffset).getOperand(), any(ZeroBound b), lowerBoundDelta,
58+
/*upper*/ false, _) and
59+
lowerBoundDelta + offsetDelta >= 0
60+
)
61+
) and
62+
// upper bound
63+
(
64+
// both offset and length are only integers
65+
length instanceof ZeroLength and
66+
offset instanceof ZeroOffset and
67+
offsetDelta < lengthDelta
68+
or
69+
exists(int lengthBound |
70+
// array length is variable+integer, and there's a fixed (integer-only)
71+
// lower bound on the variable, so we can guarantee this access is always in-bounds
72+
length instanceof VNLength and
73+
offset instanceof ZeroOffset and
74+
boundedInstruction(length.(VNLength).getInstruction(), any(ZeroBound b), lengthBound,
75+
/* upper*/ false, _) and
76+
offsetDelta < lengthBound + lengthDelta
77+
)
78+
or
79+
exists(int offsetBoundDelta |
80+
length instanceof ZeroLength and
81+
offset instanceof OpOffset and
82+
boundedOperand(offset.(OpOffset).getOperand(), any(ZeroBound b), offsetBoundDelta,
83+
/* upper */ true, _) and
84+
// offset <= offsetBoundDelta, so offset + offsetDelta <= offsetDelta + offsetBoundDelta
85+
// Thus, in-bounds if offsetDelta + offsetBoundDelta < lengthDelta
86+
// as we have length instanceof ZeroLength
87+
offsetDelta + offsetBoundDelta < lengthDelta
88+
)
89+
or
90+
exists(ValueNumberBound b, int offsetBoundDelta |
91+
length instanceof VNLength and
92+
offset instanceof OpOffset and
93+
b.getValueNumber() = length.(VNLength).getValueNumber() and
94+
// It holds that offset <= length + offsetBoundDelta
95+
boundedOperand(offset.(OpOffset).getOperand(), b, offsetBoundDelta, /*upper*/ true, _) and
96+
// it also holds that
97+
offsetDelta < lengthDelta - offsetBoundDelta
98+
// taking both inequalities together we get
99+
// offset <= length + offsetBoundDelta
100+
// => offset + offsetDelta <= length + offsetBoundDelta + offsetDelta < length + offsetBoundDelta + lengthDelta - offsetBoundDelta
101+
// as required
102+
)
103+
)
104+
)
105+
}

cpp/ql/src/semmle/code/cpp/Function.qll

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -184,17 +184,8 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
184184
* For example: for a function `int Foo(int p1, int p2)` this would
185185
* return `int p1, int p2`.
186186
*/
187-
string getParameterString() { result = getParameterStringFrom(0) }
188-
189-
private string getParameterStringFrom(int index) {
190-
index = getNumberOfParameters() and
191-
result = ""
192-
or
193-
index = getNumberOfParameters() - 1 and
194-
result = getParameter(index).getTypedName()
195-
or
196-
index < getNumberOfParameters() - 1 and
197-
result = getParameter(index).getTypedName() + ", " + getParameterStringFrom(index + 1)
187+
string getParameterString() {
188+
result = concat(int i | | min(getParameter(i).getTypedName()), ", " order by i)
198189
}
199190

200191
/** Gets a call to this function. */
@@ -616,18 +607,8 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
616607
* For example: for a function 'int Foo(int p1, int p2)' this would
617608
* return 'int p1, int p2'.
618609
*/
619-
string getParameterString() { result = getParameterStringFrom(0) }
620-
621-
private string getParameterStringFrom(int index) {
622-
index = getNumberOfParameters() and
623-
result = ""
624-
or
625-
index = getNumberOfParameters() - 1 and
626-
result = getParameterDeclarationEntry(index).getTypedName()
627-
or
628-
index < getNumberOfParameters() - 1 and
629-
result =
630-
getParameterDeclarationEntry(index).getTypedName() + ", " + getParameterStringFrom(index + 1)
610+
string getParameterString() {
611+
result = concat(int i | | min(getParameterDeclarationEntry(i).getTypedName()), ", " order by i)
631612
}
632613

633614
/**

cpp/ql/src/semmle/code/cpp/exprs/Access.qll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ private import semmle.code.cpp.dataflow.EscapesTree
66
/**
77
* A C/C++ access expression. This refers to a function, variable, or enum constant.
88
*/
9-
abstract class Access extends Expr, NameQualifiableElement {
9+
class Access extends Expr, NameQualifiableElement, @access {
10+
// As `@access` is a union type containing `@routineexpr` (which describes function accesses
11+
// that are called), we need to exclude function calls.
12+
Access() { this instanceof @routineexpr implies not iscall(underlyingElement(this), _) }
13+
1014
/** Gets the accessed function, variable, or enum constant. */
11-
abstract Declaration getTarget();
15+
Declaration getTarget() { none() } // overridden in subclasses
1216

1317
override predicate mayBeImpure() { none() }
1418

cpp/ql/src/semmle/code/cpp/exprs/Cast.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ private import semmle.code.cpp.internal.ResolveClass
77
* Instances of this class are not present in the main AST which is navigated by parent/child links. Instead,
88
* instances of this class are attached to nodes in the main AST via special conversion links.
99
*/
10-
abstract class Conversion extends Expr {
10+
class Conversion extends Expr, @conversion {
1111
/** Gets the expression being converted. */
1212
Expr getExpr() { result.getConversion() = this }
1313

cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ private newtype TOpcode =
6161
TReThrow() or
6262
TUnwind() or
6363
TUnmodeledDefinition() or
64-
TUnmodeledUse() or
6564
TAliasedDefinition() or
6665
TInitializeNonLocal() or
6766
TAliasedUse() or
@@ -587,14 +586,6 @@ module Opcode {
587586
}
588587
}
589588

590-
class UnmodeledUse extends Opcode, TUnmodeledUse {
591-
final override string toString() { result = "UnmodeledUse" }
592-
593-
final override predicate hasOperandInternal(OperandTag tag) {
594-
tag instanceof UnmodeledUseOperandTag
595-
}
596-
}
597-
598589
class AliasedDefinition extends Opcode, TAliasedDefinition {
599590
final override string toString() { result = "AliasedDefinition" }
600591

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock {
3131
config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction())
3232
) and
3333
this =
34-
rank[result + 1](IRBlock funcBlock |
35-
funcBlock.getEnclosingFunction() = getEnclosingFunction()
34+
rank[result + 1](IRBlock funcBlock, int sortOverride |
35+
funcBlock.getEnclosingFunction() = getEnclosingFunction() and
36+
// Ensure that the block containing `EnterFunction` always comes first.
37+
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
38+
then sortOverride = 0
39+
else sortOverride = 1
3640
|
37-
funcBlock order by funcBlock.getUniqueId()
41+
funcBlock order by sortOverride, funcBlock.getUniqueId()
3842
)
3943
}
4044

0 commit comments

Comments
 (0)