Skip to content

Commit 9d7a2d2

Browse files
authored
Merge branch 'main' into python-add-global-flow-steps
2 parents 1d6558b + 4a3118b commit 9d7a2d2

File tree

200 files changed

+12755
-2651
lines changed

Some content is hidden

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

200 files changed

+12755
-2651
lines changed

change-notes/1.26/analysis-cpp.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ The following changes in version 1.26 affect C/C++ analysis in all applications.
2323
* The QL class `Block`, denoting the `{ ... }` statement, is renamed to `BlockStmt`.
2424
* The models library now models many taint flows through `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`.
2525
* The models library now models many more taint flows through `std::string`.
26-
* The models library now models some taint flows through `std::ostream`.
26+
* The models library now models many taint flows through `std::istream` and `std::ostream`.
2727
* The models library now models some taint flows through `std::shared_ptr`, `std::unique_ptr`, `std::make_shared` and `std::make_unique`.
2828
* The `SimpleRangeAnalysis` library now supports multiplications of the form
2929
`e1 * e2` and `x *= e2` when `e1` and `e2` are unsigned or constant.

change-notes/1.26/analysis-javascript.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,21 @@
33
## General improvements
44

55
* Support for the following frameworks and libraries has been improved:
6+
- [bluebird](https://www.npmjs.com/package/bluebird)
7+
- [express](https://www.npmjs.com/package/express)
68
- [fast-json-stable-stringify](https://www.npmjs.com/package/fast-json-stable-stringify)
79
- [fast-safe-stringify](https://www.npmjs.com/package/fast-safe-stringify)
10+
- [http](https://nodejs.org/api/http.html)
811
- [javascript-stringify](https://www.npmjs.com/package/javascript-stringify)
912
- [js-stringify](https://www.npmjs.com/package/js-stringify)
1013
- [json-stable-stringify](https://www.npmjs.com/package/json-stable-stringify)
1114
- [json-stringify-safe](https://www.npmjs.com/package/json-stringify-safe)
1215
- [json3](https://www.npmjs.com/package/json3)
16+
- [lodash](https://www.npmjs.com/package/lodash)
1317
- [object-inspect](https://www.npmjs.com/package/object-inspect)
1418
- [pretty-format](https://www.npmjs.com/package/pretty-format)
1519
- [stringify-object](https://www.npmjs.com/package/stringify-object)
20+
- [underscore](https://www.npmjs.com/package/underscore)
1621

1722
* Analyzing files with the ".cjs" extension is now supported.
1823

@@ -32,6 +37,7 @@
3237
| Unused loop iteration variable (`js/unused-loop-variable`) | Fewer results | This query no longer flags variables in a destructuring array assignment that are not the last variable in the destructed array. |
3338
| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | More results | This query now recognizes more commands where colon, dash, and underscore are used. |
3439
| Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | More results | This query now detects more unsafe uses of nested option properties. |
40+
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | More results | This query now recognizes some unsafe uses of `importScripts()` inside WebWorkers. |
3541

3642

3743
## Changes to libraries

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,23 @@ class Location extends @location {
105105
}
106106

107107
/**
108+
* DEPRECATED: Use `Location` instead.
108109
* A location of an element. Not used for expressions or statements, which
109110
* instead use LocationExpr and LocationStmt respectively.
110111
*/
111-
library class LocationDefault extends Location, @location_default { }
112+
deprecated library class LocationDefault extends Location, @location_default { }
112113

113-
/** A location of a statement. */
114-
library class LocationStmt extends Location, @location_stmt { }
114+
/**
115+
* DEPRECATED: Use `Location` instead.
116+
* A location of a statement.
117+
*/
118+
deprecated library class LocationStmt extends Location, @location_stmt { }
115119

116-
/** A location of an expression. */
117-
library class LocationExpr extends Location, @location_expr { }
120+
/**
121+
* DEPRECATED: Use `Location` instead.
122+
* A location of an expression.
123+
*/
124+
deprecated library class LocationExpr extends Location, @location_expr { }
118125

119126
/**
120127
* Gets the length of the longest line in file `f`.

cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -279,20 +279,62 @@ private predicate reachableRecursive(ControlFlowNode n) {
279279
reachableRecursive(n.getAPredecessor())
280280
}
281281

282+
/** Holds if `e` is a compile time constant with integer value `val`. */
282283
private predicate compileTimeConstantInt(Expr e, int val) {
283-
val = e.getFullyConverted().getValue().toInt() and
284-
not e instanceof StringLiteral and
285-
not exists(Expr e1 | e1.getConversion() = e) // only values for fully converted expressions
284+
(
285+
// If we have an integer value then we are done.
286+
if exists(e.getValue().toInt())
287+
then val = e.getValue().toInt()
288+
else
289+
// Otherwise, if we are a conversion of another expression with an
290+
// integer value, and that value can be converted into our type,
291+
// then we have that value.
292+
exists(Expr x, int valx |
293+
x.getConversion() = e and
294+
compileTimeConstantInt(x, valx) and
295+
val = convertIntToType(valx, e.getType().getUnspecifiedType())
296+
)
297+
) and
298+
// If our unconverted expression is a string literal `"123"`, then we
299+
// do not have integer value `123`.
300+
not e.getUnconverted() instanceof StringLiteral
286301
}
287302

288-
library class CompileTimeConstantInt extends Expr {
289-
CompileTimeConstantInt() { compileTimeConstantInt(this, _) }
303+
/**
304+
* Get `val` represented as type `t`, if that is possible without
305+
* overflow or underflows.
306+
*/
307+
bindingset[val, t]
308+
private int convertIntToType(int val, IntegralType t) {
309+
if t instanceof BoolType
310+
then if val = 0 then result = 0 else result = 1
311+
else
312+
if t.isUnsigned()
313+
then if val >= 0 and val.bitShiftRight(t.getSize() * 8) = 0 then result = val else none()
314+
else
315+
if val >= 0 and val.bitShiftRight(t.getSize() * 8 - 1) = 0
316+
then result = val
317+
else
318+
if (-(val + 1)).bitShiftRight(t.getSize() * 8 - 1) = 0
319+
then result = val
320+
else none()
321+
}
322+
323+
/**
324+
* INTERNAL: Do not use.
325+
* An expression that has been found to have an integer value at compile
326+
* time.
327+
*/
328+
class CompileTimeConstantInt extends Expr {
329+
int val;
330+
331+
CompileTimeConstantInt() { compileTimeConstantInt(this.getFullyConverted(), val) }
290332

291-
int getIntValue() { compileTimeConstantInt(this, result) }
333+
int getIntValue() { result = val }
292334
}
293335

294336
library class CompileTimeVariableExpr extends Expr {
295-
CompileTimeVariableExpr() { not compileTimeConstantInt(this, _) }
337+
CompileTimeVariableExpr() { not this instanceof CompileTimeConstantInt }
296338
}
297339

298340
/** A helper class for evaluation of expressions. */

cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["
2929
*/
3030
private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") }
3131

32-
private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
32+
private predicate lvalueToLvalueStepPure(Expr lvalueIn, Expr lvalueOut) {
3333
lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr)
3434
or
3535
// When an object is implicitly converted to a reference to one of its base
@@ -42,6 +42,10 @@ private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
4242
// such casts.
4343
lvalueIn.getConversion() = lvalueOut and
4444
lvalueOut.(CStyleCast).isImplicit()
45+
}
46+
47+
private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
48+
lvalueToLvalueStepPure(lvalueIn, lvalueOut)
4549
or
4650
// C++ only
4751
lvalueIn = lvalueOut.(PrefixCrementOperation).getOperand().getFullyConverted()
@@ -214,6 +218,69 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode
214218
)
215219
}
216220

221+
private predicate lvalueFromVariableAccess(VariableAccess va, Expr lvalue) {
222+
// Base case for non-reference types.
223+
lvalue = va and
224+
not va.getConversion() instanceof ReferenceDereferenceExpr
225+
or
226+
// Base case for reference types where we pretend that they are
227+
// non-reference types. The type of the target of `va` can be `ReferenceType`
228+
// or `FunctionReferenceType`.
229+
lvalue = va.getConversion().(ReferenceDereferenceExpr)
230+
or
231+
// lvalue -> lvalue
232+
exists(Expr prev |
233+
lvalueFromVariableAccess(va, prev) and
234+
lvalueToLvalueStep(prev, lvalue)
235+
)
236+
or
237+
// pointer -> lvalue
238+
exists(Expr prev |
239+
pointerFromVariableAccess(va, prev) and
240+
pointerToLvalueStep(prev, lvalue)
241+
)
242+
or
243+
// reference -> lvalue
244+
exists(Expr prev |
245+
referenceFromVariableAccess(va, prev) and
246+
referenceToLvalueStep(prev, lvalue)
247+
)
248+
}
249+
250+
private predicate pointerFromVariableAccess(VariableAccess va, Expr pointer) {
251+
// pointer -> pointer
252+
exists(Expr prev |
253+
pointerFromVariableAccess(va, prev) and
254+
pointerToPointerStep(prev, pointer)
255+
)
256+
or
257+
// reference -> pointer
258+
exists(Expr prev |
259+
referenceFromVariableAccess(va, prev) and
260+
referenceToPointerStep(prev, pointer)
261+
)
262+
or
263+
// lvalue -> pointer
264+
exists(Expr prev |
265+
lvalueFromVariableAccess(va, prev) and
266+
lvalueToPointerStep(prev, pointer)
267+
)
268+
}
269+
270+
private predicate referenceFromVariableAccess(VariableAccess va, Expr reference) {
271+
// reference -> reference
272+
exists(Expr prev |
273+
referenceFromVariableAccess(va, prev) and
274+
referenceToReferenceStep(prev, reference)
275+
)
276+
or
277+
// lvalue -> reference
278+
exists(Expr prev |
279+
lvalueFromVariableAccess(va, prev) and
280+
lvalueToReferenceStep(prev, reference)
281+
)
282+
}
283+
217284
/**
218285
* Holds if `node` is a control-flow node that may modify `inner` (or what it
219286
* points to) through `outer`. The two expressions may be `Conversion`s. Plain
@@ -236,7 +303,7 @@ predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) {
236303
(
237304
inner instanceof VariableAccess and
238305
// Don't track non-field assignments
239-
(assignmentTo(outer, _) implies inner instanceof FieldAccess)
306+
not (assignmentTo(outer, _) and outer.(VariableAccess).getTarget() instanceof StackVariable)
240307
or
241308
inner instanceof ThisExpr
242309
or
@@ -245,3 +312,27 @@ predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) {
245312
// can't do anything useful with those at the moment.
246313
)
247314
}
315+
316+
/**
317+
* Holds if `e` is a fully-converted expression that evaluates to an lvalue
318+
* derived from `va` and is used for reading from or assigning to. This is in
319+
* contrast with a variable access that is used for taking an address (`&x`)
320+
* or simply discarding its value (`x;`).
321+
*
322+
* This analysis does not propagate across assignments or calls, and unlike
323+
* `variableAccessedAsValue` in `semmle.code.cpp.dataflow.EscapesTree` it
324+
* propagates through array accesses but not field accesses. The analysis is
325+
* also not concerned with whether the lvalue `e` is converted to an rvalue --
326+
* to examine that, use the relevant member predicates on `Expr`.
327+
*
328+
* If `va` has reference type, the analysis concerns the value pointed to by
329+
* the reference rather than the reference itself. The expression `e` may be a
330+
* `Conversion`.
331+
*/
332+
predicate variablePartiallyAccessed(VariableAccess va, Expr e) {
333+
lvalueFromVariableAccess(va, e) and
334+
not lvalueToLvalueStepPure(e, _) and
335+
not lvalueToPointerStep(e, _) and
336+
not lvalueToReferenceStep(e, _) and
337+
not e = any(ExprInVoidContext eivc | e = eivc.getConversion*())
338+
}

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

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ private import cpp
66
private import semmle.code.cpp.dataflow.internal.FlowVar
77
private import semmle.code.cpp.models.interfaces.DataFlow
88
private import semmle.code.cpp.controlflow.Guards
9+
private import semmle.code.cpp.dataflow.internal.AddressFlow
910

1011
cached
1112
private newtype TNode =
@@ -610,6 +611,15 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
610611
or
611612
toExpr.(AddressOfExpr).getOperand() = fromExpr
612613
or
614+
// This rule enables flow from an array to its elements. Example: `a` to
615+
// `a[i]` or `*a`, where `a` is an array type. It does not enable flow from a
616+
// pointer to its indirection as in `p[i]` where `p` is a pointer type.
617+
exists(Expr toConverted |
618+
variablePartiallyAccessed(fromExpr, toConverted) and
619+
toExpr = toConverted.getUnconverted() and
620+
not toExpr = fromExpr
621+
)
622+
or
613623
toExpr.(BuiltInOperationBuiltInAddressOf).getOperand() = fromExpr
614624
or
615625
// The following case is needed to track the qualifier object for flow
@@ -629,14 +639,25 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
629639
// `ClassAggregateLiteral` (`{ capture1, ..., captureN }`).
630640
toExpr.(LambdaExpression).getInitializer() = fromExpr
631641
or
642+
// Data flow through a function model.
632643
toExpr =
633644
any(Call call |
634-
exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel, int iIn |
635-
call.getTarget() = f and
645+
exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel |
636646
f.hasDataFlow(inModel, outModel) and
637-
outModel.isReturnValue() and
638-
inModel.isParameter(iIn) and
639-
fromExpr = call.getArgument(iIn)
647+
(
648+
exists(int iIn |
649+
inModel.isParameter(iIn) and
650+
fromExpr = call.getArgument(iIn)
651+
)
652+
or
653+
inModel.isQualifierObject() and
654+
fromExpr = call.getQualifier()
655+
or
656+
inModel.isQualifierAddress() and
657+
fromExpr = call.getQualifier()
658+
) and
659+
call.getTarget() = f and
660+
outModel.isReturnValue()
640661
)
641662
)
642663
}

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,6 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
264264
t instanceof Union
265265
or
266266
t instanceof ArrayType
267-
or
268-
// Buffers of unknown size
269-
t instanceof UnknownType
270267
)
271268
or
272269
exists(BinaryInstruction bin |

0 commit comments

Comments
 (0)