Skip to content

Commit c9e1ccf

Browse files
committed
Merge branch 'master' into strftime
2 parents 1baf144 + 688f540 commit c9e1ccf

Some content is hidden

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

41 files changed

+1547
-187
lines changed

change-notes/1.25/analysis-javascript.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@
3636

3737
| **Query** | **Expected impact** | **Change** |
3838
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
39+
| Client-side cross-site scripting (`js/xss`) | Fewer results | This query no longer flags optionally sanitized values. |
3940
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. |
40-
| Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe strings based on URLs. |
41+
| Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe patterns of constructing HTML. |
4142
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. |
4243
| Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. |
4344
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. |

cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/**
2+
* Provides a library for reasoning about control flow at the granularity of basic blocks.
3+
* This is usually much more efficient than reasoning directly at the level of `ControlFlowNode`s.
4+
*/
5+
16
import cpp
27
private import internal.PrimitiveBasicBlocks
38
private import internal.ConstantExprs
@@ -148,22 +153,37 @@ predicate bb_successor = bb_successor_cached/2;
148153
class BasicBlock extends ControlFlowNodeBase {
149154
BasicBlock() { basic_block_entry_node(this) }
150155

156+
/** Holds if this basic block contains `node`. */
151157
predicate contains(ControlFlowNode node) { basic_block_member(node, this, _) }
152158

159+
/** Gets the `ControlFlowNode` at position `pos` in this basic block. */
153160
ControlFlowNode getNode(int pos) { basic_block_member(result, this, pos) }
154161

162+
/** Gets a `ControlFlowNode` in this basic block. */
155163
ControlFlowNode getANode() { basic_block_member(result, this, _) }
156164

165+
/** Gets a `BasicBlock` that is a direct successor of this basic block. */
157166
BasicBlock getASuccessor() { bb_successor(this, result) }
158167

168+
/** Gets a `BasicBlock` that is a direct predecessor of this basic block. */
159169
BasicBlock getAPredecessor() { bb_successor(result, this) }
160170

171+
/**
172+
* Gets a `BasicBlock` such that the control-flow edge `(this, result)` may be taken
173+
* when the outgoing edge of this basic block is an expression that is true.
174+
*/
161175
BasicBlock getATrueSuccessor() { result.getStart() = this.getEnd().getATrueSuccessor() }
162176

177+
/**
178+
* Gets a `BasicBlock` such that the control-flow edge `(this, result)` may be taken
179+
* when the outgoing edge of this basic block is an expression that is false.
180+
*/
163181
BasicBlock getAFalseSuccessor() { result.getStart() = this.getEnd().getAFalseSuccessor() }
164182

183+
/** Gets the final `ControlFlowNode` of this basic block. */
165184
ControlFlowNode getEnd() { basic_block_member(result, this, bb_length(this) - 1) }
166185

186+
/** Gets the first `ControlFlowNode` of this basic block. */
167187
ControlFlowNode getStart() { result = this }
168188

169189
/** Gets the number of `ControlFlowNode`s in this basic block. */
@@ -192,6 +212,7 @@ class BasicBlock extends ControlFlowNodeBase {
192212
this.getEnd().getLocation().hasLocationInfo(endf, _, _, endl, endc)
193213
}
194214

215+
/** Gets the function containing this basic block. */
195216
Function getEnclosingFunction() { result = this.getStart().getControlFlowScope() }
196217

197218
/**

cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/**
2+
* Provides a library for reasoning about control flow at the granularity of
3+
* individual nodes in the control-flow graph.
4+
*/
5+
16
import cpp
27
import BasicBlocks
38
private import semmle.code.cpp.controlflow.internal.ConstantExprs
@@ -29,8 +34,10 @@ private import semmle.code.cpp.controlflow.internal.CFG
2934
* `Handler`. There are no edges from function calls to `Handler`s.
3035
*/
3136
class ControlFlowNode extends Locatable, ControlFlowNodeBase {
37+
/** Gets a direct successor of this control-flow node, if any. */
3238
ControlFlowNode getASuccessor() { successors_adapted(this, result) }
3339

40+
/** Gets a direct predecessor of this control-flow node, if any. */
3441
ControlFlowNode getAPredecessor() { this = result.getASuccessor() }
3542

3643
/** Gets the function containing this control-flow node. */
@@ -71,6 +78,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
7178
result = getASuccessor()
7279
}
7380

81+
/** Gets the `BasicBlock` containing this control-flow node. */
7482
BasicBlock getBasicBlock() { result.getANode() = this }
7583
}
7684

