Skip to content

Commit 9b384d8

Browse files
committed
Merge branch 'main' into atorralba/promote-ognl-injection
2 parents 351a245 + 3b676d4 commit 9b384d8

File tree

158 files changed

+4118
-1843
lines changed

Some content is hidden

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

158 files changed

+4118
-1843
lines changed

cpp/change-notes/2021-06-15-path-sensitive-stack-reachability.md

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
lgtm,codescanning
2+
* The "Cleartext storage of sensitive information in file" (cpp/cleartext-storage-file) query now uses dataflow to produce additional results.
3+
* Heuristics in the SensitiveExprs.qll library have been improved, making the "Cleartext storage of sensitive information in file" (cpp/cleartext-storage-file), "Cleartext storage of sensitive information in buffer" (cpp/cleartext-storage-buffer) and "Cleartext storage of sensitive information in an SQLite" (cpp/cleartext-storage-database) queries more accurate.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Improvements have been made to the `cpp/toctou-race-condition` query, both to find more correct results and fewer false positive results.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Virtual function specifiers are now accessible via the new predicates on `Function` (`.isDeclaredVirtual`, `.isOverride`, and `.isFinal`).

cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ DeclStmt declWithNoInit(LocalVariable v) {
4141
result.getADeclaration() = v and
4242
not exists(v.getInitializer()) and
4343
/* The type of the variable is not stack-allocated. */
44-
not allocatedType(v.getType())
44+
exists(Type t | t = v.getType() | not allocatedType(t))
4545
}
4646

