Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751875AbdISRsb (ORCPT ); Tue, 19 Sep 2017 13:48:31 -0400 Received: from mail-io0-f175.google.com ([209.85.223.175]:56167 "EHLO mail-io0-f175.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751556AbdISRs2 (ORCPT ); Tue, 19 Sep 2017 13:48:28 -0400 X-Google-Smtp-Source: AOwi7QBavu1N56CYRUV9udQAyHhssZzDuV53IZUwIQXN9Dk543KM7WVgd+CfOSbY4zTxKQKRmur1bg== From: Tycho Andersen To: Kees Cook Cc: linux-kernel@vger.kernel.org, criu@openvz.org, Tycho Andersen , Andy Lutomirski , Oleg Nesterov Subject: [PATCH] ptrace, seccomp: add support for retrieving seccomp flags Date: Tue, 19 Sep 2017 11:47:43 -0600 Message-Id: <20170919174743.19814-1-tycho@docker.com> X-Mailer: git-send-email 2.11.0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5226 Lines: 180 With the new SECCOMP_FILTER_FLAG_LOG, we need to be able to extract these flags for checkpoint restore, since they describe the state of a filter. So, let's add PTRACE_SECCOMP_GET_FLAGS, similar to ..._GET_FILTER, which returns the flags of the nth filter. Signed-off-by: Tycho Andersen CC: Kees Cook CC: Andy Lutomirski CC: Oleg Nesterov --- include/linux/seccomp.h | 7 +++++ include/uapi/linux/ptrace.h | 1 + kernel/ptrace.c | 4 +++ kernel/seccomp.c | 74 ++++++++++++++++++++++++++++++++++----------- 4 files changed, 68 insertions(+), 18 deletions(-) diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index c8bef436b61d..4713d62378e3 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -94,11 +94,18 @@ static inline void get_seccomp_filter(struct task_struct *tsk) #if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_CHECKPOINT_RESTORE) extern long seccomp_get_filter(struct task_struct *task, unsigned long filter_off, void __user *data); +extern long seccomp_get_flags(struct task_struct *task, + unsigned long filter_off); #else static inline long seccomp_get_filter(struct task_struct *task, unsigned long n, void __user *data) { return -EINVAL; } +static inline long seccomp_get_flags(struct task_struct *task, + unsigned long filter_off) +{ + 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 fb8106509000..52903f0f6600 100644 --- a/include/uapi/linux/ptrace.h +++ b/include/uapi/linux/ptrace.h @@ -65,6 +65,7 @@ struct ptrace_peeksiginfo_args { #define PTRACE_SETSIGMASK 0x420b #define PTRACE_SECCOMP_GET_FILTER 0x420c +#define PTRACE_SECCOMP_GET_FLAGS 0x420d /* Read signals from a shared (process wide) queue */ #define PTRACE_PEEKSIGINFO_SHARED (1 << 0) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 60f356d91060..fa3d2b4d3bf0 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -1094,6 +1094,10 @@ int ptrace_request(struct task_struct *child, long request, ret = seccomp_get_filter(child, addr, datavp); break; + case PTRACE_SECCOMP_GET_FLAGS: + ret = seccomp_get_flags(child, addr); + break; + default: break; } diff --git a/kernel/seccomp.c b/kernel/seccomp.c index c24579dfa7a1..67768aaa7952 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -968,24 +968,16 @@ long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) } #if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_CHECKPOINT_RESTORE) -long seccomp_get_filter(struct task_struct *task, unsigned long filter_off, - void __user *data) +static struct seccomp_filter *get_nth_filter(struct task_struct *task, + unsigned long filter_off) { struct seccomp_filter *filter; - struct sock_fprog_kern *fprog; - long ret; unsigned long count = 0; - if (!capable(CAP_SYS_ADMIN) || - current->seccomp.mode != SECCOMP_MODE_DISABLED) { - return -EACCES; - } + WARN_ON_ONCE(!spin_is_locked(&task->sighand->siglock)); - spin_lock_irq(&task->sighand->siglock); - if (task->seccomp.mode != SECCOMP_MODE_FILTER) { - ret = -EINVAL; - goto out; - } + if (task->seccomp.mode != SECCOMP_MODE_FILTER) + return ERR_PTR(-EINVAL); filter = task->seccomp.filter; while (filter) { @@ -993,10 +985,9 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off, count++; } - if (filter_off >= count) { - ret = -ENOENT; - goto out; - } + if (filter_off >= count) + return ERR_PTR(-ENOENT); + count -= filter_off; filter = task->seccomp.filter; @@ -1007,7 +998,28 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off, if (WARN_ON(count != 1 || !filter)) { /* The filter tree shouldn't shrink while we're using it. */ - ret = -ENOENT; + return ERR_PTR(-ENOENT); + } + + return filter; +} + +long seccomp_get_filter(struct task_struct *task, unsigned long filter_off, + void __user *data) +{ + struct seccomp_filter *filter; + struct sock_fprog_kern *fprog; + long ret; + + if (!capable(CAP_SYS_ADMIN) || + current->seccomp.mode != SECCOMP_MODE_DISABLED) { + return -EACCES; + } + + spin_lock_irq(&task->sighand->siglock); + filter = get_nth_filter(task, filter_off); + if (IS_ERR(filter)) { + ret = PTR_ERR(filter); goto out; } @@ -1038,6 +1050,32 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off, spin_unlock_irq(&task->sighand->siglock); return ret; } + +long seccomp_get_flags(struct task_struct *task, unsigned long filter_off) +{ + long flags = 0L; + struct seccomp_filter *filter; + + if (!capable(CAP_SYS_ADMIN) || + current->seccomp.mode != SECCOMP_MODE_DISABLED) { + return -EACCES; + } + + spin_lock_irq(&task->sighand->siglock); + filter = get_nth_filter(task, filter_off); + if (IS_ERR(filter)) { + flags = PTR_ERR(filter); + goto out; + } + + if (filter->log) + flags |= SECCOMP_FILTER_FLAG_LOG; + +out: + spin_unlock_irq(&task->sighand->siglock); + return flags; + +} #endif #ifdef CONFIG_SYSCTL -- 2.11.0