[RFC v1 12/17] audit,seccomp: Extend audit with seccomp state

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

Signed-off-by: Mickaël Salaün <mic@xxxxxxxxxxx>
Cc: Andy Lutomirski <luto@xxxxxxxxxx>
Cc: Eric Paris <eparis@xxxxxxxxxx>
Cc: Kees Cook <keescook@xxxxxxxxxxxx>
Cc: Paul Moore <pmoore@xxxxxxxxxx>
Cc: Will Drewry <wad@xxxxxxxxxxxx>
---
 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

--
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



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux