Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 24 Mar 2016 03:53:57 +0100
From: Mickaël Salaün <mic@...ikod.net>
To: linux-security-module@...r.kernel.org
Cc: Mickaël Salaün <mic@...ikod.net>,
	Andreas Gruenbacher <agruenba@...hat.com>,
	Andy Lutomirski <luto@...capital.net>,
	Andy Lutomirski <luto@...nel.org>,
	Arnd Bergmann <arnd@...db.de>,
	Casey Schaufler <casey@...aufler-ca.com>,
	Daniel Borkmann <daniel@...earbox.net>,
	David Drysdale <drysdale@...gle.com>,
	Eric Paris <eparis@...hat.com>,
	James Morris <james.l.morris@...cle.com>,
	Jeff Dike <jdike@...toit.com>,
	Julien Tinnes <jln@...gle.com>,
	Kees Cook <keescook@...omium.org>,
	Michael Kerrisk <mtk@...7.org>,
	Paul Moore <pmoore@...hat.com>,
	Richard Weinberger <richard@....at>,
	"Serge E . Hallyn" <serge@...lyn.com>,
	Stephen Smalley <sds@...ho.nsa.gov>,
	Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>,
	Will Drewry <wad@...omium.org>,
	linux-api@...r.kernel.org,
	kernel-hardening@...ts.openwall.com
Subject: [RFC v1 12/17] audit,seccomp: Extend audit with seccomp state

Extend the audit framework to known if we are in a seccomp filter
evaluation or not.

Signed-off-by: Mickaël Salaün <mic@...ikod.net>
Cc: Andy Lutomirski <luto@...nel.org>
Cc: Eric Paris <eparis@...hat.com>
Cc: Kees Cook <keescook@...omium.org>
Cc: Paul Moore <pmoore@...hat.com>
Cc: Will Drewry <wad@...omium.org>
---
 include/linux/audit.h | 25 +++++++++++++++++++++++++
 kernel/audit.h        |  3 +++
 kernel/auditsc.c      | 36 ++++++++++++++++++++++++++++++++++--
 kernel/seccomp.c      | 21 ++++++++++++++++++---
 4 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index b40ed5df5542..480df19473d9 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -230,6 +230,8 @@ extern void __audit_free(struct task_struct *task);
 extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1,
 				  unsigned long a2, unsigned long a3);
 extern void __audit_syscall_exit(int ret_success, long ret_value);
+extern void __audit_seccomp_entry(void);
+extern void __audit_seccomp_exit(int do_free);
 extern struct filename *__audit_reusename(const __user char *uptr);
 extern void __audit_getname(struct filename *name);
 
@@ -270,17 +272,40 @@ static inline void audit_syscall_exit(void *pt_regs)
 		__audit_syscall_exit(success, return_code);
 	}
 }
+
+static inline void audit_seccomp_entry(void)
+{
+	if (unlikely(current->audit_context))
+		__audit_seccomp_entry();
+}
+
+static inline void audit_seccomp_exit(int do_free)
+{
+	if (unlikely(current->audit_context))
+		__audit_seccomp_exit(do_free);
+}
+
 static inline struct filename *audit_reusename(const __user char *name)
 {
 	if (unlikely(!audit_dummy_context()))
 		return __audit_reusename(name);
+#ifdef CONFIG_SECURITY_SECCOMP
+	if (current->audit_context)
+		return __audit_reusename(name);
+#endif /* CONFIG_SECURITY_SECCOMP */
 	return NULL;
 }
+
 static inline void audit_getname(struct filename *name)
 {
 	if (unlikely(!audit_dummy_context()))
 		__audit_getname(name);
+#ifdef CONFIG_SECURITY_SECCOMP
+	else if (current->audit_context)
+		__audit_getname(name);
+#endif /* CONFIG_SECURITY_SECCOMP */
 }
