Skip to content

Commit 9cb01d4

Browse files
authored
Merge branch 'main' into go/mad/convert-sinks
2 parents 1aa63c3 + c989e01 commit 9cb01d4

File tree

98 files changed

+66377
-485
lines changed

Some content is hidden

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

98 files changed

+66377
-485
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Improved performance of alias analysis of large function bodies. In rare cases, alerts that depend on alias analysis of large function bodies may be affected.

cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,19 +215,16 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
215215
predicate localMustFlowStep(Node node1, Node node2) { none() }
216216

217217
/** Gets the type of `n` used for type pruning. */
218-
Type getNodeType(Node n) {
218+
DataFlowType getNodeType(Node n) {
219219
exists(n) and
220220
result instanceof VoidType // stub implementation
221221
}
222222

223-
/** Gets a string representation of a type returned by `getNodeType`. */
224-
string ppReprType(Type t) { none() } // stub implementation
225-
226223
/**
227224
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
228225
* a node of type `t1` to a node of type `t2`.
229226
*/
230-
predicate compatibleTypes(Type t1, Type t2) {
227+
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
231228
t1 instanceof VoidType and t2 instanceof VoidType // stub implementation
232229
}
233230

@@ -243,7 +240,11 @@ class DataFlowCallable extends Function { }
243240

244241
class DataFlowExpr = Expr;
245242

246-
class DataFlowType = Type;
243+
final private class TypeFinal = Type;
244+
245+
class DataFlowType extends TypeFinal {
246+
string toString() { result = "" }
247+
}
247248

248249
/** A function call relevant for data flow. */
249250
class DataFlowCall extends Expr instanceof Call {

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -994,9 +994,6 @@ DataFlowType getNodeType(Node n) {
994994
result instanceof VoidType // stub implementation
995995
}
996996

997-
/** Gets a string representation of a type returned by `getNodeType`. */
998-
string ppReprType(DataFlowType t) { none() } // stub implementation
999-
1000997
/**
1001998
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
1002999
* a node of type `t1` to a node of type `t2`.
@@ -1097,7 +1094,11 @@ class SummarizedCallable extends DataFlowCallable, TSummarizedCallable {
10971094

10981095
class DataFlowExpr = Expr;
10991096

1100-
class DataFlowType = Type;
1097+
final private class TypeFinal = Type;
1098+
1099+
class DataFlowType extends TypeFinal {
1100+
string toString() { result = "" }
1101+
}
11011102

11021103
cached
11031104
private newtype TDataFlowCall =

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

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,15 @@ private newtype TMemoryLocation =
227227
TAllAliasedMemory(IRFunction irFunc, Boolean isMayAccess)
228228

229229
/**
230-
* Represents the memory location accessed by a memory operand or memory result. In this implementation, the location is
230+
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
231231
* one of the following:
232232
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
233233
* unknown.
234234
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
235+
*
236+
* Some of these memory locations will be filtered out for performance reasons before being passed to SSA construction.
235237
*/
236-
abstract class MemoryLocation extends TMemoryLocation {
238+
abstract private class MemoryLocation0 extends TMemoryLocation {
237239
final string toString() {
238240
if this.isMayAccess()
239241
then result = "?" + this.toStringInternal()
@@ -294,9 +296,9 @@ abstract class MemoryLocation extends TMemoryLocation {
294296
* represented by a `MemoryLocation` that totally overlaps all other
295297
* `MemoryLocations` in the set.
296298
*/
297-
abstract class VirtualVariable extends MemoryLocation { }
299+
abstract class VirtualVariable extends MemoryLocation0 { }
298300

299-
abstract class AllocationMemoryLocation extends MemoryLocation {
301+
abstract class AllocationMemoryLocation extends MemoryLocation0 {
300302
Allocation var;
301303
boolean isMayAccess;
302304

@@ -424,7 +426,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
424426
* `{a, b}` into a memory location that represents _all_ of the allocations
425427
* in the set.
426428
*/
427-
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation {
429+
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation0 {
428430
VariableGroup vg;
429431
boolean isMayAccess;
430432
boolean isAll;
@@ -528,7 +530,7 @@ class GroupedVirtualVariable extends GroupedMemoryLocation, VirtualVariable {
528530
/**
529531
* An access to memory that is not known to be confined to a specific `IRVariable`.
530532
*/
531-
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
533+
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation0 {
532534
IRFunction irFunc;
533535
boolean isMayAccess;
534536

@@ -555,7 +557,7 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
555557
* An access to memory that is not known to be confined to a specific `IRVariable`, but is known to
556558
* not access memory on the current function's stack frame.
557559
*/
558-
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
560+
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation0 {
559561
IRFunction irFunc;
560562
boolean isMayAccess;
561563

@@ -589,7 +591,7 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
589591
/**
590592
* An access to all aliased memory.
591593
*/
592-
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
594+
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation0 {
593595
IRFunction irFunc;
594596
boolean isMayAccess;
595597

@@ -620,7 +622,7 @@ class AliasedVirtualVariable extends AllAliasedMemory, VirtualVariable {
620622
/**
621623
* Gets the overlap relationship between the definition location `def` and the use location `use`.
622624
*/
623-
Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
625+
Overlap getOverlap(MemoryLocation0 def, MemoryLocation0 use) {
624626
exists(Overlap overlap |
625627
// Compute the overlap based only on the extent.
626628
overlap = getExtentOverlap(def, use) and
@@ -648,7 +650,7 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
648650
* based only on the set of memory locations accessed. Handling of "may" accesses and read-only
649651
* locations occurs in `getOverlap()`.
650652
*/
651-
private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
653+
private Overlap getExtentOverlap(MemoryLocation0 def, MemoryLocation0 use) {
652654
// The def and the use must have the same virtual variable, or no overlap is possible.
653655
(
654656
// AllAliasedMemory must totally overlap any location within the same virtual variable.
@@ -861,6 +863,40 @@ predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMem
861863
bindingset[result, b]
862864
private boolean unbindBool(boolean b) { result != b.booleanNot() }
863865

866+
/** Gets the number of overlapping uses of `def`. */
867+
private int numberOfOverlappingUses(MemoryLocation0 def) {
868+
result = strictcount(MemoryLocation0 use | exists(getOverlap(def, use)))
869+
}
870+
871+
/**
872+
* Holds if `def` is a busy definition. That is, it has a large number of
873+
* overlapping uses.
874+
*/
875+
private predicate isBusyDef(MemoryLocation0 def) { numberOfOverlappingUses(def) > 1024 }
876+
877+
/** Holds if `use` is a use that overlaps with a busy definition. */
878+
private predicate useOverlapWithBusyDef(MemoryLocation0 use) {
879+
exists(MemoryLocation0 def |
880+
exists(getOverlap(def, use)) and
881+
isBusyDef(def)
882+
)
883+
}
884+
885+
final private class FinalMemoryLocation = MemoryLocation0;
886+
887+
/**
888+
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
889+
* one of the following:
890+
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
891+
* unknown.
892+
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
893+
*
894+
* Compared to `MemoryLocation0`, this class does not contain memory locations that represent uses of busy definitions.
895+
*/
896+
class MemoryLocation extends FinalMemoryLocation {
897+
MemoryLocation() { not useOverlapWithBusyDef(this) }
898+
}
899+
864900
MemoryLocation getResultMemoryLocation(Instruction instr) {
865901
not canReuseSsaForOldResult(instr) and
866902
exists(MemoryAccessKind kind, boolean isMayAccess |
@@ -905,9 +941,9 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
905941
)
906942
}
907943

908-
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
944+
private MemoryLocation0 getOperandMemoryLocation0(MemoryOperand operand, boolean isMayAccess) {
909945
not canReuseSsaForOldResult(operand.getAnyDef()) and
910-
exists(MemoryAccessKind kind, boolean isMayAccess |
946+
exists(MemoryAccessKind kind |
911947
kind = operand.getMemoryAccess() and
912948
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
913949
(
@@ -948,6 +984,19 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
948984
)
949985
}
950986

987+
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
988+
exists(MemoryLocation0 use0, boolean isMayAccess |
989+
use0 = getOperandMemoryLocation0(operand, isMayAccess)
990+
|
991+
result = use0
992+
or
993+
// If `use0` overlaps with a busy definition we turn it into a use
994+
// of `UnknownMemoryLocation`.
995+
not use0 instanceof MemoryLocation and
996+
result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
997+
)
998+
}
999+
9511000
/** Gets the start bit offset of a `MemoryLocation`, if any. */
9521001
int getStartBitOffset(VariableMemoryLocation location) {
9531002
result = location.getStartBitOffset() and Ints::hasValue(result)

cpp/ql/lib/semmle/code/cpp/models/implementations/StdMath.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ private class Remquo extends Function, SideEffectFunction {
5151
override predicate hasOnlySpecificReadSideEffects() { any() }
5252

5353
override predicate hasOnlySpecificWriteSideEffects() { any() }
54+
55+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
56+
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
57+
buffer = false and
58+
mustWrite = true
59+
}
5460
}
5561

5662
private class Fma extends Function, SideEffectFunction {
@@ -95,4 +101,8 @@ private class Nan extends Function, SideEffectFunction, AliasFunction {
95101
override predicate parameterNeverEscapes(int index) { index = 0 }
96102

97103
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
104+
105+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
106+
i = 0 and buffer = true
107+
}
98108
}

cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ contains sensitive data that could somehow be retrieved by an attacker.</p>
1010
</overview>
1111
<recommendation>
1212

13-
<p>Use alternative platform-supplied functions that will not get optimized away. Examples of such
14-
functions include <code>memset_s</code>, <code>SecureZeroMemory</code>, and <code>bzero_explicit</code>.
15-
Alternatively, passing the <code>-fno-builtin-memset</code> option to the GCC/Clang compiler usually
16-
also prevents the optimization. Finally, you can use the public-domain <code>secure_memzero</code> function
17-
(see references below). This function, however, is not guaranteed to work on all platforms and compilers.</p>
13+
<p>Use <code>memset_s</code> (from C11) instead of <code>memset</code>, as <code>memset_s</code> will not
14+
get optimized away. Alternatively use platform-supplied functions such as <code>SecureZeroMemory</code> or
15+
<code>bzero_explicit</code> that make the same guarantee. Passing the <code>-fno-builtin-memset</code>
16+
option to the GCC/Clang compiler usually also prevents the optimization. Finally, you can use the
17+
public-domain <code>secure_memzero</code> function (see references below). This function, however, is not
18+
guaranteed to work on all platforms and compilers.</p>
1819

1920
</recommendation>
2021
<example>

cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* @id cpp/unsigned-difference-expression-compared-zero
66
* @problem.severity warning
77
* @security-severity 9.8
8-
* @precision medium
8+
* @precision high
99
* @tags security
1010
* correctness
1111
* external/cwe/cwe-191
Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
1-
void writeCredentials() {
2-
char *password = "cleartext password";
3-
FILE* file = fopen("credentials.txt", "w");
4-
1+
#include <sodium.h>
2+
#include <stdio.h>
3+
#include <string.h>
4+
5+
void writeCredentialsBad(FILE *file, const char *cleartextCredentials) {
56
// BAD: write password to disk in cleartext
6-
fputs(password, file);
7-
8-
// GOOD: encrypt password first
9-
char *encrypted = encrypt(password);
10-
fputs(encrypted, file);
7+
fputs(cleartextCredentials, file);
118
}
129

10+
int writeCredentialsGood(FILE *file, const char *cleartextCredentials, const unsigned char *key, const unsigned char *nonce) {
11+
size_t credentialsLen = strlen(cleartextCredentials);
12+
size_t ciphertext_len = crypto_secretbox_MACBYTES + credentialsLen;
13+
unsigned char *ciphertext = malloc(ciphertext_len);
14+
if (!ciphertext) {
15+
logError();
16+
return -1;
17+
}
18+
19+
// encrypt the password first
20+
if (crypto_secretbox_easy(ciphertext, (const unsigned char *)cleartextCredentials, credentialsLen, nonce, key) != 0) {
21+
free(ciphertext);
22+
logError();
23+
return -1;
24+
}
25+
26+
// GOOD: write encrypted password to disk
27+
fwrite(ciphertext, 1, ciphertext_len, file);
28+
29+
free(ciphertext);
30+
return 0;
31+
}

cpp/ql/src/Security/CWE/CWE-311/CleartextStorage.inc.qhelp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,20 @@ cleartext.</p>
1919
<example>
2020

2121
<p>The following example shows two ways of storing user credentials in a file. In the 'BAD' case,
22-
the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before
22+
the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before
2323
storing them.</p>
2424

2525
<sample src="CleartextStorage.c" />
2626

27+
<p>Note that for the 'GOOD' example to work we need to link against an encryption library (in this case libsodium),
28+
initialize it with a call to <code>sodium_init</code>, and create the key and nonce with
29+
<code>crypto_secretbox_keygen</code> and <code>randombytes_buf</code> respectively. We also need to store those
30+
details securely so they can be used for decryption.</p>
31+
2732
</example>
2833
<references>
2934

30-
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
35+
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
3136
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
3237

3338

cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
void bad(void) {
3-
char *password = "cleartext password";
3+
const char *password = "cleartext password";
44
sqlite3 *credentialsDB;
55
sqlite3_stmt *stmt;
66

@@ -16,14 +16,15 @@ void bad(void) {
1616
}
1717
}
1818

19-
void good(void) {
20-
char *password = "cleartext password";
19+
void good(const char *secretKey) {
20+
const char *password = "cleartext password";
2121
sqlite3 *credentialsDB;
2222
sqlite3_stmt *stmt;
2323

2424
if (sqlite3_open("credentials.db", &credentialsDB) == SQLITE_OK) {
2525
// GOOD: database encryption enabled:
26-
sqlite3_exec(credentialsDB, "PRAGMA key = 'secretKey!'", NULL, NULL, NULL);
26+
std::string setKeyString = std::string("PRAGMA key = '") + secretKey + "'";
27+
sqlite3_exec(credentialsDB, setKeyString.c_str(), NULL, NULL, NULL);
2728
sqlite3_exec(credentialsDB, "CREATE TABLE IF NOT EXISTS creds (password TEXT);", NULL, NULL, NULL);
2829
if (sqlite3_prepare_v2(credentialsDB, "INSERT INTO creds(password) VALUES(?)", -1, &stmt, NULL) == SQLITE_OK) {
2930
sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);
@@ -33,4 +34,3 @@ void good(void) {
3334
}
3435
}
3536
}
36-

0 commit comments

Comments
 (0)