Skip to content

Commit 939979d

Browse files
authored
Merge branch 'master' into overflowcalc
2 parents ab0be19 + a13748f commit 939979d

104 files changed

Lines changed: 1133 additions & 456 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.

.github/workflows/labeler.yml

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

change-notes/1.24/analysis-javascript.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,3 @@
2727
## Changes to libraries
2828

2929
* The predicates `RegExpTerm.getSuccessor` and `RegExpTerm.getPredecessor` have been changed to reflect textual, not operational, matching order. This only makes a difference in lookbehind assertions, which are operationally matched backwards. Previously, `getSuccessor` would mimick this, so in an assertion `(?<=ab)` the term `b` would be considered the predecessor, not the successor, of `a`. Textually, however, `a` is still matched before `b`, and this is the order we now follow.
30-
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[[ condition: enterprise-only ]]
2+
3+
# Improvements to JavaScript analysis
4+
5+
## Changes to code extraction
6+
7+
* `import.meta` expressions no longer result in a syntax error in JavaScript files.

config/identical-files.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,5 +265,11 @@
265265
"C# IR ValueNumberingImports": [
266266
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
267267
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll"
268+
],
269+
"XML": [
270+
"cpp/ql/src/semmle/code/cpp/XML.qll",
271+
"java/ql/src/semmle/code/xml/XML.qll",
272+
"javascript/ql/src/semmle/javascript/XML.qll",
273+
"python/ql/src/semmle/python/xml/XML.qll"
268274
]
269275
}