+
 static inline void audit_inode(struct filename *name,
 				const struct dentry *dentry,
 				unsigned int parent) {
diff --git a/kernel/audit.h b/kernel/audit.h
index cbbe6bb6496e..c63ce77b44ae 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -108,6 +108,9 @@ struct audit_proctitle {
 struct audit_context {
 	int		    dummy;	/* must be the first element */
 	int		    in_syscall;	/* 1 if task is in a syscall */
+#ifdef CONFIG_SECURITY_SECCOMP
+	int		    in_seccomp;	/* 1 if task is in seccomp */
+#endif
 	enum audit_state    state, current_state;
 	unsigned int	    serial;     /* serial number for record */
 	int		    major;      /* syscall number */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 195ffaee50b9..dd1d9f4b1c61 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1501,7 +1501,10 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
 	if (!context)
 		return;
 
-	BUG_ON(context->in_syscall || context->name_count);
+	BUG_ON(context->in_syscall);
+#ifndef CONFIG_SECURITY_SECCOMP
+	BUG_ON(context->name_count);
+#endif /* CONFIG_SECURITY_SECCOMP */
 
 	if (!audit_enabled)
 		return;
@@ -1580,6 +1583,35 @@ void __audit_syscall_exit(int success, long return_code)
 	tsk->audit_context = context;
 }
 
+void __audit_seccomp_entry(void)
+{
+	struct audit_context *context = current->audit_context;
+
+	if (!context)
+		return;
+	BUG_ON(context->in_seccomp || context->name_count);
+	if (!audit_enabled)
+		return;
+
+	context->in_seccomp = 1;
+}
+
+void __audit_seccomp_exit(int do_free)
+{
+	struct audit_context *context = current->audit_context;
+
+	if (!context)
+		return;
+	BUG_ON(!context->in_seccomp);
+	if (!audit_enabled)
+		return;
+
+	BUG_ON(!context->in_seccomp);
+	context->in_seccomp = 0;
+	if (do_free)
+		audit_free_names(context);
+}
+
 static inline void handle_one(const struct inode *inode)
 {
 #ifdef CONFIG_AUDIT_TREE
@@ -1728,7 +1760,7 @@ void __audit_getname(struct filename *name)
 	struct audit_context *context = current->audit_context;
 	struct audit_names *n;
 
-	if (!context->in_syscall)
+	if (!context->in_syscall && !context->in_seccomp)
 		return;
 
 	n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 60e11863857e..a8a6ba31ecc4 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -881,7 +881,7 @@ int __secure_computing(void)
 static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd)
 {
 	u32 filter_ret, action;
-	int data;
+	int data, ret;
 
 	/*
 	 * Make sure that any changes to mode from another thread have
@@ -889,6 +889,9 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd)
 	 */
 	rmb();
 
+	/* Enable caching */
+	audit_seccomp_entry();
+
 	filter_ret = seccomp_run_filters(sd);
 	data = filter_ret & SECCOMP_RET_DATA;
 	action = filter_ret & SECCOMP_RET_ACTION;
@@ -910,13 +913,15 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd)
 		goto skip;
 
 	case SECCOMP_RET_TRACE:
-		return filter_ret;  /* Save the rest for phase 2. */
+		ret = filter_ret;  /* Save the rest for phase 2. */
+		goto audit_exit;
 
 	case SECCOMP_RET_ARGEVAL:
 		/* Handled in seccomp_run_filters() */
 		BUG();
 	case SECCOMP_RET_ALLOW:
-		return SECCOMP_PHASE1_OK;
+		ret = SECCOMP_PHASE1_OK;
+		goto audit_exit;
 
 	case SECCOMP_RET_KILL:
 	default:
@@ -926,7 +931,12 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd)
 
 	unreachable();
 
+audit_exit:
+	audit_seccomp_exit(0);
+	return ret;
+
 skip:
+	audit_seccomp_exit(1);
 	audit_seccomp(this_syscall, 0, action);
 	return SECCOMP_PHASE1_SKIP;
 }
@@ -1139,6 +1149,11 @@ static long seccomp_add_checker_group(unsigned int flags, const char __user *gro
 	unsigned long group_size, kcheckers_size, full_group_size;
 	long result;
 
+	/* FIXME: Deny unsecure path evaluation (i.e. without audit_names) for
+	 * the entire task life.
+	 */
+	if (!current->audit_context)
+		return -EPERM;
 	if (!task_no_new_privs(current) &&
 	    security_capable_noaudit(current_cred(),
 				     current_user_ns(), CAP_SYS_ADMIN) != 0)
-- 
2.8.0.rc3

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.