Skip to content

Commit fe9f974

Browse files
committed
Merge branch 'master' into alistairs-docs-preparation-1
2 parents fab7955 + dcb41a1 commit fe9f974

171 files changed

Lines changed: 4465 additions & 1084 deletions

File tree

Some content is hidden

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

change-notes/1.24/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
1919
| Memory is never freed (`cpp/memory-never-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
2020
| Memory may not be freed (`cpp/memory-may-not-be-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
2121
| Missing return statement (`cpp/missing-return`) | Fewer false positive results | Functions containing `asm` statements are no longer highlighted by this query. |
22+
| No space for zero terminator (`cpp/no-space-for-terminator`) | More correct results | String arguments to formatting functions are now (usually) expected to be null terminated strings. |
2223
| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. |
2324
| No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. |
2425
| Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. |

change-notes/1.24/analysis-csharp.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ The following changes in version 1.24 affect C# analysis in all applications.
2727
## Changes to code extraction
2828

2929
* Tuple expressions, for example `(int,bool)` in `default((int,bool))` are now extracted correctly.
30-
* Expression nullability flow state is extracted.
30+
* Expression nullability flow state is extracted.
31+
* Implicitly typed `stackalloc` expressions are now extracted correctly.
32+
* The difference between `stackalloc` array creations and normal array creations is extracted.
3133

3234
## Changes to libraries
3335

@@ -38,5 +40,6 @@ The following changes in version 1.24 affect C# analysis in all applications.
3840
* The taint tracking library now tracks flow through (implicit or explicit) conversion operator calls.
3941
* [Code contracts](https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts) are now recognized, and are treated like any other assertion methods.
4042
* Expression nullability flow state is given by the predicates `Expr.hasNotNullFlowState()` and `Expr.hasMaybeNullFlowState()`.
43+
* `stackalloc` array creations are now represented by the QL class `Stackalloc`. Previously they were represented by the class `ArrayCreation`.
4144

4245
## Changes to autobuilder
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Improvements to Python analysis
2+
3+
The following changes in version 1.24 affect Python 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+
### Web framework support
18+
19+
The QL-library support for the web frameworks Bottle, CherryPy, Falcon, Pyramid, TurboGears, Tornado, and Twisted have
20+
been fixed so they provide a proper HttpRequestTaintSource, instead of a TaintSource. This will enable results for the following queries:
21+
22+
- py/path-injection
23+
- py/command-line-injection
24+
- py/reflective-xss
25+
- py/sql-injection
26+
- py/code-injection
27+
- py/unsafe-deserialization
28+
- py/url-redirection
29+
30+
The QL-library support for the web framework Twisted have been fixed so they provide a proper
31+
HttpResponseTaintSink, instead of a TaintSink. This will enable results for the following
32+
queries:
33+
34+
- py/reflective-xss
35+
- py/stack-trace-exposure
36+
37+
## Changes to libraries

cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,25 @@ import semmle.code.cpp.models.interfaces.Allocation
2222
predicate terminationProblem(AllocationExpr malloc, string msg) {
2323
// malloc(strlen(...))
2424
exists(StrlenCall strlen | DataFlow::localExprFlow(strlen, malloc.getSizeExpr())) and
25-
// flows into a null-terminated string function
25+
// flows to a call that implies this is a null-terminated string
2626
exists(ArrayFunction af, FunctionCall fc, int arg |
2727
DataFlow::localExprFlow(malloc, fc.getArgument(arg)) and
2828
fc.getTarget() = af and
2929
(
30-
// null terminated string
30+
// flows into null terminated string argument
3131
af.hasArrayWithNullTerminator(arg)
3232
or
33-
// likely a null terminated string (such as `strcpy`, `strcat`)
33+
// flows into likely null terminated string argument (such as `strcpy`, `strcat`)
3434
af.hasArrayWithUnknownSize(arg)
35+
or
36+
// flows into string argument to a formatting function (such as `printf`)
37+
exists(int n, FormatLiteral fl |
38+
fc.getArgument(arg) = fc.(FormattingFunctionCall).getConversionArgument(n) and
39+
fl = fc.(FormattingFunctionCall).getFormat() and
40+
fl.getConversionType(n) instanceof PointerType and // `%s`, `%ws` etc
41+
not fl.getConversionType(n) instanceof VoidPointerType and // exclude: `%p`
42+
not fl.hasPrecision(n) // exclude: `%.*s`
43+
)
3544
)
3645
) and
3746
msg = "This allocation does not include space to null-terminate the string."

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,12 @@ private Element adjustedSink(DataFlow::Node sink) {
335335
// For compatibility, send flow into a `NotExpr` even if it's part of a
336336
// short-circuiting condition and thus might get skipped.
337337
result.(NotExpr).getOperand() = sink.asExpr()
338+
or
339+
// Taint postfix and prefix crement operations when their operand is tainted.
340+
result.(CrementOperation).getAnOperand() = sink.asExpr()
341+
or
342+
// Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted.
343+
result.(AssignOperation).getAnOperand() = sink.asExpr()
338344
}
339345

340346
predicate tainted(Expr source, Element tainted) {

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,10 @@ private predicate modelFlow(Instruction iFrom, Instruction iTo) {
365365
modelOut.isReturnValueDeref() and
366366
iTo = call
367367
or
368-
exists(WriteSideEffectInstruction outNode |
369-
modelOut.isParameterDeref(outNode.getIndex()) and
368+
exists(int index, WriteSideEffectInstruction outNode |
369+
modelOut.isParameterDeref(index) and
370370
iTo = outNode and
371-
outNode.getPrimaryInstruction() = call
371+
outNode = getSideEffectFor(call, index)
372372
)
373373
// TODO: add write side effects for qualifiers
374374
) and
@@ -380,8 +380,7 @@ private predicate modelFlow(Instruction iFrom, Instruction iTo) {
380380
or
381381
exists(int index, ReadSideEffectInstruction read |
382382
modelIn.isParameterDeref(index) and
383-
read.getIndex() = index and
384-
read.getPrimaryInstruction() = call and
383+
read = getSideEffectFor(call, index) and
385384
iFrom = read.getSideEffectOperand().getAnyDef()
386385
)
387386
or
@@ -392,6 +391,18 @@ private predicate modelFlow(Instruction iFrom, Instruction iTo) {
392391
)
393392
}
394393

394+
/**
395+
* Holds if the result is a side effect for instruction `call` on argument
396+
* index `argument`. This helper predicate makes it easy to join on both of
397+
* these columns at once, avoiding pathological join orders in case the
398+
* argument index should get joined first.
399+
*/
400+
pragma[noinline]
401+
SideEffectInstruction getSideEffectFor(CallInstruction call, int argument) {
402+
call = result.getPrimaryInstruction() and
403+
argument = result.(IndexedInstruction).getIndex()
404+
}
405+
395406
/**
396407
* Holds if data flows from `source` to `sink` in zero or more local
397408
* (intra-procedural) steps.

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,19 @@ cached
1111
private newtype TOperand =
1212
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
1313
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
14-
not Construction::isInCycle(useInstr)
14+
not Construction::isInCycle(useInstr) and
15+
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
1516
} or
1617
TNonPhiMemoryOperand(
1718
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
1819
) {
1920
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
20-
not Construction::isInCycle(useInstr)
21+
not Construction::isInCycle(useInstr) and
22+
(
23+
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
24+
or
25+
tag instanceof UnmodeledUseOperandTag
26+
)
2127
} or
2228
TPhiOperand(
2329
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ private import ValueNumberingImports
22
private import cpp
33

44
newtype TValueNumber =
5-
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
6-
variableAddressValueNumber(_, irFunc, var)
5+
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
6+
variableAddressValueNumber(_, irFunc, ast)
77
} or
8-
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
8+
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
99
initializeParameterValueNumber(_, irFunc, var)
1010
} or
1111
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
@@ -100,17 +100,23 @@ private predicate numberableInstruction(Instruction instr) {
100100
}
101101

102102
private predicate variableAddressValueNumber(
103-
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
103+
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
104104
) {
105105
instr.getEnclosingIRFunction() = irFunc and
106-
instr.getIRVariable() = var
106+
// The underlying AST element is used as value-numbering key instead of the
107+
// `IRVariable` to work around a problem where a variable or expression with
108+
// multiple types gives rise to multiple `IRVariable`s.
109+
instr.getIRVariable().getAST() = ast
107110
}
108111

109112
private predicate initializeParameterValueNumber(
110-
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
113+
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
111114
) {
112115
instr.getEnclosingIRFunction() = irFunc and
113-
instr.getIRVariable() = var
116+
// The underlying AST element is used as value-numbering key instead of the
117+
// `IRVariable` to work around a problem where a variable or expression with
118+
// multiple types gives rise to multiple `IRVariable`s.
119+
instr.getIRVariable().getAST() = var
114120
}
115121

116122
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
@@ -236,12 +242,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
236242
exists(IRFunction irFunc |
237243
irFunc = instr.getEnclosingIRFunction() and
238244
(
239-
exists(IRVariable var |
240-
variableAddressValueNumber(instr, irFunc, var) and
241-
result = TVariableAddressValueNumber(irFunc, var)
245+
exists(Language::AST ast |
246+
variableAddressValueNumber(instr, irFunc, ast) and
247+
result = TVariableAddressValueNumber(irFunc, ast)
242248
)
243249
or
244-
exists(IRVariable var |
250+
exists(Language::AST var |
245251
initializeParameterValueNumber(instr, irFunc, var) and
246252
result = TInitializeParameterValueNumber(irFunc, var)
247253
)

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,12 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
220220
/**
221221
* Holds if this memory location covers the entire variable.
222222
*/
223-
final predicate coversEntireVariable() {
224-
startBitOffset = 0 and
225-
endBitOffset = var.getIRType().getByteSize() * 8
223+
final predicate coversEntireVariable() { varIRTypeHasBitRange(startBitOffset, endBitOffset) }
224+
225+
pragma[noinline]
226+
private predicate varIRTypeHasBitRange(int start, int end) {
227+
start = 0 and
228+
end = var.getIRType().getByteSize() * 8
226229
}
227230
}
228231

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,19 @@ cached
1111
private newtype TOperand =
1212
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
1313
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
14-
not Construction::isInCycle(useInstr)
14+
not Construction::isInCycle(useInstr) and
15+
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
1516
} or
1617
TNonPhiMemoryOperand(
1718
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
1819
) {
1920
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
20-
not Construction::isInCycle(useInstr)
21+
not Construction::isInCycle(useInstr) and
22+
(
23+
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
24+
or
25+
tag instanceof UnmodeledUseOperandTag
26+
)
2127
} or
2228
TPhiOperand(
2329
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap

0 commit comments

Comments
 (0)