Skip to content

Commit 25f3f67

Browse files
committed
Merge branch 'master' into rdmarsh/cpp/ir-flow-through-outparams
Fixes test conflicts and reveals a bug in parameter handling
2 parents d529fed + ca9b892 commit 25f3f67

File tree

996 files changed

+31473
-29650
lines changed

Some content is hidden

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

996 files changed

+31473
-29650
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
.vs/*
1515
!.vs/VSWorkspaceSettings.json
1616

17+
# Byte-compiled python files
18+
*.pyc
19+
1720
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
1821
/codeql/
1922
.vscode/settings.json

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
| Potentially dangerous use of non-short-circuit logic (`cs/non-short-circuit`) | Fewer false positive results | Results have been removed when the expression contains an `out` parameter. |
2222
| Dereferenced variable may be null (`cs/dereferenced-value-may-be-null`) | More results | Results are reported from parameters with a default value of `null`. |
2323
| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the value assigned is an (implicitly or explicitly) cast default-like value. For example, `var s = (string)null` and `string s = default`. |
24+
| XPath injection (`cs/xml/xpath-injection`) | More results | The query now recognizes calls to methods on `System.Xml.XPath.XPathNavigator` objects. |
2425

2526
## Removal of old queries
2627

change-notes/1.24/analysis-javascript.md

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@
66

77
* Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`).
88

9-
* Imports with the `.js` extension can now be resolved to a TypeScript file,
9+
* Resolution of imports has improved, leading to more results from the security queries:
10+
- Imports with the `.js` extension can now be resolved to a TypeScript file,
1011
when the import refers to a file generated by TypeScript.
12+
- Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved.
13+
- Export declarations of the form `export * as ns from "x"` are now analyzed more precisely.
1114

12-
* Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved.
15+
* The analysis of sanitizers has improved, leading to more accurate results from the security queries.
16+
In particular:
17+
- Sanitizer guards now act across function boundaries in more cases.
18+
- Sanitizers can now better distinguish between a tainted value and an object _containing_ a tainted value.
1319

14-
* Export declarations of the form `export * as ns from "x"` are now analyzed more precisely.
15-
16-
* The analysis of sanitizer guards has improved, leading to fewer false-positive results from the security queries.
17-
18-
* The call graph construction has been improved, leading to more results from the security queries:
20+
* Call graph construction has been improved, leading to more results from the security queries:
1921
- Calls can now be resolved to indirectly-defined class members in more cases.
2022
- Calls through partial invocations such as `.bind` can now be resolved in more cases.
2123

@@ -40,11 +42,14 @@
4042
- [ncp](https://www.npmjs.com/package/ncp)
4143
- [node-dir](https://www.npmjs.com/package/node-dir)
4244
- [path-exists](https://www.npmjs.com/package/path-exists)
45+
- [pg](https://www.npmjs.com/package/pg)
4346
- [react](https://www.npmjs.com/package/react)
4447
- [recursive-readdir](https://www.npmjs.com/package/recursive-readdir)
4548
- [request](https://www.npmjs.com/package/request)
4649
- [rimraf](https://www.npmjs.com/package/rimraf)
4750
- [send](https://www.npmjs.com/package/send)
51+
- [SockJS](https://www.npmjs.com/package/sockjs)
52+
- [SockJS-client](https://www.npmjs.com/package/sockjs-client)
4853
- [typeahead.js](https://www.npmjs.com/package/typeahead.js)
4954
- [vinyl-fs](https://www.npmjs.com/package/vinyl-fs)
5055
- [write-file-atomic](https://www.npmjs.com/package/write-file-atomic)
@@ -80,8 +85,14 @@
8085
| Use of password hash with insufficient computational effort (`js/insufficient-password-hash`) | Fewer false positive results | This query now recognizes additional cases that do not require secure hashing. |
8186
| Useless regular-expression character escape (`js/useless-regexp-character-escape`) | Fewer false positive results | This query now distinguishes escapes in strings and regular expression literals. |
8287
| Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. |
88+
| Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. |
8389

8490
## Changes to libraries
8591

8692
* 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.
8793
* An extensible model of the `EventEmitter` pattern has been implemented.
94+
* Taint-tracking configurations now interact differently with the `data` flow label, which may affect queries
95+
that combine taint-tracking and flow labels.
96+
- Sources added by the 1-argument `isSource` predicate are associated with the `taint` label now, instead of the `data` label.
97+
- Sanitizers now only block the `taint` label. As a result, sanitizers no longer block the flow of tainted values wrapped inside a property of an object.
98+
To retain the old behavior, instead use a barrier, or block the `data` flow label using a labeled sanitizer.

change-notes/1.24/analysis-python.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ The following changes in version 1.24 affect Python analysis in all applications
44

55
## General improvements
66

7+
Support for Django version 2.x and 3.x
8+
79
## New queries
810

911
| **Query** | **Tags** | **Purpose** |
@@ -13,6 +15,7 @@ The following changes in version 1.24 affect Python analysis in all applications
1315

1416
| **Query** | **Expected impact** | **Change** |
1517
|----------------------------|------------------------|------------------------------------------------------------------|
18+
| Uncontrolled command line (`py/command-line-injection`) | More results | We now model the `fabric` and `invoke` pacakges for command execution. |
1619

1720
### Web framework support
1821

config/identical-files.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@
3939
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
4040
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll"
4141
],
42+
"DataFlow Java/C++/C# Consistency checks": [
43+
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
44+
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll",
45+
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
46+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll"
47+
],
4248
"C++ SubBasicBlocks": [
4349
"cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll",
4450
"cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll"

config/sync-files.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#!/usr/bin/env python3
2+
3+
# Due to various technical limitations, we sometimes have files that need to be
4+
# kept identical in the repository. This script loads a database of such
5+
# files and can perform two functions: check whether they are still identical,
6+
# and overwrite the others with a master copy if needed.
7+
8+
import hashlib
9+
import shutil
10+
import os
11+
import sys
12+
import json
13+
import re
14+
path = os.path
15+
16+
file_groups = {}
17+
18+
def add_prefix(prefix, relative):
19+
result = path.join(prefix, relative)
20+
if path.commonprefix((path.realpath(result), path.realpath(prefix))) != \
21+
path.realpath(prefix):
22+
raise Exception("Path {} is not below {}".format(
23+
result, prefix))
24+
return result
25+
26+
def load_if_exists(prefix, json_file_relative):
27+
json_file_name = path.join(prefix, json_file_relative)
28+
if path.isfile(json_file_name):
29+
print("Loading file groups from", json_file_name)
30+
with open(json_file_name, 'r', encoding='utf-8') as fp:
31+
raw_groups = json.load(fp)
32+
prefixed_groups = {
33+
name: [
34+
add_prefix(prefix, relative)
35+
for relative in relatives
36+
]
37+
for name, relatives in raw_groups.items()
38+
}
39+
file_groups.update(prefixed_groups)
40+
41+
# Generates a list of C# test files that should be in sync
42+
def csharp_test_files():
43+
test_file_re = re.compile('.*(Bad|Good)[0-9]*\\.cs$')
44+
csharp_doc_files = {
45+
file:os.path.join(root, file)
46+
for root, dirs, files in os.walk("csharp/ql/src")
47+
for file in files
48+
if test_file_re.match(file)
49+
}
50+
return {
51+
"C# test '" + file + "'" : [os.path.join(root, file), csharp_doc_files[file]]
52+
for root, dirs, files in os.walk("csharp/ql/test")
53+
for file in files
54+
if file in csharp_doc_files
55+
}
56+
57+
def file_checksum(filename):
58+
with open(filename, 'rb') as file_handle:
59+
return hashlib.sha1(file_handle.read()).hexdigest()
60+
61+
def check_group(group_name, files, master_file_picker, emit_error):
62+
checksums = {file_checksum(f) for f in files}
63+
64+
if len(checksums) == 1:
65+
return
66+
67+
master_file = master_file_picker(files)
68+
if master_file is None:
69+
emit_error(__file__, 0,
70+
"Files from group '"+ group_name +"' not in sync.")
71+
emit_error(__file__, 0,
72+
"Run this script with a file-name argument among the "
73+
"following to overwrite the remaining files with the contents "
74+
"of that file or run with the --latest switch to update each "
75+
"group of files from the most recently modified file in the group.")
76+
for filename in files:
77+
emit_error(__file__, 0, " " + filename)
78+
else:
79+
print(" Syncing others from", master_file)
80+
for filename in files:
81+
if filename == master_file:
82+
continue
83+
print(" " + filename)
84+
os.replace(filename, filename + '~')
85+
shutil.copy(master_file, filename)
86+
print(" Backups written with '~' appended to file names")
87+
88+
def chdir_repo_root():
89+
root_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
90+
os.chdir(root_path)
91+
92+
def choose_master_file(master_file, files):
93+
if master_file in files:
94+
return master_file
95+
else:
96+
return None
97+
98+
def choose_latest_file(files):
99+
latest_time = None
100+
latest_file = None
101+
for filename in files:
102+
file_time = os.path.getmtime(filename)
103+
if (latest_time is None) or (latest_time < file_time):
104+
latest_time = file_time
105+
latest_file = filename
106+
return latest_file
107+
108+
local_error_count = 0
109+
def emit_local_error(path, line, error):
110+
print('ERROR: ' + path + ':' + line + " - " + error)
111+
global local_error_count
112+
local_error_count += 1
113+
114+
# This function is invoked directly by a CI script, which passes a different error-handling
115+
# callback.
116+
def sync_identical_files(emit_error):
117+
if len(sys.argv) == 1:
118+
master_file_picker = lambda files: None
119+
elif len(sys.argv) == 2:
120+
if sys.argv[1] == "--latest":
121+
master_file_picker = choose_latest_file
122+
elif os.path.isfile(sys.argv[1]):
123+
master_file_picker = lambda files: choose_master_file(sys.argv[1], files)
124+
else:
125+
raise Exception("File not found")
126+
else:
127+
raise Exception("Bad command line or file not found")
128+
chdir_repo_root()
129+
load_if_exists('.', 'config/identical-files.json')
130+
file_groups.update(csharp_test_files())
131+
for group_name, files in file_groups.items():
132+
check_group(group_name, files, master_file_picker, emit_error)
133+
134+
def main():
135+
sync_identical_files(emit_local_error)
136+
if local_error_count > 0:
137+
exit(1)
138+
139+
if __name__ == "__main__":
140+
main()

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,16 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
133133
*/
134134
Type getUnspecifiedType() { result = getType().getUnspecifiedType() }
135135

