| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <errno.h> | 5 #include <errno.h> |
| 6 #include <fcntl.h> | 6 #include <fcntl.h> |
| 7 #include <linux/unistd.h> | 7 #include <linux/unistd.h> |
| 8 #include <netinet/in.h> | 8 #include <netinet/in.h> |
| 9 #include <netinet/tcp.h> | 9 #include <netinet/tcp.h> |
| 10 #include <netinet/udp.h> | 10 #include <netinet/udp.h> |
| 11 #include <pthread.h> | 11 #include <pthread.h> |
| 12 #include <signal.h> | 12 #include <signal.h> |
| 13 #include <stdarg.h> |
| 13 #include <stdio.h> | 14 #include <stdio.h> |
| 14 #include <stdlib.h> | 15 #include <stdlib.h> |
| 15 #include <string.h> | 16 #include <string.h> |
| 16 #include <sys/ioctl.h> | 17 #include <sys/ioctl.h> |
| 17 #include <sys/ipc.h> | 18 #include <sys/ipc.h> |
| 18 #include <sys/mman.h> | 19 #include <sys/mman.h> |
| 19 #include <sys/prctl.h> | 20 #include <sys/prctl.h> |
| 20 #include <sys/resource.h> | 21 #include <sys/resource.h> |
| 21 #include <sys/shm.h> | 22 #include <sys/shm.h> |
| 22 #include <sys/socket.h> | 23 #include <sys/socket.h> |
| 23 #include <sys/time.h> | 24 #include <sys/time.h> |
| 24 #include <sys/types.h> | 25 #include <sys/types.h> |
| 25 #include <time.h> | 26 #include <time.h> |
| 26 #include <unistd.h> | 27 #include <unistd.h> |
| 27 | 28 |
| 28 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 29 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| 29 #include "sandbox/linux/seccomp-bpf/util.h" | |
| 30 | 30 |
| 31 using playground2::arch_seccomp_data; | 31 using playground2::arch_seccomp_data; |
| 32 using playground2::ErrorCode; | 32 using playground2::ErrorCode; |
| 33 using playground2::Sandbox; | 33 using playground2::Sandbox; |
| 34 using playground2::Util; | |
| 35 | 34 |
| 36 #define ERR EPERM | 35 #define ERR EPERM |
| 37 | 36 |
| 38 // We don't expect our sandbox to do anything useful yet. So, we will fail | 37 // We don't expect our sandbox to do anything useful yet. So, we will fail |
| 39 // almost immediately. For now, force the code to continue running. The | 38 // almost immediately. For now, force the code to continue running. The |
| 40 // following line should be removed as soon as the sandbox is starting to | 39 // following line should be removed as soon as the sandbox is starting to |
| 41 // actually enforce restrictions in a meaningful way: | 40 // actually enforce restrictions in a meaningful way: |
| 42 #define _exit(x) do { } while (0) | 41 #define _exit(x) do { } while (0) |
| 43 | 42 |
| 43 namespace { |
| 44 |
| 45 bool SendFds(int transport, const void *buf, size_t len, ...) { |
| 46 int count = 0; |
| 47 va_list ap; |
| 48 va_start(ap, len); |
| 49 while (va_arg(ap, int) >= 0) { |
| 50 ++count; |
| 51 } |
| 52 va_end(ap); |
| 53 if (!count) { |
| 54 return false; |
| 55 } |
| 56 char cmsg_buf[CMSG_SPACE(count*sizeof(int))]; |
| 57 memset(cmsg_buf, 0, sizeof(cmsg_buf)); |
| 58 struct iovec iov[2] = { { 0 } }; |
| 59 struct msghdr msg = { 0 }; |
| 60 int dummy = 0; |
| 61 iov[0].iov_base = &dummy; |
| 62 iov[0].iov_len = sizeof(dummy); |
| 63 if (buf && len > 0) { |
| 64 iov[1].iov_base = const_cast<void *>(buf); |
| 65 iov[1].iov_len = len; |
| 66 } |
| 67 msg.msg_iov = iov; |
| 68 msg.msg_iovlen = (buf && len > 0) ? 2 : 1; |
| 69 msg.msg_control = cmsg_buf; |
| 70 msg.msg_controllen = CMSG_LEN(count*sizeof(int)); |
| 71 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); |
| 72 cmsg->cmsg_level = SOL_SOCKET; |
| 73 cmsg->cmsg_type = SCM_RIGHTS; |
| 74 cmsg->cmsg_len = CMSG_LEN(count*sizeof(int)); |
| 75 va_start(ap, len); |
| 76 for (int i = 0, fd; (fd = va_arg(ap, int)) >= 0; ++i) { |
| 77 (reinterpret_cast<int *>(CMSG_DATA(cmsg)))[i] = fd; |
| 78 } |
| 79 return sendmsg(transport, &msg, 0) == |
| 80 static_cast<ssize_t>(sizeof(dummy) + ((buf && len > 0) ? len : 0)); |
| 81 } |
| 82 |
| 83 bool GetFds(int transport, void *buf, size_t *len, ...) { |
| 84 int count = 0; |
| 85 va_list ap; |
| 86 va_start(ap, len); |
| 87 for (int *fd; (fd = va_arg(ap, int *)) != NULL; ++count) { |
| 88 *fd = -1; |
| 89 } |
| 90 va_end(ap); |
| 91 if (!count) { |
| 92 return false; |
| 93 } |
| 94 char cmsg_buf[CMSG_SPACE(count*sizeof(int))]; |
| 95 memset(cmsg_buf, 0, sizeof(cmsg_buf)); |
| 96 struct iovec iov[2] = { { 0 } }; |
| 97 struct msghdr msg = { 0 }; |
| 98 int err; |
| 99 iov[0].iov_base = &err; |
| 100 iov[0].iov_len = sizeof(int); |
| 101 if (buf && len && *len > 0) { |
| 102 iov[1].iov_base = buf; |
| 103 iov[1].iov_len = *len; |
| 104 } |
| 105 msg.msg_iov = iov; |
| 106 msg.msg_iovlen = (buf && len && *len > 0) ? 2 : 1; |
| 107 msg.msg_control = cmsg_buf; |
| 108 msg.msg_controllen = CMSG_LEN(count*sizeof(int)); |
| 109 ssize_t bytes = recvmsg(transport, &msg, 0); |
| 110 if (len) { |
| 111 *len = bytes > static_cast<int>(sizeof(int)) ? bytes - sizeof(int) : 0; |
| 112 } |
| 113 if (bytes != static_cast<ssize_t>(sizeof(int) + iov[1].iov_len)) { |
| 114 if (bytes >= 0) { |
| 115 errno = 0; |
| 116 } |
| 117 return false; |
| 118 } |
| 119 if (err) { |
| 120 // "err" is the first four bytes of the payload. If these are non-zero, |
| 121 // the sender on the other side of the socketpair sent us an errno value. |
| 122 // We don't expect to get any file handles in this case. |
| 123 errno = err; |
| 124 return false; |
| 125 } |
| 126 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); |
| 127 if ((msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) || |
| 128 !cmsg || |
| 129 cmsg->cmsg_level != SOL_SOCKET || |
| 130 cmsg->cmsg_type != SCM_RIGHTS || |
| 131 cmsg->cmsg_len != CMSG_LEN(count*sizeof(int))) { |
| 132 errno = EBADF; |
| 133 return false; |
| 134 } |
| 135 va_start(ap, len); |
| 136 for (int *fd, i = 0; (fd = va_arg(ap, int *)) != NULL; ++i) { |
| 137 *fd = (reinterpret_cast<int *>(CMSG_DATA(cmsg)))[i]; |
| 138 } |
| 139 va_end(ap); |
| 140 return true; |
| 141 } |
| 142 |
| 44 | 143 |
| 45 // POSIX doesn't define any async-signal safe function for converting | 144 // POSIX doesn't define any async-signal safe function for converting |
| 46 // an integer to ASCII. We'll have to define our own version. | 145 // an integer to ASCII. We'll have to define our own version. |
| 47 // itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the | 146 // itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the |
| 48 // conversion was successful or NULL otherwise. It never writes more than "sz" | 147 // conversion was successful or NULL otherwise. It never writes more than "sz" |
| 49 // bytes. Output will be truncated as needed, and a NUL character is always | 148 // bytes. Output will be truncated as needed, and a NUL character is always |
| 50 // appended. | 149 // appended. |
| 51 static char *itoa_r(int i, char *buf, size_t sz) { | 150 char *itoa_r(int i, char *buf, size_t sz) { |
| 52 // Make sure we can write at least one NUL byte. | 151 // Make sure we can write at least one NUL byte. |
| 53 size_t n = 1; | 152 size_t n = 1; |
| 54 if (n > sz) { | 153 if (n > sz) { |
| 55 return NULL; | 154 return NULL; |
| 56 } | 155 } |
| 57 | 156 |
| 58 // Handle negative numbers. | 157 // Handle negative numbers. |
| 59 char *start = buf; | 158 char *start = buf; |
| 60 int minint = 0; | 159 int minint = 0; |
| 61 if (i < 0) { | 160 if (i < 0) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 } | 208 } |
| 110 return buf; | 209 return buf; |
| 111 } | 210 } |
| 112 | 211 |
| 113 // This handler gets called, whenever we encounter a system call that we | 212 // This handler gets called, whenever we encounter a system call that we |
| 114 // don't recognize explicitly. For the purposes of this program, we just | 213 // don't recognize explicitly. For the purposes of this program, we just |
| 115 // log the system call and then deny it. More elaborate sandbox policies | 214 // log the system call and then deny it. More elaborate sandbox policies |
| 116 // might try to evaluate the system call in user-space, instead. | 215 // might try to evaluate the system call in user-space, instead. |
| 117 // The only notable complication is that this function must be async-signal | 216 // The only notable complication is that this function must be async-signal |
| 118 // safe. This restricts the libary functions that we can call. | 217 // safe. This restricts the libary functions that we can call. |
| 119 static intptr_t defaultHandler(const struct arch_seccomp_data& data, | 218 intptr_t DefaultHandler(const struct arch_seccomp_data& data, void *) { |
| 120 void *) { | |
| 121 static const char msg0[] = "Disallowed system call #"; | 219 static const char msg0[] = "Disallowed system call #"; |
| 122 static const char msg1[] = "\n"; | 220 static const char msg1[] = "\n"; |
| 123 char buf[sizeof(msg0) - 1 + 25 + sizeof(msg1)]; | 221 char buf[sizeof(msg0) - 1 + 25 + sizeof(msg1)]; |
| 124 | 222 |
| 125 *buf = '\000'; | 223 *buf = '\000'; |
| 126 strncat(buf, msg0, sizeof(buf)); | 224 strncat(buf, msg0, sizeof(buf)); |
| 127 | 225 |
| 128 char *ptr = strrchr(buf, '\000'); | 226 char *ptr = strrchr(buf, '\000'); |
| 129 itoa_r(data.nr, ptr, sizeof(buf) - (ptr - buf)); | 227 itoa_r(data.nr, ptr, sizeof(buf) - (ptr - buf)); |
| 130 | 228 |
| 131 ptr = strrchr(ptr, '\000'); | 229 ptr = strrchr(ptr, '\000'); |
| 132 strncat(ptr, msg1, sizeof(buf) - (ptr - buf)); | 230 strncat(ptr, msg1, sizeof(buf) - (ptr - buf)); |
| 133 | 231 |
| 134 ptr = strrchr(ptr, '\000'); | 232 ptr = strrchr(ptr, '\000'); |
| 135 if (HANDLE_EINTR(write(2, buf, ptr - buf))) { } | 233 if (HANDLE_EINTR(write(2, buf, ptr - buf))) { } |
| 136 | 234 |
| 137 return -ERR; | 235 return -ERR; |
| 138 } | 236 } |
| 139 | 237 |
| 140 static ErrorCode evaluator(int sysno, void *) { | 238 ErrorCode Evaluator(Sandbox *sandbox, int sysno, void *) { |
| 141 switch (sysno) { | 239 switch (sysno) { |
| 142 #if defined(__NR_accept) | 240 #if defined(__NR_accept) |
| 143 case __NR_accept: case __NR_accept4: | 241 case __NR_accept: case __NR_accept4: |
| 144 #endif | 242 #endif |
| 145 case __NR_alarm: | 243 case __NR_alarm: |
| 146 case __NR_brk: | 244 case __NR_brk: |
| 147 case __NR_clock_gettime: | 245 case __NR_clock_gettime: |
| 148 case __NR_close: | 246 case __NR_close: |
| 149 case __NR_dup: case __NR_dup2: | 247 case __NR_dup: case __NR_dup2: |
| 150 case __NR_epoll_create: case __NR_epoll_ctl: case __NR_epoll_wait: | 248 case __NR_epoll_create: case __NR_epoll_ctl: case __NR_epoll_wait: |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 #if defined(__NR_socketpair) | 317 #if defined(__NR_socketpair) |
| 220 case __NR_socketpair: | 318 case __NR_socketpair: |
| 221 #endif | 319 #endif |
| 222 case __NR_time: | 320 case __NR_time: |
| 223 case __NR_uname: | 321 case __NR_uname: |
| 224 case __NR_write: case __NR_writev: | 322 case __NR_write: case __NR_writev: |
| 225 return ErrorCode(ErrorCode::ERR_ALLOWED); | 323 return ErrorCode(ErrorCode::ERR_ALLOWED); |
| 226 | 324 |
| 227 case __NR_prctl: | 325 case __NR_prctl: |
| 228 // Allow PR_SET_DUMPABLE and PR_GET_DUMPABLE. Do not allow anything else. | 326 // Allow PR_SET_DUMPABLE and PR_GET_DUMPABLE. Do not allow anything else. |
| 229 return Sandbox::Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 327 return sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, |
| 230 PR_SET_DUMPABLE, | 328 PR_SET_DUMPABLE, |
| 231 ErrorCode(ErrorCode::ERR_ALLOWED), | 329 ErrorCode(ErrorCode::ERR_ALLOWED), |
| 232 Sandbox::Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 330 sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, |
| 233 PR_GET_DUMPABLE, | 331 PR_GET_DUMPABLE, |
| 234 ErrorCode(ErrorCode::ERR_ALLOWED), | 332 ErrorCode(ErrorCode::ERR_ALLOWED), |
| 235 Sandbox::Trap(defaultHandler, NULL))); | 333 sandbox->Trap(DefaultHandler, NULL))); |
| 236 | 334 |
| 237 // The following system calls are temporarily permitted. This must be | 335 // The following system calls are temporarily permitted. This must be |
| 238 // tightened later. But we currently don't implement enough of the sandboxing | 336 // tightened later. But we currently don't implement enough of the sandboxing |
| 239 // API to do so. | 337 // API to do so. |
| 240 // As is, this sandbox isn't exactly safe :-/ | 338 // As is, this sandbox isn't exactly safe :-/ |
| 241 #if defined(__NR_sendmsg) | 339 #if defined(__NR_sendmsg) |
| 242 case __NR_sendmsg: case __NR_sendto: | 340 case __NR_sendmsg: case __NR_sendto: |
| 243 case __NR_recvmsg: case __NR_recvfrom: | 341 case __NR_recvmsg: case __NR_recvfrom: |
| 244 case __NR_getsockopt: case __NR_setsockopt: | 342 case __NR_getsockopt: case __NR_setsockopt: |
| 245 #elif defined(__NR_socketcall) | 343 #elif defined(__NR_socketcall) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 260 #endif | 358 #endif |
| 261 case __NR_getrlimit: | 359 case __NR_getrlimit: |
| 262 case __NR_ioctl: | 360 case __NR_ioctl: |
| 263 case __NR_clone: | 361 case __NR_clone: |
| 264 case __NR_munmap: case __NR_mprotect: case __NR_madvise: | 362 case __NR_munmap: case __NR_mprotect: case __NR_madvise: |
| 265 case __NR_remap_file_pages: | 363 case __NR_remap_file_pages: |
| 266 return ErrorCode(ErrorCode::ERR_ALLOWED); | 364 return ErrorCode(ErrorCode::ERR_ALLOWED); |
| 267 | 365 |
| 268 // Everything that isn't explicitly allowed is denied. | 366 // Everything that isn't explicitly allowed is denied. |
| 269 default: | 367 default: |
| 270 return Sandbox::Trap(defaultHandler, NULL); | 368 return sandbox->Trap(DefaultHandler, NULL); |
| 271 } | 369 } |
| 272 } | 370 } |
| 273 | 371 |
| 274 static void *threadFnc(void *arg) { | 372 void *ThreadFnc(void *arg) { |
| 275 return arg; | 373 return arg; |
| 276 } | 374 } |
| 277 | 375 |
| 278 static void *sendmsgStressThreadFnc(void *arg) { | 376 void *SendmsgStressThreadFnc(void *arg) { |
| 279 if (arg) { } | 377 if (arg) { } |
| 280 static const int repetitions = 100; | 378 static const int repetitions = 100; |
| 281 static const int kNumFds = 3; | 379 static const int kNumFds = 3; |
| 282 for (int rep = 0; rep < repetitions; ++rep) { | 380 for (int rep = 0; rep < repetitions; ++rep) { |
| 283 int fds[2 + kNumFds]; | 381 int fds[2 + kNumFds]; |
| 284 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { | 382 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { |
| 285 perror("socketpair()"); | 383 perror("socketpair()"); |
| 286 _exit(1); | 384 _exit(1); |
| 287 } | 385 } |
| 288 size_t len = 4; | 386 size_t len = 4; |
| 289 char buf[4]; | 387 char buf[4]; |
| 290 if (!Util::SendFds(fds[0], "test", 4, fds[1], fds[1], fds[1], -1) || | 388 if (!SendFds(fds[0], "test", 4, fds[1], fds[1], fds[1], -1) || |
| 291 !Util::GetFds(fds[1], buf, &len, fds+2, fds+3, fds+4, NULL) || | 389 !GetFds(fds[1], buf, &len, fds+2, fds+3, fds+4, NULL) || |
| 292 len != 4 || | 390 len != 4 || |
| 293 memcmp(buf, "test", len) || | 391 memcmp(buf, "test", len) || |
| 294 write(fds[2], "demo", 4) != 4 || | 392 write(fds[2], "demo", 4) != 4 || |
| 295 read(fds[0], buf, 4) != 4 || | 393 read(fds[0], buf, 4) != 4 || |
| 296 memcmp(buf, "demo", 4)) { | 394 memcmp(buf, "demo", 4)) { |
| 297 perror("sending/receiving of fds"); | 395 perror("sending/receiving of fds"); |
| 298 _exit(1); | 396 _exit(1); |
| 299 } | 397 } |
| 300 for (int i = 0; i < 2+kNumFds; ++i) { | 398 for (int i = 0; i < 2+kNumFds; ++i) { |
| 301 if (close(fds[i])) { | 399 if (close(fds[i])) { |
| 302 perror("close"); | 400 perror("close"); |
| 303 _exit(1); | 401 _exit(1); |
| 304 } | 402 } |
| 305 } | 403 } |
| 306 } | 404 } |
| 307 return NULL; | 405 return NULL; |
| 308 } | 406 } |
| 309 | 407 |
| 408 } // namespace |
| 409 |
| 310 int main(int argc, char *argv[]) { | 410 int main(int argc, char *argv[]) { |
| 311 if (argc) { } | 411 if (argc) { } |
| 312 if (argv) { } | 412 if (argv) { } |
| 313 int proc_fd = open("/proc", O_RDONLY|O_DIRECTORY); | 413 int proc_fd = open("/proc", O_RDONLY|O_DIRECTORY); |
| 314 if (Sandbox::SupportsSeccompSandbox(proc_fd) != | 414 if (Sandbox::SupportsSeccompSandbox(proc_fd) != |
| 315 Sandbox::STATUS_AVAILABLE) { | 415 Sandbox::STATUS_AVAILABLE) { |
| 316 perror("sandbox"); | 416 perror("sandbox"); |
| 317 _exit(1); | 417 _exit(1); |
| 318 } | 418 } |
| 319 Sandbox::set_proc_fd(proc_fd); | 419 Sandbox sandbox; |
| 320 Sandbox::SetSandboxPolicy(evaluator, NULL); | 420 sandbox.set_proc_fd(proc_fd); |
| 321 Sandbox::StartSandbox(); | 421 sandbox.SetSandboxPolicy(Evaluator, NULL); |
| 422 sandbox.StartSandbox(); |
| 322 | 423 |
| 323 // Check that we can create threads | 424 // Check that we can create threads |
| 324 pthread_t thr; | 425 pthread_t thr; |
| 325 if (!pthread_create(&thr, NULL, threadFnc, | 426 if (!pthread_create(&thr, NULL, ThreadFnc, |
| 326 reinterpret_cast<void *>(0x1234))) { | 427 reinterpret_cast<void *>(0x1234))) { |
| 327 void *ret; | 428 void *ret; |
| 328 pthread_join(thr, &ret); | 429 pthread_join(thr, &ret); |
| 329 if (ret != reinterpret_cast<void *>(0x1234)) { | 430 if (ret != reinterpret_cast<void *>(0x1234)) { |
| 330 perror("clone() failed"); | 431 perror("clone() failed"); |
| 331 _exit(1); | 432 _exit(1); |
| 332 } | 433 } |
| 333 } else { | 434 } else { |
| 334 perror("clone() failed"); | 435 perror("clone() failed"); |
| 335 _exit(1); | 436 _exit(1); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 } | 470 } |
| 370 | 471 |
| 371 // Check that we can send and receive file handles. | 472 // Check that we can send and receive file handles. |
| 372 int fds[3]; | 473 int fds[3]; |
| 373 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { | 474 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { |
| 374 perror("socketpair()"); | 475 perror("socketpair()"); |
| 375 _exit(1); | 476 _exit(1); |
| 376 } | 477 } |
| 377 size_t len = 4; | 478 size_t len = 4; |
| 378 char buf[4]; | 479 char buf[4]; |
| 379 if (!Util::SendFds(fds[0], "test", 4, fds[1], -1) || | 480 if (!SendFds(fds[0], "test", 4, fds[1], -1) || |
| 380 !Util::GetFds(fds[1], buf, &len, fds+2, NULL) || | 481 !GetFds(fds[1], buf, &len, fds+2, NULL) || |
| 381 len != 4 || | 482 len != 4 || |
| 382 memcmp(buf, "test", len) || | 483 memcmp(buf, "test", len) || |
| 383 write(fds[2], "demo", 4) != 4 || | 484 write(fds[2], "demo", 4) != 4 || |
| 384 read(fds[0], buf, 4) != 4 || | 485 read(fds[0], buf, 4) != 4 || |
| 385 memcmp(buf, "demo", 4) || | 486 memcmp(buf, "demo", 4) || |
| 386 close(fds[0]) || | 487 close(fds[0]) || |
| 387 close(fds[1]) || | 488 close(fds[1]) || |
| 388 close(fds[2])) { | 489 close(fds[2])) { |
| 389 perror("sending/receiving of fds"); | 490 perror("sending/receiving of fds"); |
| 390 _exit(1); | 491 _exit(1); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 403 | 504 |
| 404 // Print a message so that the user can see the sandbox is activated. | 505 // Print a message so that the user can see the sandbox is activated. |
| 405 time_t tm = time(NULL); | 506 time_t tm = time(NULL); |
| 406 printf("Sandbox has been started at %s", ctime(&tm)); | 507 printf("Sandbox has been started at %s", ctime(&tm)); |
| 407 | 508 |
| 408 // Stress-test the sendmsg() code | 509 // Stress-test the sendmsg() code |
| 409 static const int kSendmsgStressNumThreads = 10; | 510 static const int kSendmsgStressNumThreads = 10; |
| 410 pthread_t sendmsgStressThreads[kSendmsgStressNumThreads]; | 511 pthread_t sendmsgStressThreads[kSendmsgStressNumThreads]; |
| 411 for (int i = 0; i < kSendmsgStressNumThreads; ++i) { | 512 for (int i = 0; i < kSendmsgStressNumThreads; ++i) { |
| 412 if (pthread_create(sendmsgStressThreads + i, NULL, | 513 if (pthread_create(sendmsgStressThreads + i, NULL, |
| 413 sendmsgStressThreadFnc, NULL)) { | 514 SendmsgStressThreadFnc, NULL)) { |
| 414 perror("pthread_create"); | 515 perror("pthread_create"); |
| 415 _exit(1); | 516 _exit(1); |
| 416 } | 517 } |
| 417 } | 518 } |
| 418 for (int i = 0; i < kSendmsgStressNumThreads; ++i) { | 519 for (int i = 0; i < kSendmsgStressNumThreads; ++i) { |
| 419 pthread_join(sendmsgStressThreads[i], NULL); | 520 pthread_join(sendmsgStressThreads[i], NULL); |
| 420 } | 521 } |
| 421 | 522 |
| 422 return 0; | 523 return 0; |
| 423 } | 524 } |
| OLD | NEW |