Skip to content

Commit 3bfcf0b

Browse files
author
Robert Marsh
committed
Merge branch 'master' into connect-ir-dataflow-models
2 parents 83d611d + 2b10cd6 commit 3bfcf0b

File tree

167 files changed

+5838
-564
lines changed

Some content is hidden

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

167 files changed

+5838
-564
lines changed

change-notes/1.24/analysis-java.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@ The following changes in version 1.24 affect Java analysis in all applications.
3636
general file classification mechanism and thus suppression of alerts, and
3737
also any security queries using taint tracking, as test classes act as
3838
default barriers stopping taint flow.
39+
* Parentheses are now no longer modelled directly in the AST, that is, the
40+
`ParExpr` class is empty. Instead, a parenthesized expression can be
41+
identified with the `Expr.isParenthesized()` member predicate.

change-notes/1.24/analysis-javascript.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
* Imports with the `.js` extension can now be resolved to a TypeScript file,
88
when the import refers to a file generated by TypeScript.
99

10-
- The analysis of sanitizer guards has improved, leading to fewer false-positive results from the security queries.
10+
* Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved.
11+
12+
* The analysis of sanitizer guards has improved, leading to fewer false-positive results from the security queries.
1113

1214
* Support for the following frameworks and libraries has been improved:
1315
- [react](https://www.npmjs.com/package/react)
@@ -18,6 +20,7 @@
1820
- [Socket.IO](https://socket.io/)
1921
- [ws](https://github.com/websockets/ws)
2022
- [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
23+
- [Koa](https://www.npmjs.com/package/koa)
2124

2225
## New queries
2326

cpp/ql/src/semmle/code/cpp/commons/Printf.qll

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,7 @@ class FormatLiteral extends Literal {
258258
* Gets the position in the string at which the nth conversion specifier
259259
* starts.
260260
*/
261-
int getConvSpecOffset(int n) {
262-
n = 0 and result = this.getFormat().indexOf("%", 0, 0)
263-
or
264-
n > 0 and
265-
exists(int p |
266-
n = p + 1 and result = this.getFormat().indexOf("%", 0, this.getConvSpecOffset(p) + 2)
267-
)
268-
}
261+
int getConvSpecOffset(int n) { result = this.getFormat().indexOf("%", n, 0) }
269262

270263
/*
271264
* Each of these predicates gets a regular expressions to match each individual

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

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,19 @@ private predicate predictableInstruction(Instruction instr) {
2121
predictableInstruction(instr.(UnaryInstruction).getUnary())
2222
}
2323

24+
private DataFlow::Node getNodeForSource(Expr source) {
25+
isUserInput(source, _) and
26+
(
27+
result = DataFlow::exprNode(source)
28+
or
29+
result = DataFlow::definitionByReferenceNode(source)
30+
)
31+
}
32+
2433
private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
2534
DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" }
2635

27-
override predicate isSource(DataFlow::Node source) {
28-
exists(CallInstruction ci, WriteSideEffectInstruction wsei |
29-
userInputArgument(ci.getConvertedResultExpression(), wsei.getIndex()) and
30-
source.asInstruction() = wsei and
31-
wsei.getPrimaryInstruction() = ci
32-
)
33-
or
34-
userInputReturned(source.asExpr())
35-
or
36-
isUserInput(source.asExpr(), _)
37-
or
38-
source.asExpr() instanceof EnvironmentRead
39-
or
40-
source
41-
.asInstruction()
42-
.(LoadInstruction)
43-
.getSourceAddress()
44-
.(VariableAddressInstruction)
45-
.getASTVariable()
46-
.hasName("argv") and
47-
source.asInstruction().getEnclosingFunction().hasGlobalName("main")
48-
}
36+
override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
4937

5038
override predicate isSink(DataFlow::Node sink) { any() }
5139

@@ -59,7 +47,7 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
5947
private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
6048
ToGlobalVarTaintTrackingCfg() { this = "GlobalVarTaintTrackingCfg" }
6149

62-
override predicate isSource(DataFlow::Node source) { isUserInput(source.asExpr(), _) }
50+
override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
6351

6452
override predicate isSink(DataFlow::Node sink) {
6553
exists(GlobalOrNamespaceVariable gv | writesVariable(sink.asInstruction(), gv))
@@ -163,6 +151,22 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
163151
// from `a`.
164152
i2.(PointerAddInstruction).getLeft() = i1
165153
or
154+
// Until we have from through indirections across calls, we'll take flow out
155+
// of the parameter and into its indirection.
156+
exists(IRFunction f, Parameter parameter |
157+
i1 = getInitializeParameter(f, parameter) and
158+
i2 = getInitializeIndirection(f, parameter)
159+
)
160+
or
161+
// Until we have flow through indirections across calls, we'll take flow out
162+
// of the indirection and into the argument.
163+
// When we get proper flow through indirections across calls, this code can be
164+
// moved to `adjusedSink` or possibly into the `DataFlow::ExprNode` class.
165+
exists(ReadSideEffectInstruction read |
166+
read.getAnOperand().(SideEffectOperand).getAnyDef() = i1 and
167+
read.getArgumentDef() = i2
168+
)
169+
or
166170
// Flow from argument to return value
167171
i2 =
168172
any(CallInstruction call |
@@ -188,6 +192,33 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
188192
)
189193
}
190194

195+
pragma[noinline]
196+
private InitializeIndirectionInstruction getInitializeIndirection(IRFunction f, Parameter p) {
197+
result.getParameter() = p and
198+
result.getEnclosingIRFunction() = f
199+
}
200+
201+
pragma[noinline]
202+
private InitializeParameterInstruction getInitializeParameter(IRFunction f, Parameter p) {
203+
result.getParameter() = p and
204+
result.getEnclosingIRFunction() = f
205+
}
206+
207+
/**
208+
* Get an instruction that goes into argument `argumentIndex` of `call`. This
209+
* can be either directly or through one pointer indirection.
210+
*/
211+
private Instruction getACallArgumentOrIndirection(CallInstruction call, int argumentIndex) {
212+
result = call.getPositionalArgument(argumentIndex)
213+
or
214+
exists(ReadSideEffectInstruction readSE |
215+
// TODO: why are read side effect operands imprecise?
216+
result = readSE.getSideEffectOperand().getAnyDef() and
217+
readSE.getPrimaryInstruction() = call and
218+
readSE.getIndex() = argumentIndex
219+
)
220+
}
221+
191222
private predicate modelTaintToParameter(Function f, int parameterIn, int parameterOut) {
192223
exists(FunctionInput modelIn, FunctionOutput modelOut |
193224
(
@@ -270,31 +301,11 @@ private Element adjustedSink(DataFlow::Node sink) {
270301
// For compatibility, send flow into a `NotExpr` even if it's part of a
271302
// short-circuiting condition and thus might get skipped.
272303
result.(NotExpr).getOperand() = sink.asExpr()
273-
or
274-
// For compatibility, send flow from argument read side effects to their
275-
// corresponding argument expression
276-
exists(IndirectReadSideEffectInstruction read |
277-
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
278-
read.getArgumentDef().getUnconvertedResultExpression() = result
279-
)
280-
or
281-
exists(BufferReadSideEffectInstruction read |
282-
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
283-
read.getArgumentDef().getUnconvertedResultExpression() = result
284-
)
285-
or
286-
exists(SizedBufferReadSideEffectInstruction read |
287-
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
288-
read.getArgumentDef().getUnconvertedResultExpression() = result
289-
)
290304
}
291305

292306
predicate tainted(Expr source, Element tainted) {
293307
exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink |
294-
cfg.hasFlow(DataFlow::exprNode(source), sink)
295-
or
296-
cfg.hasFlow(DataFlow::definitionByReferenceNode(source), sink)
297-
|
308+
cfg.hasFlow(getNodeForSource(source), sink) and
298309
tainted = adjustedSink(sink)
299310
)
300311
}
@@ -307,7 +318,7 @@ predicate taintedIncludingGlobalVars(Expr source, Element tainted, string global
307318
ToGlobalVarTaintTrackingCfg toCfg, FromGlobalVarTaintTrackingCfg fromCfg, DataFlow::Node store,
308319
GlobalOrNamespaceVariable global, DataFlow::Node load, DataFlow::Node sink
309320
|
310-
toCfg.hasFlow(DataFlow::exprNode(source), store) and
321+
toCfg.hasFlow(getNodeForSource(source), store) and
311322
store
312323
.asInstruction()
313324
.(StoreInstruction)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,18 @@
2121
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:33 | (const char *)... |
2222
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:25 | call to getenv |
2323
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:32 | (const char *)... |
24+
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | (const char *)... |
25+
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | array to pointer conversion |
2426
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | buf |
2527
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
28+
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:31:40:31:53 | dotted_address |
2629
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:32:11:32:26 | p#0 |
2730
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:11:38:21 | env_pointer |
2831
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:30 | call to getenv |
2932
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:37 | (void *)... |
3033
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:22:39:22 | a |
3134
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:26:39:34 | call to inet_addr |
35+
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:36:39:61 | (const char *)... |
3236
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:50:39:61 | & ... |
3337
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:40:10:40:10 | a |
3438
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:3:21:3:22 | s1 | AST only |
66
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:21:8:21:10 | buf | AST only |
77
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:15:22:17 | buf | AST only |
8-
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:31:40:31:53 | dotted_address | AST only |
9-
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:36:39:61 | (const char *)... | AST only |
8+
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | (const char *)... | IR only |
9+
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | array to pointer conversion | IR only |
1010
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:51:39:61 | env_pointer | AST only |
1111
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | IR only |
1212
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | IR only |

java/ql/src/Language Abuse/UselessUpcast.ql

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import java
1515
predicate usefulUpcast(CastExpr e) {
1616
// Upcasts that may be performed to affect resolution of methods or constructors.
1717
exists(Call c, int i, Callable target |
18-
c.getArgument(i).getProperExpr() = e and
18+
c.getArgument(i) = e and
1919
target = c.getCallee() and
2020
// An upcast to the type of the corresponding parameter.
2121
e.getType() = target.getParameterType(i)
@@ -31,27 +31,25 @@ predicate usefulUpcast(CastExpr e) {
3131
)
3232
or
3333
// Upcasts of a varargs argument.
34-
exists(Call c, int iArg, int iParam | c.getArgument(iArg).getProperExpr() = e |
34+
exists(Call c, int iArg, int iParam | c.getArgument(iArg) = e |
3535
c.getCallee().getParameter(iParam).isVarargs() and iArg >= iParam
3636
)
3737
or
3838
// Upcasts that are performed on an operand of a ternary expression.
39-
exists(ConditionalExpr ce |
40-
e = ce.getTrueExpr().getProperExpr() or e = ce.getFalseExpr().getProperExpr()
41-
)
39+
exists(ConditionalExpr ce | e = ce.getTrueExpr() or e = ce.getFalseExpr())
4240
or
4341
// Upcasts to raw types.
4442
e.getType() instanceof RawType
4543
or
4644
e.getType().(Array).getElementType() instanceof RawType
4745
or
4846
// Upcasts that are performed to affect field, private method, or static method resolution.
49-
exists(FieldAccess fa | e = fa.getQualifier().getProperExpr() |
47+
exists(FieldAccess fa | e = fa.getQualifier() |
5048
not e.getExpr().getType().(RefType).inherits(fa.getField())
5149
)
5250
or
5351
exists(MethodAccess ma, Method m |
54-
e = ma.getQualifier().getProperExpr() and
52+
e = ma.getQualifier() and
5553
m = ma.getMethod() and
5654
(m.isStatic() or m.isPrivate())
5755
|

java/ql/src/Likely Bugs/Arithmetic/BadCheckOdd.ql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import java
1515
import semmle.code.java.Collections
1616

1717
predicate isDefinitelyPositive(Expr e) {
18-
isDefinitelyPositive(e.getProperExpr()) or
18+
isDefinitelyPositive(e) or
1919
e.(IntegerLiteral).getIntValue() >= 0 or
2020
e.(MethodAccess).getMethod() instanceof CollectionSizeMethod or
2121
e.(MethodAccess).getMethod() instanceof StringLengthMethod or
@@ -24,10 +24,10 @@ predicate isDefinitelyPositive(Expr e) {
2424

2525
from BinaryExpr t, RemExpr lhs, IntegerLiteral rhs, string parity
2626
where
27-
t.getLeftOperand().getProperExpr() = lhs and
28-
t.getRightOperand().getProperExpr() = rhs and
27+
t.getLeftOperand() = lhs and
28+
t.getRightOperand() = rhs and
2929
not isDefinitelyPositive(lhs.getLeftOperand()) and
30-
lhs.getRightOperand().getProperExpr().(IntegerLiteral).getIntValue() = 2 and
30+
lhs.getRightOperand().(IntegerLiteral).getIntValue() = 2 and
3131
(
3232
t instanceof EQExpr and rhs.getIntValue() = 1 and parity = "oddness"
3333
or

java/ql/src/Likely Bugs/Arithmetic/ConstantExpAppearsNonConstant.ql

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ predicate isConstantExp(Expr e) {
1717
// A literal is constant.
1818
e instanceof Literal
1919
or
20-
// A parenthesized expression is constant if its proper expression is.
21-
isConstantExp(e.(ParExpr).getProperExpr())
22-
or
2320
e instanceof TypeAccess
2421
or
2522
e instanceof ArrayTypeAccess
@@ -33,26 +30,22 @@ predicate isConstantExp(Expr e) {
3330
)
3431
or
3532
// A cast expression is constant if its expression is.
36-
exists(CastExpr c | c = e | isConstantExp(c.getExpr().getProperExpr()))
33+
exists(CastExpr c | c = e | isConstantExp(c.getExpr()))
3734
or
3835
// Multiplication by 0 is constant.
39-
exists(MulExpr m | m = e | eval(m.getAnOperand().getProperExpr()) = 0)
36+
exists(MulExpr m | m = e | eval(m.getAnOperand()) = 0)
4037
or
4138
// Integer remainder by 1 is constant.
4239
exists(RemExpr r | r = e |
4340
r.getLeftOperand().getType() instanceof IntegralType and
44-
eval(r.getRightOperand().getProperExpr()) = 1
41+
eval(r.getRightOperand()) = 1
4542
)
4643
or
47-
exists(AndBitwiseExpr a | a = e | eval(a.getAnOperand().getProperExpr()) = 0)
44+
exists(AndBitwiseExpr a | a = e | eval(a.getAnOperand()) = 0)
4845
or
49-
exists(AndLogicalExpr a | a = e |
50-
a.getAnOperand().getProperExpr().(BooleanLiteral).getBooleanValue() = false
51-
)
46+
exists(AndLogicalExpr a | a = e | a.getAnOperand().(BooleanLiteral).getBooleanValue() = false)
5247
or
53-
exists(OrLogicalExpr o | o = e |
54-
o.getAnOperand().getProperExpr().(BooleanLiteral).getBooleanValue() = true
55-
)
48+
exists(OrLogicalExpr o | o = e | o.getAnOperand().(BooleanLiteral).getBooleanValue() = true)
5649
}
5750

5851
from Expr e

java/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ float exprBound(Expr e) {
3535
/** A multiplication that does not overflow. */
3636
predicate small(MulExpr e) {
3737
exists(NumType t, float lhs, float rhs, float res | t = e.getType() |
38-
lhs = exprBound(e.getLeftOperand().getProperExpr()) and
39-
rhs = exprBound(e.getRightOperand().getProperExpr()) and
38+
lhs = exprBound(e.getLeftOperand()) and
39+
rhs = exprBound(e.getRightOperand()) and
4040
lhs * rhs = res and
4141
res <= t.getOrdPrimitiveType().getMaxValue()
4242
)
@@ -47,7 +47,7 @@ predicate small(MulExpr e) {
4747
*/
4848
Expr getRestrictedParent(Expr e) {
4949
result = e.getParent() and
50-
(result instanceof ArithExpr or result instanceof ConditionalExpr or result instanceof ParExpr)
50+
(result instanceof ArithExpr or result instanceof ConditionalExpr)
5151
}
5252

5353
from ConversionSite c, MulExpr e, NumType sourceType, NumType destType

0 commit comments

Comments
 (0)