@@ -86,10 +94,18 @@ import ControlFlowGraphPublic
8694
*/
8795
class ControlFlowNodeBase extends ElementBase, @cfgnode { }
8896

97+
/**
98+
* Holds when `n2` is a control-flow node such that the control-flow
99+
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
100+
*/
89101
predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
90102
qlCFGTrueSuccessor(n1, n2)
91103
}
92104

105+
/**
106+
* Holds when `n2` is a control-flow node such that the control-flow
107+
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
108+
*/
93109
predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
94110
qlCFGFalseSuccessor(n1, n2)
95111
}

cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,25 @@ import Dereferenced
1515
abstract class DataflowAnnotation extends string {
1616
DataflowAnnotation() { this = "pointer-null" or this = "pointer-valid" }
1717

18+
/** Holds if this annotation is the default annotation. */
1819
abstract predicate isDefault();
1920

21+
/** Holds if this annotation is generated when analyzing expression `e`. */
2022
abstract predicate generatedOn(Expr e);
2123

24+
/**
25+
* Holds if this annotation is generated for the variable `v` when
26+
* the control-flow edge `(src, dest)` is taken.
27+
*/
2228
abstract predicate generatedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest);
2329

30+
/**
31+
* Holds if this annotation is removed for the variable `v` when
32+
* the control-flow edge `(src, dest)` is taken.
33+
*/
2434
abstract predicate killedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest);
2535

36+
/** Holds if expression `e` is given this annotation. */
2637
predicate marks(Expr e) {
2738
this.generatedOn(e) and reachable(e)
2839
or
@@ -31,6 +42,7 @@ abstract class DataflowAnnotation extends string {
3142
exists(LocalScopeVariable v | this.marks(v, e) and e = v.getAnAccess())
3243
}
3344

45+
/** Holds if the variable `v` accessed in control-flow node `n` is given this annotation. */
3446
predicate marks(LocalScopeVariable v, ControlFlowNode n) {
3547
v.getAnAccess().getEnclosingFunction().getBlock() = n and
3648
this.isDefault()
@@ -57,13 +69,21 @@ abstract class DataflowAnnotation extends string {
5769
)
5870
}
5971

72+
/**
73+
* Holds if the variable `v` preserves this annotation when the control-flow
74+
* edge `(src, dest)` is taken.
75+
*/
6076
predicate preservedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest) {
6177
this.marks(v, src) and
6278
src.getASuccessor() = dest and
6379
not v.getInitializer() = dest and
6480
not v.getAnAssignment() = src
6581
}
6682

