Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cb8dcf7

Browse files
raulgarciamsftgeoffw0
authored andcommitted
Publishing queries to the OSS Semmle repository
1 parent c66e5dd commit cb8dcf7

81 files changed

Lines changed: 3410 additions & 39 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import cpp
2+
import semmle.code.cpp.dataflow.TaintTracking
3+
private import semmle.code.cpp.dataflow.RecursionPrevention
4+
5+
/**
6+
* A buffer which includes an allocation size.
7+
*/
8+
abstract class BufferWithSize extends DataFlow::Node {
9+
abstract Expr getSizeExpr();
10+
11+
BufferAccess getAnAccess() {
12+
any(BufferWithSizeConfig bsc).hasFlow(this, DataFlow::exprNode(result.getPointer()))
13+
}
14+
}
15+
16+
/** An allocation function. */
17+
abstract class Alloc extends Function { }
18+
19+
/**
20+
* Allocation functions identified by the QL for C/C++ standard library.
21+
*/
22+
class DefaultAlloc extends Alloc {
23+
DefaultAlloc() {
24+
allocationFunction(this)
25+
}
26+
}
27+
28+
/** A buffer created through a call to an allocation function. */
29+
class AllocBuffer extends BufferWithSize {
30+
FunctionCall call;
31+
AllocBuffer() {
32+
asExpr() = call and
33+
call.getTarget() instanceof Alloc
34+
}
35+
36+
override Expr getSizeExpr() {
37+
result = call.getArgument(0)
38+
}
39+
}
40+
41+
/**
42+
* Find accesses of buffers for which we have a size expression.
43+
*/
44+
private class BufferWithSizeConfig extends TaintTracking::Configuration {
45+
BufferWithSizeConfig() {
46+
this = "BufferWithSize"
47+
}
48+
49+
override predicate isSource(DataFlow::Node n) {
50+
n = any(BufferWithSize b)
51+
}
52+
53+
override predicate isSink(DataFlow::Node n) {
54+
n.asExpr() = any(BufferAccess ae).getPointer()
55+
}
56+
57+
override predicate isSanitizer(DataFlow::Node s) {
58+
s = any(BufferWithSize b) and
59+
s.asExpr().getControlFlowScope() instanceof Alloc
60+
}
61+
}
62+
63+
64+
/**
65+
* An access(read or write) to a buffer, provided as a pair of
66+
* a pointer to the buffer and the length of data to be read or written.
67+
* Extend this class to support different kinds of buffer access.
68+
*/
69+
abstract class BufferAccess extends Locatable {
70+
/** Gets the pointer to the buffer being accessed. */
71+
abstract Expr getPointer();
72+
/** Gets the length of the data being read or written by this buffer access. */
73+
abstract Expr getAccessedLength();
74+
}
75+
76+
/**
77+
* A buffer access through an array expression.
78+
*/
79+
class ArrayBufferAccess extends BufferAccess, ArrayExpr {
80+
override Expr getPointer() {
81+
result = this.getArrayBase()
82+
}
83+
84+
override Expr getAccessedLength() {
85+
result = this.getArrayOffset()
86+
}
87+
}
88+
89+
/**
90+
* A buffer access through an overloaded array expression.
91+
*/
92+
class OverloadedArrayBufferAccess extends BufferAccess, OverloadedArrayExpr {
93+
override Expr getPointer() {
94+
result = this.getQualifier()
95+
}
96+
97+
override Expr getAccessedLength() {
98+
result = this.getAnArgument()
99+
}
100+
}
101+
102+
/**
103+
* A buffer access through pointer arithmetic.
104+
*/
105+
class PointerArithmeticAccess extends BufferAccess, Expr {
106+
PointerArithmeticOperation p;
107+
PointerArithmeticAccess() {
108+
this = p and
109+
p.getAnOperand().getType().getUnspecifiedType() instanceof IntegralType and
110+
not p.getParent() instanceof ComparisonOperation
111+
}
112+
113+
override Expr getPointer() {
114+
result = p.getAnOperand() and
115+
result.getType().getUnspecifiedType() instanceof PointerType
116+
}
117+
118+
override Expr getAccessedLength() {
119+
result = p.getAnOperand() and
120+
result.getType().getUnspecifiedType() instanceof IntegralType
121+
}
122+
}
123+
124+
/**
125+
* A pair of buffer accesses through a call to memcpy.
126+
*/
127+
class MemCpy extends BufferAccess, FunctionCall {
128+
MemCpy() {
129+
getTarget().hasName("memcpy")
130+
}
131+
132+
override Expr getPointer() {
133+
result = getArgument(0) or
134+
result = getArgument(1)
135+
}
136+
137+
override Expr getAccessedLength() {
138+
result = getArgument(2)
139+
}
140+
}
141+
142+
class StrncpySizeExpr extends BufferAccess, FunctionCall {
143+
StrncpySizeExpr() {
144+
getTarget().hasName("strncpy")
145+
}
146+
147+
override Expr getPointer() {
148+
result = getArgument(0) or
149+
result = getArgument(1)
150+
}
151+
152+
override Expr getAccessedLength() {
153+
result = getArgument(2)
154+
}
155+
}
156+
157+
class RecvSizeExpr extends BufferAccess, FunctionCall {
158+
RecvSizeExpr() {
159+
getTarget().hasName("recv")
160+
}
161+
162+
override Expr getPointer() {
163+
result = getArgument(1)
164+
}
165+
override Expr getAccessedLength() {
166+
result = getArgument(2)
167+
}
168+
}
169+
170+
class SendSizeExpr extends BufferAccess, FunctionCall {
171+
SendSizeExpr() {
172+
getTarget().hasName("send")
173+
}
174+
175+
override Expr getPointer() {
176+
result = getArgument(1)
177+
}
178+
override Expr getAccessedLength() {
179+
result = getArgument(2)
180+
}
181+
}
182+
183+
184+
class SnprintfSizeExpr extends BufferAccess, FunctionCall {
185+
SnprintfSizeExpr() {
186+
getTarget().hasName("snprintf")
187+
}
188+
189+
override Expr getPointer() {
190+
result = getArgument(0)
191+
}
192+
override Expr getAccessedLength() {
193+
result = getArgument(1)
194+
}
195+
}
196+
197+
class MemcmpSizeExpr extends BufferAccess, FunctionCall {
198+
MemcmpSizeExpr() {
199+
getTarget().hasName("Memcmp")
200+
}
201+
202+
override Expr getPointer() {
203+
result = getArgument(0) or
204+
result = getArgument(1)
205+
}
206+
override Expr getAccessedLength() {
207+
result = getArgument(2)
208+
}
209+
}
210+
211+
class MallocSizeExpr extends BufferAccess, FunctionCall {
212+
MallocSizeExpr() {
213+
getTarget().hasName("malloc")
214+
}
215+
216+
override Expr getPointer() {
217+
none()
218+
}
219+
override Expr getAccessedLength() {
220+
result = getArgument(1)
221+
}
222+
}
223+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
int get_number_from_network();
2+
3+
int process_network(int[] buff, int buffSize) {
4+
int i = ntohl(get_number_from_network());
5+
return buff[i];
6+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
uint32_t get_number_from_network();
2+
3+
int process_network(int[] buff, uint32_t buffSize) {
4+
uint32_t i = ntohl(get_number_from_network());
5+
if (i < buffSize) {
6+
return buff[i];
7+
} else {
8+
return -1;
9+
}
10+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import cpp
2+
import semmle.code.cpp.dataflow.DataFlow
3+
import semmle.code.cpp.controlflow.Guards
4+
import BufferAccess
5+
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
6+
7+
class NetworkFunctionCall extends FunctionCall {
8+
NetworkFunctionCall() {
9+
getTarget().hasName("ntohd") or
10+
getTarget().hasName("ntohf") or
11+
getTarget().hasName("ntohl") or
12+
getTarget().hasName("ntohll") or
13+
getTarget().hasName("ntohs")
14+
}
15+
}
16+
17+
class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {
18+
NetworkToBufferSizeConfiguration() {
19+
this = "NetworkToBufferSizeConfiguration"
20+
}
21+
22+
override predicate isSource(DataFlow::Node node) {
23+
node.asExpr() instanceof NetworkFunctionCall
24+
}
25+
26+
override predicate isSink(DataFlow::Node node) {
27+
node.asExpr() = any(BufferAccess ba).getAccessedLength()
28+
}
29+
30+
override predicate isBarrier(DataFlow::Node node) {
31+
exists(GuardCondition gc, GVN gvn |
32+
gc.getAChild*() = gvn.getAnExpr() and
33+
globalValueNumber(node.asExpr()) = gvn and
34+
gc.controls(node.asExpr().getBasicBlock(), _)
35+
)
36+
}
37+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>
8+
Data received over a network connection may be received in a different byte order than
9+
the byte order used by the local host, making the data difficult to process. To address this,
10+
data received over the wire is usually converted to host byte order by a call to a network-to-host
11+
byte order function, such as <code>ntohl</code>.
12+
</p>
13+
<p>
14+
The use of a network-to-host byte order function is therefore a good indicator that the returned
15+
value is unvalidated data retrieved from the network, and should not be used without further
16+
validation. In particular, the returned value should not be used as an array index or array length
17+
value without validation, which may result in a buffer overflow vulnerability.
18+
</p>
19+
</overview>
20+
21+
<recommendation>
22+
<p>
23+
Validate data returned by network-to-host byte order functions before use and especially before
24+
using the value as an array index or bound.
25+
</p>
26+
</recommendation>
27+
28+
<example>
29+
<p>In the example below, network data is retrieved and passed to <code>ntohl</code></p> to convert
30+
it to host byte order. The data is then used as an index in an array access expression. However,
31+
there is no validation that the data returned by <code>ntohl</code> is within the bounds of the array,
32+
which could lead to reading outside the bounds of the buffer.
33+
</p>
34+
<sample src="NtohlArrayBad.cpp" />
35+
<p>In the corrected example, the returned data is validated against the known size of the buffer,
36+
before being used as an array index.</p>
37+
<sample src="NtohlArrayGood.cpp" />
38+
</example>
39+
40+
<references>
41+
<li>
42+
<a href="https://docs.microsoft.com/en-us/windows/desktop/api/winsock/nf-winsock-ntohl">
43+
ntohl - winsock reference
44+
</a>
45+
</li>
46+
<li>
47+
<a href="https://linux.die.net/man/3/ntohl">
48+
ntohl - Linux man page
49+
</a>
50+
</li>
51+
52+
</references>
53+
54+
</qhelp>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* @id cpp/network-to-host-function-as-array-bound
3+
* @name Untrusted network-to-host usage
4+
* @description Using the result of a network-to-host byte order function, such as ntohl, as an
5+
* array bound or length value without checking it may result in buffer overflows or
6+
* other vulnerabilties.
7+
* @kind problem
8+
* @problem.severity error
9+
*/
10+
11+
import cpp
12+
import NtohlArrayNoBound
13+
import semmle.code.cpp.dataflow.DataFlow
14+
15+
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink
16+
where bufConfig.hasFlow(source, sink)
17+
select sink, "Unchecked use of data from network function $@", source, source.toString()

0 commit comments

Comments
 (0)