Skip to content

Commit fef824c

Browse files
committed
C++: Implement models for poll, accept and select.
1 parent dae65f6 commit fef824c

File tree

6 files changed

+277
-0
lines changed

6 files changed

+277
-0
lines changed

cpp/ql/src/semmle/code/cpp/models/Models.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@ private import implementations.SmartPointer
3030
private import implementations.Sscanf
3131
private import implementations.Send
3232
private import implementations.Recv
33+
private import implementations.Accept
34+
private import implementations.Poll
35+
private import implementations.Select
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* Provides implementation classes modeling `accept` and various similar
3+
* functions. See `semmle.code.cpp.models.Models` for usage information.
4+
*/
5+
6+
import semmle.code.cpp.Function
7+
import semmle.code.cpp.models.interfaces.ArrayFunction
8+
import semmle.code.cpp.models.interfaces.Taint
9+
import semmle.code.cpp.models.interfaces.Alias
10+
import semmle.code.cpp.models.interfaces.SideEffect
11+
12+
/**
13+
* The function `accept` and its assorted variants
14+
*/
15+
private class Accept extends ArrayFunction, AliasFunction, TaintFunction, SideEffectFunction {
16+
Accept() { this.hasGlobalName(["accept", "accept4", "WSAAccept"]) }
17+
18+
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
19+
bufParam = 1 and countParam = 2
20+
}
21+
22+
override predicate hasArrayInput(int bufParam) { bufParam = [1, 2] }
23+
24+
override predicate hasArrayOutput(int bufParam) { bufParam = [1, 2] }
25+
26+
override predicate parameterNeverEscapes(int index) { exists(this.getParameter(index)) }
27+
28+
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
29+
30+
override predicate parameterIsAlwaysReturned(int index) { none() }
31+
32+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
33+
(input.isParameter(0) or input.isParameterDeref(1)) and
34+
(output.isReturnValue() or output.isParameterDeref(1))
35+
}
36+
37+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
38+
i = 1 and buffer = true and mustWrite = false
39+
or
40+
i = 2 and buffer = false and mustWrite = false
41+
}
42+
43+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
44+
i = 0 and buffer = true
45+
or
46+
i = 1 and buffer = false
47+
}
48+
49+
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
50+
51+
// NOTE: We implement thse two predicates as none because we can't model the low-level changes made to
52+
// the structure pointed to by the file-descriptor argument.
53+
override predicate hasOnlySpecificReadSideEffects() { none() }
54+
55+
override predicate hasOnlySpecificWriteSideEffects() { none() }
56+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Provides implementation classes modeling `poll` and various similar
3+
* functions. See `semmle.code.cpp.models.Models` for usage information.
4+
*/
5+
6+
import semmle.code.cpp.Function
7+
import semmle.code.cpp.models.interfaces.ArrayFunction
8+
import semmle.code.cpp.models.interfaces.Taint
9+
import semmle.code.cpp.models.interfaces.Alias
10+
import semmle.code.cpp.models.interfaces.SideEffect
11+
12+
/**
13+
* The function `poll` and its assorted variants
14+
*/
15+
private class Poll extends ArrayFunction, AliasFunction, TaintFunction, SideEffectFunction {
16+
Poll() { this.hasGlobalName(["poll", "ppoll", "WSAPoll"]) }
17+
18+
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
19+
bufParam = 0 and countParam = 1
20+
}
21+
22+
override predicate hasArrayInput(int bufParam) {
23+
getParameter(bufParam).getUnspecifiedType() instanceof PointerType
24+
}
25+
26+
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
27+
28+
override predicate parameterNeverEscapes(int index) { exists(this.getParameter(index)) }
29+
30+
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
31+
32+
override predicate parameterIsAlwaysReturned(int index) { none() }
33+
34+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
35+
input.isParameterDeref(0) and
36+
output.isParameterDeref(0)
37+
}
38+
39+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
40+
i = 0 and buffer = true and mustWrite = false
41+
}
42+
43+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
44+
getParameter(i).getUnspecifiedType() instanceof PointerType and buffer = true
45+
}
46+
47+
override predicate hasOnlySpecificReadSideEffects() { any() }
48+
49+
override predicate hasOnlySpecificWriteSideEffects() { any() }
50+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* Provides implementation classes modeling `select` and various similar
3+
* functions. See `semmle.code.cpp.models.Models` for usage information.
4+
*/
5+
6+
import semmle.code.cpp.Function
7+
import semmle.code.cpp.models.interfaces.ArrayFunction
8+
import semmle.code.cpp.models.interfaces.Taint
9+
import semmle.code.cpp.models.interfaces.Alias
10+
import semmle.code.cpp.models.interfaces.SideEffect
11+
12+
/**
13+
* The function `select` and its assorted variants
14+
*/
15+
private class Select extends ArrayFunction, AliasFunction, TaintFunction, SideEffectFunction {
16+
Select() { this.hasGlobalName(["select", "pselect"]) }
17+
18+
override predicate hasArrayWithUnknownSize(int bufParam) { bufParam = [1 .. 3] }
19+
20+
override predicate hasArrayInput(int bufParam) { bufParam = [1 .. 3] }
21+
22+
override predicate hasArrayOutput(int bufParam) { bufParam = [1 .. 3] }
23+
24+
override predicate parameterNeverEscapes(int index) { exists(this.getParameter(index)) }
25+
26+
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
27+
28+
override predicate parameterIsAlwaysReturned(int index) { none() }
29+
30+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
31+
exists(int i | i = [1 .. 3] |
32+
input.isParameterDeref(i) and
33+
output.isParameterDeref(i)
34+
)
35+
}
36+
37+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
38+
i = [1 .. 3] and buffer = true and mustWrite = false
39+
}
40+
41+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
42+
i = [1 .. 5] and buffer = true
43+
}
44+
45+
override predicate hasOnlySpecificReadSideEffects() { any() }
46+
47+
override predicate hasOnlySpecificWriteSideEffects() { any() }
48+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
void sink(...);
2+
int source();
3+
4+
// --- accept ---
5+
6+
struct sockaddr {
7+
unsigned char length;
8+
int sa_family;
9+
char* sa_data;
10+
};
11+
12+
int accept(int, const sockaddr*, int*);
13+
14+
void sink(sockaddr);
15+
16+
void test_accept() {
17+
int s = source();
18+
sockaddr addr;
19+
int size = sizeof(sockaddr);
20+
int a = accept(s, &addr, &size);
21+
22+
sink(a); // $ ast=17:11 SPURIOUS: ast=18:12 MISSING: ir
23+
sink(addr); // $ ast MISSING: ir
24+
}
25+
26+
// --- poll ---
27+
28+
struct pollfd {
29+
int fd;
30+
short events;
31+
short revents;
32+
};
33+
34+
int poll(struct pollfd *, int, int);
35+
36+
void test_poll() {
37+
pollfd pfds;
38+
39+
pfds.events = 1;
40+
pfds.fd = source();
41+
poll(&pfds, 1, -1);
42+
43+
sink(pfds); // $ ast MISSING: ir
44+
}
45+
46+
// --- select ---
47+
48+
typedef struct {} timeval;
49+
50+
typedef struct fd_set {
51+
int fd_count;
52+
int fd_array[4096];
53+
} fd_set;
54+
55+
int select(int, fd_set *, fd_set *, fd_set *, timeval *);
56+
57+
void test_select(timeval timeout) {
58+
fd_set readfds;
59+
60+
readfds.fd_count = 1;
61+
readfds.fd_array[0] = source();
62+
select(2, &readfds, nullptr, nullptr, &timeout);
63+
sink(&readfds); // $ ast MISSING: ir
64+
}

cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,62 @@
135135
| arrayassignment.cpp:145:12:145:12 | 5 | arrayassignment.cpp:145:7:145:13 | access to array | TAINT |
136136
| arrayassignment.cpp:146:7:146:10 | arr3 | arrayassignment.cpp:146:7:146:13 | access to array | |
137137
| arrayassignment.cpp:146:12:146:12 | 5 | arrayassignment.cpp:146:7:146:13 | access to array | TAINT |
138+
| bsd.cpp:17:11:17:16 | call to source | bsd.cpp:20:18:20:18 | s | |
139+
| bsd.cpp:18:12:18:15 | addr | bsd.cpp:20:22:20:25 | addr | |
140+
| bsd.cpp:18:12:18:15 | addr | bsd.cpp:23:8:23:11 | addr | |
141+
| bsd.cpp:19:14:19:29 | sizeof(sockaddr) | bsd.cpp:20:29:20:32 | size | |
142+
| bsd.cpp:20:11:20:16 | call to accept | bsd.cpp:22:8:22:8 | a | |
143+
| bsd.cpp:20:18:20:18 | s | bsd.cpp:20:11:20:16 | call to accept | TAINT |
144+
| bsd.cpp:20:21:20:25 | & ... | bsd.cpp:20:11:20:16 | call to accept | TAINT |
145+
| bsd.cpp:20:22:20:25 | addr | bsd.cpp:20:11:20:16 | call to accept | TAINT |
146+
| bsd.cpp:20:22:20:25 | addr | bsd.cpp:20:21:20:25 | & ... | |
147+
| bsd.cpp:20:28:20:32 | ref arg & ... | bsd.cpp:20:29:20:32 | size [inner post update] | |
148+
| bsd.cpp:20:29:20:32 | size | bsd.cpp:20:28:20:32 | & ... | |
149+
| bsd.cpp:37:10:37:13 | pfds | bsd.cpp:39:3:39:6 | pfds | |
150+
| bsd.cpp:37:10:37:13 | pfds | bsd.cpp:40:3:40:6 | pfds | |
151+
| bsd.cpp:37:10:37:13 | pfds | bsd.cpp:41:9:41:12 | pfds | |
152+
| bsd.cpp:37:10:37:13 | pfds | bsd.cpp:43:8:43:11 | pfds | |
153+
| bsd.cpp:39:3:39:6 | pfds [post update] | bsd.cpp:40:3:40:6 | pfds | |
154+
| bsd.cpp:39:3:39:6 | pfds [post update] | bsd.cpp:41:9:41:12 | pfds | |
155+
| bsd.cpp:39:3:39:6 | pfds [post update] | bsd.cpp:43:8:43:11 | pfds | |
156+
| bsd.cpp:39:3:39:17 | ... = ... | bsd.cpp:39:8:39:13 | events [post update] | |
157+
| bsd.cpp:39:17:39:17 | 1 | bsd.cpp:39:3:39:17 | ... = ... | |
158+
| bsd.cpp:40:3:40:6 | pfds [post update] | bsd.cpp:41:9:41:12 | pfds | |
159+
| bsd.cpp:40:3:40:6 | pfds [post update] | bsd.cpp:43:8:43:11 | pfds | |
160+
| bsd.cpp:40:3:40:20 | ... = ... | bsd.cpp:40:8:40:9 | fd [post update] | |
161+
| bsd.cpp:40:13:40:18 | call to source | bsd.cpp:40:3:40:20 | ... = ... | |
162+
| bsd.cpp:41:8:41:12 | & ... | bsd.cpp:41:8:41:12 | ref arg & ... | TAINT |
163+
| bsd.cpp:41:8:41:12 | ref arg & ... | bsd.cpp:41:9:41:12 | pfds [inner post update] | |
164+
| bsd.cpp:41:8:41:12 | ref arg & ... | bsd.cpp:43:8:43:11 | pfds | |
165+
| bsd.cpp:41:9:41:12 | pfds | bsd.cpp:41:8:41:12 | & ... | |
166+
| bsd.cpp:41:9:41:12 | pfds | bsd.cpp:41:8:41:12 | ref arg & ... | TAINT |
167+
| bsd.cpp:41:19:41:19 | 1 | bsd.cpp:41:18:41:19 | - ... | TAINT |
168+
| bsd.cpp:57:26:57:32 | timeout | bsd.cpp:62:42:62:48 | timeout | |
169+
| bsd.cpp:58:10:58:16 | readfds | bsd.cpp:60:3:60:9 | readfds | |
170+
| bsd.cpp:58:10:58:16 | readfds | bsd.cpp:61:3:61:9 | readfds | |
171+
| bsd.cpp:58:10:58:16 | readfds | bsd.cpp:62:14:62:20 | readfds | |
172+
| bsd.cpp:58:10:58:16 | readfds | bsd.cpp:63:9:63:15 | readfds | |
173+
| bsd.cpp:60:3:60:9 | readfds [post update] | bsd.cpp:61:3:61:9 | readfds | |
174+
| bsd.cpp:60:3:60:9 | readfds [post update] | bsd.cpp:62:14:62:20 | readfds | |
175+
| bsd.cpp:60:3:60:9 | readfds [post update] | bsd.cpp:63:9:63:15 | readfds | |
176+
| bsd.cpp:60:3:60:22 | ... = ... | bsd.cpp:60:11:60:18 | fd_count [post update] | |
177+
| bsd.cpp:60:22:60:22 | 1 | bsd.cpp:60:3:60:22 | ... = ... | |
178+
| bsd.cpp:61:3:61:9 | readfds [post update] | bsd.cpp:62:14:62:20 | readfds | |
179+
| bsd.cpp:61:3:61:9 | readfds [post update] | bsd.cpp:63:9:63:15 | readfds | |
180+
| bsd.cpp:61:3:61:21 | access to array [post update] | bsd.cpp:61:11:61:18 | fd_array [inner post update] | |
181+
| bsd.cpp:61:3:61:32 | ... = ... | bsd.cpp:61:3:61:21 | access to array [post update] | |
182+
| bsd.cpp:61:11:61:18 | fd_array | bsd.cpp:61:3:61:21 | access to array | |
183+
| bsd.cpp:61:20:61:20 | 0 | bsd.cpp:61:3:61:21 | access to array | TAINT |
184+
| bsd.cpp:61:25:61:30 | call to source | bsd.cpp:61:3:61:32 | ... = ... | |
185+
| bsd.cpp:62:13:62:20 | & ... | bsd.cpp:62:13:62:20 | ref arg & ... | TAINT |
186+
| bsd.cpp:62:13:62:20 | ref arg & ... | bsd.cpp:62:14:62:20 | readfds [inner post update] | |
187+
| bsd.cpp:62:13:62:20 | ref arg & ... | bsd.cpp:63:9:63:15 | readfds | |
188+
| bsd.cpp:62:14:62:20 | readfds | bsd.cpp:62:13:62:20 | & ... | |
189+
| bsd.cpp:62:14:62:20 | readfds | bsd.cpp:62:13:62:20 | ref arg & ... | TAINT |
190+
| bsd.cpp:62:41:62:48 | ref arg & ... | bsd.cpp:62:42:62:48 | timeout [inner post update] | |
191+
| bsd.cpp:62:42:62:48 | timeout | bsd.cpp:62:41:62:48 | & ... | |
192+
| bsd.cpp:63:8:63:15 | ref arg & ... | bsd.cpp:63:9:63:15 | readfds [inner post update] | |
193+
| bsd.cpp:63:9:63:15 | readfds | bsd.cpp:63:8:63:15 | & ... | |
138194
| constructor_delegation.cpp:8:2:8:8 | this | constructor_delegation.cpp:8:20:8:24 | constructor init of field x [pre-this] | |
139195
| constructor_delegation.cpp:8:14:8:15 | _x | constructor_delegation.cpp:8:22:8:23 | _x | |
140196
| constructor_delegation.cpp:8:22:8:23 | _x | constructor_delegation.cpp:8:20:8:24 | constructor init of field x | TAINT |

0 commit comments

Comments
 (0)