83+
/**
84+
* Holds if the variable `v` is assigned this annotation when `src` is an assignment
85+
* expression that assigns to `v` and the control-flow edge `(src, dest)` is taken.
86+
*/
6787
predicate assignedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest) {
6888
this.marks(src.(AssignExpr).getRValue()) and
6989
src = v.getAnAssignment() and

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import cpp
22
import semmle.code.cpp.security.Security
33
private import semmle.code.cpp.ir.dataflow.DataFlow
4+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
45
private import semmle.code.cpp.ir.dataflow.DataFlow2
56
private import semmle.code.cpp.ir.dataflow.DataFlow3
67
private import semmle.code.cpp.ir.IR

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

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,7 @@ class Node extends TIRDataFlowNode {
7171
* `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is
7272
* a partial definition of `&x`).
7373
*/
74-
Expr asPartialDefinition() {
75-
result = this.(PartialDefinitionNode).getInstruction().getUnconvertedResultExpression()
76-
}
74+
Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefinedExpr() }
7775

7876
/**
7977
* DEPRECATED: See UninitializedNode.
@@ -251,14 +249,17 @@ abstract class PostUpdateNode extends InstructionNode {
251249
* setY(&x); // a partial definition of the object `x`.
252250
* ```
253251
*/
254-
abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { }
252+
abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {
253+
abstract Expr getDefinedExpr();
254+
}
255255

256256
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
257257
override ChiInstruction instr;
258+
FieldAddressInstruction field;
258259

259260
ExplicitFieldStoreQualifierNode() {
260261
not instr.isResultConflated() and
261-
exists(StoreInstruction store, FieldInstruction field |
262+
exists(StoreInstruction store |
262263
instr.getPartial() = store and field = store.getDestinationAddress()
263264
)
264265
}
@@ -268,6 +269,10 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
268269
// DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications
269270
// this consistency failure has.
270271
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
272+
273+
override Expr getDefinedExpr() {
274+
result = field.getObjectAddress().getUnconvertedResultExpression()
275+
}
271276
}
272277

273278
/**
@@ -278,15 +283,18 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
278283
*/
279284
private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
280285
override StoreInstruction instr;
286+
FieldAddressInstruction field;
281287

282288
ExplicitSingleFieldStoreQualifierNode() {
283-
exists(FieldAddressInstruction field |
284-
field = instr.getDestinationAddress() and
285-
not exists(ChiInstruction chi | chi.getPartial() = instr)
286-
)
289+
field = instr.getDestinationAddress() and
290+
not exists(ChiInstruction chi | chi.getPartial() = instr)
287291
}
288292

289293
override Node getPreUpdateNode() { none() }
294+
295+
override Expr getDefinedExpr() {
296+
result = field.getObjectAddress().getUnconvertedResultExpression()
297+
}
290298
}
291299

292300
/**
@@ -458,9 +466,9 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
458466
// for now.
459467
iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom
460468
or
461-
// The next two rules allow flow from partial definitions in setters to succeeding loads in the caller.
462-
// First, we add flow from write side-effects to non-conflated chi instructions through their
463-
// partial operands. Consider the following example:
469+
// Add flow from write side-effects to non-conflated chi instructions through their
470+
// partial operands. From there, a `readStep` will find subsequent reads of that field.
471+
// Consider the following example:
464472
// ```
465473
// void setX(Point* p, int new_x) {
466474
// p->x = new_x;
@@ -470,14 +478,9 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
470478
// ```
471479
// Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to
472480
// `setX`, which will be melded into `p` through a chi instruction.
473-
iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom.(WriteSideEffectInstruction) and
474-
not iTo.isResultConflated()
475-
or
476-
// Next, we add flow from non-conflated chi instructions to loads (even when they are not precise).
477-
// This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above.
478-
exists(ChiInstruction chi | iFrom = chi |
479-
not chi.isResultConflated() and
480-
iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi
481+
exists(ChiInstruction chi | chi = iTo |
482+
chi.getPartialOperand().getDef() = iFrom.(WriteSideEffectInstruction) and
483+
not chi.isResultConflated()
481484
)
482485
or
483486
// Flow from stores to structs with a single field to a load of that field.

cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ CppType getTypeForPRValueOrUnknown(Type type) {
362362
/**
363363
* Gets the `CppType` that represents a glvalue of type `type`.
364364
*/
365-
CppType getTypeForGLValue(Type type) { result.hasType(type, true) }
365+
CppGLValueAddressType getTypeForGLValue(Type type) { result.hasType(type, true) }
366366

367367
/**
368368
* Gets the `CppType` that represents a prvalue of type `int`.

cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,5 @@ void test_conflated_fields3() {
115115
XY xy;
116116
xy.x = 0;
117117
taint_y(&xy);
118-
sink(xy.x); // not tainted [FALSE POSITIVE]
118+
sink(xy.x); // not tainted
119119
}

cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@
103103
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | (int)... |
104104
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | access to array |
105105
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:12:111:18 | tainted |
106-
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:118:11:118:11 | x |
107-
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | shared.h:6:15:6:23 | sinkparam |
108106
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:24:28:27 | call to atoi |
109107
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:34 | call to getenv |
110108
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:45 | (const char *)... |

cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | p2 | IR only |
2222
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR only |
2323
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:8:111:8 | y | AST only |
24-
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:118:11:118:11 | x | IR only |
25-
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only |
2624
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only |
2725
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only |
2826
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only |

0 commit comments

Comments
 (0)