Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / sandbox / linux / seccomp-bpf / demo.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <linux/unistd.h>
8 #include <netinet/in.h>
9 #include <netinet/tcp.h>
10 #include <netinet/udp.h>
11 #include <pthread.h>
12 #include <signal.h>
13 #include <stdarg.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/ioctl.h>
18 #include <sys/ipc.h>
19 #include <sys/mman.h>
20 #include <sys/prctl.h>
21 #include <sys/resource.h>
22 #include <sys/shm.h>
23 #include <sys/socket.h>
24 #include <sys/time.h>
25 #include <sys/types.h>
26 #include <time.h>
27 #include <unistd.h>
28
29 #include "base/macros.h"
30 #include "base/posix/eintr_wrapper.h"
31 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
32 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
33 #include "sandbox/linux/services/linux_syscalls.h"
34
35 using sandbox::ErrorCode;
36 using sandbox::SandboxBPF;
37 using sandbox::SandboxBPFPolicy;
38 using sandbox::arch_seccomp_data;
39
40 #define ERR EPERM
41
42 // We don't expect our sandbox to do anything useful yet. So, we will fail
43 // almost immediately. For now, force the code to continue running. The
44 // following line should be removed as soon as the sandbox is starting to
45 // actually enforce restrictions in a meaningful way:
46 #define _exit(x) do { } while (0)
47
48 namespace {
49
50 bool SendFds(int transport, const void *buf, size_t len, ...) {
51   int count = 0;
52   va_list ap;
53   va_start(ap, len);
54   while (va_arg(ap, int) >= 0) {
55     ++count;
56   }
57   va_end(ap);
58   if (!count) {
59     return false;
60   }
61   char cmsg_buf[CMSG_SPACE(count*sizeof(int))];
62   memset(cmsg_buf, 0, sizeof(cmsg_buf));
63   struct iovec  iov[2] = { { 0 } };
64   struct msghdr msg    = { 0 };
65   int dummy            = 0;
66   iov[0].iov_base      = &dummy;
67   iov[0].iov_len       = sizeof(dummy);
68   if (buf && len > 0) {
69     iov[1].iov_base    = const_cast<void *>(buf);
70     iov[1].iov_len     = len;
71   }
72   msg.msg_iov          = iov;
73   msg.msg_iovlen       = (buf && len > 0) ? 2 : 1;
74   msg.msg_control      = cmsg_buf;
75   msg.msg_controllen   = CMSG_LEN(count*sizeof(int));
76   struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
77   cmsg->cmsg_level     = SOL_SOCKET;
78   cmsg->cmsg_type      = SCM_RIGHTS;
79   cmsg->cmsg_len       = CMSG_LEN(count*sizeof(int));
80   va_start(ap, len);
81   for (int i = 0, fd; (fd = va_arg(ap, int)) >= 0; ++i) {
82     (reinterpret_cast<int *>(CMSG_DATA(cmsg)))[i] = fd;
83   }
84   return sendmsg(transport, &msg, 0) ==
85       static_cast<ssize_t>(sizeof(dummy) + ((buf && len > 0) ? len : 0));
86 }
87
88 bool GetFds(int transport, void *buf, size_t *len, ...) {
89   int count = 0;
90   va_list ap;
91   va_start(ap, len);
92   for (int *fd; (fd = va_arg(ap, int *)) != NULL; ++count) {
93     *fd = -1;
94   }
95   va_end(ap);
96   if (!count) {
97     return false;
98   }
99   char cmsg_buf[CMSG_SPACE(count*sizeof(int))];
100   memset(cmsg_buf, 0, sizeof(cmsg_buf));
101   struct iovec iov[2] = { { 0 } };
102   struct msghdr msg   = { 0 };
103   int err;
104   iov[0].iov_base     = &err;
105   iov[0].iov_len      = sizeof(int);
106   if (buf && len && *len > 0) {
107     iov[1].iov_base   = buf;
108     iov[1].iov_len    = *len;
109   }
110   msg.msg_iov         = iov;
111   msg.msg_iovlen      = (buf && len && *len > 0) ? 2 : 1;
112   msg.msg_control     = cmsg_buf;
113   msg.msg_controllen  = CMSG_LEN(count*sizeof(int));
114   ssize_t bytes = recvmsg(transport, &msg, 0);
115   if (len) {
116     *len = bytes > static_cast<int>(sizeof(int)) ? bytes - sizeof(int) : 0;
117   }
118   if (bytes != static_cast<ssize_t>(sizeof(int) + iov[1].iov_len)) {
119     if (bytes >= 0) {
120       errno = 0;
121     }
122     return false;
123   }
124   if (err) {
125     // "err" is the first four bytes of the payload. If these are non-zero,
126     // the sender on the other side of the socketpair sent us an errno value.
127     // We don't expect to get any file handles in this case.
128     errno = err;
129     return false;
130   }
131   struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
132   if ((msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) ||
133       !cmsg                                    ||
134       cmsg->cmsg_level != SOL_SOCKET           ||
135       cmsg->cmsg_type  != SCM_RIGHTS           ||
136       cmsg->cmsg_len   != CMSG_LEN(count*sizeof(int))) {
137     errno = EBADF;
138     return false;
139   }
140   va_start(ap, len);
141   for (int *fd, i = 0; (fd = va_arg(ap, int *)) != NULL; ++i) {
142     *fd = (reinterpret_cast<int *>(CMSG_DATA(cmsg)))[i];
143   }
144   va_end(ap);
145   return true;
146 }
147
148
149 // POSIX doesn't define any async-signal safe function for converting
150 // an integer to ASCII. We'll have to define our own version.
151 // itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
152 // conversion was successful or NULL otherwise. It never writes more than "sz"
153 // bytes. Output will be truncated as needed, and a NUL character is always
154 // appended.
155 char *itoa_r(int i, char *buf, size_t sz) {
156   // Make sure we can write at least one NUL byte.
157   size_t n = 1;
158   if (n > sz) {
159     return NULL;
160   }
161
162   // Handle negative numbers.
163   char *start = buf;
164   int minint = 0;
165   if (i < 0) {
166     // Make sure we can write the '-' character.
167     if (++n > sz) {
168       *start = '\000';
169       return NULL;
170     }
171     *start++ = '-';
172
173     // Turn our number positive.
174     if (i == -i) {
175       // The lowest-most negative integer needs special treatment.
176       minint = 1;
177       i = -(i + 1);
178     } else {
179       // "Normal" negative numbers are easy.
180       i = -i;
181     }
182   }
183
184   // Loop until we have converted the entire number. Output at least one
185   // character (i.e. '0').
186   char *ptr = start;
187   do {
188     // Make sure there is still enough space left in our output buffer.
189     if (++n > sz) {
190       buf = NULL;
191       goto truncate;
192     }
193
194     // Output the next digit and (if necessary) compensate for the lowest-most
195     // negative integer needing special treatment. This works because, no
196     // matter the bit width of the integer, the lowest-most integer always ends
197     // in 2, 4, 6, or 8.
198     *ptr++ = i%10 + '0' + minint;
199     minint = 0;
200     i /= 10;
201   } while (i);
202  truncate:  // Terminate the output with a NUL character.
203   *ptr = '\000';
204
205   // Conversion to ASCII actually resulted in the digits being in reverse
206   // order. We can't easily generate them in forward order, as we can't tell
207   // the number of characters needed until we are done converting.
208   // So, now, we reverse the string (except for the possible "-" sign).
209   while (--ptr > start) {
210     char ch = *ptr;
211     *ptr = *start;
212     *start++ = ch;
213   }
214   return buf;
215 }
216
217 // This handler gets called, whenever we encounter a system call that we
218 // don't recognize explicitly. For the purposes of this program, we just
219 // log the system call and then deny it. More elaborate sandbox policies
220 // might try to evaluate the system call in user-space, instead.
221 // The only notable complication is that this function must be async-signal
222 // safe. This restricts the libary functions that we can call.
223 intptr_t DefaultHandler(const struct arch_seccomp_data& data, void *) {
224   static const char msg0[] = "Disallowed system call #";
225   static const char msg1[] = "\n";
226   char buf[sizeof(msg0) - 1 + 25 + sizeof(msg1)];
227
228   *buf = '\000';
229   strncat(buf, msg0, sizeof(buf) - 1);
230
231   char *ptr = strrchr(buf, '\000');
232   itoa_r(data.nr, ptr, sizeof(buf) - (ptr - buf));
233
234   ptr = strrchr(ptr, '\000');
235   strncat(ptr, msg1, sizeof(buf) - (ptr - buf));
236
237   ptr = strrchr(ptr, '\000');
238   if (HANDLE_EINTR(write(2, buf, ptr - buf))) { }
239
240   return -ERR;
241 }
242
243 class DemoPolicy : public SandboxBPFPolicy {
244  public:
245   DemoPolicy() {}
246   virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox,
247                                     int sysno) const OVERRIDE;
248
249  private:
250   DISALLOW_COPY_AND_ASSIGN(DemoPolicy);
251 };
252
253 ErrorCode DemoPolicy::EvaluateSyscall(SandboxBPF* sandbox, int sysno) const {
254   switch (sysno) {
255 #if defined(__NR_accept)
256   case __NR_accept: case __NR_accept4:
257 #endif
258   case __NR_alarm:
259   case __NR_brk:
260   case __NR_clock_gettime:
261   case __NR_close:
262   case __NR_dup: case __NR_dup2:
263   case __NR_epoll_create: case __NR_epoll_ctl: case __NR_epoll_wait:
264   case __NR_exit: case __NR_exit_group:
265   case __NR_fcntl:
266 #if defined(__NR_fcntl64)
267   case __NR_fcntl64:
268 #endif
269   case __NR_fdatasync:
270   case __NR_fstat:
271 #if defined(__NR_fstat64)
272   case __NR_fstat64:
273 #endif
274   case __NR_ftruncate:
275   case __NR_futex:
276   case __NR_getdents: case __NR_getdents64:
277   case __NR_getegid:
278 #if defined(__NR_getegid32)
279   case __NR_getegid32:
280 #endif
281   case __NR_geteuid:
282 #if defined(__NR_geteuid32)
283   case __NR_geteuid32:
284 #endif
285   case __NR_getgid:
286 #if defined(__NR_getgid32)
287   case __NR_getgid32:
288 #endif
289   case __NR_getitimer: case __NR_setitimer:
290 #if defined(__NR_getpeername)
291   case __NR_getpeername:
292 #endif
293   case __NR_getpid: case __NR_gettid:
294 #if defined(__NR_getsockname)
295   case __NR_getsockname:
296 #endif
297   case __NR_gettimeofday:
298   case __NR_getuid:
299 #if defined(__NR_getuid32)
300   case __NR_getuid32:
301 #endif
302 #if defined(__NR__llseek)
303   case __NR__llseek:
304 #endif
305   case __NR_lseek:
306   case __NR_nanosleep:
307   case __NR_pipe: case __NR_pipe2:
308   case __NR_poll:
309   case __NR_pread64: case __NR_preadv:
310   case __NR_pwrite64: case __NR_pwritev:
311   case __NR_read: case __NR_readv:
312   case __NR_restart_syscall:
313   case __NR_set_robust_list:
314   case __NR_rt_sigaction:
315 #if defined(__NR_sigaction)
316   case __NR_sigaction:
317 #endif
318 #if defined(__NR_signal)
319   case __NR_signal:
320 #endif
321   case __NR_rt_sigprocmask:
322 #if defined(__NR_sigprocmask)
323   case __NR_sigprocmask:
324 #endif
325 #if defined(__NR_shutdown)
326   case __NR_shutdown:
327 #endif
328   case __NR_rt_sigreturn:
329 #if defined(__NR_sigreturn)
330   case __NR_sigreturn:
331 #endif
332 #if defined(__NR_socketpair)
333   case __NR_socketpair:
334 #endif
335   case __NR_time:
336   case __NR_uname:
337   case __NR_write: case __NR_writev:
338     return ErrorCode(ErrorCode::ERR_ALLOWED);
339
340   case __NR_prctl:
341     // Allow PR_SET_DUMPABLE and PR_GET_DUMPABLE. Do not allow anything else.
342     return sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
343                          PR_SET_DUMPABLE,
344                          ErrorCode(ErrorCode::ERR_ALLOWED),
345            sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
346                          PR_GET_DUMPABLE,
347                          ErrorCode(ErrorCode::ERR_ALLOWED),
348            sandbox->Trap(DefaultHandler, NULL)));
349
350   // The following system calls are temporarily permitted. This must be
351   // tightened later. But we currently don't implement enough of the sandboxing
352   // API to do so.
353   // As is, this sandbox isn't exactly safe :-/
354 #if defined(__NR_sendmsg)
355   case __NR_sendmsg: case __NR_sendto:
356   case __NR_recvmsg: case __NR_recvfrom:
357   case __NR_getsockopt: case __NR_setsockopt:
358 #elif defined(__NR_socketcall)
359   case __NR_socketcall:
360 #endif
361 #if defined(__NR_shmat)
362   case __NR_shmat: case __NR_shmctl: case __NR_shmdt: case __NR_shmget:
363 #elif defined(__NR_ipc)
364   case __NR_ipc:
365 #endif
366 #if defined(__NR_mmap2)
367   case __NR_mmap2:
368 #else
369   case __NR_mmap:
370 #endif
371 #if defined(__NR_ugetrlimit)
372   case __NR_ugetrlimit:
373 #endif
374   case __NR_getrlimit:
375   case __NR_ioctl:
376   case __NR_clone:
377   case __NR_munmap: case __NR_mprotect: case __NR_madvise:
378   case __NR_remap_file_pages:
379     return ErrorCode(ErrorCode::ERR_ALLOWED);
380
381   // Everything that isn't explicitly allowed is denied.
382   default:
383     return sandbox->Trap(DefaultHandler, NULL);
384   }
385 }
386
387 void *ThreadFnc(void *arg) {
388   return arg;
389 }
390
391 void *SendmsgStressThreadFnc(void *arg) {
392   if (arg) { }
393   static const int repetitions = 100;
394   static const int kNumFds = 3;
395   for (int rep = 0; rep < repetitions; ++rep) {
396     int fds[2 + kNumFds];
397     if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
398       perror("socketpair()");
399       _exit(1);
400     }
401     size_t len = 4;
402     char buf[4];
403     if (!SendFds(fds[0], "test", 4, fds[1], fds[1], fds[1], -1) ||
404         !GetFds(fds[1], buf, &len, fds+2, fds+3, fds+4, NULL) ||
405         len != 4 ||
406         memcmp(buf, "test", len) ||
407         write(fds[2], "demo", 4) != 4 ||
408         read(fds[0], buf, 4) != 4 ||
409         memcmp(buf, "demo", 4)) {
410       perror("sending/receiving of fds");
411       _exit(1);
412     }
413     for (int i = 0; i < 2+kNumFds; ++i) {
414       if (close(fds[i])) {
415         perror("close");
416         _exit(1);
417       }
418     }
419   }
420   return NULL;
421 }
422
423 }  // namespace
424
425 int main(int argc, char *argv[]) {
426   if (argc) { }
427   if (argv) { }
428   int proc_fd = open("/proc", O_RDONLY|O_DIRECTORY);
429   if (SandboxBPF::SupportsSeccompSandbox(proc_fd) !=
430       SandboxBPF::STATUS_AVAILABLE) {
431     perror("sandbox");
432     _exit(1);
433   }
434   SandboxBPF sandbox;
435   sandbox.set_proc_fd(proc_fd);
436   sandbox.SetSandboxPolicy(new DemoPolicy());
437   if (!sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)) {
438     fprintf(stderr, "StartSandbox() failed");
439     _exit(1);
440   }
441
442   // Check that we can create threads
443   pthread_t thr;
444   if (!pthread_create(&thr, NULL, ThreadFnc,
445                       reinterpret_cast<void *>(0x1234))) {
446     void *ret;
447     pthread_join(thr, &ret);
448     if (ret != reinterpret_cast<void *>(0x1234)) {
449       perror("clone() failed");
450       _exit(1);
451     }
452   } else {
453     perror("clone() failed");
454     _exit(1);
455   }
456
457   // Check that we handle restart_syscall() without dieing. This is a little
458   // tricky to trigger. And I can't think of a good way to verify whether it
459   // actually executed.
460   signal(SIGALRM, SIG_IGN);
461   const struct itimerval tv = { { 0, 0 }, { 0, 5*1000 } };
462   const struct timespec tmo = { 0, 100*1000*1000 };
463   setitimer(ITIMER_REAL, &tv, NULL);
464   nanosleep(&tmo, NULL);
465
466   // Check that we can query the size of the stack, but that all other
467   // calls to getrlimit() fail.
468   if (((errno = 0), !getrlimit(RLIMIT_STACK, NULL)) || errno != EFAULT ||
469       ((errno = 0), !getrlimit(RLIMIT_CORE,  NULL)) || errno != ERR) {
470     perror("getrlimit()");
471     _exit(1);
472   }
473
474   // Check that we can query TCGETS and TIOCGWINSZ, but no other ioctls().
475   if (((errno = 0), !ioctl(2, TCGETS,     NULL)) || errno != EFAULT ||
476       ((errno = 0), !ioctl(2, TIOCGWINSZ, NULL)) || errno != EFAULT ||
477       ((errno = 0), !ioctl(2, TCSETS,     NULL)) || errno != ERR) {
478     perror("ioctl()");
479     _exit(1);
480   }
481
482   // Check that prctl() can manipulate the dumpable flag, but nothing else.
483   if (((errno = 0), !prctl(PR_GET_DUMPABLE))    || errno ||
484       ((errno = 0),  prctl(PR_SET_DUMPABLE, 1)) || errno ||
485       ((errno = 0), !prctl(PR_SET_SECCOMP,  0)) || errno != ERR) {
486     perror("prctl()");
487     _exit(1);
488   }
489
490   // Check that we can send and receive file handles.
491   int fds[3];
492   if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
493     perror("socketpair()");
494     _exit(1);
495   }
496   size_t len = 4;
497   char buf[4];
498   if (!SendFds(fds[0], "test", 4, fds[1], -1) ||
499       !GetFds(fds[1], buf, &len, fds+2, NULL) ||
500       len != 4 ||
501       memcmp(buf, "test", len) ||
502       write(fds[2], "demo", 4) != 4 ||
503       read(fds[0], buf, 4) != 4 ||
504       memcmp(buf, "demo", 4) ||
505       close(fds[0]) ||
506       close(fds[1]) ||
507       close(fds[2])) {
508     perror("sending/receiving of fds");
509     _exit(1);
510   }
511
512   // Check whether SysV IPC works.
513   int shmid;
514   void *addr;
515   if ((shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|0600)) < 0 ||
516       (addr = shmat(shmid, NULL, 0)) == reinterpret_cast<void *>(-1) ||
517       shmdt(addr) ||
518       shmctl(shmid, IPC_RMID, NULL)) {
519     perror("sysv IPC");
520     _exit(1);
521   }
522
523   // Print a message so that the user can see the sandbox is activated.
524   time_t tm = time(NULL);
525   printf("Sandbox has been started at %s", ctime(&tm));
526
527   // Stress-test the sendmsg() code
528   static const int kSendmsgStressNumThreads = 10;
529   pthread_t sendmsgStressThreads[kSendmsgStressNumThreads];
530   for (int i = 0; i < kSendmsgStressNumThreads; ++i) {
531     if (pthread_create(sendmsgStressThreads + i, NULL,
532                        SendmsgStressThreadFnc, NULL)) {
533       perror("pthread_create");
534       _exit(1);
535     }
536   }
537   for (int i = 0; i < kSendmsgStressNumThreads; ++i) {
538     pthread_join(sendmsgStressThreads[i], NULL);
539   }
540
541   return 0;
542 }