Skip to content

Commit 06e13cb

Browse files
committed
Merge branch 'master' of git.semmle.com:Semmle/ql into FalsySanitizer
2 parents 1ece6b9 + 3c8aeb9 commit 06e13cb

File tree

62 files changed

+3424
-1716
lines changed

Some content is hidden

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

62 files changed

+3424
-1716
lines changed

change-notes/1.24/analysis-csharp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ The following changes in version 1.24 affect C# analysis in all applications.
2020
| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the variable is named `_` in a `foreach` statement. |
2121
| Potentially dangerous use of non-short-circuit logic (`cs/non-short-circuit`) | Fewer false positive results | Results have been removed when the expression contains an `out` parameter. |
2222
| Dereferenced variable may be null (`cs/dereferenced-value-may-be-null`) | More results | Results are reported from parameters with a default value of `null`. |
23+
| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the value assigned is an (implicitly or explicitly) cast default-like value. For example, `var s = (string)null` and `string s = default`. |
2324

2425
## Removal of old queries
2526

change-notes/1.24/analysis-javascript.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
- [ws](https://github.com/websockets/ws)
2222
- [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
2323
- [Koa](https://www.npmjs.com/package/koa)
24+
- [lazy-cache](https://www.npmjs.com/package/lazy-cache)
25+
- [for-in](https://www.npmjs.com/package/for-in)
26+
- [for-own](https://www.npmjs.com/package/for-own)
2427

2528
## New queries
2629

config/identical-files.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,12 @@
222222
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll",
223223
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll"
224224
],
225-
"IR ValueNumber": [
225+
"C++ IR ValueNumberInternal": [
226+
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll",
227+
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll",
228+
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll"
229+
],
230+
"C++ IR ValueNumber": [
226231
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll",
227232
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll",
228233
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll",

cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll

Lines changed: 65 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,40 @@ private predicate predictableInstruction(Instruction instr) {
2121
predictableInstruction(instr.(UnaryInstruction).getUnary())
2222
}
2323

24+
/**
25+
* Functions that we should only allow taint to flow through (to the return
26+
* value) if all but the source argument are 'predictable'. This is done to
27+
* emulate the old security library's implementation rather than due to any
28+
* strong belief that this is the right approach.
29+
*
30+
* Note that the list itself is not very principled; it consists of all the
31+
* functions listed in the old security library's [default] `isPureFunction`
32+
* that have more than one argument, but are not in the old taint tracking
33+
* library's `returnArgument` predicate. In addition, `strlen` is included
34+
* because it's also a special case in flow to return values.
35+
*/
36+
predicate predictableOnlyFlow(string name) {
37+
name = "strcasestr" or
38+
name = "strchnul" or
39+
name = "strchr" or
40+
name = "strchrnul" or
41+
name = "strcmp" or
42+
name = "strcspn" or
43+
name = "strlen" or // special case
44+
name = "strncmp" or
45+
name = "strndup" or
46+
name = "strnlen" or
47+
name = "strrchr" or
48+
name = "strspn" or
49+
name = "strstr" or
50+
name = "strtod" or
51+
name = "strtof" or
52+
name = "strtol" or
53+
name = "strtoll" or
54+
name = "strtoq" or
55+
name = "strtoul"
56+
}
57+
2458
private DataFlow::Node getNodeForSource(Expr source) {
2559
isUserInput(source, _) and
2660
(
@@ -35,7 +69,7 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
3569

3670
override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
3771

38-
override predicate isSink(DataFlow::Node sink) { any() }
72+
override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
3973

4074
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
4175
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
@@ -50,18 +84,15 @@ private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
5084
override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
5185

5286
override predicate isSink(DataFlow::Node sink) {
53-
exists(GlobalOrNamespaceVariable gv | writesVariable(sink.asInstruction(), gv))
87+
sink.asVariable() instanceof GlobalOrNamespaceVariable
5488
}
5589

5690
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
5791
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
5892
or
59-
exists(StoreInstruction i1, LoadInstruction i2, GlobalOrNamespaceVariable gv |
60-
writesVariable(i1, gv) and
61-
readsVariable(i2, gv) and
62-
i1 = n1.asInstruction() and
63-
i2 = n2.asInstruction()
64-
)
93+
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
94+
or
95+
readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable))
6596
}
6697

6798
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
@@ -71,19 +102,20 @@ private class FromGlobalVarTaintTrackingCfg extends DataFlow2::Configuration {
71102
FromGlobalVarTaintTrackingCfg() { this = "FromGlobalVarTaintTrackingCfg" }
72103

73104
override predicate isSource(DataFlow::Node source) {
74-
exists(
75-
ToGlobalVarTaintTrackingCfg other, DataFlow::Node prevSink, GlobalOrNamespaceVariable gv
76-
|
77-
other.hasFlowTo(prevSink) and
78-
writesVariable(prevSink.asInstruction(), gv) and
79-
readsVariable(source.asInstruction(), gv)
80-
)
105+
// This set of sources should be reasonably small, which is good for
106+
// performance since the set of sinks is very large.
107+
exists(ToGlobalVarTaintTrackingCfg otherCfg | otherCfg.hasFlowTo(source))
81108
}
82109

83-
override predicate isSink(DataFlow::Node sink) { any() }
110+
override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
84111

85112
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
86113
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
114+
or
115+
// Additional step for flow out of variables. There is no flow _into_
116+
// variables in this configuration, so this step only serves to take flow
117+
// out of a variable that's a source.
118+
readsVariable(n2.asInstruction(), n1.asVariable())
87119
}
88120

89121
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
@@ -123,15 +155,16 @@ private predicate nodeIsBarrier(DataFlow::Node node) {
123155

124156
private predicate instructionTaintStep(Instruction i1, Instruction i2) {
125157
// Expressions computed from tainted data are also tainted
126-
i2 =
127-
any(CallInstruction call |
128-
isPureFunction(call.getStaticCallTarget().getName()) and
129-
call.getAnArgument() = i1 and
130-
forall(Instruction arg | arg = call.getAnArgument() | arg = i1 or predictableInstruction(arg)) and
131-
// flow through `strlen` tends to cause dubious results, if the length is
132-
// bounded.
133-
not call.getStaticCallTarget().getName() = "strlen"
134-
)
158+
exists(CallInstruction call, int argIndex | call = i2 |
159+
isPureFunction(call.getStaticCallTarget().getName()) and
160+
i1 = getACallArgumentOrIndirection(call, argIndex) and
161+
forall(Instruction arg | arg = call.getAnArgument() |
162+
arg = getACallArgumentOrIndirection(call, argIndex) or predictableInstruction(arg)
163+
) and
164+
// flow through `strlen` tends to cause dubious results, if the length is
165+
// bounded.
166+
not call.getStaticCallTarget().getName() = "strlen"
167+
)
135168
or
136169
// Flow through pointer dereference
137170
i2.(LoadInstruction).getSourceAddress() = i1
@@ -172,7 +205,8 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
172205
any(CallInstruction call |
173206
exists(int indexIn |
174207
modelTaintToReturnValue(call.getStaticCallTarget(), indexIn) and
175-
i1 = getACallArgumentOrIndirection(call, indexIn)
208+
i1 = getACallArgumentOrIndirection(call, indexIn) and
209+
not predictableOnlyFlow(call.getStaticCallTarget().getName())
176210
)
177211
)
178212
or
@@ -315,23 +349,12 @@ predicate taintedIncludingGlobalVars(Expr source, Element tainted, string global
315349
globalVar = ""
316350
or
317351
exists(
318-
ToGlobalVarTaintTrackingCfg toCfg, FromGlobalVarTaintTrackingCfg fromCfg, DataFlow::Node store,
319-
GlobalOrNamespaceVariable global, DataFlow::Node load, DataFlow::Node sink
352+
ToGlobalVarTaintTrackingCfg toCfg, FromGlobalVarTaintTrackingCfg fromCfg,
353+
DataFlow::VariableNode variableNode, GlobalOrNamespaceVariable global, DataFlow::Node sink
320354
|
321-
toCfg.hasFlow(getNodeForSource(source), store) and
322-
store
323-
.asInstruction()
324-
.(StoreInstruction)
325-
.getDestinationAddress()
326-
.(VariableAddressInstruction)
327-
.getASTVariable() = global and
328-
load
329-
.asInstruction()
330-
.(LoadInstruction)
331-
.getSourceAddress()
332-
.(VariableAddressInstruction)
333-
.getASTVariable() = global and
334-
fromCfg.hasFlow(load, sink) and
355+
global = variableNode.getVariable() and
356+
toCfg.hasFlow(getNodeForSource(source), variableNode) and
357+
fromCfg.hasFlow(variableNode, sink) and
335358
tainted = adjustedSink(sink) and
336359
global = globalVarFromId(globalVar)
337360
)

cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ private import DataFlowDispatch
77
* A data flow node that occurs as the argument of a call and is passed as-is
88
* to the callable. Instance arguments (`this` pointer) are also included.
99
*/
10-
class ArgumentNode extends Node {
11-
ArgumentNode() { exists(CallInstruction call | this.asInstruction() = call.getAnArgument()) }
10+
class ArgumentNode extends InstructionNode {
11+
ArgumentNode() { exists(CallInstruction call | this.getInstruction() = call.getAnArgument()) }
1212

1313
/**
1414
* Holds if this argument occurs at the given position in the given call.
1515
* The instance argument is considered to have index `-1`.
1616
*/
1717
predicate argumentOf(DataFlowCall call, int pos) {
18-
this.asInstruction() = call.getPositionalArgument(pos)
18+
this.getInstruction() = call.getPositionalArgument(pos)
1919
or
20-
this.asInstruction() = call.getThisArgument() and pos = -1
20+
this.getInstruction() = call.getThisArgument() and pos = -1
2121
}
2222

2323
/** Gets the call in which this node is an argument. */
@@ -36,15 +36,15 @@ class ReturnKind extends TReturnKind {
3636
}
3737

3838
/** A data flow node that occurs as the result of a `ReturnStmt`. */
39-
class ReturnNode extends Node {
40-
ReturnNode() { exists(ReturnValueInstruction ret | this.asInstruction() = ret.getReturnValue()) }
39+
class ReturnNode extends InstructionNode {
40+
ReturnNode() { exists(ReturnValueInstruction ret | this.getInstruction() = ret.getReturnValue()) }
4141

4242
/** Gets the kind of this returned value. */
4343
ReturnKind getKind() { result = TNormalReturnKind() }
4444
}
4545

4646
/** A data flow node that represents the output of a call. */
47-
class OutNode extends Node {
47+
class OutNode extends InstructionNode {
4848
override CallInstruction instr;
4949

5050
/** Gets the underlying call. */
@@ -181,11 +181,17 @@ private predicate suppressUnusedType(Type t) { any() }
181181
// Java QL library compatibility wrappers
182182
//////////////////////////////////////////////////////////////////////////////
183183
/** A node that performs a type cast. */
184-
class CastNode extends Node {
184+
class CastNode extends InstructionNode {
185185
CastNode() { none() } // stub implementation
186186
}
187187

188-
class DataFlowCallable = Function;
188+
/**
189+
* A function that may contain code or a variable that may contain itself. When
190+
* flow crosses from one _enclosing callable_ to another, the interprocedural
191+
* data-flow library discards call contexts and inserts a node in the big-step
192+
* relation used for human-readable path explanations.
193+
*/
194+
class DataFlowCallable = Declaration;
189195

190196
class DataFlowExpr = Expr;
191197

0 commit comments

Comments
 (0)