Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: sandbox/linux/seccomp_bpf/demo.cc

Issue 10458040: Initial snapshot of the new BPF-enabled seccomp sandbox. This code is (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sandbox/linux/seccomp_bpf/Makefile ('k') | sandbox/linux/seccomp_bpf/sandbox_bpf.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <linux/unistd.h>
4 #include <netinet/in.h>
5 #include <netinet/tcp.h>
6 #include <netinet/udp.h>
7 #include <pthread.h>
8 #include <signal.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/ioctl.h>
13 #include <sys/ipc.h>
14 #include <sys/mman.h>
15 #include <sys/prctl.h>
16 #include <sys/resource.h>
17 #include <sys/shm.h>
18 #include <sys/socket.h>
19 #include <sys/time.h>
20 #include <sys/types.h>
21 #include <time.h>
22 #include <unistd.h>
23
24 #include "sandbox/linux/seccomp_bpf/sandbox_bpf.h"
25 #include "sandbox/linux/seccomp_bpf/util.h"
26
27 #define ERR EPERM
28
29 // We don't expect our sandbox to do anything useful yet. So, we will fail
30 // almost immediately. For now, force the code to continue running. The
31 // following line should be removed as soon as the sandbox is starting to
32 // actually enforce restrictions in a meaningful way:
33 #define _exit(x) do { } while (0)
34
35 static playground2::Sandbox::ErrorCode evaluator(int sysno) {
36 switch (sysno) {
37 #if defined(__NR_accept)
38 case __NR_accept: case __NR_accept4:
39 #endif
40 case __NR_alarm:
41 case __NR_brk:
42 case __NR_clock_gettime:
43 case __NR_close:
44 case __NR_dup: case __NR_dup2:
45 case __NR_epoll_create: case __NR_epoll_ctl: case __NR_epoll_wait:
46 case __NR_exit: case __NR_exit_group:
47 case __NR_fcntl:
48 #if defined(__NR_fcntl64)
49 case __NR_fcntl64:
50 #endif
51 case __NR_fdatasync:
52 case __NR_fstat:
53 #if defined(__NR_fstat64)
54 case __NR_fstat64:
55 #endif
56 case __NR_ftruncate:
57 case __NR_futex:
58 case __NR_getdents: case __NR_getdents64:
59 case __NR_getegid:
60 #if defined(__NR_getegid32)
61 case __NR_getegid32:
62 #endif
63 case __NR_geteuid:
64 #if defined(__NR_geteuid32)
65 case __NR_geteuid32:
66 #endif
67 case __NR_getgid:
68 #if defined(__NR_getgid32)
69 case __NR_getgid32:
70 #endif
71 case __NR_getitimer: case __NR_setitimer:
72 #if defined(__NR_getpeername)
73 case __NR_getpeername:
74 #endif
75 case __NR_getpid: case __NR_gettid:
76 #if defined(__NR_getsockname)
77 case __NR_getsockname:
78 #endif
79 case __NR_gettimeofday:
80 case __NR_getuid:
81 #if defined(__NR_getuid32)
82 case __NR_getuid32:
83 #endif
84 #if defined(__NR__llseek)
85 case __NR__llseek:
86 #endif
87 case __NR_lseek:
88 case __NR_nanosleep:
89 case __NR_pipe: case __NR_pipe2:
90 case __NR_poll:
91 case __NR_pread64: case __NR_preadv:
92 case __NR_pwrite64: case __NR_pwritev:
93 case __NR_read: case __NR_readv:
94 case __NR_restart_syscall:
95 case __NR_set_robust_list:
96 case __NR_rt_sigaction:
97 #if defined(__NR_sigaction)
98 case __NR_sigaction:
99 #endif
100 #if defined(__NR_signal)
101 case __NR_signal:
102 #endif
103 case __NR_rt_sigprocmask:
104 #if defined(__NR_sigprocmask)
105 case __NR_sigprocmask:
106 #endif
107 #if defined(__NR_shutdown)
108 case __NR_shutdown:
109 #endif
110 case __NR_rt_sigreturn:
111 #if defined(__NR_sigreturn)
112 case __NR_sigreturn:
113 #endif
114 #if defined(__NR_socketpair)
115 case __NR_socketpair:
116 #endif
117 case __NR_time:
118 case __NR_uname:
119 case __NR_write: case __NR_writev:
120 return playground2::Sandbox::SB_ALLOWED;
121
122 // The following system calls are temporarily permitted. This must be
123 // tightened later. But we currently don't implement enough of the sandboxing
124 // API to do so.
125 // As is, this sandbox isn't exactly safe :-/
126 #if defined(__NR_sendmsg)
127 case __NR_sendmsg: case __NR_sendto:
128 case __NR_recvmsg: case __NR_recvfrom:
129 case __NR_getsockopt: case __NR_setsockopt:
130 #elif defined(__NR_socketcall)
131 case __NR_socketcall:
132 #endif
133 #if defined(__NR_shmat)
134 case __NR_shmat: case __NR_shmctl: case __NR_shmdt: case __NR_shmget:
135 #elif defined(__NR_ipc)
136 case __NR_ipc:
137 #endif
138 #if defined(__NR_mmap2)
139 case __NR_mmap2:
140 #else
141 case __NR_mmap:
142 #endif
143 #if defined(__NR_ugetrlimit)
144 case __NR_ugetrlimit:
145 #endif
146 case __NR_getrlimit:
147 case __NR_ioctl:
148 case __NR_prctl:
149 case __NR_clone:
150 case __NR_munmap: case __NR_mprotect: case __NR_madvise:
151 case __NR_remap_file_pages:
152 return playground2::Sandbox::SB_ALLOWED;
153
154 // Everything that isn't explicitly allowed is denied.
155 default:
156 return (playground2::Sandbox::ErrorCode)ERR;
157 }
158 }
159
160 static void *threadFnc(void *arg) {
161 return arg;
162 }
163
164 static void *sendmsgStressThreadFnc(void *arg) {
165 static const int repetitions = 100;
166 static const int kNumFds = 3;
167 for (int rep = 0; rep < repetitions; ++rep) {
168 int fds[2 + kNumFds];
169 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
170 perror("socketpair()");
171 _exit(1);
172 }
173 size_t len = 4;
174 char buf[4];
175 if (!playground2::Util::sendFds(fds[0], "test", 4,
176 fds[1], fds[1], fds[1], -1) ||
177 !playground2::Util::getFds(fds[1], buf, &len,
178 fds+2, fds+3, fds+4, NULL) ||
179 len != 4 ||
180 memcmp(buf, "test", len) ||
181 write(fds[2], "demo", 4) != 4 ||
182 read(fds[0], buf, 4) != 4 ||
183 memcmp(buf, "demo", 4)) {
184 perror("sending/receiving of fds");
185 _exit(1);
186 }
187 for (int i = 0; i < 2+kNumFds; ++i) {
188 if (close(fds[i])) {
189 perror("close");
190 _exit(1);
191 }
192 }
193 }
194 return NULL;
195 }
196
197 int main(int argc, char *argv[]) {
198 int proc_fd = open("/proc", O_RDONLY|O_DIRECTORY);
199 if (playground2::Sandbox::supportsSeccompSandbox(proc_fd) !=
200 playground2::Sandbox::STATUS_AVAILABLE) {
201 perror("sandbox");
202 _exit(1);
203 }
204 playground2::Sandbox::setProcFd(proc_fd);
205 playground2::Sandbox::setSandboxPolicy(evaluator, NULL);
206 playground2::Sandbox::startSandbox();
207
208 // Check that we can create threads
209 pthread_t thr;
210 if (!pthread_create(&thr, NULL, threadFnc,
211 reinterpret_cast<void *>(0x1234))) {
212 void *ret;
213 pthread_join(thr, &ret);
214 if (ret != reinterpret_cast<void *>(0x1234)) {
215 perror("clone() failed");
216 _exit(1);
217 }
218 } else {
219 perror("clone() failed");
220 _exit(1);
221 }
222
223 // Check that we handle restart_syscall() without dieing. This is a little
224 // tricky to trigger. And I can't think of a good way to verify whether it
225 // actually executed.
226 signal(SIGALRM, SIG_IGN);
227 const struct itimerval tv = { { 0, 0 }, { 0, 5*1000 } };
228 const struct timespec tmo = { 0, 100*1000*1000 };
229 setitimer(ITIMER_REAL, &tv, NULL);
230 nanosleep(&tmo, NULL);
231
232 // Check that we can query the size of the stack, but that all other
233 // calls to getrlimit() fail.
234 if (((errno = 0), !getrlimit(RLIMIT_STACK, NULL)) || errno != EFAULT ||
235 ((errno = 0), !getrlimit(RLIMIT_CORE, NULL)) || errno != ERR) {
236 perror("getrlimit()");
237 _exit(1);
238 }
239
240 // Check that we can query TCGETS and TIOCGWINSZ, but no other ioctls().
241 if (((errno = 0), !ioctl(2, TCGETS, NULL)) || errno != EFAULT ||
242 ((errno = 0), !ioctl(2, TIOCGWINSZ, NULL)) || errno != EFAULT ||
243 ((errno = 0), !ioctl(2, TCSETS, NULL)) || errno != ERR) {
244 perror("ioctl()");
245 _exit(1);
246 }
247
248 // Check that prctl() can manipulate the dumpable flag, but nothing else.
249 if (((errno = 0), !prctl(PR_GET_DUMPABLE)) || errno ||
250 ((errno = 0), prctl(PR_SET_DUMPABLE, 1)) || errno ||
251 ((errno = 0), !prctl(PR_SET_SECCOMP, 0)) || errno != ERR) {
252 perror("prctl()");
253 _exit(1);
254 }
255
256 // Check that we can send and receive file handles.
257 int fds[3];
258 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
259 perror("socketpair()");
260 _exit(1);
261 }
262 size_t len = 4;
263 char buf[4];
264 if (!playground2::Util::sendFds(fds[0], "test", 4, fds[1], -1) ||
265 !playground2::Util::getFds(fds[1], buf, &len, fds+2, NULL) ||
266 len != 4 ||
267 memcmp(buf, "test", len) ||
268 write(fds[2], "demo", 4) != 4 ||
269 read(fds[0], buf, 4) != 4 ||
270 memcmp(buf, "demo", 4) ||
271 close(fds[0]) ||
272 close(fds[1]) ||
273 close(fds[2])) {
274 perror("sending/receiving of fds");
275 _exit(1);
276 }
277
278 // Check whether SysV IPC works.
279 int shmid;
280 void *addr;
281 if ((shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|0600)) < 0 ||
282 (addr = shmat(shmid, NULL, 0)) == reinterpret_cast<void *>(-1) ||
283 shmdt(addr) ||
284 shmctl(shmid, IPC_RMID, NULL)) {
285 perror("sysv IPC");
286 _exit(1);
287 }
288
289 // Print a message so that the user can see the sandbox is activated.
290 time_t tm = time(NULL);
291 printf("Sandbox has been started at %s", ctime(&tm));
292
293 // Stress-test the sendmsg() code
294 static const int kSendmsgStressNumThreads = 10;
295 pthread_t sendmsgStressThreads[kSendmsgStressNumThreads];
296 for (int i = 0; i < kSendmsgStressNumThreads; ++i) {
297 if (pthread_create(sendmsgStressThreads + i, NULL,
298 sendmsgStressThreadFnc, NULL)) {
299 perror("pthread_create");
300 _exit(1);
301 }
302 }
303 for (int i = 0; i < kSendmsgStressNumThreads; ++i) {
304 pthread_join(sendmsgStressThreads[i], NULL);
305 }
306
307 return 0;
308 }
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp_bpf/Makefile ('k') | sandbox/linux/seccomp_bpf/sandbox_bpf.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698