4747
class UninitialisedLocalReachability extends StackVariableReachability {

cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* @kind problem
66
* @problem.severity warning
77
* @security-severity 7.5
8-
* @precision medium
8+
* @precision high
99
* @id cpp/cleartext-storage-file
1010
* @tags security
1111
* external/cwe/cwe-313
@@ -14,10 +14,40 @@
1414
import cpp
1515
import semmle.code.cpp.security.SensitiveExprs
1616
import semmle.code.cpp.security.FileWrite
17+
import semmle.code.cpp.dataflow.DataFlow
18+
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
1719

18-
from FileWrite w, SensitiveExpr source, Expr dest
20+
/**
21+
* An operation on a filename.
22+
*/
23+
predicate filenameOperation(FunctionCall op, Expr path) {
24+
exists(string name | name = op.getTarget().getName() |
25+
name =
26+
[
27+
"remove", "unlink", "rmdir", "rename", "fopen", "open", "freopen", "_open", "_wopen",
28+
"_wfopen", "_fsopen", "_wfsopen", "chmod", "chown", "stat", "lstat", "fstat", "access",
29+
"_access", "_waccess", "_access_s", "_waccess_s"
30+
] and
31+
path = op.getArgument(0)
32+
or
33+
name = ["fopen_s", "wfopen_s", "rename"] and
34+
path = op.getArgument(1)
35+
)
36+
}
37+
38+
predicate isFileName(GVN gvn) {
39+
exists(FunctionCall op, Expr path |
40+
filenameOperation(op, path) and
41+
gvn = globalValueNumber(path)
42+
)
43+
}
44+
45+
from FileWrite w, SensitiveExpr source, Expr mid, Expr dest
1946
where
20-
source = w.getASource() and
21-
dest = w.getDest()
47+
DataFlow::localFlow(DataFlow::exprNode(source), DataFlow::exprNode(mid)) and
48+
mid = w.getASource() and
49+
dest = w.getDest() and
50+
not isFileName(globalValueNumber(source)) and // file names are not passwords
51+
not exists(string convChar | convChar = w.getSourceConvChar(mid) | not convChar = ["s", "S"]) // ignore things written with other conversion characters
2252
select w, "This write into file '" + dest.toString() + "' may contain unencrypted data from $@",
2353
source, "this source."

cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* @kind problem
77
* @problem.severity warning
88
* @security-severity 7.7
9-
* @precision medium
9+
* @precision high
1010
* @id cpp/toctou-race-condition
1111
* @tags security
1212
* external/cwe/cwe-367
@@ -26,28 +26,29 @@ import semmle.code.cpp.controlflow.Guards
2626
*/
2727
FunctionCall filenameOperation(Expr path) {
2828
exists(string name | name = result.getTarget().getName() |
29-
(
30-
name = "remove" or
31-
name = "unlink" or
32-
name = "rmdir" or
33-
name = "rename" or
34-
name = "chmod" or
35-
name = "chown" or
36-
name = "fopen" or
37-
name = "open" or
38-
name = "freopen" or
39-
name = "_open" or
40-
name = "_wopen" or
41-
name = "_wfopen"
42-
) and
29+
name =
30+
[
31+
"remove", "unlink", "rmdir", "rename", "fopen", "open", "freopen", "_open", "_wopen",
32+
"_wfopen", "_fsopen", "_wfsopen"
33+
] and
4334
result.getArgument(0) = path
4435
or
45-
(
46-
name = "fopen_s" or
47-
name = "wfopen_s"
48-
) and
36+
name = ["fopen_s", "wfopen_s", "rename"] and
4937
result.getArgument(1) = path
5038
)
39+
or
40+
result = sensitiveFilenameOperation(path)
41+
}
42+
43+
/**
44+
* An operation on a filename that is likely to modify the security properties
45+
* of the corresponding file and may return an indication of success.
46+
*/
47+
FunctionCall sensitiveFilenameOperation(Expr path) {
48+
exists(string name | name = result.getTarget().getName() |
49+
name = ["chmod", "chown"] and
50+
result.getArgument(0) = path
51+
)
5152
}
5253

5354
/**
@@ -56,11 +57,7 @@ FunctionCall filenameOperation(Expr path) {
5657
*/
5758
FunctionCall accessCheck(Expr path) {
5859
exists(string name | name = result.getTarget().getName() |
59-
name = "access" or
60-
name = "_access" or
61-
name = "_waccess" or
62-
name = "_access_s" or
63-
name = "_waccess_s"
60+
name = ["access", "_access", "_waccess", "_access_s", "_waccess_s"]
6461
) and
6562
path = result.getArgument(0)
6663
}
@@ -72,9 +69,7 @@ FunctionCall accessCheck(Expr path) {
7269
*/
7370
FunctionCall stat(Expr path, Expr buf) {
7471
exists(string name | name = result.getTarget().getName() |
75-
name = "stat" or
76-
name = "lstat" or
77-
name = "fstat" or
72+
name = ["stat", "lstat", "fstat"] or
7873
name.matches("\\_stat%") or
7974
name.matches("\\_wstat%")
8075
) and
@@ -98,29 +93,36 @@ from Expr check, Expr checkPath, FunctionCall use, Expr usePath
9893
where
9994
// `check` looks like a check on a filename
10095
(
101-
// either:
102-
// an access check
103-
check = accessCheck(checkPath)
104-
or
105-
// a stat
106-
check = stat(checkPath, _)
96+
(
97+
// either:
98+
// an access check
99+
check = accessCheck(checkPath)
100+
or
101+
// a stat
102+
check = stat(checkPath, _)
103+
or
104+
// access to a member variable on the stat buf
105+
// (morally, this should be a use-use pair, but it seems unlikely
106+
// that this variable will get reused in practice)
107+
exists(Expr call, Expr e, Variable v |
108+
call = stat(checkPath, e) and
109+
e.getAChild*().(VariableAccess).getTarget() = v and
110+
check.(VariableAccess).getTarget() = v and
111+
not e.getAChild*() = check // the call that writes to the pointer is not where the pointer is checked.
112+
)
113+
) and
114+
// `op` looks like an operation on a filename
115+
use = filenameOperation(usePath)
107116
or
108117
// another filename operation (null pointers can indicate errors)
109-
check = filenameOperation(checkPath)
110-
or
111-
// access to a member variable on the stat buf
112-
// (morally, this should be a use-use pair, but it seems unlikely
113-
// that this variable will get reused in practice)
114-
exists(Variable buf | exists(stat(checkPath, buf.getAnAccess())) |
115-
check.(VariableAccess).getQualifier() = buf.getAnAccess()
116-
)
118+
check = filenameOperation(checkPath) and
119+
// `op` looks like a sensitive operation on a filename
120+
use = sensitiveFilenameOperation(usePath)
117121
) and
118122
// `checkPath` and `usePath` refer to the same SSA variable
119123
exists(SsaDefinition def, StackVariable v |
120124
def.getAUse(v) = checkPath and def.getAUse(v) = usePath
121125
) and
122-
// `op` looks like an operation on a filename
123-
use = filenameOperation(usePath) and
124126
// the return value of `check` is used (possibly with one step of
125127
// variable indirection) in a guard which controls `use`
126128
exists(GuardCondition guard | referenceTo(check, guard.getAChild*()) |

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,23 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
8282
/** Holds if this function is inline. */
8383
predicate isInline() { this.hasSpecifier("inline") }
8484

85-
/** Holds if this function is virtual. */
85+
/**
86+
* Holds if this function is virtual.
87+
*
88+
* Unlike `isDeclaredVirtual()`, `isVirtual()` holds even if the function
89+
* is not explicitly declared with the `virtual` specifier.
90+
*/
8691
predicate isVirtual() { this.hasSpecifier("virtual") }
8792

93+
/** Holds if this function is declared with the `virtual` specifier. */
94+
predicate isDeclaredVirtual() { this.hasSpecifier("declared_virtual") }
95+
96+
/** Holds if this function is declared with the `override` specifier. */
97+
predicate isOverride() { this.hasSpecifier("override") }
98+
99+
/** Holds if this function is declared with the `final` specifier. */
100+
predicate isFinal() { this.hasSpecifier("final") }
101+
88102
/**
89103
* Holds if this function is deleted.
90104
* This may be because it was explicitly deleted with an `= delete`

cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ private predicate bbSuccessorEntryReachesDefOrUse(
208208
boolean skipsFirstLoopAlwaysTrueUponEntry
209209
) {
210210
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
211-
bbSuccessorEntryReachesLoopInvariant0(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
211+
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
212212
succSkipsFirstLoopAlwaysTrueUponEntry)
213213
|
214214
bbEntryReachesDefOrUseLocally(succ, v, defOrUse) and

0 commit comments

Comments
 (0)