static void install_filter(void) { struct sock_filter filter[] = { /* Load architecture */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))), /* Kill process if the architecture is not what we expect */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), /* Load system call number */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), /* Allow system calls other than open() */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_open, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), /* Kill process on open() */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL) }; struct sock_fprog prog = { .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])), .filter = filter, }; if (seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog) == -1) errExit("seccomp"); /* On Linux 3.16 and earlier, we must instead use: if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) errExit("prctl-PR_SET_SECCOMP"); */ } int main(int argc, char **argv) { if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) errExit("prctl"); install_filter(); if (open("/tmp/a", O_RDONLY) == -1) errExit("open"); printf("We shouldn't see this message\n"); exit(EXIT_SUCCESS); }
int main(int argc, char* argv[]) { struct sigaction sa; pthread_t thread; pthread_t w_thread; char ch; test_assert(0 == pipe(pipe_fds)); sa.sa_sigaction = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO; sigaction(SIGSYS, &sa, NULL); pthread_create(&w_thread, NULL, waiting_thread, NULL); /* Prepare syscallbuf patch path. Need to do this after pthread_create since when we have more than one thread we take a different syscall path... */ open("/dev/null", O_RDONLY); test_assert(0 == prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); test_assert(1 == prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0)); install_filter(); test_assert(2 == prctl(PR_GET_SECCOMP)); test_assert(1 == write(pipe_fds[1], "c", 1)); pthread_join(w_thread, NULL); test_assert(-1 == syscall(SYS_pipe, pipe_fds)); test_assert(ESRCH == errno); /* Spawning a thread will execute an rrcall_init_buffers syscall, which our filter tries to block but shouldn't be able to. */ pthread_create(&thread, NULL, run_thread, NULL); pthread_join(thread, NULL); /* Check that the ioctls used by syscallbuf aren't blocked */ test_assert(1 == write(pipe_fds[1], "c", 1)); test_assert(1 == read(pipe_fds[0], &ch, 1)); test_assert(1 == write(pipe_fds[1], "c", 1)); test_assert(1 == read(pipe_fds[0], &ch, 1)); syscall(SYS_geteuid); open("/dev/null", O_RDONLY); test_assert(count_SIGSYS == 2); atomic_puts("SUCCESS"); return 0; }
static void install_filter(void) { struct sock_filter filter[] = { /* Allow all system calls */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), .filter = filter, }; int ret; ret = syscall(RR_seccomp, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog); if (ret == -1 && errno == ENOSYS) { atomic_puts("seccomp syscall not supported"); atomic_puts("EXIT-SUCCESS"); exit(0); } test_assert(ret == 0); } static void* waiting_thread(__attribute__((unused)) void* p) { char buf; test_assert(1 == read(pipe_fds[0], &buf, 1)); /* Check this thread *was* affected by SECCOMP_FILTER_FLAG_TSYNC */ test_assert(2 == prctl(PR_GET_SECCOMP)); return NULL; } int main(void) { pthread_t w_thread; test_assert(0 == pipe(pipe_fds)); pthread_create(&w_thread, NULL, waiting_thread, NULL); /* Prepare syscallbuf patch path. Need to do this after pthread_create since when we have more than one thread we take a different syscall path... */ test_assert(0 == prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); install_filter(); test_assert(2 == prctl(PR_GET_SECCOMP)); test_assert(1 == write(pipe_fds[1], "c", 1)); pthread_join(w_thread, NULL); atomic_puts("EXIT-SUCCESS"); return 0; }
int main(int argc, char **argv) { int fd; if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) errExit("prctl"); install_filter(); fd = open("/dev/zero", O_RDWR); if (fd == -1) errExit("open"); seek_test(fd, 0); seek_test(fd, 10000); seek_test(fd, 0x100000001); exit(EXIT_SUCCESS); }
static int install_filter(int nr, int arch, int error) { struct sock_filter filter[] = { BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, arch, 0, 3), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, nr))), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(error & SECCOMP_RET_DATA)), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), .filter = filter, }; if (prctl(PR_SET_SECCOMP, 2, &prog)) { perror("prctl"); return 1; } return 0; } int main(int argc, char **argv) { if (argc < 5) { fprintf(stderr, "Usage:\n" "dropper <syscall_nr> <arch> <errno> <prog> [<args>]\n" "Hint: AUDIT_ARCH_I386: 0x%X\n" " AUDIT_ARCH_X86_64: 0x%X\n" "\n", AUDIT_ARCH_I386, AUDIT_ARCH_X86_64); return 1; } if (install_filter(strtol(argv[1], NULL, 0), strtol(argv[2], NULL, 0), strtol(argv[3], NULL, 0))) return 1; execv(argv[4], &argv[4]); printf("Failed to execv\n"); return 255; }
static void install_filter(void) { struct sock_filter filter[] = { /* Load system call number from 'seccomp_data' buffer into accumulator */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)), /* Jump forward 1 instruction if system call number is not SYS_pipe */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_pipe, 0, 1), /* Error out with ESRCH */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (ESRCH & SECCOMP_RET_DATA)), /* Jump forward 1 instruction if system call number is not SYS_geteuid */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_geteuid, 0, 1), /* Trigger SIGSYS */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), /* Jump forward 1 instruction if system call number is not SYS_open */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_open, 0, 1), /* Trigger SIGSYS */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), /* Jump forward 1 instruction if system call number is not SYS_rrcall_init_buffers */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_rrcall_init_buffers, 0, 1), /* Trigger SIGSYS */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), /* Jump forward 1 instruction if system call number is not SYS_ioctl */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_ioctl, 0, 1), /* Trigger SIGSYS */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), /* Destination of system call number mismatch: allow other system calls */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), .filter = filter, }; int ret; ret = syscall(RR_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog); if (ret == -1 && errno == ENOSYS) { ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); } test_assert(ret == 0); } static void* waiting_thread(__attribute__((unused)) void* p) { char buf; test_assert(1 == read(pipe_fds[0], &buf, 1)); /* Check this thread wasn't affected by the SET_SECCOMP */ test_assert(0 == prctl(PR_GET_SECCOMP)); return NULL; } static void* run_thread(__attribute__((unused)) void* p) { atomic_printf("EXIT-"); return NULL; } int main(void) { struct sigaction sa; pthread_t thread; pthread_t w_thread; char ch; test_assert(0 == pipe(pipe_fds)); sa.sa_sigaction = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO; sigaction(SIGSYS, &sa, NULL); pthread_create(&w_thread, NULL, waiting_thread, NULL); /* Prepare syscallbuf patch path. Need to do this after pthread_create since when we have more than one thread we take a different syscall path... */ open("/dev/null", O_RDONLY); test_assert(0 == prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); test_assert(1 == prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0)); install_filter(); test_assert(2 == prctl(PR_GET_SECCOMP)); test_assert(1 == write(pipe_fds[1], "c", 1)); pthread_join(w_thread, NULL); test_assert(-1 == syscall(SYS_pipe, pipe_fds)); test_assert(ESRCH == errno); /* Spawning a thread will execute an rrcall_init_buffers syscall, which our filter tries to block but shouldn't be able to. */ pthread_create(&thread, NULL, run_thread, NULL); pthread_join(thread, NULL); /* Check that the ioctls used by syscallbuf aren't blocked */ test_assert(1 == write(pipe_fds[1], "c", 1)); test_assert(1 == read(pipe_fds[0], &ch, 1)); test_assert(1 == write(pipe_fds[1], "c", 1)); test_assert(1 == read(pipe_fds[0], &ch, 1)); syscall(SYS_geteuid); open("/dev/null", O_RDONLY); test_assert(count_SIGSYS == 2); atomic_puts("SUCCESS"); return 0; }
void main_loop(int icmp_sock, __u8 *packet, int packlen) { char addrbuf[128]; char ans_data[4096]; struct iovec iov; struct msghdr msg; struct cmsghdr *c; int cc; int next; int polling; iov.iov_base = (char *)packet; for (;;) { /* Check exit conditions. */ if (exiting) break; if (npackets && nreceived + nerrors >= npackets) break; if (deadline && nerrors) break; /* Check for and do special actions. */ if (status_snapshot) status(); /* Send probes scheduled to this time. */ do { next = pinger(); next = schedule_exit(next); } while (next <= 0); /* "next" is time to send next probe, if positive. * If next<=0 send now or as soon as possible. */ /* Technical part. Looks wicked. Could be dropped, * if everyone used the newest kernel. :-) * Its purpose is: * 1. Provide intervals less than resolution of scheduler. * Solution: spinning. * 2. Avoid use of poll(), when recvmsg() can provide * timed waiting (SO_RCVTIMEO). */ polling = 0; if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next<SCHINT(interval)) { int recv_expected = in_flight(); /* If we are here, recvmsg() is unable to wait for * required timeout. */ if (1000 % HZ == 0 ? next <= 1000 / HZ : (next < INT_MAX / HZ && next * HZ <= 1000)) { /* Very short timeout... So, if we wait for * something, we sleep for MININTERVAL. * Otherwise, spin! */ if (recv_expected) { next = MININTERVAL; } else { next = 0; /* When spinning, no reasons to poll. * Use nonblocking recvmsg() instead. */ polling = MSG_DONTWAIT; /* But yield yet. */ sched_yield(); } } if (!polling && ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) { struct pollfd pset; pset.fd = icmp_sock; pset.events = POLLIN|POLLERR; pset.revents = 0; if (poll(&pset, 1, next) < 1 || !(pset.revents&(POLLIN|POLLERR))) continue; polling = MSG_DONTWAIT; } } for (;;) { struct timeval *recv_timep = NULL; struct timeval recv_time; int not_ours = 0; /* Raw socket can receive messages * destined to other running pings. */ iov.iov_len = packlen; memset(&msg, 0, sizeof(msg)); msg.msg_name = addrbuf; msg.msg_namelen = sizeof(addrbuf); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ans_data; msg.msg_controllen = sizeof(ans_data); cc = recvmsg(icmp_sock, &msg, polling); polling = MSG_DONTWAIT; if (cc < 0) { if (errno == EAGAIN || errno == EINTR) break; if (!receive_error_msg()) { if (errno) { perror("ping: recvmsg"); break; } not_ours = 1; } } else { #ifdef SO_TIMESTAMP for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) { if (c->cmsg_level != SOL_SOCKET || c->cmsg_type != SO_TIMESTAMP) continue; if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval))) continue; recv_timep = (struct timeval*)CMSG_DATA(c); } #endif if ((options&F_LATENCY) || recv_timep == NULL) { if ((options&F_LATENCY) || ioctl(icmp_sock, SIOCGSTAMP, &recv_time)) gettimeofday(&recv_time, NULL); recv_timep = &recv_time; } not_ours = parse_reply(&msg, cc, addrbuf, recv_timep); } /* See? ... someone runs another ping on this host. */ if (not_ours && !using_ping_socket) install_filter(); /* If nothing is in flight, "break" returns us to pinger. */ if (in_flight() == 0) break; /* Otherwise, try to recvmsg() again. recvmsg() * is nonblocking after the first iteration, so that * if nothing is queued, it will receive EAGAIN * and return to pinger. */ } } finish(); }
static void install_filter(void) { struct sock_filter filter[] = { /* Load architecture */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))), /* Kill process if the architecture is not what we expect */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), /* Load system call number */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), /* Allow system calls other than open() */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_open, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), /* Kill process on open() */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL) }; struct sock_fprog prog = { .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])), .filter = filter, }; if (seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog) == -1) errExit("seccomp"); } int main(int argc, char *argv[]) { int j, nloops; if (argc < 2) { fprintf(stderr, "Usage: %s <num-loops> [x]\n", argv[0]); fprintf(stderr, " (use 'x' to run with BPF filter applied)\n"); exit(EXIT_FAILURE); } if (argc > 2) { printf("Appling BPF filter\n"); if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) errExit("prctl"); install_filter(); } nloops = atoi(argv[1]); for (j = 0; j < nloops; j++) getppid(); exit(EXIT_SUCCESS); }
void install_filter(void) { struct sock_filter filter[] = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRACE) }; struct sock_fprog prog = { .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])), .filter = filter, }; prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); } int main(int argc, char **argv) { pid_t child; struct user_regs_struct regs; // fork into tracee & tracer child = fork(); if (child == 0) { // tracee ptrace(PTRACE_TRACEME, 0, NULL); install_filter(); argv++; execvp(argv[0], argv); // execute tracee } else { // tracer int status; siginfo_t siginfo; waitpid(child, &status, 0); // wait for execve ptrace(PTRACE_SETOPTIONS, child, NULL, PTRACE_O_TRACESECCOMP); ptrace(PTRACE_CONT, child, NULL, NULL); while (1) { // trace loop waitpid(child, &status, 0); if (WIFEXITED(status) || WIFSIGNALED(status)) break; ptrace(PTRACE_GETSIGINFO, child, NULL, &siginfo); printf("signal %d ", siginfo.si_signo); ptrace(PTRACE_GETREGS, child, NULL, ®s); printf("syscall %llu\n", regs.orig_rax); ptrace(PTRACE_CONT, child, NULL, NULL); } printf("\n"); } return 0; }
bool net::filter::parse(const char* filter) { if (!init()) { return false; } bool tcp = false; bool udp = false; bool src = false; bool dest = false; unsigned first = 0; unsigned last = 0; int state = 0; // Initial state. while (*filter) { switch (state) { case 0: // Initial state. switch (*filter) { case 'i': case 'I': filter++; state = 1; // ICMP. break; case 's': case 'S': tcp = true; udp = true; src = true; dest = false; filter++; state = 4; // "port". break; case 'd': case 'D': tcp = true; udp = true; src = false; dest = true; filter++; state = 4; // "port". break; case 't': case 'T': tcp = true; udp = false; src = false; dest = false; filter++; state = 2; // TCP. break; case 'u': case 'U': tcp = false; udp = true; src = false; dest = false; filter++; state = 3; // UDP. break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': tcp = true; udp = true; src = true; dest = true; first = *filter - '0'; filter++; state = 5; // Port or range of ports. break; case ' ': case '\t': filter++; break; default: return false; } break; case 1: // ICMP. if (((filter[0] != 'c') && (filter[0] != 'C')) || \ ((filter[1] != 'm') && (filter[1] != 'M')) || \ ((filter[2] != 'p') && (filter[2] != 'P'))) { return false; } if ((filter[3]) && (!IS_WHITE_SPACE(filter[3]))) { return false; } _M_icmp = true; filter += 3; state = 0; // Initial state. break; case 2: // TCP. if (((filter[0] != 'c') && (filter[0] != 'C')) || \ ((filter[1] != 'p') && (filter[1] != 'P'))) { return false; } if ((!filter[2]) || (IS_WHITE_SPACE(filter[2]))) { set_tcp_ports(0, USHRT_MAX, true); filter += 2; state = 0; // Initial state. } else if (filter[2] == ':') { if ((filter[3] == 's') || (filter[3] == 'S')) { src = true; filter += 4; state = 4; // "port". } else if ((filter[3] == 'd') || (filter[3] == 'D')) { dest = true; filter += 4; state = 4; // "port". } else if (IS_DIGIT(filter[3])) { src = true; dest = true; first = filter[3] - '0'; filter += 4; state = 5; // Port or range of ports. } else { return false; } } else { return false; } break; case 3: // UDP. if (((filter[0] != 'd') && (filter[0] != 'D')) || \ ((filter[1] != 'p') && (filter[1] != 'P'))) { return false; } if ((!filter[2]) || (IS_WHITE_SPACE(filter[2]))) { set_udp_ports(0, USHRT_MAX, true); filter += 2; state = 0; // Initial state. } else if (filter[2] == ':') { if ((filter[3] == 's') || (filter[3] == 'S')) { src = true; filter += 4; state = 4; // "port". } else if ((filter[3] == 'd') || (filter[3] == 'D')) { dest = true; filter += 4; state = 4; // "port". } else if (IS_DIGIT(filter[3])) { src = true; dest = true; first = filter[3] - '0'; filter += 4; state = 5; // Port or range of ports. } else { return false; } } else { return false; } break; case 4: // "port". if (((filter[0] != 'p') && (filter[0] != 'P')) || \ ((filter[1] != 'o') && (filter[1] != 'O')) || \ ((filter[2] != 'r') && (filter[2] != 'R')) || \ ((filter[3] != 't') && (filter[3] != 'T')) || \ (filter[4] != ':') || \ (!IS_DIGIT(filter[5]))) { return false; } first = filter[5] - '0'; filter += 6; state = 5; // Port or range of ports. break; case 5: // Port or range of ports. while (IS_DIGIT(*filter)) { if ((first = (first * 10) + (*filter - '0')) > USHRT_MAX) { return false; } filter++; } if (first == 0) { return false; } if (*filter == '-') { last = 0; filter++; state = 6; // Range of ports. } else if ((!*filter) || (IS_WHITE_SPACE(*filter))) { install_filter(tcp, udp, src, dest, first, first, true); state = 0; // Initial state. } else { return false; } break; case 6: // Range of ports. while (IS_DIGIT(*filter)) { if ((last = (last * 10) + (*filter - '0')) > USHRT_MAX) { return false; } filter++; } if (last == 0) { return false; } if ((*filter) && (!IS_WHITE_SPACE(*filter))) { return false; } if (first > last) { return false; } install_filter(tcp, udp, src, dest, first, last, true); state = 0; // Initial state. break; } } if (state != 0) { return false; } _M_filter = true; return true; }
static void install_filter(void) { struct sock_filter filter[] = { /* Load architecture */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))), /* Kill the process if the architecture is not what we expect */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), /* Load system call number */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), /* Allow syscalls other than open() */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_open, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), /* Load second argument of open() (flags) into accumulator */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, args[1]))), /* Kill the process if O_CREAT was specified */ BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, O_CREAT, 0, 1), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), /* Give ENOTSUP error on attempt to open for writing. Relies on the fact that O_RDWR and O_WRONLY are defined as single, nonoverlapping bits */ BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, O_WRONLY | O_RDWR, 0, 1), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (ENOTSUP & SECCOMP_RET_DATA)), /* Otherwise allow the open() */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) }; struct sock_fprog prog = { .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])), .filter = filter, }; if (seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog)) errExit("seccomp"); /* On Linux 3.16 and earlier, we must instead use: if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) errExit("prctl-PR_SET_SECCOMP"); */ } int main(int argc, char **argv) { if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) errExit("prctl"); install_filter(); if (open("/tmp/a", O_RDONLY) == -1) perror("open1"); if (open("/tmp/a", O_WRONLY) == -1) perror("open2"); if (open("/tmp/a", O_RDWR) == -1) perror("open3"); if (open("/tmp/a", O_CREAT | O_RDWR, 0600) == -1) perror("open4"); exit(EXIT_SUCCESS); }
int main() { char intf[] = "mon0"; //any interface name so that tcpdump doesn't complain char filter_text[] = "type data or subtype ack"; //do_ls_etc(); install_filter(intf, filter_text); }
static int install_filter(void) { struct sock_filter filter[] = { /* Grab the system call number */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr), /* Jump table for the allowed syscalls */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_rt_sigreturn, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), #ifdef __NR_sigreturn BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_sigreturn, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), #endif BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit_group, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_read, 1, 0), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_write, 3, 2), /* Check that read is only using stdin. */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_arg(0)), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDIN_FILENO, 4, 0), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), /* Check that write is only using stdout */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_arg(0)), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDOUT_FILENO, 1, 0), /* Trap attempts to write to stderr */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDERR_FILENO, 1, 2), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), .filter = filter, }; if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("prctl(NO_NEW_PRIVS)"); return 1; } if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { perror("prctl"); return 1; } return 0; } #define payload(_c) (_c), sizeof((_c)) int main(int argc, char **argv) { char buf[4096]; ssize_t bytes = 0; if (install_emulator()) return 1; if (install_filter()) return 1; syscall(__NR_write, STDOUT_FILENO, payload("OHAI! WHAT IS YOUR NAME? ")); bytes = syscall(__NR_read, STDIN_FILENO, buf, sizeof(buf)); syscall(__NR_write, STDOUT_FILENO, payload("HELLO, ")); syscall(__NR_write, STDOUT_FILENO, buf, bytes); syscall(__NR_write, STDERR_FILENO, payload("Error message going to STDERR\n")); return 0; }