From: Kees Cook <keescook@chromium.org>
To: linux-kernel@vger.kernel.org
Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
Will Drewry <wad@chromium.org>, Kees Cook <keescook@chromium.org>,
linux-security-module@vger.kernel.org, linux-api@vger.kernel.org,
x86@kernel.org, Oleg Nesterov <oleg@redhat.com>,
Andy Lutomirski <luto@amacapital.net>,
Daniel Borkmann <dborkman@redhat.com>,
Julien Tinnes <jln@chromium.org>,
"Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com>,
Andrew Morton <akpm@linux-foundation.org>,
David Drysdale <drysdale@google.com>,
linux-arm-kernel@lists.infradead.org,
Alexei Starovoitov <ast@plumgrid.com>
Subject: [PATCH v10 08/11] seccomp: split filter prep from check and apply
Date: Thu, 10 Jul 2014 11:40:28 -0700 [thread overview]
Message-ID: <1405017631-27346-9-git-send-email-keescook@chromium.org> (raw)
In-Reply-To: <1405017631-27346-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 | 93 +++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 64 insertions(+), 29 deletions(-)
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 137e40c7ae3b..502e54d7f86d 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>
#include <linux/syscalls.h>
/* #define SECCOMP_DEBUG 1 */
@@ -27,7 +28,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>
@@ -213,27 +213,21 @@ static inline void seccomp_assign_mode(unsigned long seccomp_mode)
#ifdef CONFIG_SECCOMP_FILTER
/**
- * 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->prog->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
@@ -244,11 +238,11 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
if (!task_no_new_privs(current) &&
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;
@@ -292,13 +286,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
sk_filter_select_runtime(filter->prog);
- /*
- * 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_prog:
kfree(filter->prog);
@@ -306,19 +294,20 @@ 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.
*/
-static long seccomp_attach_user_filter(const char __user *user_filter)
+static struct seccomp_filter *
+seccomp_prepare_user_filter(const 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()) {
@@ -331,9 +320,39 @@ static long seccomp_attach_user_filter(const 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
+ * @flags: flags to change filter behavior
+ * @filter: seccomp filter to add to the current process
+ *
+ * Returns 0 on success, -ve on error.
+ */
+static long seccomp_attach_filter(unsigned int flags,
+ struct seccomp_filter *filter)
+{
+ unsigned long total_insns;
+ struct seccomp_filter *walker;
+
+ /* Validate resulting filter length. */
+ total_insns = filter->prog->len;
+ for (walker = current->seccomp.filter; walker; walker = walker->prev)
+ total_insns += walker->prog->len + 4; /* 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 */
@@ -346,6 +365,14 @@ void get_seccomp_filter(struct task_struct *tsk)
atomic_inc(&orig->usage);
}
+static inline void seccomp_filter_free(struct seccomp_filter *filter)
+{
+ if (filter) {
+ sk_filter_free(filter->prog);
+ kfree(filter);
+ }
+}
+
/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
void put_seccomp_filter(struct task_struct *tsk)
{
@@ -354,8 +381,7 @@ void put_seccomp_filter(struct task_struct *tsk)
while (orig && atomic_dec_and_test(&orig->usage)) {
struct seccomp_filter *freeme = orig;
orig = orig->prev;
- sk_filter_free(freeme->prog);
- kfree(freeme);
+ seccomp_filter_free(freeme);
}
}
@@ -533,21 +559,30 @@ static long seccomp_set_mode_filter(unsigned int flags,
const char __user *filter)
{
const unsigned long seccomp_mode = SECCOMP_MODE_FILTER;
+ struct seccomp_filter *prepared = NULL;
long ret = -EINVAL;
/* Validate flags. */
if (flags != 0)
goto out;
+ /* Prepare the new filter before holding any locks. */
+ prepared = seccomp_prepare_user_filter(filter);
+ if (IS_ERR(prepared))
+ return PTR_ERR(prepared);
+
if (!seccomp_check_mode(seccomp_mode))
goto out;
- ret = seccomp_attach_user_filter(filter);
+ ret = seccomp_attach_filter(flags, prepared);
if (ret)
goto out;
+ /* Do not free the successfully attached filter. */
+ prepared = NULL;
seccomp_assign_mode(seccomp_mode);
out:
+ seccomp_filter_free(prepared);
return ret;
}
#else
--
1.7.9.5
next prev parent reply other threads:[~2014-07-10 18:40 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-10 18:40 [PATCH v10 0/11] seccomp: add thread sync ability Kees Cook
2014-07-10 18:40 ` [PATCH v10 01/11] seccomp: create internal mode-setting function Kees Cook
2014-07-10 18:40 ` [PATCH v10 02/11] seccomp: extract check/assign mode helpers Kees Cook
2014-07-10 18:40 ` [PATCH v10 03/11] seccomp: split mode setting routines Kees Cook
2014-07-10 18:40 ` [PATCH v10 04/11] seccomp: add "seccomp" syscall Kees Cook
2014-07-10 18:40 ` [PATCH v10 05/11] ARM: add seccomp syscall Kees Cook
2014-07-10 18:40 ` [PATCH v10 06/11] MIPS: " Kees Cook
2014-07-10 18:40 ` [PATCH v10 07/11] sched: move no_new_privs into new atomic flags Kees Cook
2014-07-10 18:40 ` Kees Cook [this message]
2014-07-10 18:40 ` [PATCH v10 09/11] seccomp: introduce writer locking Kees Cook
2014-07-10 18:40 ` [PATCH v10 10/11] seccomp: allow mode setting across threads Kees Cook
2014-07-10 18:40 ` [PATCH v10 11/11] seccomp: implement SECCOMP_FILTER_FLAG_TSYNC Kees Cook
2014-07-11 16:49 ` [PATCH v10 0/11] seccomp: add thread sync ability Oleg Nesterov
2014-07-11 17:55 ` Kees Cook
[not found] ` <CAGXu5jK-x0=Rr7kX2a=b4Z8ueA77uwmhNZZAayG8cwmNOKa8Ug-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-14 18:59 ` Kees Cook
2014-07-15 1:53 ` James Morris
[not found] ` <53C48986.5010109-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2014-07-17 21:39 ` Andy Lutomirski
2014-07-14 19:04 ` Andy Lutomirski
[not found] ` <CALCETrVXgA9a2f7VwnCYW4_XB+JAPRSR8xsuH_ZYbA82=ZozRw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-14 20:34 ` Kees Cook
2014-07-16 17:54 ` Kees Cook
2014-07-16 19:45 ` Andy Lutomirski
2014-07-16 21:23 ` Kees Cook
2014-07-16 21:27 ` Andy Lutomirski
2014-07-16 16:44 ` James Morris
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=1405017631-27346-9-git-send-email-keescook@chromium.org \
--to=keescook@chromium.org \
--cc=akpm@linux-foundation.org \
--cc=ast@plumgrid.com \
--cc=dborkman@redhat.com \
--cc=drysdale@google.com \
--cc=jln@chromium.org \
--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=mtk.manpages@gmail.com \
--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: link
Be 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).