136-
/** Gets the nth parameter of this function. */
136+
/**
137+
* Gets the nth parameter of this function. There is no result for the
138+
* implicit `this` parameter, and there is no `...` varargs pseudo-parameter.
139+
*/
137140
Parameter getParameter(int n) { params(unresolveElement(result), underlyingElement(this), n, _) }
138141

139-
/** Gets a parameter of this function. */
142+
/**
143+
* Gets a parameter of this function. There is no result for the implicit
144+
* `this` parameter, and there is no `...` varargs pseudo-parameter.
145+
*/
140146
Parameter getAParameter() { params(unresolveElement(result), underlyingElement(this), _, _) }
141147

142148
/**

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,16 +397,21 @@ class StaticStorageDurationVariable extends Variable {
397397
*/
398398
private predicate runtimeExprInStaticInitializer(Expr e) {
399399
inStaticInitializer(e) and
400-
if e instanceof AggregateLiteral
400+
if e instanceof AggregateLiteral // in sync with the cast in `inStaticInitializer`
401401
then runtimeExprInStaticInitializer(e.getAChild())
402402
else not e.getFullyConverted().isConstant()
403403
}
404404

405-
/** Holds if `e` is part of the initializer of a `StaticStorageDurationVariable`. */
405+
/**
406+
* Holds if `e` is the initializer of a `StaticStorageDurationVariable`, either
407+
* directly or below some top-level `AggregateLiteral`s.
408+
*/
406409
private predicate inStaticInitializer(Expr e) {
407410
exists(StaticStorageDurationVariable var | e = var.getInitializer().getExpr())
408411
or
409-
inStaticInitializer(e.getParent())
412+
// The cast to `AggregateLiteral` ensures we only compute what'll later be
413+
// needed by `runtimeExprInStaticInitializer`.
414+
inStaticInitializer(e.getParent().(AggregateLiteral))
410415
}
411416

412417
/**

0 commit comments

Comments
 (0)