-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathOverflowStatic.ql
More file actions
128 lines (116 loc) · 4.07 KB
/
OverflowStatic.ql
File metadata and controls
128 lines (116 loc) · 4.07 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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/**
* @name Static array access may cause overflow
* @description Exceeding the size of a static array during write or access operations
* may result in a buffer overflow.
* @kind problem
* @problem.severity warning
* @precision medium
* @id cpp/static-buffer-overflow
* @tags reliability
* security
* external/cwe/cwe-119
* external/cwe/cwe-131
*/
import cpp
import semmle.code.cpp.commons.Buffer
import LoopBounds
private predicate staticBufferBase(VariableAccess access, Variable v)
{
v.getType().(ArrayType).getBaseType() instanceof CharType and
access = v.getAnAccess() and
not memberMayBeVarSize(_, v)
}
predicate staticBuffer(VariableAccess access, Variable v, int size)
{
staticBufferBase(access, v) and
size = getBufferSize(access, _)
}
class BufferAccess extends ArrayExpr
{
BufferAccess() {
exists(int size |
staticBuffer(this.getArrayBase(), _, size) and
size != 0
) and
// exclude accesses in macro implementation of `strcmp`,
// which are carefully controlled but can look dangerous.
not exists(Macro m |
m.getName() = "strcmp" and
m.getAnInvocation().getAnExpandedElement() = this
)
}
int bufferSize() {
staticBuffer(this.getArrayBase(), _, result)
}
Variable buffer() {
result.getAnAccess() = this.getArrayBase()
}
}
predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg)
{
exists(ClassicForLoop loop |
loop.getStmt().getAChild*() = bufaccess.getEnclosingStmt() and
loop.limit() >= bufaccess.bufferSize() and
loop.counter().getAnAccess() = bufaccess.getArrayOffset() and
msg = "Potential buffer-overflow: counter '" + loop.counter().toString()
+ "' <= " + loop.limit().toString() + " but '" + bufaccess.buffer().getName()
+ "' has " + bufaccess.bufferSize().toString() + " elements.")
}
predicate bufferAndSizeFunction(Function f, int buf, int size)
{
(f.hasQualifiedName("read") and buf = 1 and size = 2) or
(f.hasQualifiedName("fgets") and buf = 0 and size = 1) or
(f.hasQualifiedName("strncpy") and buf = 0 and size = 2) or
(f.hasQualifiedName("strncat") and buf = 0 and size = 2) or
(f.hasQualifiedName("memcpy") and buf = 0 and size = 2) or
(f.hasQualifiedName("memmove") and buf = 0 and size = 2) or
(f.hasQualifiedName("snprintf") and buf = 0 and size = 1) or
(f.hasQualifiedName("vsnprintf") and buf = 0 and size = 1)
}
class CallWithBufferSize extends FunctionCall
{
CallWithBufferSize() { bufferAndSizeFunction(this.getTarget(), _, _) }
Expr buffer() {
exists(int i |
bufferAndSizeFunction(this.getTarget(), i, _) and
result = this.getArgument(i)
)
}
Expr statedSizeExpr() {
exists(int i |
bufferAndSizeFunction(this.getTarget(), _, i) and
result = this.getArgument(i)
)
}
int statedSizeValue() {
exists(Expr statedSizeSrc |
DataFlow::localFlow(DataFlow::exprNode(statedSizeSrc), DataFlow::exprNode(statedSizeExpr())) and
result = statedSizeSrc.getValue().toInt()
)
}
}
predicate wrongBufferSize(Expr error, string msg) {
exists(CallWithBufferSize call, int bufsize, Variable buf, int statedSize |
staticBuffer(call.buffer(), buf, bufsize) and
statedSize = min(call.statedSizeValue()) and
statedSize > bufsize and
error = call.statedSizeExpr() and
msg = "Potential buffer-overflow: '" + buf.getName() +
"' has size " + bufsize.toString() + " not " + statedSize + ".")
}
predicate outOfBounds(BufferAccess bufaccess, string msg)
{
exists(int size, int access, string buf |
buf = bufaccess.buffer().getName() and
bufaccess.bufferSize() = size and
bufaccess.getArrayOffset().getValue().toInt() = access and
( access > size or
(access = size and not exists(AddressOfExpr addof | bufaccess = addof.getOperand()))) and
msg = "Potential buffer-overflow: '" + buf + "' has size " + size.toString() +
" but '" + buf + "[" + access.toString() + "]' is accessed here.")
}
from Element error, string msg
where overflowOffsetInLoop(error, msg)
or wrongBufferSize(error, msg)
or outOfBounds(error, msg)
select error, msg