HI Tycho On 11 September 2015 at 02:21, Tycho Andersen <tycho.andersen@xxxxxxxxxxxxx> wrote: > This patch adds a way for a process that is "real root" to access the > seccomp filters of another process. The process first does a > PTRACE_SECCOMP_GET_FILTER_FD to get an fd with that process' seccomp filter > attached, and then iterates on this with PTRACE_SECCOMP_NEXT_FILTER using > bpf(BPF_PROG_DUMP) to dump the actual program at each step. Do you have a man- page patch for this change? Cheers, Michael > Signed-off-by: Tycho Andersen <tycho.andersen@xxxxxxxxxxxxx> > CC: Kees Cook <keescook@xxxxxxxxxxxx> > CC: Will Drewry <wad@xxxxxxxxxxxx> > CC: Oleg Nesterov <oleg@xxxxxxxxxx> > CC: Andy Lutomirski <luto@xxxxxxxxxxxxxx> > CC: Pavel Emelyanov <xemul@xxxxxxxxxxxxx> > CC: Serge E. Hallyn <serge.hallyn@xxxxxxxxxx> > CC: Alexei Starovoitov <ast@xxxxxxxxxx> > CC: Daniel Borkmann <daniel@xxxxxxxxxxxxx> > --- > include/linux/bpf.h | 12 ++++++++++ > include/linux/seccomp.h | 14 +++++++++++ > include/uapi/linux/ptrace.h | 3 +++ > kernel/bpf/syscall.c | 26 ++++++++++++++++++++- > kernel/ptrace.c | 7 ++++++ > kernel/seccomp.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ > 6 files changed, 118 insertions(+), 1 deletion(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index f57d7fe..bfd9cab 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -162,6 +162,8 @@ void bpf_register_prog_type(struct bpf_prog_type_list *tl); > void bpf_register_map_type(struct bpf_map_type_list *tl); > > struct bpf_prog *bpf_prog_get(u32 ufd); > +int bpf_prog_set(u32 ufd, struct bpf_prog *new); > +int bpf_new_fd(struct bpf_prog *prog, int flags); > void bpf_prog_put(struct bpf_prog *prog); > void bpf_prog_put_rcu(struct bpf_prog *prog); > > @@ -180,6 +182,16 @@ static inline struct bpf_prog *bpf_prog_get(u32 ufd) > return ERR_PTR(-EOPNOTSUPP); > } > > +static inline int bpf_prog_set(u32 ufd, struct bpf_prog *new) > +{ > + return -EINVAL; > +} > + > +static inline int bpf_new_fd(struct bpf_prog *prog, int flags) > +{ > + return -EINVAL; > +} > + > static inline void bpf_prog_put(struct bpf_prog *prog) > { > } > diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h > index a19ddac..41b083c 100644 > --- a/include/linux/seccomp.h > +++ b/include/linux/seccomp.h > @@ -95,4 +95,18 @@ static inline void get_seccomp_filter(struct task_struct *tsk) > return; > } > #endif /* CONFIG_SECCOMP_FILTER */ > + > +#if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_CHECKPOINT_RESTORE) > +extern long seccomp_get_filter_fd(struct task_struct *child); > +extern long seccomp_next_filter(struct task_struct *child, u32 fd); > +#else > +static inline long seccomp_get_filter_fd(struct task_struct *child) > +{ > + return -EINVAL; > +} > +static inline long seccomp_next_filter(struct task_struct *child, u32 fd) > +{ > + return -EINVAL; > +} > +#endif /* CONFIG_SECCOMP_FILTER && CONFIG_CHECKPOINT_RESTORE */ > #endif /* _LINUX_SECCOMP_H */ > diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h > index cf1019e..041c3c3 100644 > --- a/include/uapi/linux/ptrace.h > +++ b/include/uapi/linux/ptrace.h > @@ -23,6 +23,9 @@ > > #define PTRACE_SYSCALL 24 > > +#define PTRACE_SECCOMP_GET_FILTER_FD 40 > +#define PTRACE_SECCOMP_NEXT_FILTER 41 > + > /* 0x4200-0x4300 are reserved for architecture-independent additions. */ > #define PTRACE_SETOPTIONS 0x4200 > #define PTRACE_GETEVENTMSG 0x4201 > diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c > index 58ae9f4..ac3ed1c 100644 > --- a/kernel/bpf/syscall.c > +++ b/kernel/bpf/syscall.c > @@ -506,6 +506,30 @@ struct bpf_prog *bpf_prog_get(u32 ufd) > } > EXPORT_SYMBOL_GPL(bpf_prog_get); > > +int bpf_prog_set(u32 ufd, struct bpf_prog *new) > +{ > + struct fd f; > + struct bpf_prog *prog; > + > + f = fdget(ufd); > + > + prog = get_prog(f); > + if (!IS_ERR(prog) && prog) > + bpf_prog_put(prog); > + > + atomic_inc(&new->aux->refcnt); > + f.file->private_data = new; > + fdput(f); > + return 0; > +} > +EXPORT_SYMBOL_GPL(bpf_prog_set); > + > +int bpf_new_fd(struct bpf_prog *prog, int flags) > +{ > + return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, flags); > +} > +EXPORT_SYMBOL_GPL(bpf_new_fd); > + > /* last field in 'union bpf_attr' used by this command */ > #define BPF_PROG_LOAD_LAST_FIELD kern_version > > @@ -572,7 +596,7 @@ static int bpf_prog_load(union bpf_attr *attr) > if (err < 0) > goto free_used_maps; > > - err = anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, O_RDWR | O_CLOEXEC); > + err = bpf_new_fd(prog, O_RDWR | O_CLOEXEC); > if (err < 0) > /* failed to allocate fd */ > goto free_used_maps; > diff --git a/kernel/ptrace.c b/kernel/ptrace.c > index c8e0e05..a151c35 100644 > --- a/kernel/ptrace.c > +++ b/kernel/ptrace.c > @@ -1003,6 +1003,13 @@ int ptrace_request(struct task_struct *child, long request, > break; > } > #endif > + > + case PTRACE_SECCOMP_GET_FILTER_FD: > + return seccomp_get_filter_fd(child); > + > + case PTRACE_SECCOMP_NEXT_FILTER: > + return seccomp_next_filter(child, data); > + > default: > break; > } > diff --git a/kernel/seccomp.c b/kernel/seccomp.c > index afaeddf..1856f69 100644 > --- a/kernel/seccomp.c > +++ b/kernel/seccomp.c > @@ -26,6 +26,8 @@ > #endif > > #ifdef CONFIG_SECCOMP_FILTER > +#include <linux/bpf.h> > +#include <uapi/linux/bpf.h> > #include <linux/filter.h> > #include <linux/pid.h> > #include <linux/ptrace.h> > @@ -807,6 +809,61 @@ static inline long seccomp_set_mode_filter(unsigned int flags, > } > #endif > > +#if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_CHECKPOINT_RESTORE) > +long seccomp_get_filter_fd(struct task_struct *child) > +{ > + long fd; > + struct seccomp_filter *filter; > + > + if (!capable(CAP_SYS_ADMIN)) > + return -EACCES; > + > + if (child->seccomp.mode != SECCOMP_MODE_FILTER) > + return -EINVAL; > + > + filter = child->seccomp.filter; > + > + fd = bpf_new_fd(filter->prog, O_RDONLY); > + if (fd > 0) > + atomic_inc(&filter->prog->aux->refcnt); > + > + return fd; > +} > + > +long seccomp_next_filter(struct task_struct *child, u32 fd) > +{ > + struct seccomp_filter *cur; > + struct bpf_prog *prog; > + long ret = -ESRCH; > + > + if (!capable(CAP_SYS_ADMIN)) > + return -EACCES; > + > + if (child->seccomp.mode != SECCOMP_MODE_FILTER) > + return -EINVAL; > + > + prog = bpf_prog_get(fd); > + if (IS_ERR(prog)) { > + ret = PTR_ERR(prog); > + goto out; > + } > + > + for (cur = child->seccomp.filter; cur; cur = cur->prev) { > + if (cur->prog == prog) { > + if (!cur->prev) > + ret = -ENOENT; > + else > + ret = bpf_prog_set(fd, cur->prev->prog); > + break; > + } > + } > + > +out: > + bpf_prog_put(prog); > + return ret; > +} > +#endif > + > /* Common entry point for both prctl and syscall. */ > static long do_seccomp(unsigned int op, unsigned int flags, > const char __user *uargs) > -- > 2.1.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-api" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ -- To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html