OLD | NEW |
(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.h" |
| 25 #include "util.h" |
| 26 |
| 27 #define ERR EPERM |
| 28 |
| 29 |
| 30 static void *threadFnc(void *arg) { |
| 31 return arg; |
| 32 } |
| 33 |
| 34 static void *sendmsgStressThreadFnc(void *arg) { |
| 35 static const int repetitions = 100; |
| 36 static const int numFds = 3; |
| 37 for (int rep = 0; rep < repetitions; ++rep) { |
| 38 int fds[2 + numFds]; |
| 39 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { |
| 40 perror("socketpair()"); |
| 41 _exit(1); |
| 42 } |
| 43 size_t len = 4; |
| 44 char buf[4]; |
| 45 if (!playground2::Util::sendFds(fds[0], "test", 4, |
| 46 fds[1], fds[1], fds[1], -1) || |
| 47 !playground2::Util::getFds(fds[1], buf, &len, |
| 48 fds+2, fds+3, fds+4, NULL) || |
| 49 len != 4 || |
| 50 memcmp(buf, "test", len) || |
| 51 write(fds[2], "demo", 4) != 4 || |
| 52 read(fds[0], buf, 4) != 4 || |
| 53 memcmp(buf, "demo", 4)) { |
| 54 perror("sending/receiving of fds"); |
| 55 _exit(1); |
| 56 } |
| 57 for (int i = 0; i < 2+numFds; ++i) { |
| 58 if (close(fds[i])) { |
| 59 perror("close"); |
| 60 _exit(1); |
| 61 } |
| 62 } |
| 63 } |
| 64 return NULL; |
| 65 } |
| 66 |
| 67 int main(int argc, char *argv[]) { |
| 68 int proc_fd = open("/proc", O_RDONLY|O_DIRECTORY); |
| 69 if (!SupportsSeccomp2Sandbox(proc_fd)) { |
| 70 perror("sandbox"); |
| 71 _exit(1); |
| 72 } |
| 73 Seccomp2SandboxSetProcFd(proc_fd); |
| 74 StartSeccomp2Sandbox(); |
| 75 |
| 76 // Check that we can create threads |
| 77 pthread_t thr; |
| 78 if (!pthread_create(&thr, NULL, threadFnc, (void *)0x1234)) { |
| 79 void *ret; |
| 80 pthread_join(thr, &ret); |
| 81 if (ret != (void *)0x1234) { |
| 82 perror("clone() failed"); |
| 83 _exit(1); |
| 84 } |
| 85 } else { |
| 86 perror("clone() failed"); |
| 87 _exit(1); |
| 88 } |
| 89 |
| 90 // Check that we handle restart_syscall() without dieing. This is a little |
| 91 // tricky to trigger. And I can't think of a good way to verify whether it |
| 92 // actually executed. |
| 93 signal(SIGALRM, SIG_IGN); |
| 94 const struct itimerval tv = { { 0, 0 }, { 0, 5*1000 } }; |
| 95 const struct timespec tmo = { 0, 100*1000*1000 }; |
| 96 setitimer(ITIMER_REAL, &tv, NULL); |
| 97 nanosleep(&tmo, NULL); |
| 98 |
| 99 // Check that we can query the size of the stack, but that all other |
| 100 // calls to getrlimit() fail. |
| 101 if (((errno = 0), !getrlimit(RLIMIT_STACK, NULL)) || errno != EFAULT || |
| 102 ((errno = 0), !getrlimit(RLIMIT_CORE, NULL)) || errno != ERR) { |
| 103 perror("getrlimit()"); |
| 104 _exit(1); |
| 105 } |
| 106 |
| 107 // Check that we can query TCGETS and TIOCGWINSZ, but no other ioctls(). |
| 108 if (((errno = 0), !ioctl(2, TCGETS, NULL)) || errno != EFAULT || |
| 109 ((errno = 0), !ioctl(2, TIOCGWINSZ, NULL)) || errno != EFAULT || |
| 110 ((errno = 0), !ioctl(2, TCSETS, NULL)) || errno != ERR) { |
| 111 perror("ioctl()"); |
| 112 _exit(1); |
| 113 } |
| 114 |
| 115 // Check that prctl() can manipulate the dumpable flag, but nothing else. |
| 116 if (((errno = 0), !prctl(PR_GET_DUMPABLE)) || errno || |
| 117 ((errno = 0), prctl(PR_SET_DUMPABLE, 1)) || errno || |
| 118 ((errno = 0), !prctl(PR_SET_SECCOMP, 0)) || errno != ERR) { |
| 119 perror("prctl()"); |
| 120 _exit(1); |
| 121 } |
| 122 |
| 123 // Check that we can send and receive file handles. |
| 124 int fds[3]; |
| 125 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { |
| 126 perror("socketpair()"); |
| 127 _exit(1); |
| 128 } |
| 129 size_t len = 4; |
| 130 char buf[4]; |
| 131 if (!playground2::Util::sendFds(fds[0], "test", 4, fds[1], -1) || |
| 132 !playground2::Util::getFds(fds[1], buf, &len, fds+2, NULL) || |
| 133 len != 4 || |
| 134 memcmp(buf, "test", len) || |
| 135 write(fds[2], "demo", 4) != 4 || |
| 136 read(fds[0], buf, 4) != 4 || |
| 137 memcmp(buf, "demo", 4) || |
| 138 close(fds[0]) || |
| 139 close(fds[1]) || |
| 140 close(fds[2])) { |
| 141 perror("sending/receiving of fds"); |
| 142 _exit(1); |
| 143 } |
| 144 |
| 145 // Check whether SysV IPC works. |
| 146 int shmid; |
| 147 void *addr; |
| 148 if ((shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|0600)) < 0 || |
| 149 (addr = shmat(shmid, NULL, 0)) == (void *)-1 || |
| 150 shmdt(addr) || |
| 151 shmctl(shmid, IPC_RMID, NULL)) { |
| 152 perror("sysv IPC"); |
| 153 _exit(1); |
| 154 } |
| 155 |
| 156 // Print a message so that the user can see the sandbox is activated. |
| 157 time_t tm = time(NULL); |
| 158 printf("Sandbox has been started at %s", ctime(&tm)); |
| 159 |
| 160 // Stress-test the sendmsg() code |
| 161 static const int sendmsgStressNumThreads = 10; |
| 162 pthread_t sendmsgStressThreads[sendmsgStressNumThreads]; |
| 163 for (int i = 0; i < sendmsgStressNumThreads; ++i) { |
| 164 if (pthread_create(sendmsgStressThreads + i, NULL, |
| 165 sendmsgStressThreadFnc, NULL)) { |
| 166 perror("pthread_create"); |
| 167 _exit(1); |
| 168 } |
| 169 } |
| 170 for (int i = 0; i < sendmsgStressNumThreads; ++i) { |
| 171 pthread_join(sendmsgStressThreads[i], NULL); |
| 172 } |
| 173 |
| 174 return 0; |
| 175 } |
OLD | NEW |