123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- #include <seccomp.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/ioctl.h>
- enum {
- PLEDGE_STDIO = 1 << 0,
- PLEDGE_RPATH = 1 << 1,
- PLEDGE_WPATH = 1 << 2,
- PLEDGE_CPATH = 1 << 3,
- PLEDGE_DPATH = 1 << 4,
- PLEDGE_TMPPATH = 1 << 5,
- PLEDGE_INET = 1 << 6,
- PLEDGE_FATTR = 1 << 7,
- PLEDGE_FLOCK = 1 << 8,
- PLEDGE_UNIX = 1 << 9,
- PLEDGE_DNS = 1 << 10,
- PLEDGE_GETPW = 1 << 11,
- PLEDGE_SENDFD = 1 << 12,
- PLEDGE_RECVFD = 1 << 13,
- PLEDGE_IOCTL = 1 << 14,
- PLEDGE_TTY = 1 << 15,
- PLEDGE_PROC = 1 << 16,
- PLEDGE_EXEC = 1 << 17,
- PLEDGE_PROT_EXEC = 1 << 18,
- PLEDGE_SETTIME = 1 << 19,
- PLEDGE_PS = 1 << 20,
- PLEDGE_VMINFO = 1 << 21,
- PLEDGE_ID = 1 << 22,
- PLEDGE_PF = 1 << 23,
- PLEDGE_AUDIO = 1 << 24,
- };
- typedef struct {
- char *name;
- int mask;
- } promise;
- promise ptable[] = {
- { .name = "stdio", .mask = PLEDGE_STDIO },
- { .name = "rpath", .mask = PLEDGE_RPATH },
- { .name = "wpath", .mask = PLEDGE_WPATH },
- { .name = "cpath", .mask = PLEDGE_CPATH },
- { .name = "dpath", .mask = PLEDGE_DPATH },
- { .name = "tmppath", .mask = PLEDGE_TMPPATH },
- { .name = "inet", .mask = PLEDGE_INET },
- { .name = "fattr", .mask = PLEDGE_FATTR },
- { .name = "flock", .mask = PLEDGE_FLOCK },
- { .name = "unix", .mask = PLEDGE_UNIX },
- { .name = "dns", .mask = PLEDGE_DNS },
- { .name = "getpw", .mask = PLEDGE_GETPW },
- { .name = "sendfd", .mask = PLEDGE_SENDFD },
- { .name = "recvfd", .mask = PLEDGE_RECVFD },
- { .name = "ioctl", .mask = PLEDGE_IOCTL },
- { .name = "tty", .mask = PLEDGE_TTY },
- { .name = "proc", .mask = PLEDGE_PROC },
- { .name = "exec", .mask = PLEDGE_EXEC },
- { .name = "prot_exec", .mask = PLEDGE_PROT_EXEC },
- { .name = "settime", .mask = PLEDGE_SETTIME },
- { .name = "ps", .mask = PLEDGE_PS },
- { .name = "vminfo", .mask = PLEDGE_VMINFO },
- { .name = "id", .mask = PLEDGE_ID },
- { .name = "pf", .mask = PLEDGE_PF },
- { .name = "audio", .mask = PLEDGE_AUDIO },
- };
- int
- pledge(const char *promises, const char *paths[])
- {
- int i, n, f;
- int flags = 0;
- int rc = -1;
- scmp_filter_ctx ctx;
- ctx = seccomp_init(SCMP_ACT_TRAP);
- if (!ctx) {
- errno = EACCES;
- goto out;
- }
- while (*promises) {
- // skip spaces
- while (*promises && *promises == ' ') promises++;
- // look for a token
- f = 0;
- for (i = 0; i < sizeof(ptable)/sizeof(*ptable); i++) {
- n = strlen(ptable[i].name);
- if (!strncmp(promises, ptable[i].name, n)) {
- // this can be removed once every promise has been implemented
- if (!ptable[i].mask) {
- errno = ENOSYS;
- goto out;
- }
- flags |= ptable[i].mask;
- promises += n;
- f = 1;
- break;
- }
- }
- // what we saw was not any valid token
- if (!f) {
- errno = EINVAL;
- goto out;
- }
- // ensure the token is terminated by a space or end of string
- if (*promises && *promises != ' ') {
- errno = EINVAL;
- goto out;
- }
- }
- #define RULE(syscall) \
- rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(syscall), 0); \
- if (rc < 0) goto out
- // everyone is allowed to exit
- RULE(exit_group);
- if (flags & PLEDGE_STDIO) {
- RULE(clock_getres);
- RULE(clock_gettime);
- RULE(close);
- /* RULE(closefrom); */
- RULE(dup);
- RULE(dup2);
- RULE(dup3);
- RULE(fchdir);
- RULE(fcntl);
- RULE(fstat);
- RULE(fsync);
- RULE(ftruncate);
- RULE(getdents);
- /* RULE(getdtablecount); */
- RULE(getegid);
- /* RULE(getentropy); */
- RULE(geteuid);
- RULE(getgid);
- RULE(getgroups);
- RULE(getitimer);
- /* RULE(getlogin); */
- RULE(getpgid);
- RULE(getpgrp);
- RULE(getpid);
- RULE(getppid);
- RULE(getresgid);
- RULE(getresuid);
- RULE(getrlimit);
- RULE(getsid);
- /* RULE(getthrid); */
- RULE(gettimeofday);
- RULE(getuid);
- RULE(getuid);
- /* RULE(issetugid); */
- /* RULE(kevent); */
- /* RULE(kqueue); */
- RULE(lseek);
- RULE(madvise);
- /* RULE(minherit); */
- RULE(mmap);
- RULE(mprotect);
- /* RULE(mquery); */
- RULE(munmap);
- RULE(nanosleep);
- RULE(pipe);
- RULE(pipe2);
- RULE(poll);
- /* RULE(pread); */
- RULE(preadv);
- /* RULE(pwrite); */
- RULE(pwritev);
- RULE(read);
- RULE(readv);
- RULE(recvfrom);
- RULE(recvmsg);
- RULE(select);
- RULE(sendmsg);
- /* RULE(sendsyslog); */
- /* sendto: only if dest sockaddr is NULL */
- RULE(sendto);
- RULE(setitimer);
- RULE(shutdown);
- RULE(sigaction);
- RULE(sigprocmask);
- RULE(sigreturn);
- RULE(socketpair);
- RULE(umask);
- RULE(wait4);
- RULE(write);
- RULE(writev);
- }
- if (flags & PLEDGE_RPATH) {
- /* Allowed if the only cause read-only effects on file system */
- RULE(chdir);
- RULE(getcwd);
- RULE(openat);
- /* RULE(fstatat); */
- RULE(faccessat);
- RULE(readlinkat);
- RULE(lstat);
- RULE(chmod);
- RULE(fchmod);
- RULE(fchmodat);
- /* RULE(chflags); */
- /* RULE(chflagsat); */
- RULE(chown);
- RULE(fchown);
- RULE(fchownat);
- RULE(fstat);
- /* RULE(getfsstat); */
- }
- if (flags & PLEDGE_WPATH) {
- /* system calls may have write effects on file system */
- RULE(getcwd);
- RULE(openat);
- /* RULE(fstatat); */
- RULE(faccessat);
- RULE(readlinkat);
- RULE(lstat);
- RULE(chmod);
- RULE(fchmod);
- RULE(fchmodat);
- /* RULE(chflags); */
- /* RULE(chflagsat); */
- RULE(chown);
- RULE(fchown);
- RULE(fchownat);
- RULE(fstat);
- }
- if (flags & PLEDGE_CPATH) {
- /* system calls may create new files or directories on file system */
- RULE(rename);
- RULE(rmdir);
- RULE(renameat);
- RULE(link);
- RULE(linkat);
- RULE(symlink);
- RULE(unlink);
- RULE(unlinkat);
- RULE(mkdir);
- RULE(mkdirat);
- }
- if (flags & PLEDGE_DPATH) {
- /* may create special files */
- /* RULE(mkfifo); */
- RULE(mknod);
- }
- if (flags & PLEDGE_TMPPATH) {
- /* system calls permitted to read, write, and create in /tmp directory */
- RULE(lstat);
- RULE(chmod);
- /* RULE(chflags); */
- RULE(chown);
- RULE(unlink);
- RULE(fstat);
- }
- if (flags & PLEDGE_INET) {
- /* system calls may operate in AF_INET and AF_INET6 domains */
- RULE(socket);
- RULE(listen);
- RULE(bind);
- RULE(connect);
- RULE(accept4);
- RULE(accept);
- RULE(getpeername);
- RULE(getsockname);
- /* setsockopt: substantially reduced in functionality */
- RULE(setsockopt);
- RULE(getsockopt);
- }
- if (flags & PLEDGE_FATTR) {
- /* system calls may make explicit changes in struct stat of a file */
- RULE(socket);
- RULE(listen);
- RULE(bind);
- RULE(connect);
- RULE(accept4);
- RULE(accept);
- RULE(getpeername);
- RULE(getsockname);
- RULE(setsockopt);
- RULE(getsockopt);
- }
- if (flags & PLEDGE_FLOCK) {
- /* no distinction btw shared/exclusive locks; required for lock/unlock */
- RULE(fcntl);
- RULE(flock);
- /* RULE(lockf); */
- RULE(open);
- }
- if (flags & PLEDGE_UNIX) {
- /* system calls may operate in AF_UNIX domain */
- RULE(socket);
- RULE(listen);
- RULE(bind);
- RULE(connect);
- RULE(accept4);
- RULE(accept);
- RULE(getpeername);
- RULE(getsockname);
- RULE(setsockopt);
- RULE(getsockopt);
- }
- if (flags & PLEDGE_DNS) {
- /* subsequent to successful open of /etc/resolv.conf; allow DNS xaction */
- RULE(sendto);
- RULE(recvfrom);
- RULE(socket);
- RULE(connect);
- }
- if (flags & PLEDGE_GETPW) {
- /* ro opening of files in /etc */
- /* RULE(getpwnam); */
- /* RULE(getgrnam); */
- /* RULE(getgrouplist); */
- /* RULE(initgroups); */
- }
- if (flags & PLEDGE_SENDFD) {
- /* directory FDs not permitted */
- RULE(sendmsg);
- }
- if (flags & PLEDGE_RECVFD) {
- /* directory FDs not permitted */
- RULE(recvmsg);
- }
- if (flags & PLEDGE_IOCTL) {
- /* allows subset of ioctl:
- * FIOCLEX
- * FIONCLEX
- * FIOASYNC
- * FIOGETOWN
- * FIOSETOWN
- * TIOCGETA succeed on tty device, otherwise fail with EPERM
- * TIOCGPGRP and TIOCGWINSZ allowed on tty device
- * Rather than test for tty device, just let ioctl fail on ENOTTY
- * A few other operations are allowed, but not listed here (?)
- */
- rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, FIOCLEX));
- rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, FIONCLEX));
- rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, FIOASYNC));
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, FIOGETOWN)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, FIOSETOWN)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 2,
- SCMP_A1(SCMP_CMP_EQ, TIOCGETA)); */
- rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 2,
- SCMP_A1(SCMP_CMP_EQ, TIOCGPGRP));
- }
- if (flags & PLEDGE_TTY) {
- /* allows subset of ioctl:
- * TIOCSPGRP
- * TIOCGETA
- * TIOCGPGRP
- * TIOCGWINSZ
- * TIOCSWINSZ
- * TIOCSBRK
- * TIOCCDTR
- * TIOCSETA
- * TIOCSETAW
- * TIOCSETAF
- */
- rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, TIOCSPGRP));
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, TIOCGETA)); */
- rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, TIOCGPGRP));
- 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, TIOCSWINSZ));
- rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, TIOCSBRK));
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, TIOCCDTR)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, TIOCSETA)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, TIOCSETAW)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, TIOCSETAF)); */
- /* Also, allow r/w operations on /dev/tty */
- }
- if (flags & PLEDGE_TTY & PLEDGE_RPATH) {
- /* RULE(revoke); */
- }
- if (flags & PLEDGE_PROC) {
- RULE(fork);
- RULE(vfork);
- RULE(kill);
- RULE(getpriority);
- RULE(setpriority);
- RULE(setrlimit);
- RULE(setpgid);
- RULE(setsid);
- }
- if (flags & PLEDGE_EXEC) {
- RULE(execve);
- }
- if (flags & PLEDGE_PROT_EXEC) {
- /* Allows use of PROT_EXEC with the following system calls */
- RULE(mmap);
- RULE(mprotect);
- }
- if (flags & PLEDGE_SETTIME) {
- /* Allows setting of system time via the following system calls */
- RULE(settimeofday);
- /* RULE(adjtime); */
- /* RULE(and adjfreq); */
- }
- if (flags & PLEDGE_PS) {
- /* Allows sufficient sysctl access for inspection of procs, as in ps */
- /* RULE(sysctl); */
- }
- if (flags & PLEDGE_VMINFO) {
- /* Allows sufficient sysctl access for inspection of virtual mem,
- * as in top, vmstat */
- /* RULE(sysctl); */
- }
- if (flags & PLEDGE_ID) {
- RULE(setuid);
- /* RULE(seteuid); */
- RULE(setreuid);
- RULE(setresuid);
- RULE(setgid);
- /* RULE(setegid); */
- RULE(setregid);
- RULE(setresgid);
- RULE(setgroups);
- /* RULE(setlogin); */
- RULE(setrlimit);
- RULE(getpriority);
- RULE(setpriority);
- }
- if (flags & PLEDGE_PF) {
- /* Allows the following subset of ioctl operations on the pf(4) device:
- * DIOCADDRULE
- * DIOCGETSTATUS
- * DIOCNATLOOK
- * DIOCRADDTABLES
- * DIOCRCLRADDRS
- * DIOCRCLRTABLES
- * DIOCRCLRTSTATS
- * DIOCRGETTSTATS
- * DIOCRSETADDRS
- * DIOCXBEGIN
- * DIOCXCOMMIT
- */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, DIOCADDRULE)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, DIOCGETSTATUS)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, DIOCNATLOOK)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, DIOCRADDTABLES)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, DIOCRCLRADDRS)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, DIOCRCLRTABLES)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, DIOCRCLRTSTATS)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, DIOCRGETTSTATS)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, DIOCRSETADDRS)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, DIOCXBEGIN)); */
- }
- if (flags & PLEDGE_AUDIO) {
- /* Allows the following subset of ioctl operations on the audio(4) device:
- * AUDIO_GETPOS
- * AUDIO_SETINFO
- * AUDIO_GETINFO
- * AUDIO_GETENC
- * AUDIO_SETFD
- * AUDIO_GETPROPS
- */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, AUDIO_GETPOS)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, AUDIO_SETINFO)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, AUDIO_GETINFO)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, AUDIO_GETENC)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, AUDIO_SETFD)); */
- /* rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
- SCMP_A1(SCMP_CMP_EQ, AUDIO_GETPROPS)); */
- }
- rc = seccomp_load(ctx);
- if (rc < 0) goto out;
- rc = 0;
- out:
- seccomp_release(ctx);
- return rc;
- }
|