-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathArrayAccessProductFlow.ql
More file actions
84 lines (73 loc) · 2.71 KB
/
Copy pathArrayAccessProductFlow.ql
File metadata and controls
84 lines (73 loc) · 2.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
* @name Off-by-one in array access
* @description TODO
* @kind path-problem
* @problem.severity error
* @id cpp/off-by-one-array-access
* @tags reliability
* security
* experimental
*/
import cpp
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Bound
import semmle.code.cpp.ir.IR
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.models.interfaces.Allocation
import semmle.code.cpp.ir.IRConfiguration
import ArraySizeFlow::PathGraph1
// temporary - custom allocator for ffmpeg
class AvBufferAlloc extends AllocationFunction {
AvBufferAlloc() { this.hasGlobalName(["av_mallocz", "av_malloc"]) }
override int getSizeArg() { result = 0 }
}
// temporary - custom allocator for php
class PhpEmalloc extends AllocationFunction {
PhpEmalloc() { this.hasGlobalName(["_emalloc"]) }
override int getSizeArg() { result = 0 }
}
predicate bounded(Instruction i, Bound b, int delta, boolean upper) {
// TODO: reason
semBounded(getSemanticExpr(i), b, delta, upper, _)
}
module ArraySizeConfig implements ProductFlow::ConfigSig {
predicate isSourcePair(DataFlow::Node source1, DataFlow::Node source2) {
source1.asConvertedExpr().(AllocationExpr).getSizeExpr() = source2.asConvertedExpr()
}
predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2) {
exists(PointerAddInstruction pai, int delta |
isSinkPair1(sink1, sink2, pai, delta) and
(
delta = 0 and
exists(DataFlow::Node paiNode, DataFlow::Node derefNode |
DataFlow::localFlow(paiNode, derefNode) and
paiNode.asInstruction() = pai and
derefNode.asOperand() instanceof AddressOperand
)
or
delta >= 1
)
)
}
}
module ArraySizeFlow = ProductFlow::Global<ArraySizeConfig>;
pragma[nomagic]
predicate isSinkPair1(
DataFlow::Node sink1, DataFlow::Node sink2, PointerAddInstruction pai, int delta
) {
exists(Instruction index, ValueNumberBound b |
pai.getRight() = index and
pai.getLeft() = sink1.asInstruction() and
bounded(index, b, delta, true) and
sink2.asInstruction() = b.getInstruction()
)
}
from
ArraySizeFlow::PathNode1 source1, ArraySizeFlow::PathNode2 source2,
ArraySizeFlow::PathNode1 sink1, ArraySizeFlow::PathNode2 sink2
where ArraySizeFlow::flowPath(source1, source2, sink1, sink2)
// TODO: pull delta out and display it
select sink1.getNode(), source1, sink1, "Off-by one error allocated at $@ bounded by $@.", source1,
source1.toString(), sink2, sink2.toString()