playground

Sandbox, container or whatever utilities for linux.
git clone https://pi.duncano.de/git/playground.git
Log | Files | Refs | README

commit 70f512a5c5ce8028f9f78232bcaa0d307878f3b1
parent dc525808e440e5f7a0c6fb284046744a888a17c4
Author: Duncaen <mail@duncano.de>
Date:   Tue, 21 Feb 2017 04:32:42 +0100

libpledge: more filters (SYS_open flags) and some fixes

Diffstat:
config.mk | 2+-
include/pledge.h | 5+++++
include/seccomp_bpf_utils.h | 6++++++
libpledge.c | 56+++++++++++++++++++++++++++++++++++++++++---------------
tests/pledge/test_filter_conditions.c | 4++++
5 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/config.mk b/config.mk @@ -6,6 +6,6 @@ MANDIR=$(PREFIX)/share/man CFLAGS+=-std=c99 -g -O2 -fstack-protector-strong -Iinclude CFLAGS+=-Wall -Wextra -Wwrite-strings -Wno-switch -Wno-extended-offsetof -pedantic -CPPFLAGS+=-D_DEFAULT_SOURCE -D_FORTIFY_SOURCE=2 +CPPFLAGS+=-D_DEFAULT_SOURCE -D_GNU_SOURCE -D_FORTIFY_SOURCE=2 CC=cc diff --git a/include/pledge.h b/include/pledge.h @@ -32,6 +32,11 @@ #define _FLAG_DROPPED(x) \ ((oldflags&(x)) && (~flags&(x))) +#define _FILTER_OPEN \ + (!oldflags && !(flags&PLEDGE_CPATH)) || _FLAG_DROPPED(PLEDGE_CPATH) \ + ? FILTER_BLACKLIST \ + : 0 + #define _FILTER_CHOWN \ (!oldflags && !(flags&PLEDGE_CHOWNUID)) \ ? FILTER_WHITELIST \ diff --git a/include/seccomp_bpf_utils.h b/include/seccomp_bpf_utils.h @@ -63,6 +63,12 @@ union arg64 { fp++; \ } while (0) +#define _JUMP_SET(v, t, f) do { \ + *fp = (struct sock_filter)BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, \ + (v), (t), (f)); \ + fp++; \ +} while (0) + #define _JUMP_EQ64(val, jt, jf) do { \ *fp = (struct sock_filter)BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \ ((union arg64){.u64 = (val)}).u32.hi, 0, (jf)); \ diff --git a/libpledge.c b/libpledge.c @@ -1,24 +1,26 @@ -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdint.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <endian.h> - -#include <asm/bitsperlong.h> /* for __BITS_PER_LONG */ - #include <sys/prctl.h> #include <sys/ioctl.h> #include <sys/syscall.h> #include <sys/socket.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <asm/bitsperlong.h> /* for __BITS_PER_LONG */ #include <linux/filter.h> #include <linux/seccomp.h> #include <linux/audit.h> +#include <endian.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + #include "pledge.h" #include "pledge_syscalls.h" #include "seccomp_bpf_utils.h" @@ -177,6 +179,7 @@ pledge_filter(uint64_t flags, uint64_t oldflags) struct sock_filter *fp; uint64_t len; int allow_prctl, allow_socket, allow_selfkill, allow_fcntl, allow_selfchown, allow_ioctl_always, allow_ioctl_ioctl; + int filter_open; len = 0; @@ -187,6 +190,10 @@ pledge_filter(uint64_t flags, uint64_t oldflags) allow_fcntl = _FILTER_FCNTL; allow_ioctl_always = _FILTER_IOCTL_ALWAYS; allow_ioctl_ioctl= _FILTER_IOCTL_IOCTL; + filter_open = _FILTER_OPEN; + + if (filter_open) + len += 9; /* chown(2), fchown(2), lchown(2), fchownat(2) */ if (allow_selfchown) @@ -212,11 +219,11 @@ pledge_filter(uint64_t flags, uint64_t oldflags) len += 3; if (allow_ioctl_always || allow_ioctl_ioctl) { - len += 5; + len += 6; if (allow_ioctl_always) len += 12; if (allow_ioctl_ioctl) - len += 18; + len += 21; } /* no new filters */ @@ -235,6 +242,7 @@ pledge_filter(uint64_t flags, uint64_t oldflags) printf("allowfcntl %d\n", allow_fcntl); printf("allow ioctl always %d\n", allow_ioctl_always); printf("allow ioctl ioctl %d\n", allow_ioctl_ioctl); + printf("filter open %d\n", filter_open); if (!(fprog = calloc(1, sizeof(struct sock_fprog)))) return 0; @@ -251,6 +259,21 @@ pledge_filter(uint64_t flags, uint64_t oldflags) _LOAD_SYSCALL_NR; + if (filter_open) { + /* allow kill(0 | getpid(), ...) */ + _JUMP_EQ(SYS_open, 0, 8); + _ARG32(1); + _JUMP_SET(O_RDWR, _EPERM, 0); + _JUMP_SET(O_WRONLY, _EPERM, 0); + _JUMP_SET(O_APPEND, _EPERM, 0); + _JUMP_SET(O_CREAT, _EPERM, 0); + /* O_TMPFILE and O_DIRECTORY conflict... */ + /* _JUMP_SET(O_TMPFILE, _EPERM, 0); */ + _JUMP_SET(O_TRUNC, _EPERM, 0); + _JUMP_SET(O_TRUNC, _EPERM, 0); + _LOAD_SYSCALL_NR; + } + if (allow_selfkill) { pid_t pid = getpid(); /* allow kill(0 | getpid(), ...) */ @@ -316,7 +339,7 @@ pledge_filter(uint64_t flags, uint64_t oldflags) /* allow ioctl(..., FIONREAD|FIONBIO|FIOCLEX|FIONCLEX, ...) */ _JUMP_EQ(SYS_ioctl, 0, 5 + (allow_ioctl_always ? 12 : 0) + - (allow_ioctl_ioctl ? 18 : 0)); + (allow_ioctl_ioctl ? 21 : 0)); _ARG64(1); // 4 if (allow_ioctl_always) { _JUMP_EQ64(FIONREAD, _ALLOW, 0); @@ -330,6 +353,7 @@ pledge_filter(uint64_t flags, uint64_t oldflags) _JUMP_EQ64(TCGETS, _JTRUE, 0); _JUMP_EQ64(TIOCGWINSZ, _JTRUE, 0); _JUMP_EQ64(TIOCGPGRP, _JTRUE, 0); + _JUMP_EQ64(TIOCSPGRP, _JTRUE, 0); _JUMP_EQ64(TCSETSF, _JTRUE, 0); _JUMP_EQ64(TCSETSW, _JTRUE, 0); } @@ -347,6 +371,8 @@ pledge_filter(uint64_t flags, uint64_t oldflags) _RET(SECCOMP_RET_KILL); #endif + printf("length=%ld expected=%ld\n", (fp-fprog->filter), len); + return fprog; } diff --git a/tests/pledge/test_filter_conditions.c b/tests/pledge/test_filter_conditions.c @@ -18,6 +18,10 @@ main() int rv, fail, pass; fail = pass = 0; + TEST("open", PLEDGE_CPATH, PLEDGE_CPATH, _FILTER_OPEN, 0); + TEST("open", 0LLU, 0LLU, _FILTER_OPEN, FILTER_BLACKLIST); + TEST("open", PLEDGE_CPATH, 0LLU, _FILTER_OPEN, FILTER_BLACKLIST); + TEST("chown", PLEDGE_CHOWNUID, 0LLU, _FILTER_CHOWN, 0); TEST("chown", 0LLU, 0LLU, _FILTER_CHOWN, 1); TEST("chown", PLEDGE_CHOWNUID, PLEDGE_CHOWNUID, _FILTER_CHOWN, 0);