Skip to content

Commit 2408230

Browse files
author
Dave Bartolomeo
committed
Merge remote-tracking branch 'upstream/master' into dbartol/MissingToString
2 parents 60c40ad + 9193a81 commit 2408230

File tree

35 files changed

+401
-132
lines changed

35 files changed

+401
-132
lines changed

.github/workflows/labeler.yml

Lines changed: 0 additions & 11 deletions
This file was deleted.

change-notes/1.24/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
1313

1414
| **Query** | **Expected impact** | **Change** |
1515
|----------------------------|------------------------|------------------------------------------------------------------|
16+
| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. |
1617
| 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. |
1718

1819
## Changes to libraries

change-notes/1.24/analysis-csharp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ The following changes in version 1.24 affect C# analysis in all applications.
2121
## Changes to libraries
2222

2323
* The taint tracking library now tracks flow through (implicit or explicit) conversion operator calls.
24+
* [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.
2425

2526
## Changes to autobuilder
2627

cpp/ql/src/Architecture/FeatureEnvy.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @description A function that uses more functions and variables from another file than functions and variables from its own file. This function might be better placed in the other file, to avoid exposing internals of the file it depends on.
44
* @kind problem
55
* @problem.severity recommendation
6-
* @precision high
6+
* @precision medium
77
* @id cpp/feature-envy
88
* @tags maintainability
99
* modularity

cpp/ql/src/Architecture/InappropriateIntimacy.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @description Two files share too much information about each other (accessing many operations or variables in both directions). It would be better to invert some of the dependencies to reduce the coupling between the two files.
44
* @kind problem
55
* @problem.severity recommendation
6-
* @precision high
6+
* @precision medium
77
* @id cpp/file-intimacy
88
* @tags maintainability
99
* modularity

cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @description Finds classes with many fields; they could probably be refactored by breaking them down into smaller classes, and using composition.
44
* @kind problem
55
* @problem.severity recommendation
6-
* @precision high
6+
* @precision medium
77
* @id cpp/class-many-fields
88
* @tags maintainability
99
* statistical

cpp/ql/src/Best Practices/Magic Constants/JapaneseEraDate.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @kind problem
55
* @problem.severity warning
66
* @id cpp/japanese-era/exact-era-date
7-
* @precision medium
7+
* @precision low
88
* @tags reliability
99
* japanese-era
1010
*/

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ abstract class XMLLocatable extends @xmllocatable {
3131
* both of which can contain other elements.
3232
*/
3333
class XMLParent extends @xmlparent {
34+
XMLParent() {
35+
// explicitly restrict `this` to be either an `XMLElement` or an `XMLFile`;
36+
// the type `@xmlparent` currently also includes non-XML files
37+
this instanceof @xmlelement or xmlEncoding(this, _)
38+
}
39+
3440
/**
3541
* Gets a printable representation of this XML parent.
3642
* (Intended to be overridden in subclasses.)

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,11 @@ predicate allocationFunction(Function f) {
5151
name = "HeapReAlloc" or
5252
name = "VirtualAlloc" or
5353
name = "CoTaskMemAlloc" or
54-
name = "CoTaskMemRealloc"
54+
name = "CoTaskMemRealloc" or
55+
name = "kmem_alloc" or
56+
name = "kmem_zalloc" or
57+
name = "pool_get" or
58+
name = "pool_cache_get"
5559
)
5660
)
5761
}
@@ -77,6 +81,12 @@ predicate freeFunction(Function f, int argNum) {
7781
name = "free" and argNum = 0
7882
or
7983
name = "realloc" and argNum = 0
84+
or
85+
name = "kmem_free" and argNum = 0
86+
or
87+
name = "pool_put" and argNum = 1
88+
or
89+
name = "pool_cache_put" and argNum = 1
8090
)
8191
or
8292
f.hasGlobalOrStdName(name) and

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

Lines changed: 113 additions & 43 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.DataFlow2
45
private import semmle.code.cpp.ir.IR
56
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
67

@@ -29,20 +30,60 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
2930
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
3031
}
3132

32-
override predicate isBarrier(DataFlow::Node node) {
33-
exists(Variable checkedVar |
34-
accessesVariable(node.asInstruction(), checkedVar) and
35-
hasUpperBoundsCheck(checkedVar)
33+
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
34+
}
35+
36+
private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
37+
ToGlobalVarTaintTrackingCfg() { this = "GlobalVarTaintTrackingCfg" }
38+
39+
override predicate isSource(DataFlow::Node source) { isUserInput(source.asExpr(), _) }
40+
41+
override predicate isSink(DataFlow::Node sink) {
42+
exists(GlobalOrNamespaceVariable gv | writesVariable(sink.asInstruction(), gv))
43+
}
44+
45+
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
46+
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
47+
or
48+
exists(StoreInstruction i1, LoadInstruction i2, GlobalOrNamespaceVariable gv |
49+
writesVariable(i1, gv) and
50+
readsVariable(i2, gv) and
51+
i1 = n1.asInstruction() and
52+
i2 = n2.asInstruction()
3653
)
3754
}
55+
56+
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
3857
}
3958

40-
private predicate accessesVariable(CopyInstruction copy, Variable var) {
41-
exists(VariableAddressInstruction va | va.getASTVariable() = var |
42-
copy.(StoreInstruction).getDestinationAddress() = va
43-
or
44-
copy.(LoadInstruction).getSourceAddress() = va
45-
)
59+
private class FromGlobalVarTaintTrackingCfg extends DataFlow2::Configuration {
60+
FromGlobalVarTaintTrackingCfg() { this = "FromGlobalVarTaintTrackingCfg" }
61+
62+
override predicate isSource(DataFlow::Node source) {
63+
exists(
64+
ToGlobalVarTaintTrackingCfg other, DataFlow::Node prevSink, GlobalOrNamespaceVariable gv
65+
|
66+
other.hasFlowTo(prevSink) and
67+
writesVariable(prevSink.asInstruction(), gv) and
68+
readsVariable(source.asInstruction(), gv)
69+
)
70+
}
71+
72+
override predicate isSink(DataFlow::Node sink) { any() }
73+
74+
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
75+
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
76+
}
77+
78+
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
79+
}
80+
81+
private predicate readsVariable(LoadInstruction load, Variable var) {
82+
load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var
83+
}
84+
85+
private predicate writesVariable(StoreInstruction store, Variable var) {
86+
store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() = var
4687
}
4788

4889
/**
@@ -62,6 +103,13 @@ private predicate hasUpperBoundsCheck(Variable var) {
62103
)
63104
}
64105

106+
private predicate nodeIsBarrier(DataFlow::Node node) {
107+
exists(Variable checkedVar |
108+
readsVariable(node.asInstruction(), checkedVar) and
109+
hasUpperBoundsCheck(checkedVar)
110+
)
111+
}
112+
65113
private predicate instructionTaintStep(Instruction i1, Instruction i2) {
66114
// Expressions computed from tainted data are also tainted
67115
i2 = any(CallInstruction call |
@@ -99,51 +147,73 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
99147
// addition expression.
100148
}
101149

150+
private Element adjustedSink(DataFlow::Node sink) {
151+
// TODO: is it more appropriate to use asConvertedExpr here and avoid
152+
// `getConversion*`? Or will that cause us to miss some cases where there's
153+
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
154+
// pretend there was flow to the converted `Expr` for the sake of
155+
// compatibility.
156+
sink.asExpr().getConversion*() = result
157+
or
158+
// For compatibility, send flow from arguments to parameters, even for
159+
// functions with no body.
160+
exists(FunctionCall call, int i |
161+
sink.asExpr() = call.getArgument(i) and
162+
result = resolveCall(call).getParameter(i)
163+
)
164+
or
165+
// For compatibility, send flow into a `Variable` if there is flow to any
166+
// Load or Store of that variable.
167+
exists(CopyInstruction copy |
168+
copy.getSourceValue() = sink.asInstruction() and
169+
(
170+
readsVariable(copy, result) or
171+
writesVariable(copy, result)
172+
) and
173+
not hasUpperBoundsCheck(result)
174+
)
175+
or
176+
// For compatibility, send flow into a `NotExpr` even if it's part of a
177+
// short-circuiting condition and thus might get skipped.
178+
result.(NotExpr).getOperand() = sink.asExpr()
179+
}
180+
102181
predicate tainted(Expr source, Element tainted) {
103182
exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink |
104183
cfg.hasFlow(DataFlow::exprNode(source), sink)
105184
|
106-
// TODO: is it more appropriate to use asConvertedExpr here and avoid
107-
// `getConversion*`? Or will that cause us to miss some cases where there's
108-
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
109-
// pretend there was flow to the converted `Expr` for the sake of
110-
// compatibility.
111-
sink.asExpr().getConversion*() = tainted
112-
or
113-
// For compatibility, send flow from arguments to parameters, even for
114-
// functions with no body.
115-
exists(FunctionCall call, int i |
116-
sink.asExpr() = call.getArgument(i) and
117-
tainted = resolveCall(call).getParameter(i)
118-
)
119-
or
120-
// For compatibility, send flow into a `Variable` if there is flow to any
121-
// Load or Store of that variable.
122-
exists(CopyInstruction copy |
123-
copy.getSourceValue() = sink.asInstruction() and
124-
accessesVariable(copy, tainted) and
125-
not hasUpperBoundsCheck(tainted)
126-
)
127-
or
128-
// For compatibility, send flow into a `NotExpr` even if it's part of a
129-
// short-circuiting condition and thus might get skipped.
130-
tainted.(NotExpr).getOperand() = sink.asExpr()
185+
tainted = adjustedSink(sink)
131186
)
132187
}
133188

134189
predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) {
135190
tainted(source, tainted) and
136-
// TODO: Find a way to emulate how `security.TaintTracking` reports the last
137-
// global variable that taint has passed through. Also make sure we emulate
138-
// its behavior for interprocedural flow through globals.
139191
globalVar = ""
192+
or
193+
exists(
194+
ToGlobalVarTaintTrackingCfg toCfg, FromGlobalVarTaintTrackingCfg fromCfg, DataFlow::Node store,
195+
GlobalOrNamespaceVariable global, DataFlow::Node load, DataFlow::Node sink
196+
|
197+
toCfg.hasFlow(DataFlow::exprNode(source), store) and
198+
store
199+
.asInstruction()
200+
.(StoreInstruction)
201+
.getDestinationAddress()
202+
.(VariableAddressInstruction)
203+
.getASTVariable() = global and
204+
load
205+
.asInstruction()
206+
.(LoadInstruction)
207+
.getSourceAddress()
208+
.(VariableAddressInstruction)
209+
.getASTVariable() = global and
210+
fromCfg.hasFlow(load, sink) and
211+
tainted = adjustedSink(sink) and
212+
global = globalVarFromId(globalVar)
213+
)
140214
}
141215

142-
GlobalOrNamespaceVariable globalVarFromId(string id) {
143-
// TODO: Implement this when `taintedIncludingGlobalVars` has support for
144-
// global variables.
145-
none()
146-
}
216+
GlobalOrNamespaceVariable globalVarFromId(string id) { id = result.getQualifiedName() }
147217

148218
Function resolveCall(Call call) {
149219
exists(CallInstruction callInstruction |

0 commit comments

Comments
 (0)