void setup_seccomp() { scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL); if(!ctx) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0)) exit(-1); #if (SCMP_SYS(setsockopt)) #warning System does not have sys_setsockopt, the expected way to do SO_REUSEADDR. if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), 0)) exit(-1); #endif #ifdef NEEDS_SOCKETCALL #warning NEEDS_SOCKETCALL=1 has been set, I wish it was not needed on some systems. if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketcall), 0)) exit(-1); #endif if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(bind), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(listen), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setresuid32), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setresgid32), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(alarm), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(dup2), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0)) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0)) exit(-1); // Allow further restrictions. if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 1, SCMP_A0(SCMP_CMP_EQ, PR_SET_NO_NEW_PRIVS))) exit(-1); if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 1, SCMP_A0(SCMP_CMP_EQ, PR_SET_SECCOMP))) exit(-1); if(seccomp_load(ctx)) exit(-1); seccomp_release(ctx); }
int seccomp_start(void) { int rc = 0; unsigned int i = 0; scmp_filter_ctx ctx; ctx = seccomp_init(SCMP_ACT_KILL); if (ctx == NULL) { rc = -1; goto seccomp_return; } for (i = 0; i < ARRAY_SIZE(seccomp_whitelist); i++) { rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, seccomp_whitelist[i].num, 0); if (rc < 0) { goto seccomp_return; } rc = seccomp_syscall_priority(ctx, seccomp_whitelist[i].num, seccomp_whitelist[i].priority); if (rc < 0) { goto seccomp_return; } } rc = seccomp_load(ctx); seccomp_return: seccomp_release(ctx); return rc; }
int main(int argc, char *argv[]) { if (argc < 6 || strcmp(argv[1], "--error") || (strcmp(argv[3], "--allow") && strcmp(argv[3], "--deny"))) { usage(argv[0]); return 1; } const int err = parse_positive(argv[2]); if (err < 0) { return 2; } const bool default_block = !strcmp(argv[3], "--allow"); if (-1 == prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("prctl"); return 10; } uint32_t rule_action = !default_block ? SCMP_ACT_ERRNO(err) : SCMP_ACT_ALLOW; scmp_filter_ctx ctx = seccomp_init(default_block ? SCMP_ACT_ERRNO(err) : SCMP_ACT_ALLOW); int arg = 4; for (; arg < argc; ++arg) { if (!strcmp(argv[arg], "--")) { ++arg; break; } const int syscall_no = parse_positive(argv[arg]); if (syscall_no < 0) { seccomp_release(ctx); return 5; } if (seccomp_rule_add(ctx, rule_action, syscall_no, 0)) { perror("rule add"); fprintf(stderr, "not a valid syscall number for a rule: '%s'\n", argv[arg]); seccomp_release(ctx); return 20; } } if (arg == argc) { usage(argv[0]); return 3; } if (seccomp_load(ctx)) { perror("load"); seccomp_release(ctx); return 4; } seccomp_release(ctx); execvp(argv[arg], &argv[arg]); perror("execve"); return 5; }
void drop_privileges(void) { scmp_filter_ctx ctx = seccomp_init(DENY_ACTION); if (ctx == NULL) { return; } int rc = 0; rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sigreturn), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_wait), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_pwait), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(writev), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(shmctl), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1, SCMP_A1(SCMP_CMP_EQ, TIOCGWINSZ)); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1, SCMP_A1(SCMP_CMP_EQ, TCGETS)); #ifdef MEMCACHED_DEBUG rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(readv), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(lseek), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0); if (settings.relaxed_privileges) { rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mkdir), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(access), 0); } #endif if (rc != 0) { goto fail; } rc = seccomp_load(ctx); if (rc < 0) { goto fail; } seccomp_release(ctx); return; fail: seccomp_release(ctx); fprintf(stderr, "Failed to set a seccomp profile on the main thread\n"); exit(EXIT_FAILURE); }
int main() { char *addr; int fd,ret; char buf[20]={0}; char sc[128]={0}; scmp_filter_ctx ctx; ctx = seccomp_init(SCMP_ACT_KILL); if (!ctx) { perror("seccomp_init"); return -1; } ret = seccomp_rule_add(ctx,SCMP_ACT_ALLOW,SCMP_SYS(write),0); if(ret) { perror("add rule"); return -1; } ret = seccomp_rule_add(ctx,SCMP_ACT_ALLOW,SCMP_SYS(access),0); if(ret) { perror("add rule"); return -1; } fd = open("./.passwd",O_RDONLY); if(fd == -1) { perror("open"); return -1; } read(fd,buf,20); addr = mmap(0,4096,PROT_READ|PROT_WRITE,MAP_SHARED |MAP_ANONYMOUS,-1,0); if (addr == (char*)-1) { perror("mmap"); return -1; } memset(addr,0,4096); memcpy(addr,"MCSC",4); memcpy(addr+4,"2014",4); memcpy(&addr[8],buf,20); printf("put you shellcode here : "); fflush(stdout); ssize_t rc = read(0,sc,128); sc[rc-1]=0; seccomp_load(ctx); ((void (*)(void))sc)(); return 0; }
void pcm_install_policy() { int rc; rc = seccomp_load(PCM_GLOBAL.seccomp); if(rc < 0) { errx(EXIT_FAILURE, "Failed to load the seccomp policy into the process"); } seccomp_release(PCM_GLOBAL.seccomp); PCM_GLOBAL.seccomp = NULL; }
int main(int argc, char *argv[]) { int rc; scmp_filter_ctx ctx = NULL; rc = util_action_parse(argv[1]); if (rc != SCMP_ACT_ALLOW) { rc = 1; goto out; } rc = util_trap_install(); if (rc != 0) goto out; ctx = seccomp_init(SCMP_ACT_TRAP); if (ctx == NULL) return ENOMEM; rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0); if (rc != 0) goto out; rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0); if (rc != 0) goto out; rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); if (rc != 0) goto out; rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); if (rc != 0) goto out; rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); if (rc != 0) goto out; rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); if (rc != 0) goto out; rc = seccomp_load(ctx); if (rc != 0) goto out; rc = util_file_write("/dev/null"); if (rc != 0) goto out; rc = 160; out: seccomp_release(ctx); return (rc < 0 ? -rc : rc); }
// keep filter for seccomp option int seccomp_filter_keep(void) { if (arg_debug) printf("Build drop seccomp filter\n"); // build the seccomp filter as a regular user sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, PATH_FSECCOMP, "keep", RUN_SECCOMP_CFG, cfg.seccomp_list_keep); if (arg_debug) printf("seccomp filter configured\n"); return seccomp_load(RUN_SECCOMP_CFG); }
static void setup_seccomp() { scmp_filter_ctx ctx; unsigned int i; int ret; /* Make sure the lists are in sync */ INSIST((sizeof(scmp_syscalls) / sizeof(int)) == (sizeof(scmp_syscall_names) / sizeof(const char *))); ctx = seccomp_init(SCMP_ACT_KILL); if (ctx == NULL) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_WARNING, "libseccomp activation failed"); return; } for (i = 0 ; i < sizeof(scmp_syscalls)/sizeof(*(scmp_syscalls)); i++) { ret = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, scmp_syscalls[i], 0); if (ret < 0) isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_WARNING, "libseccomp rule failed: %s", scmp_syscall_names[i]); else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(9), "added libseccomp rule: %s", scmp_syscall_names[i]); } ret = seccomp_load(ctx); if (ret < 0) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_WARNING, "libseccomp unable to load filter"); } else { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_NOTICE, "libseccomp sandboxing active"); } /* * Release filter in ctx. Filters already loaded are not * affected. */ seccomp_release(ctx); }
static void init_seccomp_addconn(uint32_t def_action) { scmp_filter_ctx ctx = seccomp_init(def_action); int rc = 0; if (ctx == NULL) { printf("seccomp_init_addconn() failed!"); exit(EXIT_SECCOMP_FAIL); } rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(access), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(arch_prctl), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(connect), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getrlimit), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(readlink), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(set_robust_list), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(set_tid_address), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(statfs), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); if (rc != 0) { printf("seccomp_rule_add() failed!"); seccomp_release(ctx); exit(EXIT_SECCOMP_FAIL); } rc = seccomp_load(ctx); if (rc < 0) { printf("seccomp_load() failed!"); seccomp_release(ctx); exit(EXIT_SECCOMP_FAIL); } }
static void install_seccomp_filter(const char *syscalls[]) { scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRAP); if (!ctx) { errx(EXIT_FAILURE, "Failed to init seccomp"); } for (int i = 0; ; i++) { const char *syscall = syscalls[i]; if (!syscall) break; check(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, get_syscall_nr(syscall), 0)); } check(seccomp_load(ctx)); }
int lxc_seccomp_load(struct lxc_conf *conf) { int ret; if (!conf->seccomp) return 0; ret = seccomp_load( #if HAVE_SCMP_FILTER_CTX conf->seccomp_ctx #endif ); if (ret < 0) { ERROR("Error loading the seccomp policy"); return -1; } return 0; }
void poe_init_seccomp(uint32_t act) { scmp_filter_ctx ctx = seccomp_init(act); if (!ctx) ERROR("seccomp_init() failed"); for (int i = 0; i < syscall_rules_count; i++) { struct syscall_rule rule = syscall_rules[i]; if (seccomp_rule_add(ctx, rule.action, rule.syscall, 0) < 0) ERROR("seccomp_rule_add() failed"); } int rc = seccomp_load(ctx); if (rc < 0) ERROR("seccomp_load() failed: %s", strerror(-rc)); seccomp_release(ctx); }
void sandboxify() { if (seccomp_init(SCMP_ACT_TRAP) < 0) ERROR("Cannot go into SECCOMPv2"); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(open), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(openat), 0); // XXXX // seccomp_rule_add(SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 0); seccomp_rule_add(SCMP_ACT_ERRNO(EPERM), SCMP_SYS(access), 0); seccomp_rule_add(SCMP_ACT_ERRNO(EPERM), SCMP_SYS(fcntl), 0); // XXXX seccomp_rule_add(SCMP_ACT_ERRNO(EPERM), SCMP_SYS(fstat), 0); seccomp_rule_add(SCMP_ACT_ERRNO(EPERM), SCMP_SYS(fstat64), 0); seccomp_rule_add(SCMP_ACT_ERRNO(EPERM), SCMP_SYS(stat64), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(getdents), 0); // XXXX seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(stat), 0); // XXXX seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(dup), 0); // XXXX seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(lseek), 0); // XXXX seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(close), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(read), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(getdents64), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(write), 0); // seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(writev), 0); // XXX // seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 0); // XXX // seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(futex), 0); // XXX seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(mmap2), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(mremap), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(brk), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(gettimeofday), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(time), 0); seccomp_rule_add(SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); #ifdef DEBUG_SECCOMP if (install_syscall_reporter()) ERROR("Cannot install syscall reporter"); #endif if (seccomp_load() < 0) ERROR("Cannot load SECCOMP filters"); seccomp_release(); }
int main(int const argc, char * const * const argv) { try { alarm(10); close(fileno(stdin)); for (int fd = fileno(stderr); fd != 1024; ++fd) close(fd); dup2(fileno(stdout), fileno(stderr)); limitResource(RLIMIT_CPU, 9, 11); limitResource(RLIMIT_AS, 512*1024*1024); limitResource(RLIMIT_DATA, 512*1024*1024); limitResource(RLIMIT_FSIZE, 10*1024*1024); limitResource(RLIMIT_LOCKS, 0); limitResource(RLIMIT_MEMLOCK, 0); limitResource(RLIMIT_NPROC, 16); if (argc < 2) e("params: program args"); if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) e("prctl"); scmp_filter_ctx const ctx = seccomp_init(SCMP_ACT_TRAP); if (!ctx) e("seccomp_init"); if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 1, SCMP_CMP(0, SCMP_CMP_MASKED_EQ, CLONE_THREAD, CLONE_THREAD)) != 0) e("seccomp_rule_add"); for (auto && p : rules) if (seccomp_rule_add(ctx, p.second, p.first, 0) != 0) e("seccomp_rule_add"); if (seccomp_load(ctx) < 0) e("seccomp_load"); execv(argv[1], argv + 1); e("execv"); } catch (std::exception const & e) { std::cerr << "exception: " << e.what() << '\n'; return 1; } }
int installSyscallFilter (void) { // Use SCMP_ACT_TRAP to get a core dump. scmp_filter_ctx ctx = seccomp_init (SCMP_ACT_KILL); if (ctx == NULL) { return 1; } // Memory allocation. seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (mmap), 0); seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (munmap), 0); seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (mremap), 0); seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (brk), 0); // I/O seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (read), 0); seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (write), 0); // Clean exit seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (exit), 0); seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (exit_group), 0); // The bowels of stdio want to know the size of a file, even for stdout. seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (fstat), 0); // seems unnecessary, but this comes from // main/parse.c:2764 : tagFilePosition (&tagfpos); seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (lseek), 0); // libxml2 uses pthread_once, which in turn uses a futex seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS (futex), 0); verbose ("Entering sandbox\n"); int err = seccomp_load (ctx); if (err < 0) { error (WARNING, "Failed to install syscall filter"); /* Error handling is done in upper layer. */ } seccomp_release (ctx); return err; }
/** * Function responsible for setting up and enabling a global syscall filter. * The function is a prototype developed for stage 1 of sandboxing Tor. * Returns 0 on success. */ static int install_syscall_filter(sandbox_cfg_t* cfg) { int rc = 0; scmp_filter_ctx ctx; ctx = seccomp_init(SCMP_ACT_TRAP); if (ctx == NULL) { log_err(LD_BUG,"(Sandbox) failed to initialise libseccomp context"); rc = -1; goto end; } // protectign sandbox parameter strings if ((rc = prot_strings(ctx, cfg))) { goto end; } // add parameter filters if ((rc = add_param_filter(ctx, cfg))) { log_err(LD_BUG, "(Sandbox) failed to add param filters!"); goto end; } // adding filters with no parameters if ((rc = add_noparam_filter(ctx))) { log_err(LD_BUG, "(Sandbox) failed to add param filters!"); goto end; } // loading the seccomp2 filter if ((rc = seccomp_load(ctx))) { log_err(LD_BUG, "(Sandbox) failed to load: %d (%s)!", rc, strerror(-rc)); goto end; } // marking the sandbox as active sandbox_active = 1; end: seccomp_release(ctx); return (rc < 0 ? -rc : rc); }
void sc_load_seccomp_context(scmp_filter_ctx ctx) { int rc; uid_t real_uid, effective_uid, saved_uid; // if sc_prepare_seccomp_context() sees @unrestricted or @complain it bails // out early and destroys the context object. In that case we have nothing // to do. if (ctx == NULL) { return; } if (getresuid(&real_uid, &effective_uid, &saved_uid) != 0) die("could not find user IDs"); // If not root but can raise, then raise privileges to load seccomp // policy since we don't have nnp debug("raising privileges to load seccomp profile"); if (effective_uid != 0 && saved_uid == 0) { if (seteuid(0) != 0) die("seteuid failed"); if (geteuid() != 0) die("raising privs before seccomp_load did not work"); } // load it into the kernel debug("loading seccomp profile into the kernel"); rc = seccomp_load(ctx); if (rc != 0) { fprintf(stderr, "seccomp_load failed with %i\n", rc); die("aborting"); } // drop privileges again debug("dropping privileges after loading seccomp profile"); if (geteuid() == 0) { unsigned real_uid = getuid(); if (seteuid(real_uid) != 0) die("seteuid failed"); if (real_uid != 0 && geteuid() == 0) die("dropping privs after seccomp_load did not work"); } }
int main() { printf("step 1: unrestricted\n"); // ensure none of our children will ever be granted more priv // (via setuid, capabilities, ...) prctl(PR_SET_NO_NEW_PRIVS, 1); // ensure no escape is possible via ptrace prctl(PR_SET_DUMPABLE, 0); // Init the filter scmp_filter_ctx ctx; ctx = seccomp_init(SCMP_ACT_KILL); // default action: kill // setup basic whitelist seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); // setup our rule seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(dup2), 2, SCMP_A0(SCMP_CMP_EQ, 1), SCMP_A1(SCMP_CMP_EQ, 2)); // build and load the filter seccomp_load(ctx); printf("step 2: only 'write' and dup2(1, 2) syscalls\n"); // Redirect stderr to stdout dup2(1, 2); printf("step 3: stderr redirected to stdout\n"); // Duplicate stderr to arbitrary fd dup2(2, 42); printf("step 4: !! YOU SHOULD NOT SEE ME !!\n"); // Success (well, not so in this case...) return 0; }
void drop_sys(int syscall) { scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW); if(seccomp_rule_add(ctx, SCMP_ACT_KILL, syscall, 0)) exit(-1); if(seccomp_load(ctx)) exit(-1); seccomp_release(ctx); }
int main(int argc, char *argv[]) { char *filename = read_opts(argc, argv); /* set up an rnn context */ rnn_init(); rnndb = rnn_newdb(); rnn_parsefile(rnndb, "fifo/nv_objects.xml"); if (rnndb->estatus) demmt_abort(); rnn_prepdb(rnndb); domain = rnn_finddomain(rnndb, "SUBCHAN"); if (!domain) demmt_abort(); rnndb_g80_texture = rnn_newdb(); rnn_parsefile(rnndb_g80_texture, "graph/g80_texture.xml"); if (rnndb_g80_texture->estatus) demmt_abort(); rnn_parsefile(rnndb_g80_texture, "graph/gm107_texture.xml"); if (rnndb_g80_texture->estatus) demmt_abort(); rnn_prepdb(rnndb_g80_texture); rnndb_gf100_shaders = rnn_newdb(); rnn_parsefile(rnndb_gf100_shaders, "graph/gf100_shaders.xml"); if (rnndb_gf100_shaders->estatus) demmt_abort(); rnn_prepdb(rnndb_gf100_shaders); gf100_shaders_ctx = rnndec_newcontext(rnndb_gf100_shaders); gf100_shaders_ctx->colors = colors; /* doesn't matter which, just needs to exist to make it * possible to modify later. */ rnndec_varadd(gf100_shaders_ctx, "GF100_SHADER_KIND", "FP"); rnndb_nvrm_object = rnn_newdb(); rnn_parsefile(rnndb_nvrm_object, "../docs/nvrm/rnndb/nvrm_object.xml"); if (rnndb_nvrm_object->estatus) demmt_abort(); rnn_prepdb(rnndb_nvrm_object); tic_domain = rnn_finddomain(rnndb_g80_texture, "TIC"); tic2_domain = rnn_finddomain(rnndb_g80_texture, "TIC2"); tsc_domain = rnn_finddomain(rnndb_g80_texture, "TSC"); gf100_sp_header_domain = rnn_finddomain(rnndb_gf100_shaders, "GF100_SP_HEADER"); gf100_fp_header_domain = rnn_finddomain(rnndb_gf100_shaders, "GF100_FP_HEADER"); if (!gf100_sp_header_domain || !gf100_fp_header_domain) demmt_abort(); gk104_cp_header_domain = rnn_finddomain(rnndb, "GK104_COMPUTE_LAUNCH_DESC"); if (!gk104_cp_header_domain) demmt_abort(); if (filename) { close(0); if (open_input(filename) == NULL) { perror("open"); exit(1); } free(filename); } if (pager_enabled) { int pipe_fds[2]; pid_t pid; if (pipe(pipe_fds) < 0) { perror("pipe"); demmt_abort(); } pid = fork(); if (pid < 0) { perror("fork"); demmt_abort(); } if (pid > 0) { char *less_argv[] = { "less", "-ScR", NULL }; close(pipe_fds[1]); dup2(pipe_fds[0], 0); close(pipe_fds[0]); execvp(less_argv[0], less_argv); perror("exec"); demmt_abort(); } close(pipe_fds[0]); dup2(pipe_fds[1], 1); dup2(pipe_fds[1], 2); close(pipe_fds[1]); } #ifdef LIBSECCOMP_AVAILABLE if (seccomp_level) { int rc; scmp_filter_ctx ctx; if (seccomp_level == 2) ctx = seccomp_init(SCMP_ACT_KILL); else ctx = seccomp_init(SCMP_ACT_TRACE(1234)); if (!ctx) { fprintf(stderr, "seccomp_init failed\n"); exit(1); } rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, SCMP_A0(SCMP_CMP_EQ, 0)); if (rc != 0) exit(1); seccomp_syscall_priority(ctx, SCMP_SYS(read), 254); rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_LE, 2)); if (rc != 0) exit(1); seccomp_syscall_priority(ctx, SCMP_SYS(write), 255); rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); if (rc != 0) exit(1); rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 1, SCMP_A0(SCMP_CMP_EQ, 1)); if (rc != 0) exit(1); rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0); if (rc != 0) exit(1); rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0); if (rc != 0) exit(1); rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0); if (rc != 0) exit(1); rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mremap), 0); if (rc != 0) exit(1); rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); if (rc != 0) exit(1); rc = seccomp_rule_add_exact(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 2, SCMP_A0(SCMP_CMP_EQ, 1), SCMP_A1(SCMP_CMP_EQ, 0x5401/*TCGETS*/)); if (rc != 0) exit(1); rc = seccomp_load(ctx); if (rc != 0) { fprintf(stderr, "seccomp_load failed with error: %d\n", rc); exit(1); } seccomp_release(ctx); } #endif mmt_decode(&demmt_funcs.base, NULL); fflush(stdout); fini_macrodis(); demmt_cleanup_isas(); rnndec_freecontext(gf100_shaders_ctx); rnn_freedb(rnndb); rnn_freedb(rnndb_g80_texture); rnn_freedb(rnndb_gf100_shaders); rnn_freedb(rnndb_nvrm_object); rnn_fini(); return 0; }
int main(int argc, char *argv[]) { const char *argv0 = argv[0]; int opt, optidx; bool separate_read_write = false; bool proxy = false; struct sockaddr_in proxy_sin; bool join = false; #ifdef HAVE_SECCOMP int nrules = 0; uint32_t def_action = SCMP_ACT_ALLOW; char *fixed = (char *)mmap((void *)0x800000, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0); #endif struct option longopts[] = { {"abstract" , no_argument , 0 , 'a'} , {"directory" , required_argument , 0 , 'd'} , {"environment" , required_argument , 0 , 'e'} , {"join" , no_argument , 0 , 'j'} , {"policy" , required_argument , 0 , 'o'} , {"proxy" , required_argument , 0 , 'p'} , {"seccomp" , required_argument , 0 , 'c'} , {"separate" , no_argument , 0 , 's'} , {0 , 0 , 0 , 0} , }; while ((opt = getopt_long(argc, argv, "+0ac:d:e:hjo:p:s", longopts, &optidx)) != -1) { switch (opt) { case 'a': af_unix = true; break; case 'c': { #ifdef HAVE_SECCOMP char *pp = optarg, *p, *qq, *q, *saved0, *saved1; for (; ; pp = NULL) { p = strtok_r(pp, " \t,", &saved0); if (! p) break; bool negative = false; int num, pos, nfilters = 0; enum scmp_compare op; if (nrules >= SIZE(scmp_rules)) errx(BAD_ARG, "too many rules"); if (*p == '+') p++; else if (*p == '-') p++, negative = true; scmp_rules[nrules].action = negative ? SCMP_ACT_TRAP : SCMP_ACT_ALLOW; for (qq = p; ; qq = NULL) { q = strtok_r(qq, ":", &saved1); if (! q) break; if (qq) { num = seccomp_syscall_resolve_name(q); if (num < 0) errx(BAD_ARG, "unknown syscall \"%s\"", q); scmp_rules[nrules].syscall = num; } else { if (nfilters >= SIZE(scmp_rules[0].arg_array)) errx(BAD_ARG, "too many filters"); if (! ('0' <= *q && *q <= '5')) errx(BAD_ARG, "argument position should be 0-5"); pos = *q-'0'; REP(i, nfilters) if (pos == scmp_rules[nrules].arg_array[i].arg) errx(BAD_ARG, "duplicate argument position %d", pos); q++; if (*q == '=') q++, op = SCMP_CMP_EQ; else if (*q == '!' && q[1] == '=') q += 2, op = SCMP_CMP_NE; else if (*q == '<') { if (q[1] == '=') q += 2, op = SCMP_CMP_LE; else q++, op = SCMP_CMP_LT; } else if (*q == '>') { if (q[1] == '=') q += 2, op = SCMP_CMP_GE; else q++, op = SCMP_CMP_GT; } else errx(BAD_ARG, "unknown operator \"%c\"", *q); scmp_datum_t val = strtol(q, &q, 0); if (*q) errx(BAD_ARG, "invalid number"); scmp_rules[nrules].arg_array[nfilters++] = SCMP_CMP(pos, op, val); } } scmp_rules[nrules].arg_cnt = nfilters; nrules++; } #else errx(ERR_SYSCALL, "HAVE_SECCOMP not enabled"); #endif break; } case 'd': Chdir(optarg); break; case 'h': show_help(STDOUT_FILENO, argv0); break; case 'j': join = true; break; case 'e': putenv(optarg); break; case 'o': #ifdef HAVE_SECCOMP if (optarg[0] == 'k') def_action = SCMP_ACT_KILL; else if (optarg[0] == 't') def_action = SCMP_ACT_TRAP; else if (optarg[0] == 'a') def_action = SCMP_ACT_ALLOW; #else errx(ERR_SYSCALL, "HAVE_SECCOMP not enabled"); #endif break; case 'p': // proxy { char *p = strchr(optarg, ':'); if (! p) errx(BAD_ARG, "no semicolon"); *p = '\0'; proxy_sin.sin_family = AF_INET; if (inet_aton(optarg, &proxy_sin.sin_addr) < 0) errx(BAD_ARG, "gethostbyname: %s", strerror(errno)); proxy_sin.sin_port = htons(strtol(p+1, &p, 10)); if (*p) errx(BAD_ARG, "port"); proxy = true; } break; case 's': separate_read_write = true; break; default: show_help(STDERR_FILENO, argv0); break; } } argc -= optind; argv += optind; if (argc < 1) { show_help(STDERR_FILENO, argv0); return BAD_ARG; } char buf[4096]; int pipe_p2c[2], pipe_c2p1[2], pipe_c2p2[2]; if (af_unix) { unix_p2c.sun_family = AF_UNIX; unix_c2p1.sun_family = AF_UNIX; unix_c2p2.sun_family = AF_UNIX; unix_p2c.sun_path[0] = '\0'; unix_c2p1.sun_path[0] = '\0'; unix_c2p2.sun_path[0] = '\0'; sprintf(unix_p2c.sun_path+1, "/tmp/unix/%d-%d.in", getuid(), getpid()); sprintf(unix_c2p1.sun_path+1, "/tmp/unix/%d-%d.out", getuid(), getpid()); sprintf(unix_c2p2.sun_path+1, "/tmp/unix/%d-%d.err", getuid(), getpid()); pipe_p2c[0] = socket(AF_UNIX, SOCK_STREAM, 0); pipe_c2p1[1] = socket(AF_UNIX, SOCK_STREAM, 0); if (! join) pipe_c2p2[1] = socket(AF_UNIX, SOCK_STREAM, 0); atexit(atexit_rm); if (bind(pipe_p2c[0], &unix_p2c, sizeof unix_p2c) < 0 || bind(pipe_c2p1[1], &unix_c2p1, sizeof unix_c2p1) < 0) return perror(""), 0; if (! join && bind(pipe_c2p2[1], &unix_c2p2, sizeof unix_c2p2) < 0) return perror(""), 0; if (listen(pipe_p2c[0], 1) < 0 || listen(pipe_c2p1[1], 1) < 0) return perror(""), 0; if (! join && listen(pipe_c2p2[1], 1) < 0) return perror(""), 0; } else { Pipe(pipe_p2c); Pipe(pipe_c2p1); if (! join) Pipe(pipe_c2p2); } child = Fork(); if (! child) { // child if (af_unix) { // close bound sockets close(pipe_p2c[0]); close(pipe_c2p1[1]); close(pipe_c2p2[1]); // domain sockets for client pipe_p2c[1] = socket(AF_UNIX, SOCK_STREAM, 0); pipe_c2p1[0] = socket(AF_UNIX, SOCK_STREAM, 0); if (! join) pipe_c2p2[0] = socket(AF_UNIX, SOCK_STREAM, 0); if (connect(pipe_p2c[1], &unix_p2c, sizeof unix_p2c) < 0 || connect(pipe_c2p1[0], &unix_c2p1, sizeof unix_c2p1) < 0) return 0; dup2(pipe_p2c[1], STDIN_FILENO); close(pipe_p2c[1]); dup2(pipe_c2p1[0], STDOUT_FILENO); close(pipe_c2p1[0]); if (join) dup2(STDOUT_FILENO, STDERR_FILENO); else { connect(pipe_c2p2[0], &unix_c2p2, sizeof unix_c2p2); dup2(pipe_c2p2[0], STDERR_FILENO); close(pipe_c2p2[0]); } } else { close(pipe_p2c[1]); dup2(pipe_p2c[0], STDIN_FILENO); close(pipe_p2c[0]); close(pipe_c2p1[0]); dup2(pipe_c2p1[1], STDOUT_FILENO); close(pipe_c2p1[1]); if (join) dup2(STDOUT_FILENO, STDERR_FILENO); else { close(pipe_c2p2[0]); dup2(pipe_c2p2[1], STDERR_FILENO); close(pipe_c2p2[1]); } } #ifdef HAVE_SECCOMP scmp_filter_ctx ctx = seccomp_init(def_action); if (ctx == NULL) return 1; REP(i, nrules) { int ret = seccomp_rule_add_array(ctx, scmp_rules[i].action, scmp_rules[i].syscall, scmp_rules[i].arg_cnt, scmp_rules[i].arg_array); if (ret < 0) return 1; } if (seccomp_load(ctx) < 0) return 1; seccomp_release(ctx); strcpy(fixed, *argv); execv(fixed, argv); // execve will change the first argument #else execvp(*argv, argv); #endif } else {
int ntpdmain( int argc, char *argv[] ) { l_fp now; struct recvbuf *rbuf; const char * logfilename; # ifdef HAVE_UMASK mode_t uv; # endif # if defined(HAVE_GETUID) && !defined(MPE) /* MPE lacks the concept of root */ uid_t uid; # endif # if defined(HAVE_WORKING_FORK) long wait_sync = 0; int pipe_fds[2]; int rc; int exit_code; # ifdef _AIX struct sigaction sa; # endif # if !defined(HAVE_SETSID) && !defined (HAVE_SETPGID) && defined(TIOCNOTTY) int fid; # endif # endif /* HAVE_WORKING_FORK*/ # ifdef SCO5_CLOCK int fd; int zero; # endif # ifdef NEED_PTHREAD_WARMUP my_pthread_warmup(); # endif # ifdef HAVE_UMASK uv = umask(0); if (uv) umask(uv); else umask(022); # endif saved_argc = argc; saved_argv = argv; progname = argv[0]; initializing = TRUE; /* mark that we are initializing */ parse_cmdline_opts(&argc, &argv); # ifdef DEBUG debug = OPT_VALUE_SET_DEBUG_LEVEL; # ifdef HAVE_SETLINEBUF setlinebuf(stdout); # endif # endif if (HAVE_OPT(NOFORK) || HAVE_OPT(QUIT) # ifdef DEBUG || debug # endif || HAVE_OPT(SAVECONFIGQUIT)) nofork = TRUE; init_logging(progname, NLOG_SYNCMASK, TRUE); /* honor -l/--logfile option to log to a file */ if (HAVE_OPT(LOGFILE)) { logfilename = OPT_ARG(LOGFILE); syslogit = FALSE; change_logfile(logfilename, FALSE); } else { logfilename = NULL; if (nofork) msyslog_term = TRUE; if (HAVE_OPT(SAVECONFIGQUIT)) syslogit = FALSE; } msyslog(LOG_NOTICE, "%s: Starting", Version); { int i; char buf[1024]; /* Secret knowledge of msyslog buf length */ char *cp = buf; /* Note that every arg has an initial space character */ snprintf(cp, sizeof(buf), "Command line:"); cp += strlen(cp); for (i = 0; i < saved_argc ; ++i) { snprintf(cp, sizeof(buf) - (cp - buf), " %s", saved_argv[i]); cp += strlen(cp); } msyslog(LOG_INFO, "%s", buf); } /* * Install trap handlers to log errors and assertion failures. * Default handlers print to stderr which doesn't work if detached. */ isc_assertion_setcallback(assertion_failed); isc_error_setfatal(library_fatal_error); isc_error_setunexpected(library_unexpected_error); /* MPE lacks the concept of root */ # if defined(HAVE_GETUID) && !defined(MPE) uid = getuid(); if (uid && !HAVE_OPT( SAVECONFIGQUIT )) { msyslog_term = TRUE; msyslog(LOG_ERR, "must be run as root, not uid %ld", (long)uid); exit(1); } # endif /* * Enable the Multi-Media Timer for Windows? */ # ifdef SYS_WINNT if (HAVE_OPT( MODIFYMMTIMER )) set_mm_timer(MM_TIMER_HIRES); # endif #ifdef HAVE_DNSREGISTRATION /* * Enable mDNS registrations? */ if (HAVE_OPT( MDNS )) { mdnsreg = TRUE; } #endif /* HAVE_DNSREGISTRATION */ if (HAVE_OPT( NOVIRTUALIPS )) listen_to_virtual_ips = 0; /* * --interface, listen on specified interfaces */ if (HAVE_OPT( INTERFACE )) { int ifacect = STACKCT_OPT( INTERFACE ); const char** ifaces = STACKLST_OPT( INTERFACE ); sockaddr_u addr; while (ifacect-- > 0) { add_nic_rule( is_ip_address(*ifaces, AF_UNSPEC, &addr) ? MATCH_IFADDR : MATCH_IFNAME, *ifaces, -1, ACTION_LISTEN); ifaces++; } } if (HAVE_OPT( NICE )) priority_done = 0; # ifdef HAVE_SCHED_SETSCHEDULER if (HAVE_OPT( PRIORITY )) { config_priority = OPT_VALUE_PRIORITY; config_priority_override = 1; priority_done = 0; } # endif # ifdef HAVE_WORKING_FORK /* make sure the FDs are initialised */ pipe_fds[0] = -1; pipe_fds[1] = -1; do { /* 'loop' once */ if (!HAVE_OPT( WAIT_SYNC )) break; wait_sync = OPT_VALUE_WAIT_SYNC; if (wait_sync <= 0) { wait_sync = 0; break; } /* -w requires a fork() even with debug > 0 */ nofork = FALSE; if (pipe(pipe_fds)) { exit_code = (errno) ? errno : -1; msyslog(LOG_ERR, "Pipe creation failed for --wait-sync: %m"); exit(exit_code); } waitsync_fd_to_close = pipe_fds[1]; } while (0); /* 'loop' once */ # endif /* HAVE_WORKING_FORK */ init_lib(); # ifdef SYS_WINNT /* * Start interpolation thread, must occur before first * get_systime() */ init_winnt_time(); # endif /* * Initialize random generator and public key pair */ get_systime(&now); ntp_srandom((int)(now.l_i * now.l_uf)); /* * Detach us from the terminal. May need an #ifndef GIZMO. */ if (!nofork) { # ifdef HAVE_WORKING_FORK rc = fork(); if (-1 == rc) { exit_code = (errno) ? errno : -1; msyslog(LOG_ERR, "fork: %m"); exit(exit_code); } if (rc > 0) { /* parent */ exit_code = wait_child_sync_if(pipe_fds[0], wait_sync); exit(exit_code); } /* * child/daemon * close all open files excepting waitsync_fd_to_close. * msyslog() unreliable until after init_logging(). */ closelog(); if (syslog_file != NULL) { fclose(syslog_file); syslog_file = NULL; syslogit = TRUE; } close_all_except(waitsync_fd_to_close); INSIST(0 == open("/dev/null", 0) && 1 == dup2(0, 1) \ && 2 == dup2(0, 2)); init_logging(progname, 0, TRUE); /* we lost our logfile (if any) daemonizing */ setup_logfile(logfilename); # ifdef SYS_DOMAINOS { uid_$t puid; status_$t st; proc2_$who_am_i(&puid); proc2_$make_server(&puid, &st); } # endif /* SYS_DOMAINOS */ # ifdef HAVE_SETSID if (setsid() == (pid_t)-1) msyslog(LOG_ERR, "setsid(): %m"); # elif defined(HAVE_SETPGID) if (setpgid(0, 0) == -1) msyslog(LOG_ERR, "setpgid(): %m"); # else /* !HAVE_SETSID && !HAVE_SETPGID follows */ # ifdef TIOCNOTTY fid = open("/dev/tty", 2); if (fid >= 0) { ioctl(fid, (u_long)TIOCNOTTY, NULL); close(fid); } # endif /* TIOCNOTTY */ ntp_setpgrp(0, getpid()); # endif /* !HAVE_SETSID && !HAVE_SETPGID */ # ifdef _AIX /* Don't get killed by low-on-memory signal. */ sa.sa_handler = catch_danger; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGDANGER, &sa, NULL); # endif /* _AIX */ # endif /* HAVE_WORKING_FORK */ } # ifdef SCO5_CLOCK /* * SCO OpenServer's system clock offers much more precise timekeeping * on the base CPU than the other CPUs (for multiprocessor systems), * so we must lock to the base CPU. */ fd = open("/dev/at1", O_RDONLY); if (fd >= 0) { zero = 0; if (ioctl(fd, ACPU_LOCK, &zero) < 0) msyslog(LOG_ERR, "cannot lock to base CPU: %m"); close(fd); } # endif /* Setup stack size in preparation for locking pages in memory. */ # if defined(HAVE_MLOCKALL) # ifdef HAVE_SETRLIMIT ntp_rlimit(RLIMIT_STACK, DFLT_RLIMIT_STACK * 4096, 4096, "4k"); # ifdef RLIMIT_MEMLOCK /* * The default RLIMIT_MEMLOCK is very low on Linux systems. * Unless we increase this limit malloc calls are likely to * fail if we drop root privilege. To be useful the value * has to be larger than the largest ntpd resident set size. */ ntp_rlimit(RLIMIT_MEMLOCK, DFLT_RLIMIT_MEMLOCK * 1024 * 1024, 1024 * 1024, "MB"); # endif /* RLIMIT_MEMLOCK */ # endif /* HAVE_SETRLIMIT */ # else /* !HAVE_MLOCKALL follows */ # ifdef HAVE_PLOCK # ifdef PROCLOCK # ifdef _AIX /* * set the stack limit for AIX for plock(). * see get_aix_stack() for more info. */ if (ulimit(SET_STACKLIM, (get_aix_stack() - 8 * 4096)) < 0) msyslog(LOG_ERR, "Cannot adjust stack limit for plock: %m"); # endif /* _AIX */ # endif /* PROCLOCK */ # endif /* HAVE_PLOCK */ # endif /* !HAVE_MLOCKALL */ /* * Set up signals we pay attention to locally. */ # ifdef SIGDIE1 signal_no_reset(SIGDIE1, finish); signal_no_reset(SIGDIE2, finish); signal_no_reset(SIGDIE3, finish); signal_no_reset(SIGDIE4, finish); # endif # ifdef SIGBUS signal_no_reset(SIGBUS, finish); # endif # if !defined(SYS_WINNT) && !defined(VMS) # ifdef DEBUG (void) signal_no_reset(MOREDEBUGSIG, moredebug); (void) signal_no_reset(LESSDEBUGSIG, lessdebug); # else (void) signal_no_reset(MOREDEBUGSIG, no_debug); (void) signal_no_reset(LESSDEBUGSIG, no_debug); # endif /* DEBUG */ # endif /* !SYS_WINNT && !VMS */ /* * Set up signals we should never pay attention to. */ # ifdef SIGPIPE signal_no_reset(SIGPIPE, SIG_IGN); # endif /* * Call the init_ routines to initialize the data structures. * * Exactly what command-line options are we expecting here? */ INIT_SSL(); init_auth(); init_util(); init_restrict(); init_mon(); init_timer(); init_request(); init_control(); init_peer(); # ifdef REFCLOCK init_refclock(); # endif set_process_priority(); init_proto(); /* Call at high priority */ init_io(); init_loopfilter(); mon_start(MON_ON); /* monitor on by default now */ /* turn off in config if unwanted */ /* * Get the configuration. This is done in a separate module * since this will definitely be different for the gizmo board. */ getconfig(argc, argv); if (-1 == cur_memlock) { # if defined(HAVE_MLOCKALL) /* * lock the process into memory */ if ( !HAVE_OPT(SAVECONFIGQUIT) # ifdef RLIMIT_MEMLOCK && -1 != DFLT_RLIMIT_MEMLOCK # endif && 0 != mlockall(MCL_CURRENT|MCL_FUTURE)) msyslog(LOG_ERR, "mlockall(): %m"); # else /* !HAVE_MLOCKALL follows */ # ifdef HAVE_PLOCK # ifdef PROCLOCK /* * lock the process into memory */ if (!HAVE_OPT(SAVECONFIGQUIT) && 0 != plock(PROCLOCK)) msyslog(LOG_ERR, "plock(PROCLOCK): %m"); # else /* !PROCLOCK follows */ # ifdef TXTLOCK /* * Lock text into ram */ if (!HAVE_OPT(SAVECONFIGQUIT) && 0 != plock(TXTLOCK)) msyslog(LOG_ERR, "plock(TXTLOCK) error: %m"); # else /* !TXTLOCK follows */ msyslog(LOG_ERR, "plock() - don't know what to lock!"); # endif /* !TXTLOCK */ # endif /* !PROCLOCK */ # endif /* HAVE_PLOCK */ # endif /* !HAVE_MLOCKALL */ } loop_config(LOOP_DRIFTINIT, 0); report_event(EVNT_SYSRESTART, NULL, NULL); initializing = FALSE; # ifdef HAVE_DROPROOT if (droproot) { /* Drop super-user privileges and chroot now if the OS supports this */ # ifdef HAVE_LINUX_CAPABILITIES /* set flag: keep privileges accross setuid() call (we only really need cap_sys_time): */ if (prctl( PR_SET_KEEPCAPS, 1L, 0L, 0L, 0L ) == -1) { msyslog( LOG_ERR, "prctl( PR_SET_KEEPCAPS, 1L ) failed: %m" ); exit(-1); } # elif HAVE_SOLARIS_PRIVS /* Nothing to do here */ # else /* we need a user to switch to */ if (user == NULL) { msyslog(LOG_ERR, "Need user name to drop root privileges (see -u flag!)" ); exit(-1); } # endif /* HAVE_LINUX_CAPABILITIES || HAVE_SOLARIS_PRIVS */ if (user != NULL) { if (isdigit((unsigned char)*user)) { sw_uid = (uid_t)strtoul(user, &endp, 0); if (*endp != '\0') goto getuser; if ((pw = getpwuid(sw_uid)) != NULL) { free(user); user = estrdup(pw->pw_name); sw_gid = pw->pw_gid; } else { errno = 0; msyslog(LOG_ERR, "Cannot find user ID %s", user); exit (-1); } } else { getuser: errno = 0; if ((pw = getpwnam(user)) != NULL) { sw_uid = pw->pw_uid; sw_gid = pw->pw_gid; } else { if (errno) msyslog(LOG_ERR, "getpwnam(%s) failed: %m", user); else msyslog(LOG_ERR, "Cannot find user `%s'", user); exit (-1); } } } if (group != NULL) { if (isdigit((unsigned char)*group)) { sw_gid = (gid_t)strtoul(group, &endp, 0); if (*endp != '\0') goto getgroup; } else { getgroup: if ((gr = getgrnam(group)) != NULL) { sw_gid = gr->gr_gid; } else { errno = 0; msyslog(LOG_ERR, "Cannot find group `%s'", group); exit (-1); } } } if (chrootdir ) { /* make sure cwd is inside the jail: */ if (chdir(chrootdir)) { msyslog(LOG_ERR, "Cannot chdir() to `%s': %m", chrootdir); exit (-1); } if (chroot(chrootdir)) { msyslog(LOG_ERR, "Cannot chroot() to `%s': %m", chrootdir); exit (-1); } if (chdir("/")) { msyslog(LOG_ERR, "Cannot chdir() to`root after chroot(): %m"); exit (-1); } } # ifdef HAVE_SOLARIS_PRIVS if ((lowprivs = priv_str_to_set(LOWPRIVS, ",", NULL)) == NULL) { msyslog(LOG_ERR, "priv_str_to_set() failed:%m"); exit(-1); } if ((highprivs = priv_allocset()) == NULL) { msyslog(LOG_ERR, "priv_allocset() failed:%m"); exit(-1); } (void) getppriv(PRIV_PERMITTED, highprivs); (void) priv_intersect(highprivs, lowprivs); if (setppriv(PRIV_SET, PRIV_PERMITTED, lowprivs) == -1) { msyslog(LOG_ERR, "setppriv() failed:%m"); exit(-1); } # endif /* HAVE_SOLARIS_PRIVS */ if (user && initgroups(user, sw_gid)) { msyslog(LOG_ERR, "Cannot initgroups() to user `%s': %m", user); exit (-1); } if (group && setgid(sw_gid)) { msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group); exit (-1); } if (group && setegid(sw_gid)) { msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group); exit (-1); } if (group) { if (0 != setgroups(1, &sw_gid)) { msyslog(LOG_ERR, "setgroups(1, %d) failed: %m", sw_gid); exit (-1); } } else if (pw) if (0 != initgroups(pw->pw_name, pw->pw_gid)) { msyslog(LOG_ERR, "initgroups(<%s>, %d) filed: %m", pw->pw_name, pw->pw_gid); exit (-1); } if (user && setuid(sw_uid)) { msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user); exit (-1); } if (user && seteuid(sw_uid)) { msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user); exit (-1); } # if !defined(HAVE_LINUX_CAPABILITIES) && !defined(HAVE_SOLARIS_PRIVS) /* * for now assume that the privilege to bind to privileged ports * is associated with running with uid 0 - should be refined on * ports that allow binding to NTP_PORT with uid != 0 */ disable_dynamic_updates |= (sw_uid != 0); /* also notifies routing message listener */ # endif /* !HAVE_LINUX_CAPABILITIES && !HAVE_SOLARIS_PRIVS */ if (disable_dynamic_updates && interface_interval) { interface_interval = 0; msyslog(LOG_INFO, "running as non-root disables dynamic interface tracking"); } # ifdef HAVE_LINUX_CAPABILITIES { /* * We may be running under non-root uid now, but we still hold full root privileges! * We drop all of them, except for the crucial one or two: cap_sys_time and * cap_net_bind_service if doing dynamic interface tracking. */ cap_t caps; char *captext; captext = (0 != interface_interval) ? "cap_sys_time,cap_net_bind_service=pe" : "cap_sys_time=pe"; caps = cap_from_text(captext); if (!caps) { msyslog(LOG_ERR, "cap_from_text(%s) failed: %m", captext); exit(-1); } if (-1 == cap_set_proc(caps)) { msyslog(LOG_ERR, "cap_set_proc() failed to drop root privs: %m"); exit(-1); } cap_free(caps); } # endif /* HAVE_LINUX_CAPABILITIES */ # ifdef HAVE_SOLARIS_PRIVS if (priv_delset(lowprivs, "proc_setid") == -1) { msyslog(LOG_ERR, "priv_delset() failed:%m"); exit(-1); } if (setppriv(PRIV_SET, PRIV_PERMITTED, lowprivs) == -1) { msyslog(LOG_ERR, "setppriv() failed:%m"); exit(-1); } priv_freeset(lowprivs); priv_freeset(highprivs); # endif /* HAVE_SOLARIS_PRIVS */ root_dropped = TRUE; fork_deferred_worker(); } /* if (droproot) */ # endif /* HAVE_DROPROOT */ /* libssecomp sandboxing */ #if defined (LIBSECCOMP) && (KERN_SECCOMP) scmp_filter_ctx ctx; if ((ctx = seccomp_init(SCMP_ACT_KILL)) < 0) msyslog(LOG_ERR, "%s: seccomp_init(SCMP_ACT_KILL) failed: %m", __func__); else { msyslog(LOG_DEBUG, "%s: seccomp_init(SCMP_ACT_KILL) succeeded", __func__); } #ifdef __x86_64__ int scmp_sc[] = { SCMP_SYS(adjtimex), SCMP_SYS(bind), SCMP_SYS(brk), SCMP_SYS(chdir), SCMP_SYS(clock_gettime), SCMP_SYS(clock_settime), SCMP_SYS(close), SCMP_SYS(connect), SCMP_SYS(exit_group), SCMP_SYS(fstat), SCMP_SYS(fsync), SCMP_SYS(futex), SCMP_SYS(getitimer), SCMP_SYS(getsockname), SCMP_SYS(ioctl), SCMP_SYS(lseek), SCMP_SYS(madvise), SCMP_SYS(mmap), SCMP_SYS(munmap), SCMP_SYS(open), SCMP_SYS(poll), SCMP_SYS(read), SCMP_SYS(recvmsg), SCMP_SYS(rename), SCMP_SYS(rt_sigaction), SCMP_SYS(rt_sigprocmask), SCMP_SYS(rt_sigreturn), SCMP_SYS(select), SCMP_SYS(sendto), SCMP_SYS(setitimer), SCMP_SYS(setsid), SCMP_SYS(socket), SCMP_SYS(stat), SCMP_SYS(time), SCMP_SYS(write), }; #endif #ifdef __i386__ int scmp_sc[] = { SCMP_SYS(_newselect), SCMP_SYS(adjtimex), SCMP_SYS(brk), SCMP_SYS(chdir), SCMP_SYS(clock_gettime), SCMP_SYS(clock_settime), SCMP_SYS(close), SCMP_SYS(exit_group), SCMP_SYS(fsync), SCMP_SYS(futex), SCMP_SYS(getitimer), SCMP_SYS(madvise), SCMP_SYS(mmap), SCMP_SYS(mmap2), SCMP_SYS(munmap), SCMP_SYS(open), SCMP_SYS(poll), SCMP_SYS(read), SCMP_SYS(rename), SCMP_SYS(rt_sigaction), SCMP_SYS(rt_sigprocmask), SCMP_SYS(select), SCMP_SYS(setitimer), SCMP_SYS(setsid), SCMP_SYS(sigprocmask), SCMP_SYS(sigreturn), SCMP_SYS(socketcall), SCMP_SYS(stat64), SCMP_SYS(time), SCMP_SYS(write), }; #endif { int i; for (i = 0; i < COUNTOF(scmp_sc); i++) { if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, scmp_sc[i], 0) < 0) { msyslog(LOG_ERR, "%s: seccomp_rule_add() failed: %m", __func__); } } } if (seccomp_load(ctx) < 0) msyslog(LOG_ERR, "%s: seccomp_load() failed: %m", __func__); else { msyslog(LOG_DEBUG, "%s: seccomp_load() succeeded", __func__); } #endif /* LIBSECCOMP and KERN_SECCOMP */ # ifdef HAVE_IO_COMPLETION_PORT for (;;) { GetReceivedBuffers(); # else /* normal I/O */ BLOCK_IO_AND_ALARM(); was_alarmed = FALSE; for (;;) { if (alarm_flag) { /* alarmed? */ was_alarmed = TRUE; alarm_flag = FALSE; } if (!was_alarmed && !has_full_recv_buffer()) { /* * Nothing to do. Wait for something. */ io_handler(); } if (alarm_flag) { /* alarmed? */ was_alarmed = TRUE; alarm_flag = FALSE; } if (was_alarmed) { UNBLOCK_IO_AND_ALARM(); /* * Out here, signals are unblocked. Call timer routine * to process expiry. */ timer(); was_alarmed = FALSE; BLOCK_IO_AND_ALARM(); } # endif /* !HAVE_IO_COMPLETION_PORT */ # ifdef DEBUG_TIMING { l_fp pts; l_fp tsa, tsb; int bufcount = 0; get_systime(&pts); tsa = pts; # endif rbuf = get_full_recv_buffer(); while (rbuf != NULL) { if (alarm_flag) { was_alarmed = TRUE; alarm_flag = FALSE; } UNBLOCK_IO_AND_ALARM(); if (was_alarmed) { /* avoid timer starvation during lengthy I/O handling */ timer(); was_alarmed = FALSE; } /* * Call the data procedure to handle each received * packet. */ if (rbuf->receiver != NULL) { # ifdef DEBUG_TIMING l_fp dts = pts; L_SUB(&dts, &rbuf->recv_time); DPRINTF(2, ("processing timestamp delta %s (with prec. fuzz)\n", lfptoa(&dts, 9))); collect_timing(rbuf, "buffer processing delay", 1, &dts); bufcount++; # endif (*rbuf->receiver)(rbuf); } else { msyslog(LOG_ERR, "fatal: receive buffer callback NULL"); abort(); } BLOCK_IO_AND_ALARM(); freerecvbuf(rbuf); rbuf = get_full_recv_buffer(); } # ifdef DEBUG_TIMING get_systime(&tsb); L_SUB(&tsb, &tsa); if (bufcount) { collect_timing(NULL, "processing", bufcount, &tsb); DPRINTF(2, ("processing time for %d buffers %s\n", bufcount, lfptoa(&tsb, 9))); } } # endif /* * Go around again */ # ifdef HAVE_DNSREGISTRATION if (mdnsreg && (current_time - mdnsreg ) > 60 && mdnstries && sys_leap != LEAP_NOTINSYNC) { mdnsreg = current_time; msyslog(LOG_INFO, "Attempting to register mDNS"); if ( DNSServiceRegister (&mdns, 0, 0, NULL, "_ntp._udp", NULL, NULL, htons(NTP_PORT), 0, NULL, NULL, NULL) != kDNSServiceErr_NoError ) { if (!--mdnstries) { msyslog(LOG_ERR, "Unable to register mDNS, giving up."); } else { msyslog(LOG_INFO, "Unable to register mDNS, will try later."); } } else { msyslog(LOG_INFO, "mDNS service registered."); mdnsreg = FALSE; } } # endif /* HAVE_DNSREGISTRATION */ } UNBLOCK_IO_AND_ALARM(); return 1; } #endif /* !SIM */ #if !defined(SIM) && defined(SIGDIE1) /* * finish - exit gracefully */ static RETSIGTYPE finish( int sig ) { const char *sig_desc; sig_desc = NULL; #ifdef HAVE_STRSIGNAL sig_desc = strsignal(sig); #endif if (sig_desc == NULL) sig_desc = ""; msyslog(LOG_NOTICE, "%s exiting on signal %d (%s)", progname, sig, sig_desc); /* See Bug 2513 and Bug 2522 re the unlink of PIDFILE */ # ifdef HAVE_DNSREGISTRATION if (mdns != NULL) DNSServiceRefDeallocate(mdns); # endif peer_cleanup(); exit(0); } #endif /* !SIM && SIGDIE1 */ #ifndef SIM /* * wait_child_sync_if - implements parent side of -w/--wait-sync */ # ifdef HAVE_WORKING_FORK static int wait_child_sync_if( int pipe_read_fd, long wait_sync ) { int rc; int exit_code; time_t wait_end_time; time_t cur_time; time_t wait_rem; fd_set readset; struct timeval wtimeout; if (0 == wait_sync) return 0; /* waitsync_fd_to_close used solely by child */ close(waitsync_fd_to_close); wait_end_time = time(NULL) + wait_sync; do { cur_time = time(NULL); wait_rem = (wait_end_time > cur_time) ? (wait_end_time - cur_time) : 0; wtimeout.tv_sec = wait_rem; wtimeout.tv_usec = 0; FD_ZERO(&readset); FD_SET(pipe_read_fd, &readset); rc = select(pipe_read_fd + 1, &readset, NULL, NULL, &wtimeout); if (-1 == rc) { if (EINTR == errno) continue; exit_code = (errno) ? errno : -1; msyslog(LOG_ERR, "--wait-sync select failed: %m"); return exit_code; } if (0 == rc) { /* * select() indicated a timeout, but in case * its timeouts are affected by a step of the * system clock, select() again with a zero * timeout to confirm. */ FD_ZERO(&readset); FD_SET(pipe_read_fd, &readset); wtimeout.tv_sec = 0; wtimeout.tv_usec = 0; rc = select(pipe_read_fd + 1, &readset, NULL, NULL, &wtimeout); if (0 == rc) /* select() timeout */ break; else /* readable */ return 0; } else /* readable */ return 0; } while (wait_rem > 0); fprintf(stderr, "%s: -w/--wait-sync %ld timed out.\n", progname, wait_sync); return ETIMEDOUT; }
void drop_worker_privileges(void) { scmp_filter_ctx ctx = seccomp_init(DENY_ACTION); if (ctx == NULL) { return; } int rc = 0; rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sigreturn), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_wait), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_pwait), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(poll), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(readv), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpeername), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendmsg), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getrusage), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mremap), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvfrom), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1, SCMP_A1(SCMP_CMP_EQ, TIOCGWINSZ)); // for spawning the LRU crawler rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(set_robust_list), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(madvise), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0); // stat rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockname), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0); if (settings.shutdown_command) { rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(tgkill), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(tkill), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(gettid), 0); } if (settings.relaxed_privileges) { rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mkdir), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(access), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(lseek), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(writev), 0); } else { // stdout rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_EQ, 1)); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(writev), 1, SCMP_A0(SCMP_CMP_EQ, 1)); // stderr rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_EQ, 2)); rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(writev), 1, SCMP_A0(SCMP_CMP_EQ, 2)); } if (rc != 0) { goto fail; } rc = seccomp_load(ctx); if (rc < 0) { goto fail; } seccomp_release(ctx); return; fail: seccomp_release(ctx); fprintf(stderr, "Failed to set a seccomp profile on a worker thread\n"); exit(EXIT_FAILURE); }
int child_process(void *clone_args){ FILE *log_fp = ((struct clone_args *)clone_args)->log_fp; struct config *config = ((struct clone_args *)clone_args)->config; FILE *in_file = NULL, *out_file = NULL, *err_file = NULL; struct rlimit memory_limit, cpu_time_rlimit; gid_t group_list[] = {config->gid}; #ifndef __APPLE__ int i; int syscalls_whitelist[] = {SCMP_SYS(read), SCMP_SYS(fstat), SCMP_SYS(mmap), SCMP_SYS(mprotect), SCMP_SYS(munmap), SCMP_SYS(open), SCMP_SYS(arch_prctl), SCMP_SYS(brk), SCMP_SYS(access), SCMP_SYS(exit_group), SCMP_SYS(close)}; int syscalls_whitelist_length = sizeof(syscalls_whitelist) / sizeof(int); scmp_filter_ctx ctx = NULL; #endif // child process // On success, these system calls return 0. // On error, -1 is returned, and errno is set appropriately. if (config->max_memory != MEMORY_UNLIMITED) { memory_limit.rlim_cur = memory_limit.rlim_max = (rlim_t) (config->max_memory) * 2; if (setrlimit(RLIMIT_AS, &memory_limit) == -1) { LOG_FATAL(log_fp, "setrlimit memory failed, errno: %d", errno); ERROR(log_fp, SETRLIMIT_FAILED); } } if (config->max_cpu_time != CPU_TIME_UNLIMITED) { // cpu time if (set_timer(config->max_cpu_time / 1000, config->max_cpu_time % 1000, 1) != SUCCESS) { LOG_FATAL(log_fp, "set cpu time timer failed"); ERROR(log_fp, SETITIMER_FAILED); } // real time if (set_timer(config->max_real_time / 1000, config->max_real_time % 1000, 0) != SUCCESS) { LOG_FATAL(log_fp, "set real time timer failed"); ERROR(log_fp, SETITIMER_FAILED); } // child process can not inherit timeout rules from parent process defined by setitimer, so we use setrlimit to // control child process max running time cpu_time_rlimit.rlim_cur = cpu_time_rlimit.rlim_max = (config->max_cpu_time + 1000) / 1000; if (setrlimit(RLIMIT_CPU, &cpu_time_rlimit) == -1) { LOG_FATAL(log_fp, "setrlimit cpu time failed, errno: %d", errno); ERROR(log_fp, SETRLIMIT_FAILED); } } // read stdin from in file // On success, these system calls return the new descriptor. // On error, -1 is returned, and errno is set appropriately. if (config->in_file != NULL) { if ((in_file = fopen(config->in_file, "r")) == NULL) { LOG_FATAL(log_fp, "failed to open stdin redirect file"); ERROR(log_fp, DUP2_FAILED); } if (dup2(fileno(in_file), fileno(stdin)) == -1) { LOG_FATAL(log_fp, "dup2 stdin failed, errno: %d", errno); ERROR(log_fp, DUP2_FAILED); } } // write stdout to out file if (config->out_file != NULL) { if ((out_file = fopen(config->out_file, "w")) == NULL) { LOG_FATAL(log_fp, "failed to open stdout redirect file"); ERROR(log_fp, DUP2_FAILED); } if (dup2(fileno(out_file), fileno(stdout)) == -1) { LOG_FATAL(log_fp, "dup2 stdout failed, errno: %d", errno); ERROR(log_fp, DUP2_FAILED); } } // write stderr to err file if (config->err_file != NULL) { // if err_file and out_file are the same path, we use out_file pointer as err_file pointer, to avoid conflict if (strcmp(config->out_file, config->err_file) == 0) { err_file = out_file; } else { if ((err_file = fopen(config->err_file, "w")) == NULL) { LOG_FATAL(log_fp, "failed to open stderr redirect file"); ERROR(log_fp, DUP2_FAILED); } } if (dup2(fileno(err_file), fileno(stderr)) == -1) { LOG_FATAL(log_fp, "dup2 stdout failed, errno: %d", errno); ERROR(log_fp, DUP2_FAILED); } } if (config->gid != -1 && (setgid(config->gid) == -1 || setgroups(sizeof(group_list) / sizeof(gid_t), group_list) == -1)) { LOG_FATAL(log_fp, "setgid failed, errno: %d", errno); ERROR(log_fp, SET_GID_FAILED); } if (config->uid != -1 && setuid(config->uid) == -1) { LOG_FATAL(log_fp, "setuid failed, errno: %d", errno); ERROR(log_fp, SET_UID_FAILED); } #ifndef __APPLE__ if (config->use_sandbox != 0) { // load seccomp rules ctx = seccomp_init(SCMP_ACT_KILL); if (!ctx) { LOG_FATAL(log_fp, "init seccomp failed"); ERROR(log_fp, LOAD_SECCOMP_FAILED); } for (i = 0; i < syscalls_whitelist_length; i++) { if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls_whitelist[i], 0) != 0) { LOG_FATAL(log_fp, "load syscall white list failed"); ERROR(log_fp, LOAD_SECCOMP_FAILED); } } // add extra rule for execve if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(execve), 1, SCMP_A0(SCMP_CMP_EQ, (scmp_datum_t)(config->path))) != 0) { LOG_FATAL(log_fp, "load execve rule failed"); ERROR(log_fp, LOAD_SECCOMP_FAILED); } // only fd 0 1 2 are allowed if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_LE, 2)) != 0) { LOG_FATAL(log_fp, "load dup2 rule failed"); ERROR(log_fp, LOAD_SECCOMP_FAILED); } if (seccomp_load(ctx) != 0) { LOG_FATAL(log_fp, "seccomp load failed"); ERROR(log_fp, LOAD_SECCOMP_FAILED); } seccomp_release(ctx); } #endif execve(config->path, config->args, config->env); LOG_FATAL(log_fp, "execve failed, errno: %d", errno); ERROR(log_fp, EXCEVE_FAILED); return 1; }
void join(pid_t pid, int argc, char **argv, int index) { EUID_ASSERT(); char *homedir = cfg.homedir; extract_command(argc, argv, index); signal (SIGTERM, signal_handler); // if the pid is that of a firejail process, use the pid of the first child process EUID_ROOT(); char *comm = pid_proc_comm(pid); EUID_USER(); if (comm) { if (strcmp(comm, "firejail") == 0) { pid_t child; if (find_child(pid, &child) == 0) { pid = child; printf("Switching to pid %u, the first child process inside the sandbox\n", (unsigned) pid); } } free(comm); } // check privileges for non-root users uid_t uid = getuid(); if (uid != 0) { uid_t sandbox_uid = pid_get_uid(pid); if (uid != sandbox_uid) { fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n"); exit(1); } } EUID_ROOT(); // in user mode set caps seccomp, cpu, cgroup, etc if (getuid() != 0) { extract_caps_seccomp(pid); extract_cpu(pid); extract_cgroup(pid); extract_nogroups(pid); extract_user_namespace(pid); } // set cgroup if (cfg.cgroup) // not available for uid 0 set_cgroup(cfg.cgroup); // join namespaces if (arg_join_network) { if (join_namespace(pid, "net")) exit(1); } else if (arg_join_filesystem) { if (join_namespace(pid, "mnt")) exit(1); } else { if (join_namespace(pid, "ipc") || join_namespace(pid, "net") || join_namespace(pid, "pid") || join_namespace(pid, "uts") || join_namespace(pid, "mnt")) exit(1); } pid_t child = fork(); if (child < 0) errExit("fork"); if (child == 0) { // chroot into /proc/PID/root directory char *rootdir; if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) errExit("asprintf"); int rv; if (!arg_join_network) { rv = chroot(rootdir); // this will fail for processes in sandboxes not started with --chroot option if (rv == 0) printf("changing root to %s\n", rootdir); } prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died if (chdir("/") < 0) errExit("chdir"); if (homedir) { struct stat s; if (stat(homedir, &s) == 0) { /* coverity[toctou] */ if (chdir(homedir) < 0) errExit("chdir"); } } // set cpu affinity if (cfg.cpus) // not available for uid 0 set_cpu_affinity(); // set caps filter if (apply_caps == 1) // not available for uid 0 caps_set(caps); #ifdef HAVE_SECCOMP // read cfg.protocol from file if (getuid() != 0) protocol_filter_load(RUN_PROTOCOL_CFG); if (cfg.protocol) { // not available for uid 0 seccomp_load(RUN_SECCOMP_PROTOCOL); // install filter } // set seccomp filter if (apply_seccomp == 1) // not available for uid 0 seccomp_load(RUN_SECCOMP_CFG); #endif // mount user namespace or drop privileges if (arg_noroot) { // not available for uid 0 if (arg_debug) printf("Joining user namespace\n"); if (join_namespace(1, "user")) exit(1); // user namespace resets capabilities // set caps filter if (apply_caps == 1) // not available for uid 0 caps_set(caps); } else drop_privs(arg_nogroups); // nogroups not available for uid 0 // set nice if (arg_nice) { errno = 0; int rv = nice(cfg.nice); (void) rv; if (errno) { fprintf(stderr, "Warning: cannot set nice value\n"); errno = 0; } } env_defaults(); if (cfg.command_line == NULL) { assert(cfg.shell); cfg.command_line = cfg.shell; cfg.window_title = cfg.shell; } int cwd = 0; if (cfg.cwd) { if (chdir(cfg.cwd) == 0) cwd = 1; } if (!cwd) { if (chdir("/") < 0) errExit("chdir"); if (cfg.homedir) { struct stat s; if (stat(cfg.homedir, &s) == 0) { /* coverity[toctou] */ if (chdir(cfg.homedir) < 0) errExit("chdir"); } } } start_application(); // it will never get here!!! } // wait for the child to finish waitpid(child, NULL, 0); flush_stdin(); exit(0); }
/** * Initialize seccomp. * * @param remote file descriptor to talk with the unprivileged process * @param monitored monitored child * @return negative on failures or 0 if everything was setup */ int priv_seccomp_init(int remote, int child) { int rc = -1; scmp_filter_ctx ctx; log_debug("seccomp", "initialize libseccomp filter"); monitored = child; if (priv_seccomp_trap_install() < 0) { log_warn("seccomp", "unable to install SIGSYS handler"); goto failure_scmp; } if ((ctx = seccomp_init(SCMP_ACT_TRAP)) == NULL) { log_warnx("seccomp", "unable to initialize libseccomp subsystem"); goto failure_scmp; } if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, SCMP_CMP(0, SCMP_CMP_EQ, remote))) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_CMP(0, SCMP_CMP_EQ, remote))) < 0) { errno = -rc; log_warn("seccomp", "unable to allow read/write on remote socket"); goto failure_scmp; } /* We are far more generic from here. */ if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0)) < 0 || /* write needed for */ (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(kill), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(bind), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(uname), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(unlink), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendmsg), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(wait4), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(stat), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0)) < 0 || /* The following are for resolving addresses */ (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(connect), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0)) < 0 || (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0)) < 0) { errno = -rc; log_warn("seccomp", "unable to build seccomp rules"); goto failure_scmp; } if ((rc = seccomp_load(ctx)) < 0) { errno = -rc; log_warn("seccomp", "unable to load libseccomp filter"); goto failure_scmp; } failure_scmp: seccomp_release(ctx); return rc; }
void GenHash::calcGenHash() { sandbox_init(); // cannot excute execve prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); kDebug() << "execve" << execve("ls",NULL,NULL); if (child_pid){ KParts::ReadOnlyPart * part = qobject_cast<KParts::ReadOnlyPart *>(parent()); QFile file(KFileDialog::getOpenFileName(KUrl("kfiledialog:///konqueror"), i18n("*"), part->widget(), i18n("Open File To make MD5."))); if (!file.open(QIODevice::ReadOnly)) { return; } // TODO QFile //char s[1024]; // write file content { close(pipe_fd[0]); QByteArray s = file.readAll(); char *ch = s.data(); if (write(pipe_fd[1], ch, s.size()) < 0) { perror("write"); } close(pipe_fd[1]); } //read result { close(pipe_result_fd[1]); char result[128]; if (read(pipe_result_fd[0], &result[0], 128) < 0){ perror("read"); } close(pipe_result_fd[0]); KMessageBox::information(part->widget(),i18n("Md5 : %1").arg(QString(QByteArray(result, 128)))); } }else{ scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 3, SCMP_A0(SCMP_CMP_EQ, (scmp_datum_t)pipe_fd[0]), SCMP_A1(SCMP_CMP_EQ, (scmp_datum_t)buff), SCMP_A2(SCMP_CMP_LE, 1024)); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_CMP(0, SCMP_CMP_EQ, (scmp_datum_t)pipe_result_fd[1])); seccomp_load(ctx); seccomp_release(ctx); calcMD5(); } }
int disable_system_calls(struct worker_st *ws) { int ret; scmp_filter_ctx ctx; ctx = seccomp_init(SCMP_ACT_KILL); if (ctx == NULL) { oclog(ws, LOG_DEBUG, "could not initialize seccomp"); return -1; } #define ADD_SYSCALL(name, ...) \ ret = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(name), __VA_ARGS__); \ /* libseccomp returns EDOM for pseudo-syscalls due to a bug */ \ if (ret < 0 && ret != -EDOM) { \ oclog(ws, LOG_DEBUG, "could not add " #name " to seccomp filter: %s", strerror(-ret)); \ ret = -1; \ goto fail; \ } ADD_SYSCALL(time, 0); ADD_SYSCALL(gettimeofday, 0); ADD_SYSCALL(recvmsg, 0); ADD_SYSCALL(sendmsg, 0); ADD_SYSCALL(read, 0); ADD_SYSCALL(write, 0); ADD_SYSCALL(writev, 0); ADD_SYSCALL(send, 0); ADD_SYSCALL(recv, 0); /* it seems we need to add sendto and recvfrom * since send() and recv() aren't real system * calls. */ ADD_SYSCALL(sendto, 0); ADD_SYSCALL(recvfrom, 0); ADD_SYSCALL(select, 0); ADD_SYSCALL(alarm, 0); ADD_SYSCALL(close, 0); ADD_SYSCALL(exit, 0); ADD_SYSCALL(exit_group, 0); ADD_SYSCALL(socket, 0); ADD_SYSCALL(connect, 0); /* this we need to get the MTU from * the TUN device */ ADD_SYSCALL(ioctl, 1, SCMP_A1(SCMP_CMP_EQ, (int)SIOCGIFDSTADDR)); ADD_SYSCALL(ioctl, 1, SCMP_A1(SCMP_CMP_EQ, (int)SIOCGIFADDR)); ADD_SYSCALL(ioctl, 1, SCMP_A1(SCMP_CMP_EQ, (int)SIOCGIFMTU)); ret = seccomp_load(ctx); if (ret < 0) { oclog(ws, LOG_DEBUG, "could not load seccomp filter"); ret = -1; goto fail; } ret = 0; fail: seccomp_release(ctx); return ret; }
int main(int argc, char* argv[], char* envp[]) { if (argc<3 || !strcmp(argv[1], "-?") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "--version")) { fprintf(stderr, "Usage: limit_syscalls syscall1 syscall2 ... syscallN -- program [arguments]\n"); fprintf(stderr, "Example:\n" " limit_syscalls execve exit write read open close mmap2 fstat64 access mprotect set_thread_area -- /bin/echo qqq\n"); fprintf(stderr, "Advanced:\n"); fprintf(stderr, " LIMIT_SYSCALLS_DEFAULT_ACTION={a,k,eN} - by default allow, kill or return error N\n"); fprintf(stderr, " some_syscall,A0>=3,A4<<1000,A1!=4,A2&&0x0F==0x0F - compare arguments\n"); fprintf(stderr, " some_syscall,{a,k,eN} - allow, kill or return error N for this rule\n"); fprintf(stderr, "Some more example:\n"); fprintf(stderr," LIMIT_SYSCALLS_DEFAULT_ACTION=a limit_syscalls 'write,A0==1,e0' -- /usr/bin/printf --help\n"); fprintf(stderr," (this makes write to stdout in /usr/bin/printf silently fail, looping it)\n"); return 126; } // ECHRNG, just to provide more or less noticable message when we block a syscall uint32_t default_action = SCMP_ACT_ERRNO(44); if (getenv("LIMIT_SYSCALLS_DEFAULT_ACTION")) { const char* e = getenv("LIMIT_SYSCALLS_DEFAULT_ACTION"); if(!strcmp(e, "a")) default_action=SCMP_ACT_ALLOW; else if(!strcmp(e, "k")) default_action=SCMP_ACT_KILL; else if(e[0] == 'e') { int errno_; if (sscanf(e+1,"%i", &errno_)!=1) { fprintf(stderr, "LIMIT_SYSCALLS_DEFAULT_ACTION=e<number> expected\n"); return 109; } default_action=SCMP_ACT_ERRNO(errno_); } else { fprintf(stderr, "LIMIT_SYSCALLS_DEFAULT_ACTION should be a, k or e<number>\n"); return 110; } } scmp_filter_ctx ctx = seccomp_init(default_action); if (!ctx) { perror("seccomp_init"); return 126; } int i; for (i=1; i<argc; ++i) { if (!strcmp(argv[i], "--")) break; const char* syscall_name = strtok(argv[i], ","); int syscall = seccomp_syscall_resolve_name(argv[i]); if (syscall == __NR_SCMP_ERROR) { fprintf(stderr, "Failed to resolve syscall %s\n", syscall_name); return 125; } int nargs = 0; struct scmp_arg_cmp args[6]; uint32_t action = SCMP_ACT_ALLOW; const char* aa = strtok(NULL, ","); for (;aa; aa=strtok(NULL, ",")) { if (aa[0]=='A') { if(nargs==6) { fprintf(stderr, "Maximum comparator count (6) exceed in %s\n", argv[i]); return 103; } if( !(aa[1]>='0' && aa[1]<='5') ) { fprintf(stderr, "A[0-5] expected in %s\n", argv[i]); return 100; } int cmp = 0; /* invalid value */ if(!strncmp(aa+2, "!=", 2)) cmp=SCMP_CMP_NE; if(!strncmp(aa+2, "<<", 2)) cmp=SCMP_CMP_LT; if(!strncmp(aa+2, "<=", 2)) cmp=SCMP_CMP_LE; if(!strncmp(aa+2, "==", 2)) cmp=SCMP_CMP_EQ; if(!strncmp(aa+2, ">=", 2)) cmp=SCMP_CMP_GE; if(!strncmp(aa+2, ">>", 2)) cmp=SCMP_CMP_GT; if(!strncmp(aa+2, "&&", 2)) cmp=SCMP_CMP_MASKED_EQ; if (!cmp) { fprintf(stderr, "After An there should be comparison operator like" " != << <= == => >> ot &&; in %s\n", argv[i]); return 101; } if (cmp != SCMP_CMP_MASKED_EQ) { scmp_datum_t datum; if(sscanf(aa+4, "%lli", &datum)!=1) { fprintf(stderr, "After AxOP there should be some sort of number in %s\n", argv[i]); return 102; } args[nargs++] = SCMP_CMP(aa[1]-'0', cmp, datum); } else { scmp_datum_t mask; scmp_datum_t datum; if(sscanf(aa+4, "%lli==%lli", &mask, &datum)!=2) { fprintf(stderr, "After Ax&& there should be number==number; in %s\n", argv[i]); return 104; } args[nargs++] = SCMP_CMP(aa[1]-'0', SCMP_CMP_MASKED_EQ, mask, datum); } } else if (aa[0]=='e') { int errno_; if (sscanf(aa+1,"%i", &errno_)!=1) { fprintf(stderr, "After e should be number in %s\n", argv[i]); return 105; } action = SCMP_ACT_ERRNO(errno_); } else if (aa[0]=='k') { action = SCMP_ACT_KILL; } else if (aa[0]=='a') { action = SCMP_ACT_ALLOW; } else { fprintf(stderr, "Unknown %c in %s\n", aa[0], argv[i]); return 107; } } int ret = seccomp_rule_add_hack(ctx, action, syscall, nargs, args); if (ret!=0) { fprintf(stderr, "seccomp_rule_add returned %d\n", ret); return 124; } } int ret = seccomp_load(ctx); if (ret!=0) { fprintf(stderr, "seccomp_load returned %d\n", ret); } execve(argv[i+1], argv+i+1, envp); perror("execve"); return 123; }