cpp/ql/src/AlertSuppression.ql

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,25 @@ import cpp
1010
/**
1111
* An alert suppression comment.
1212
*/
13-
class SuppressionComment extends CppStyleComment {
13+
class SuppressionComment extends Comment {
1414
string annotation;
1515
string text;
1616

1717
SuppressionComment() {
18-
text = getContents().suffix(2) and
18+
(
19+
this instanceof CppStyleComment and
20+
// strip the beginning slashes
21+
text = getContents().suffix(2)
22+
or
23+
this instanceof CStyleComment and
24+
// strip both the beginning /* and the end */ the comment
25+
exists(string text0 |
26+
text0 = getContents().suffix(2) and
27+
text = text0.prefix(text0.length() - 2)
28+
) and
29+
// The /* */ comment must be a single-line comment
30+
not text.matches("%\n%")
31+
) and
1932
(
2033
// match `lgtm[...]` anywhere in the comment
2134
annotation = text.regexpFind("(?i)\\blgtm\\s*\\[[^\\]]*\\]", _, _)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,6 @@ library class SpecialNameQualifyingElement extends NameQualifyingElement,
157157
@specialnamequalifyingelement {
158158
/** Gets the name of this special qualifying element. */
159159
override string getName() { specialnamequalifyingelements(underlyingElement(this), result) }
160+
161+
override string toString() { result = getName() }
160162
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,9 @@ class PreprocessorUndef extends PreprocessorDirective, @ppd_undef {
214214
* A C/C++ preprocessor `#pragma` directive.
215215
*/
216216
class PreprocessorPragma extends PreprocessorDirective, @ppd_pragma {
217-
override string toString() { result = "#pragma " + this.getHead() }
217+
override string toString() {
218+
if exists(this.getHead()) then result = "#pragma " + this.getHead() else result = "#pragma"
219+
}
218220
}
219221

220222
/**

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

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,30 @@
22
* Provides classes and predicates for working with XML files and their content.
33
*/
44

5-
import semmle.code.cpp.Location
5+
import semmle.files.FileSystem
66

77
/** An XML element that has a location. */
88
abstract class XMLLocatable extends @xmllocatable {
99
/** Gets the source location for this element. */
1010
Location getLocation() { xmllocations(this, result) }
1111

1212
/**
13-
* Holds if this element has the specified location information,
14-
* including file path, start line, start column, end line and end column.
13+
* Holds if this element is at the specified location.
14+
* The location spans column `startcolumn` of line `startline` to
15+
* column `endcolumn` of line `endline` in file `filepath`.
16+
* For more information, see
17+
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
1518
*/
1619
predicate hasLocationInfo(
1720
string filepath, int startline, int startcolumn, int endline, int endcolumn
1821
) {
1922
exists(File f, Location l | l = this.getLocation() |
20-
locations_default(l, unresolveElement(f), startline, startcolumn, endline, endcolumn) and
23+
locations_default(l, f, startline, startcolumn, endline, endcolumn) and
2124
filepath = f.getAbsolutePath()
2225
)
2326
}
2427

25-
/** Gets a printable representation of this element. */
28+
/** Gets a textual representation of this element. */
2629
abstract string toString();
2730
}
2831

@@ -31,6 +34,12 @@ abstract class XMLLocatable extends @xmllocatable {
3134
* both of which can contain other elements.
3235
*/
3336
class XMLParent extends @xmlparent {
37+
XMLParent() {
38+
// explicitly restrict `this` to be either an `XMLElement` or an `XMLFile`;
39+
// the type `@xmlparent` currently also includes non-XML files
40+
this instanceof @xmlelement or xmlEncoding(this, _)
41+
}
42+
3443
/**
3544
* Gets a printable representation of this XML parent.
3645
* (Intended to be overridden in subclasses.)
@@ -106,15 +115,21 @@ class XMLFile extends XMLParent, File {
106115
override string toString() { result = XMLParent.super.toString() }
107116

108117
/** Gets the name of this XML file. */
109-
override string getName() { files(this, result, _, _, _) }
118+
override string getName() { result = File.super.getAbsolutePath() }
110119

111-
/** Gets the path of this XML file. */
112-
string getPath() { files(this, _, result, _, _) }
120+
/**
121+
* DEPRECATED: Use `getAbsolutePath()` instead.
122+
*
123+
* Gets the path of this XML file.
124+
*/
125+
deprecated string getPath() { result = getAbsolutePath() }
113126

114-
/** Gets the path of the folder that contains this XML file. */
115-
string getFolder() {
116-
result = this.getPath().substring(0, this.getPath().length() - this.getName().length())
117-
}
127+
/**
128+
* DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead.
129+
*
130+
* Gets the path of the folder that contains this XML file.
131+
*/
132+
deprecated string getFolder() { result = getParentContainer().getAbsolutePath() }
118133

119134
/** Gets the encoding of this XML file. */
120135
string getEncoding() { xmlEncoding(this, result) }
@@ -129,7 +144,17 @@ class XMLFile extends XMLParent, File {
129144
XMLDTD getADTD() { xmlDTDs(result, _, _, _, this) }
130145
}
131146

132-
/** A "Document Type Definition" of an XML file. */
147+
/**
148+
* An XML document type definition (DTD).
149+
*
150+
* Example:
151+
*
152+
* ```
153+
* <!ELEMENT person (firstName, lastName?)>
154+
* <!ELEMENT firstName (#PCDATA)>
155+
* <!ELEMENT lastName (#PCDATA)>
156+
* ```
157+
*/
133158
class XMLDTD extends @xmldtd {
134159
/** Gets the name of the root element of this DTD. */
135160
string getRoot() { xmlDTDs(this, result, _, _, _) }
@@ -156,7 +181,17 @@ class XMLDTD extends @xmldtd {
156181
}
157182
}
158183

159-
/** An XML tag in an XML file. */
184+
/**
185+
* An XML element in an XML file.
186+
*
187+
* Example:
188+
*
189+
* ```
190+
* <manifest xmlns:android="http://schemas.android.com/apk/res/android"
191+
* package="com.example.exampleapp" android:versionCode="1">
192+
* </manifest>
193+
* ```
194+
*/
160195
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
161196
/** Holds if this XML element has the given `name`. */
162197
predicate hasName(string name) { name = getName() }
@@ -201,7 +236,16 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
201236
override string toString() { result = XMLParent.super.toString() }
202237
}
203238

204-
/** An attribute that occurs inside an XML element. */
239+
/**
240+
* An attribute that occurs inside an XML element.
241+
*
242+
* Examples:
243+
*
244+
* ```
245+
* package="com.example.exampleapp"
246+
* android:versionCode="1"
247+
* ```
248+
*/
205249
class XMLAttribute extends @xmlattribute, XMLLocatable {
206250
/** Gets the name of this attribute. */
207251
string getName() { xmlAttrs(this, _, result, _, _, _) }
@@ -222,7 +266,15 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
222266
override string toString() { result = this.getName() + "=" + this.getValue() }
223267
}
224268

225-
/** A namespace used in an XML file */
269+
/**
270+
* A namespace used in an XML file.
271+
*
272+
* Example:
273+
*
274+
* ```
275+
* xmlns:android="http://schemas.android.com/apk/res/android"
276+
* ```
277+
*/
226278
class XMLNamespace extends @xmlnamespace {
227279
/** Gets the prefix of this namespace. */
228280
string getPrefix() { xmlNs(this, result, _, _) }
@@ -241,7 +293,15 @@ class XMLNamespace extends @xmlnamespace {
241293
}
242294
}
243295

244-
/** A comment of the form `<!-- ... -->` is an XML comment. */
296+
/**
297+
* A comment in an XML file.
298+
*
299+
* Example:
300+
*
301+
* ```
302+
* <!-- This is a comment. -->
303+
* ```
304+
*/
245305
class XMLComment extends @xmlcomment, XMLLocatable {
246306
/** Gets the text content of this XML comment. */
247307
string getText() { xmlComments(this, result, _, _) }
@@ -256,6 +316,12 @@ class XMLComment extends @xmlcomment, XMLLocatable {
256316
/**
257317
* A sequence of characters that occurs between opening and
258318
* closing tags of an XML element, excluding other elements.
319+
*
320+
* Example:
321+
*
322+
* ```
323+
* <content>This is a sequence of characters.</content>
324+
* ```
259325
*/
260326
class XMLCharacters extends @xmlcharacters, XMLLocatable {
261327
/** Gets the content of this character sequence. */

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

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,32 @@ private predicate predictableInstruction(Instruction instr) {
1919
predictableInstruction(instr.(UnaryInstruction).getUnary())
2020
}
2121

22+
private predicate userInputInstruction(Instruction instr) {
23+
exists(CallInstruction ci, WriteSideEffectInstruction wsei |
24+
userInputArgument(ci.getConvertedResultExpression(), wsei.getIndex()) and
25+
instr = wsei and
26+
wsei.getPrimaryInstruction() = ci
27+
)
28+
or
29+
userInputReturned(instr.getConvertedResultExpression())
30+
or
31+
instr.getConvertedResultExpression() instanceof EnvironmentRead
32+
or
33+
instr
34+
.(LoadInstruction)
35+
.getSourceAddress()
36+
.(VariableAddressInstruction)
37+
.getASTVariable()
38+
.hasName("argv") and
39+
instr.getEnclosingFunction().hasGlobalName("main")
40+
}
41+
2242
private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
2343
DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" }
2444

25-
override predicate isSource(DataFlow::Node source) { isUserInput(source.asExpr(), _) }
45+
override predicate isSource(DataFlow::Node source) {
46+
userInputInstruction(source.asInstruction())
47+
}
2648

2749
override predicate isSink(DataFlow::Node sink) { any() }
2850

@@ -135,6 +157,8 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
135157
// This is part of the translation of `a[i]`, where we want taint to flow
136158
// from `a`.
137159
i2.(PointerAddInstruction).getLeft() = i1
160+
// TODO: robust Chi handling
161+
//
138162
// TODO: Flow from argument to return of known functions: Port missing parts
139163
// of `returnArgument` to the `interfaces.Taint` and `interfaces.DataFlow`
140164
// libraries.
@@ -176,11 +200,30 @@ private Element adjustedSink(DataFlow::Node sink) {
176200
// For compatibility, send flow into a `NotExpr` even if it's part of a
177201
// short-circuiting condition and thus might get skipped.
178202
result.(NotExpr).getOperand() = sink.asExpr()
203+
or
204+
// For compatibility, send flow from argument read side effects to their
205+
// corresponding argument expression
206+
exists(IndirectReadSideEffectInstruction read |
207+
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
208+
read.getArgumentDef().getUnconvertedResultExpression() = result
209+
)
210+
or
211+
exists(BufferReadSideEffectInstruction read |
212+
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
213+
read.getArgumentDef().getUnconvertedResultExpression() = result
214+
)
215+
or
216+
exists(SizedBufferReadSideEffectInstruction read |
217+
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
218+
read.getArgumentDef().getUnconvertedResultExpression() = result
219+
)
179220
}
180221

181222
predicate tainted(Expr source, Element tainted) {
182223
exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink |
183224
cfg.hasFlow(DataFlow::exprNode(source), sink)
225+
or
226+
cfg.hasFlow(DataFlow::definitionByReferenceNode(source), sink)
184227
|
185228
tainted = adjustedSink(sink)
186229
)

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,48 @@ abstract class PostUpdateNode extends Node {
173173
abstract Node getPreUpdateNode();
174174
}
175175

176+
/**
177+
* A node that represents the value of a variable after a function call that
178+
* may have changed the variable because it's passed by reference.
179+
*
180+
* A typical example would be a call `f(&x)`. Firstly, there will be flow into
181+
* `x` from previous definitions of `x`. Secondly, there will be a
182+
* `DefinitionByReferenceNode` to represent the value of `x` after the call has
183+
* returned. This node will have its `getArgument()` equal to `&x` and its
184+
* `getVariableAccess()` equal to `x`.
185+
*/
186+
class DefinitionByReferenceNode extends Node {
187+
override WriteSideEffectInstruction instr;
188+
189+
/** Gets the argument corresponding to this node. */
190+
Expr getArgument() {
191+
result = instr
192+
.getPrimaryInstruction()
193+
.(CallInstruction)
194+
.getPositionalArgument(instr.getIndex())
195+
.getUnconvertedResultExpression()
196+
or
197+
result = instr
198+
.getPrimaryInstruction()
199+
.(CallInstruction)
200+
.getThisArgument()
201+
.getUnconvertedResultExpression() and
202+
instr.getIndex() = -1
203+
}
204+
205+
/** Gets the parameter through which this value is assigned. */
206+
Parameter getParameter() {
207+
exists(CallInstruction ci | result = ci.getStaticCallTarget().getParameter(instr.getIndex()))
208+
}
209+
}
210+
176211
/**
177212
* Gets the node corresponding to `instr`.
178213
*/
179214
Node instructionNode(Instruction instr) { result.asInstruction() = instr }
180215

216+
DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e }
217+
181218
/**
182219
* Gets a `Node` corresponding to `e` or any of its conversions. There is no
183220
* result if `e` is a `Conversion`.

0 commit comments

Comments
 (0)