From: Kees Cook <keescook@chromium.org> To: linux-kernel@vger.kernel.org Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org, John Johansen <john.johansen@canonical.com>, Will Drewry <wad@chromium.org>, Kees Cook <keescook@chromium.org>, linux-api@vger.kernel.org, x86@kernel.org, Oleg Nesterov <oleg@redhat.com>, Andy Lutomirski <luto@amacapital.net>, linux-security-module@vger.kernel.org, Julien Tinnes <jln@chromium.org>, Andrew Morton <akpm@linux-foundation.org>, David Drysdale <drysdale@google.com>, linux-arm-kernel@lists.infradead.org, Alexei Starovoitov <ast@plumgrid.com> Subject: [PATCH v6 2/9] seccomp: split filter prep from check and apply Date: Tue, 10 Jun 2014 20:25:14 -0700 [thread overview] Message-ID: <1402457121-8410-3-git-send-email-keescook@chromium.org> (raw) In-Reply-To: <1402457121-8410-1-git-send-email-keescook@chromium.org> In preparation for adding seccomp locking, move filter creation away from where it is checked and applied. This will allow for locking where no memory allocation is happening. The validation, filter attachment, and seccomp mode setting can all happen under the future locks. Signed-off-by: Kees Cook <keescook@chromium.org> --- kernel/seccomp.c | 86 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 28 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 552b972b8f83..7a9257ddd69c 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -18,6 +18,7 @@ #include <linux/compat.h> #include <linux/sched.h> #include <linux/seccomp.h> +#include <linux/slab.h> /* #define SECCOMP_DEBUG 1 */ @@ -26,7 +27,6 @@ #include <linux/filter.h> #include <linux/ptrace.h> #include <linux/security.h> -#include <linux/slab.h> #include <linux/tracehook.h> #include <linux/uaccess.h> @@ -197,27 +197,21 @@ static u32 seccomp_run_filters(int syscall) } /** - * seccomp_attach_filter: Attaches a seccomp filter to current. + * seccomp_prepare_filter: Prepares a seccomp filter for use. * @fprog: BPF program to install * - * Returns 0 on success or an errno on failure. + * Returns filter on success or an ERR_PTR on failure. */ -static long seccomp_attach_filter(struct sock_fprog *fprog) +static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) { struct seccomp_filter *filter; unsigned long fp_size = fprog->len * sizeof(struct sock_filter); - unsigned long total_insns = fprog->len; struct sock_filter *fp; int new_len; long ret; if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) - return -EINVAL; - - for (filter = current->seccomp.filter; filter; filter = filter->prev) - total_insns += filter->len + 4; /* include a 4 instr penalty */ - if (total_insns > MAX_INSNS_PER_PATH) - return -ENOMEM; + return ERR_PTR(-EINVAL); /* * Installing a seccomp filter requires that the task has @@ -228,11 +222,11 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) if (!current->no_new_privs && security_capable_noaudit(current_cred(), current_user_ns(), CAP_SYS_ADMIN) != 0) - return -EACCES; + return ERR_PTR(-EACCES); fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN); if (!fp) - return -ENOMEM; + return ERR_PTR(-ENOMEM); /* Copy the instructions from fprog. */ ret = -EFAULT; @@ -270,31 +264,26 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) atomic_set(&filter->usage, 1); filter->len = new_len; - /* - * If there is an existing filter, make it the prev and don't drop its - * task reference. - */ - filter->prev = current->seccomp.filter; - current->seccomp.filter = filter; - return 0; + return filter; free_filter: kfree(filter); free_prog: kfree(fp); - return ret; + return ERR_PTR(ret); } /** - * seccomp_attach_user_filter - attaches a user-supplied sock_fprog + * seccomp_prepare_user_filter - prepares a user-supplied sock_fprog * @user_filter: pointer to the user data containing a sock_fprog. * - * Returns 0 on success and non-zero otherwise. + * Returns filter on success and ERR_PTR otherwise. */ -static long seccomp_attach_user_filter(char __user *user_filter) +static +struct seccomp_filter *seccomp_prepare_user_filter(char __user *user_filter) { struct sock_fprog fprog; - long ret = -EFAULT; + struct seccomp_filter *filter = ERR_PTR(-EFAULT); #ifdef CONFIG_COMPAT if (is_compat_task()) { @@ -307,9 +296,37 @@ static long seccomp_attach_user_filter(char __user *user_filter) #endif if (copy_from_user(&fprog, user_filter, sizeof(fprog))) goto out; - ret = seccomp_attach_filter(&fprog); + filter = seccomp_prepare_filter(&fprog); out: - return ret; + return filter; +} + +/** + * seccomp_attach_filter: validate and attach filter + * @filter: seccomp filter to add to the current process + * + * Returns 0 on success, -ve on error. + */ +static long seccomp_attach_filter(struct seccomp_filter *filter) +{ + unsigned long total_insns; + struct seccomp_filter *walker; + + /* Validate resulting filter length. */ + total_insns = filter->len; + for (walker = current->seccomp.filter; walker; walker = filter->prev) + total_insns += walker->len + 4; /* include a 4 instr penalty */ + if (total_insns > MAX_INSNS_PER_PATH) + return -ENOMEM; + + /* + * If there is an existing filter, make it the prev and don't drop its + * task reference. + */ + filter->prev = current->seccomp.filter; + current->seccomp.filter = filter; + + return 0; } /* get_seccomp_filter - increments the reference count of the filter on @tsk */ @@ -480,8 +497,18 @@ long prctl_get_seccomp(void) */ static long seccomp_set_mode(unsigned long seccomp_mode, char __user *filter) { + struct seccomp_filter *prepared = NULL; long ret = -EINVAL; +#ifdef CONFIG_SECCOMP_FILTER + /* Prepare the new filter outside of the seccomp lock. */ + if (seccomp_mode == SECCOMP_MODE_FILTER) { + prepared = seccomp_prepare_user_filter(filter); + if (IS_ERR(prepared)) + return PTR_ERR(prepared); + } +#endif + if (current->seccomp.mode && current->seccomp.mode != seccomp_mode) goto out; @@ -495,9 +522,11 @@ static long seccomp_set_mode(unsigned long seccomp_mode, char __user *filter) break; #ifdef CONFIG_SECCOMP_FILTER case SECCOMP_MODE_FILTER: - ret = seccomp_attach_user_filter(filter); + ret = seccomp_attach_filter(prepared); if (ret) goto out; + /* Do not free the successfully attached filter. */ + prepared = NULL; break; #endif default: @@ -507,6 +536,7 @@ static long seccomp_set_mode(unsigned long seccomp_mode, char __user *filter) current->seccomp.mode = seccomp_mode; set_thread_flag(TIF_SECCOMP); out: + kfree(prepared); return ret; } -- 1.7.9.5
WARNING: multiple messages have this Message-ID (diff)
From: Kees Cook <keescook@chromium.org> To: linux-kernel@vger.kernel.org Cc: Kees Cook <keescook@chromium.org>, Andy Lutomirski <luto@amacapital.net>, Oleg Nesterov <oleg@redhat.com>, Will Drewry <wad@chromium.org>, Julien Tinnes <jln@chromium.org>, David Drysdale <drysdale@google.com>, Alexei Starovoitov <ast@plumgrid.com>, John Johansen <john.johansen@canonical.com>, Andrew Morton <akpm@linux-foundation.org>, x86@kernel.org, linux-arm-kernel@lists.infradead.org, linux-mips@linux-mips.org, linux-api@vger.kernel.org, linux-arch@vger.kernel.org, linux-security-module@vger.kernel.org Subject: [PATCH v6 2/9] seccomp: split filter prep from check and apply Date: Tue, 10 Jun 2014 20:25:14 -0700 [thread overview] Message-ID: <1402457121-8410-3-git-send-email-keescook@chromium.org> (raw) Message-ID: <20140611032514._vBHGQFWHcCv6bC332FWiitbl-rqr1Yge_BTqO2WCjI@z> (raw) In-Reply-To: <1402457121-8410-1-git-send-email-keescook@chromium.org> In preparation for adding seccomp locking, move filter creation away from where it is checked and applied. This will allow for locking where no memory allocation is happening. The validation, filter attachment, and seccomp mode setting can all happen under the future locks. Signed-off-by: Kees Cook <keescook@chromium.org> --- kernel/seccomp.c | 86 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 28 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 552b972b8f83..7a9257ddd69c 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -18,6 +18,7 @@ #include <linux/compat.h> #include <linux/sched.h> #include <linux/seccomp.h> +#include <linux/slab.h> /* #define SECCOMP_DEBUG 1 */ @@ -26,7 +27,6 @@ #include <linux/filter.h> #include <linux/ptrace.h> #include <linux/security.h> -#include <linux/slab.h> #include <linux/tracehook.h> #include <linux/uaccess.h> @@ -197,27 +197,21 @@ static u32 seccomp_run_filters(int syscall) } /** - * seccomp_attach_filter: Attaches a seccomp filter to current. + * seccomp_prepare_filter: Prepares a seccomp filter for use. * @fprog: BPF program to install * - * Returns 0 on success or an errno on failure. + * Returns filter on success or an ERR_PTR on failure. */ -static long seccomp_attach_filter(struct sock_fprog *fprog) +static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) { struct seccomp_filter *filter; unsigned long fp_size = fprog->len * sizeof(struct sock_filter); - unsigned long total_insns = fprog->len; struct sock_filter *fp; int new_len; long ret; if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) - return -EINVAL; - - for (filter = current->seccomp.filter; filter; filter = filter->prev) - total_insns += filter->len + 4; /* include a 4 instr penalty */ - if (total_insns > MAX_INSNS_PER_PATH) - return -ENOMEM; + return ERR_PTR(-EINVAL); /* * Installing a seccomp filter requires that the task has @@ -228,11 +222,11 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) if (!current->no_new_privs && security_capable_noaudit(current_cred(), current_user_ns(), CAP_SYS_ADMIN) != 0) - return -EACCES; + return ERR_PTR(-EACCES); fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN); if (!fp) - return -ENOMEM; + return ERR_PTR(-ENOMEM); /* Copy the instructions from fprog. */ ret = -EFAULT; @@ -270,31 +264,26 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) atomic_set(&filter->usage, 1); filter->len = new_len; - /* - * If there is an existing filter, make it the prev and don't drop its - * task reference. - */ - filter->prev = current->seccomp.filter; - current->seccomp.filter = filter; - return 0; + return filter; free_filter: kfree(filter); free_prog: kfree(fp); - return ret; + return ERR_PTR(ret); } /** - * seccomp_attach_user_filter - attaches a user-supplied sock_fprog + * seccomp_prepare_user_filter - prepares a user-supplied sock_fprog * @user_filter: pointer to the user data containing a sock_fprog. * - * Returns 0 on success and non-zero otherwise. + * Returns filter on success and ERR_PTR otherwise. */ -static long seccomp_attach_user_filter(char __user *user_filter) +static +struct seccomp_filter *seccomp_prepare_user_filter(char __user *user_filter) { struct sock_fprog fprog; - long ret = -EFAULT; + struct seccomp_filter *filter = ERR_PTR(-EFAULT); #ifdef CONFIG_COMPAT if (is_compat_task()) { @@ -307,9 +296,37 @@ static long seccomp_attach_user_filter(char __user *user_filter) #endif if (copy_from_user(&fprog, user_filter, sizeof(fprog))) goto out; - ret = seccomp_attach_filter(&fprog); + filter = seccomp_prepare_filter(&fprog); out: - return ret; + return filter; +} + +/** + * seccomp_attach_filter: validate and attach filter + * @filter: seccomp filter to add to the current process + * + * Returns 0 on success, -ve on error. + */ +static long seccomp_attach_filter(struct seccomp_filter *filter) +{ + unsigned long total_insns; + struct seccomp_filter *walker; + + /* Validate resulting filter length. */ + total_insns = filter->len; + for (walker = current->seccomp.filter; walker; walker = filter->prev) + total_insns += walker->len + 4; /* include a 4 instr penalty */ + if (total_insns > MAX_INSNS_PER_PATH) + return -ENOMEM; + + /* + * If there is an existing filter, make it the prev and don't drop its + * task reference. + */ + filter->prev = current->seccomp.filter; + current->seccomp.filter = filter; + + return 0; } /* get_seccomp_filter - increments the reference count of the filter on @tsk */ @@ -480,8 +497,18 @@ long prctl_get_seccomp(void) */ static long seccomp_set_mode(unsigned long seccomp_mode, char __user *filter) { + struct seccomp_filter *prepared = NULL; long ret = -EINVAL; +#ifdef CONFIG_SECCOMP_FILTER + /* Prepare the new filter outside of the seccomp lock. */ + if (seccomp_mode == SECCOMP_MODE_FILTER) { + prepared = seccomp_prepare_user_filter(filter); + if (IS_ERR(prepared)) + return PTR_ERR(prepared); + } +#endif + if (current->seccomp.mode && current->seccomp.mode != seccomp_mode) goto out; @@ -495,9 +522,11 @@ static long seccomp_set_mode(unsigned long seccomp_mode, char __user *filter) break; #ifdef CONFIG_SECCOMP_FILTER case SECCOMP_MODE_FILTER: - ret = seccomp_attach_user_filter(filter); + ret = seccomp_attach_filter(prepared); if (ret) goto out; + /* Do not free the successfully attached filter. */ + prepared = NULL; break; #endif default: @@ -507,6 +536,7 @@ static long seccomp_set_mode(unsigned long seccomp_mode, char __user *filter) current->seccomp.mode = seccomp_mode; set_thread_flag(TIF_SECCOMP); out: + kfree(prepared); return ret; } -- 1.7.9.5
next prev parent reply other threads:[~2014-06-11 3:25 UTC|newest] Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top 2014-06-11 3:25 [PATCH v6 0/9] seccomp: add thread sync ability Kees Cook 2014-06-11 3:25 ` Kees Cook 2014-06-11 3:25 ` [PATCH v6 1/9] seccomp: create internal mode-setting function Kees Cook 2014-06-11 3:25 ` Kees Cook [this message] 2014-06-11 3:25 ` [PATCH v6 2/9] seccomp: split filter prep from check and apply Kees Cook 2014-06-11 3:25 ` [PATCH v6 3/9] seccomp: introduce writer locking Kees Cook 2014-06-11 3:25 ` [PATCH v6 4/9] seccomp: move no_new_privs into seccomp Kees Cook 2014-06-11 3:25 ` Kees Cook 2014-06-11 3:25 ` [PATCH v6 5/9] seccomp: split mode set routines Kees Cook 2014-06-11 3:25 ` Kees Cook 2014-06-11 3:25 ` [PATCH v6 6/9] seccomp: add "seccomp" syscall Kees Cook 2014-06-11 3:25 ` Kees Cook [not found] ` <1402457121-8410-7-git-send-email-keescook-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> 2014-06-13 20:41 ` Andy Lutomirski 2014-06-13 20:41 ` Andy Lutomirski 2014-06-13 21:22 ` Alexei Starovoitov 2014-06-13 21:22 ` Alexei Starovoitov [not found] ` <CAMEtUuwKRUYN_qdnCj42G3Z1UT3vMYPoJqXd2_PjV+_J3WA+8w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2014-06-13 21:25 ` Andy Lutomirski 2014-06-13 21:25 ` Andy Lutomirski [not found] ` <CALCETrVCJvnj9yr5yhhZTn_Gq32mgSqOhMRi16Y=_LvqGOTZ5g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2014-06-13 21:37 ` Alexei Starovoitov 2014-06-13 21:37 ` Alexei Starovoitov 2014-06-13 21:42 ` Andy Lutomirski 2014-06-13 22:01 ` Kees Cook 2014-06-13 22:01 ` Kees Cook 2014-06-13 22:26 ` Alexei Starovoitov 2014-06-13 21:53 ` Kees Cook 2014-06-13 21:53 ` Kees Cook 2014-06-16 6:08 ` Michael Kerrisk (man-pages) 2014-06-11 3:25 ` [PATCH v6 7/9] seccomp: implement SECCOMP_FILTER_FLAG_TSYNC Kees Cook 2014-06-11 3:25 ` Kees Cook 2014-06-11 3:25 ` [PATCH v6 8/9] ARM: add seccomp syscall Kees Cook 2014-06-11 3:25 ` Kees Cook 2014-06-11 3:25 ` [PATCH v6 9/9] MIPS: " Kees Cook 2014-06-11 3:25 ` Kees Cook -- strict thread matches above, loose matches on Subject: below -- 2014-06-10 23:01 [PATCH v6 0/9] seccomp: add thread sync ability Kees Cook 2014-06-10 23:01 ` [PATCH v6 2/9] seccomp: split filter prep from check and apply Kees Cook
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1402457121-8410-3-git-send-email-keescook@chromium.org \ --to=keescook@chromium.org \ --cc=akpm@linux-foundation.org \ --cc=ast@plumgrid.com \ --cc=drysdale@google.com \ --cc=jln@chromium.org \ --cc=john.johansen@canonical.com \ --cc=linux-api@vger.kernel.org \ --cc=linux-arch@vger.kernel.org \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-mips@linux-mips.org \ --cc=linux-security-module@vger.kernel.org \ --cc=luto@amacapital.net \ --cc=oleg@redhat.com \ --cc=wad@chromium.org \ --cc=x86@kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).