Skip to content

Commit 73f279d

Browse files
authored
Merge pull request #10555 from MathiasVP/testcase-for-php-cve
C++: Fix missing bounds in range analysis
2 parents c2dfbd4 + f3212fe commit 73f279d

File tree

4 files changed

+130
-6
lines changed

4 files changed

+130
-6
lines changed

cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExprSpecific.qll

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ private import semmle.code.cpp.ir.IR as IR
77
private import Semantic
88
private import experimental.semmle.code.cpp.rangeanalysis.Bound as IRBound
99
private import semmle.code.cpp.controlflow.IRGuards as IRGuards
10+
private import semmle.code.cpp.ir.ValueNumbering
1011

1112
module SemanticExprConfig {
1213
class Location = Cpp::Location;
@@ -120,7 +121,15 @@ module SemanticExprConfig {
120121

121122
newtype TSsaVariable =
122123
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
123-
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
124+
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
125+
TSsaPointerArithmeticGuard(IR::PointerArithmeticInstruction instr) {
126+
exists(Guard g, IR::Operand use | use = instr.getAUse() |
127+
g.comparesLt(use, _, _, _, _) or
128+
g.comparesLt(_, use, _, _, _) or
129+
g.comparesEq(use, _, _, _, _) or
130+
g.comparesEq(_, use, _, _, _)
131+
)
132+
}
124133

125134
class SsaVariable extends TSsaVariable {
126135
string toString() { none() }
@@ -129,6 +138,8 @@ module SemanticExprConfig {
129138

130139
IR::Instruction asInstruction() { none() }
131140

141+
IR::PointerArithmeticInstruction asPointerArithGuard() { none() }
142+
132143
IR::Operand asOperand() { none() }
133144
}
134145

@@ -144,6 +155,18 @@ module SemanticExprConfig {
144155
final override IR::Instruction asInstruction() { result = instr }
145156
}
146157

158+
class SsaPointerArithmeticGuard extends SsaVariable, TSsaPointerArithmeticGuard {
159+
IR::PointerArithmeticInstruction instr;
160+
161+
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(instr) }
162+
163+
final override string toString() { result = instr.toString() }
164+
165+
final override Location getLocation() { result = instr.getLocation() }
166+
167+
final override IR::PointerArithmeticInstruction asPointerArithGuard() { result = instr }
168+
}
169+
147170
class SsaOperand extends SsaVariable, TSsaOperand {
148171
IR::Operand op;
149172

@@ -168,7 +191,11 @@ module SemanticExprConfig {
168191
)
169192
}
170193

171-
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
194+
Expr getAUse(SsaVariable v) {
195+
result.(IR::LoadInstruction).getSourceValue() = v.asInstruction()
196+
or
197+
result = valueNumber(v.asPointerArithGuard()).getAnInstruction()
198+
}
172199

173200
SemType getSsaVariableType(SsaVariable v) {
174201
result = getSemanticType(v.asInstruction().getResultIRType())
@@ -208,7 +235,9 @@ module SemanticExprConfig {
208235

209236
final override predicate hasRead(SsaVariable v) {
210237
exists(IR::Operand operand |
211-
operand.getDef() = v.asInstruction() and
238+
operand.getDef() = v.asInstruction() or
239+
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
240+
|
212241
not operand instanceof IR::PhiInputOperand and
213242
operand.getUse().getBlock() = block
214243
)
@@ -227,7 +256,9 @@ module SemanticExprConfig {
227256

228257
final override predicate hasRead(SsaVariable v) {
229258
exists(IR::PhiInputOperand operand |
230-
operand.getDef() = v.asInstruction() and
259+
operand.getDef() = v.asInstruction() or
260+
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
261+
|
231262
operand.getPredecessorBlock() = pred and
232263
operand.getUse().getBlock() = succ
233264
)

cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticSSA.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class SemSsaVariable instanceof Specific::SsaVariable {
1010

1111
final Specific::Location getLocation() { result = super.getLocation() }
1212

13-
final SemLoadExpr getAUse() { result = Specific::getAUse(this) }
13+
final SemExpr getAUse() { result = Specific::getAUse(this) }
1414

1515
final SemType getType() { result = Specific::getSsaVariableType(this) }
1616

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,74 @@ edges
609609
| test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | test.cpp:165:29:165:31 | arr indirection [begin] |
610610
| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | test.cpp:165:29:165:31 | arr indirection [end] |
611611
| test.cpp:188:15:188:20 | call to malloc | test.cpp:189:15:189:15 | Load |
612+
| test.cpp:194:23:194:28 | call to malloc | test.cpp:195:17:195:17 | Load |
613+
| test.cpp:194:23:194:28 | call to malloc | test.cpp:197:8:197:8 | Load |
614+
| test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:5 | Load |
615+
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
616+
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
617+
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
618+
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
619+
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
620+
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
621+
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
622+
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
623+
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
624+
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
625+
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
626+
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
627+
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
628+
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
629+
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
630+
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
631+
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | Store |
632+
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | Store |
633+
| test.cpp:195:17:195:23 | ... + ... | test.cpp:197:20:197:22 | Load |
634+
| test.cpp:195:17:195:23 | ... + ... | test.cpp:201:5:201:19 | Store: ... = ... |
635+
| test.cpp:195:17:195:23 | ... + ... | test.cpp:201:5:201:19 | Store: ... = ... |
636+
| test.cpp:195:17:195:23 | Store | test.cpp:197:20:197:22 | Load |
637+
| test.cpp:195:17:195:23 | Store | test.cpp:201:5:201:19 | Store: ... = ... |
638+
| test.cpp:195:17:195:23 | Store | test.cpp:201:5:201:19 | Store: ... = ... |
639+
| test.cpp:197:20:197:22 | Load | test.cpp:201:5:201:19 | Store: ... = ... |
640+
| test.cpp:197:20:197:22 | Load | test.cpp:201:5:201:19 | Store: ... = ... |
641+
| test.cpp:201:5:201:12 | access to array | test.cpp:201:5:201:19 | Store: ... = ... |
642+
| test.cpp:201:5:201:12 | access to array | test.cpp:201:5:201:19 | Store: ... = ... |
643+
| test.cpp:205:23:205:28 | call to malloc | test.cpp:206:17:206:17 | Load |
644+
| test.cpp:205:23:205:28 | call to malloc | test.cpp:208:15:208:15 | Load |
645+
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
646+
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
647+
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
648+
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
649+
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
650+
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
651+
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
652+
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
653+
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
654+
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
655+
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
656+
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
657+
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
658+
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
659+
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
660+
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
661+
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
662+
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
663+
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
664+
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
665+
| test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | Store |
666+
| test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | Store |
667+
| test.cpp:206:17:206:23 | ... + ... | test.cpp:209:12:209:14 | Load |
668+
| test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | Store: ... = ... |
669+
| test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | Store: ... = ... |
670+
| test.cpp:206:17:206:23 | Store | test.cpp:209:12:209:14 | Load |
671+
| test.cpp:206:17:206:23 | Store | test.cpp:213:5:213:13 | Store: ... = ... |
672+
| test.cpp:206:17:206:23 | Store | test.cpp:213:5:213:13 | Store: ... = ... |
673+
| test.cpp:209:12:209:14 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
674+
| test.cpp:209:12:209:14 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
675+
| test.cpp:213:5:213:6 | * ... | test.cpp:213:5:213:13 | Store: ... = ... |
676+
| test.cpp:213:5:213:6 | * ... | test.cpp:213:5:213:13 | Store: ... = ... |
677+
| test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:6 | * ... |
678+
| test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
679+
| test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
612680
#select
613681
| test.cpp:6:14:6:15 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
614682
| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
@@ -625,3 +693,5 @@ edges
625693
| test.cpp:110:9:110:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:110:9:110:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
626694
| test.cpp:157:9:157:14 | Store: ... = ... | test.cpp:143:18:143:23 | call to malloc | test.cpp:157:9:157:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:143:18:143:23 | call to malloc | call to malloc | test.cpp:144:29:144:32 | size | size |
627695
| test.cpp:171:9:171:14 | Store: ... = ... | test.cpp:143:18:143:23 | call to malloc | test.cpp:171:9:171:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:143:18:143:23 | call to malloc | call to malloc | test.cpp:144:29:144:32 | size | size |
696+
| test.cpp:201:5:201:19 | Store: ... = ... | test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:194:23:194:28 | call to malloc | call to malloc | test.cpp:195:21:195:23 | len | len |
697+
| test.cpp:213:5:213:13 | Store: ... = ... | test.cpp:205:23:205:28 | call to malloc | test.cpp:213:5:213:13 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:205:23:205:28 | call to malloc | call to malloc | test.cpp:206:21:206:23 | len | len |

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,27 @@ void test11(unsigned size) {
188188
char *p = malloc(size);
189189
char *q = p + size - 1;
190190
deref_plus_one(q);
191-
}
191+
}
192+
193+
void test12(unsigned len, unsigned index) {
194+
char* p = (char *)malloc(len);
195+
char* end = p + len;
196+
197+
if(p + index > end) {
198+
return;
199+
}
200+
201+
p[index] = '\0'; // BAD
202+
}
203+
204+
void test13(unsigned len, unsigned index) {
205+
char* p = (char *)malloc(len);
206+
char* end = p + len;
207+
208+
char* q = p + index;
209+
if(q > end) {
210+
return;
211+
}
212+
213+
*q = '\0'; // BAD
214+
}

0 commit comments

Comments
 (0)