From patchwork Sat Jun 27 13:20:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318315 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=b6lOjIz0; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDtk2lrtz9sR4 for ; Sat, 27 Jun 2020 23:22:06 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726660AbgF0NWD (ORCPT ); Sat, 27 Jun 2020 09:22:03 -0400 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:55019 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726621AbgF0NV6 (ORCPT ); Sat, 27 Jun 2020 09:21:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264115; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=eylKu87BljbIaDuVwIH2/HJvhPgrZab69miCxsWFVw4=; b=b6lOjIz0hcWanlQvGmXPm4yiu4eFxPPCA5mwxMEjpJdYWNZyCcPhOc6/uf1WboTZ0xXG6v 24WmYyQ3gYeRiMDW3/wt9PTPVw3BaQG+jQmWMcJ0NobLTvN2x4w34dClfohBegZfV78Z+b aDd8O0JnhVKP3BHm7VAaGWGE7WidJ+w= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-2-dzOW3TRiMVauT70tvpw7TQ-1; Sat, 27 Jun 2020 09:21:51 -0400 X-MC-Unique: dzOW3TRiMVauT70tvpw7TQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id E8B55805EE1; Sat, 27 Jun 2020 13:21:49 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 357687932A; Sat, 27 Jun 2020 13:21:45 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 01/13] audit: collect audit task parameters Date: Sat, 27 Jun 2020 09:20:34 -0400 Message-Id: <6abeb26e64489fc29b00c86b60b501c8b7316424.1593198710.git.rgb@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org The audit-related parameters in struct task_struct should ideally be collected together and accessed through a standard audit API. Collect the existing loginuid, sessionid and audit_context together in a new struct audit_task_info called "audit" in struct task_struct. Use kmem_cache to manage this pool of memory. Un-inline audit_free() to be able to always recover that memory. Please see the upstream github issue https://github.com/linux-audit/audit-kernel/issues/81 Signed-off-by: Richard Guy Briggs Acked-by: Neil Horman Reviewed-by: Ondrej Mosnacek --- include/linux/audit.h | 49 +++++++++++++++++++++++------------ include/linux/sched.h | 7 +---- init/init_task.c | 3 +-- init/main.c | 2 ++ kernel/audit.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++-- kernel/audit.h | 5 ++++ kernel/auditsc.c | 26 ++++++++++--------- kernel/fork.c | 1 - 8 files changed, 124 insertions(+), 40 deletions(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index 3fcd9ee49734..c2150415f9df 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -100,6 +100,16 @@ enum audit_nfcfgop { AUDIT_XT_OP_UNREGISTER, }; +struct audit_task_info { + kuid_t loginuid; + unsigned int sessionid; +#ifdef CONFIG_AUDITSYSCALL + struct audit_context *ctx; +#endif +}; + +extern struct audit_task_info init_struct_audit; + extern int is_audit_feature_set(int which); extern int __init audit_register_class(int class, unsigned *list); @@ -136,6 +146,9 @@ enum audit_nfcfgop { #ifdef CONFIG_AUDIT /* These are defined in audit.c */ /* Public API */ +extern int audit_alloc(struct task_struct *task); +extern void audit_free(struct task_struct *task); +extern void __init audit_task_init(void); extern __printf(4, 5) void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, const char *fmt, ...); @@ -179,12 +192,16 @@ extern void audit_log_path_denied(int type, static inline kuid_t audit_get_loginuid(struct task_struct *tsk) { - return tsk->loginuid; + if (!tsk->audit) + return INVALID_UID; + return tsk->audit->loginuid; } static inline unsigned int audit_get_sessionid(struct task_struct *tsk) { - return tsk->sessionid; + if (!tsk->audit) + return AUDIT_SID_UNSET; + return tsk->audit->sessionid; } extern u32 audit_enabled; @@ -192,6 +209,14 @@ static inline unsigned int audit_get_sessionid(struct task_struct *tsk) extern int audit_signal_info(int sig, struct task_struct *t); #else /* CONFIG_AUDIT */ +static inline int audit_alloc(struct task_struct *task) +{ + return 0; +} +static inline void audit_free(struct task_struct *task) +{ } +static inline void __init audit_task_init(void) +{ } static inline __printf(4, 5) void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, const char *fmt, ...) @@ -267,8 +292,6 @@ static inline int audit_signal_info(int sig, struct task_struct *t) /* These are defined in auditsc.c */ /* Public API */ -extern int audit_alloc(struct task_struct *task); -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); @@ -288,12 +311,14 @@ extern void audit_seccomp_actions_logged(const char *names, static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx) { - task->audit_context = ctx; + task->audit->ctx = ctx; } static inline struct audit_context *audit_context(void) { - return current->audit_context; + if (!current->audit) + return NULL; + return current->audit->ctx; } static inline bool audit_dummy_context(void) @@ -301,11 +326,7 @@ static inline bool audit_dummy_context(void) void *p = audit_context(); return !p || *(int *)p; } -static inline void audit_free(struct task_struct *task) -{ - if (unlikely(task->audit_context)) - __audit_free(task); -} + static inline void audit_syscall_entry(int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3) @@ -533,12 +554,6 @@ static inline void audit_log_nfcfg(const char *name, u8 af, extern int audit_n_rules; extern int audit_signals; #else /* CONFIG_AUDITSYSCALL */ -static inline int audit_alloc(struct task_struct *task) -{ - return 0; -} -static inline void audit_free(struct task_struct *task) -{ } static inline void audit_syscall_entry(int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3) diff --git a/include/linux/sched.h b/include/linux/sched.h index b62e6aaf28f0..2213ac670386 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -34,7 +34,6 @@ #include /* task_struct member predeclarations (sorted alphabetically): */ -struct audit_context; struct backing_dev_info; struct bio_list; struct blk_plug; @@ -946,11 +945,7 @@ struct task_struct { struct callback_head *task_works; #ifdef CONFIG_AUDIT -#ifdef CONFIG_AUDITSYSCALL - struct audit_context *audit_context; -#endif - kuid_t loginuid; - unsigned int sessionid; + struct audit_task_info *audit; #endif struct seccomp seccomp; diff --git a/init/init_task.c b/init/init_task.c index 15089d15010a..92d34c4b7702 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -130,8 +130,7 @@ struct task_struct init_task .thread_group = LIST_HEAD_INIT(init_task.thread_group), .thread_node = LIST_HEAD_INIT(init_signals.thread_head), #ifdef CONFIG_AUDIT - .loginuid = INVALID_UID, - .sessionid = AUDIT_SID_UNSET, + .audit = &init_struct_audit, #endif #ifdef CONFIG_PERF_EVENTS .perf_event_mutex = __MUTEX_INITIALIZER(init_task.perf_event_mutex), diff --git a/init/main.c b/init/main.c index 0ead83e86b5a..349470ad7458 100644 --- a/init/main.c +++ b/init/main.c @@ -96,6 +96,7 @@ #include #include #include +#include #include #include @@ -1028,6 +1029,7 @@ asmlinkage __visible void __init start_kernel(void) nsfs_init(); cpuset_init(); cgroup_init(); + audit_task_init(); taskstats_init_early(); delayacct_init(); diff --git a/kernel/audit.c b/kernel/audit.c index 8c201f414226..5d8147a29291 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -203,6 +203,73 @@ struct audit_reply { struct sk_buff *skb; }; +static struct kmem_cache *audit_task_cache; + +void __init audit_task_init(void) +{ + audit_task_cache = kmem_cache_create("audit_task", + sizeof(struct audit_task_info), + 0, SLAB_PANIC, NULL); +} + +/** + * audit_alloc - allocate an audit info block for a task + * @tsk: task + * + * Call audit_alloc_syscall to filter on the task information and + * allocate a per-task audit context if necessary. This is called from + * copy_process, so no lock is needed. + */ +int audit_alloc(struct task_struct *tsk) +{ + int ret = 0; + struct audit_task_info *info; + + info = kmem_cache_alloc(audit_task_cache, GFP_KERNEL); + if (!info) { + ret = -ENOMEM; + goto out; + } + info->loginuid = audit_get_loginuid(current); + info->sessionid = audit_get_sessionid(current); + tsk->audit = info; + + ret = audit_alloc_syscall(tsk); + if (ret) { + tsk->audit = NULL; + kmem_cache_free(audit_task_cache, info); + } +out: + return ret; +} + +struct audit_task_info init_struct_audit = { + .loginuid = INVALID_UID, + .sessionid = AUDIT_SID_UNSET, +#ifdef CONFIG_AUDITSYSCALL + .ctx = NULL, +#endif +}; + +/** + * audit_free - free per-task audit info + * @tsk: task whose audit info block to free + * + * Called from copy_process and do_exit + */ +void audit_free(struct task_struct *tsk) +{ + struct audit_task_info *info = tsk->audit; + + audit_free_syscall(tsk); + /* Freeing the audit_task_info struct must be performed after + * audit_log_exit() due to need for loginuid and sessionid. + */ + info = tsk->audit; + tsk->audit = NULL; + kmem_cache_free(audit_task_cache, info); +} + /** * auditd_test_task - Check to see if a given task is an audit daemon * @task: the task to check @@ -2309,8 +2376,8 @@ int audit_set_loginuid(kuid_t loginuid) sessionid = (unsigned int)atomic_inc_return(&session_id); } - current->sessionid = sessionid; - current->loginuid = loginuid; + current->audit->sessionid = sessionid; + current->audit->loginuid = loginuid; out: audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc); return rc; diff --git a/kernel/audit.h b/kernel/audit.h index f0233dc40b17..9bee09757068 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -251,6 +251,8 @@ extern void audit_log_d_path_exe(struct audit_buffer *ab, extern unsigned int audit_serial(void); extern int auditsc_get_stamp(struct audit_context *ctx, struct timespec64 *t, unsigned int *serial); +extern int audit_alloc_syscall(struct task_struct *tsk); +extern void audit_free_syscall(struct task_struct *tsk); extern void audit_put_watch(struct audit_watch *watch); extern void audit_get_watch(struct audit_watch *watch); @@ -299,6 +301,9 @@ static inline void audit_clear_dummy(struct audit_context *ctx) #else /* CONFIG_AUDITSYSCALL */ #define auditsc_get_stamp(c, t, s) 0 +#define audit_alloc_syscall(t) 0 +#define audit_free_syscall(t) {} + #define audit_put_watch(w) {} #define audit_get_watch(w) {} #define audit_to_watch(k, p, l, o) (-EINVAL) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 468a23390457..f00c1da587ea 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -914,23 +914,25 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state) return context; } -/** - * audit_alloc - allocate an audit context block for a task +/* + * audit_alloc_syscall - allocate an audit context block for a task * @tsk: task * * Filter on the task information and allocate a per-task audit context * if necessary. Doing so turns on system call auditing for the - * specified task. This is called from copy_process, so no lock is - * needed. + * specified task. This is called from copy_process via audit_alloc, so + * no lock is needed. */ -int audit_alloc(struct task_struct *tsk) +int audit_alloc_syscall(struct task_struct *tsk) { struct audit_context *context; enum audit_state state; char *key = NULL; - if (likely(!audit_ever_enabled)) + if (likely(!audit_ever_enabled)) { + audit_set_context(tsk, NULL); return 0; /* Return if not auditing. */ + } state = audit_filter_task(tsk, &key); if (state == AUDIT_DISABLED) { @@ -940,7 +942,7 @@ int audit_alloc(struct task_struct *tsk) if (!(context = audit_alloc_context(state))) { kfree(key); - audit_log_lost("out of memory in audit_alloc"); + audit_log_lost("out of memory in audit_alloc_syscall"); return -ENOMEM; } context->filterkey = key; @@ -1582,14 +1584,15 @@ static void audit_log_exit(void) } /** - * __audit_free - free a per-task audit context + * audit_free_syscall - free per-task audit context info * @tsk: task whose audit context block to free * - * Called from copy_process and do_exit + * Called from audit_free */ -void __audit_free(struct task_struct *tsk) +void audit_free_syscall(struct task_struct *tsk) { - struct audit_context *context = tsk->audit_context; + struct audit_task_info *info = tsk->audit; + struct audit_context *context = info->ctx; if (!context) return; @@ -1612,7 +1615,6 @@ void __audit_free(struct task_struct *tsk) if (context->current_state == AUDIT_RECORD_CONTEXT) audit_log_exit(); } - audit_set_context(tsk, NULL); audit_free_context(context); } diff --git a/kernel/fork.c b/kernel/fork.c index 142b23645d82..bacbff0e8a75 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -2019,7 +2019,6 @@ static __latent_entropy struct task_struct *copy_process( posix_cputimers_init(&p->posix_cputimers); p->io_context = NULL; - audit_set_context(p, NULL); cgroup_fork(p); #ifdef CONFIG_NUMA p->mempolicy = mpol_dup(p->mempolicy); From patchwork Sat Jun 27 13:20:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318330 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=SiBMPbF9; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDwB5xTYz9sQx for ; Sat, 27 Jun 2020 23:23:22 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726889AbgF0NXU (ORCPT ); Sat, 27 Jun 2020 09:23:20 -0400 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:22852 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726672AbgF0NWM (ORCPT ); Sat, 27 Jun 2020 09:22:12 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264129; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=7qLhUqCIRh+ee39/u66YTqVDI4T2w1NWmc/YTiDgZP0=; b=SiBMPbF9tqf3/XmtvEolesWXujcegW/ly6oQjQcN/I8cseeBxHn1yc5u4tviIXXYfJ8a7C MA6mqc9LNKpge98xji8UA4idGdVHZeRNrAQzXP88g1HK7RC/ju7zhKd+/9scrZ4DoFUw/S U9eBazJMpn+dEt2sGxBdkhRFaYo3wes= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-250-Yj_ryWesM4aTvReBcVljFg-1; Sat, 27 Jun 2020 09:22:05 -0400 X-MC-Unique: Yj_ryWesM4aTvReBcVljFg-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 5732818A0724; Sat, 27 Jun 2020 13:22:03 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 54D087932A; Sat, 27 Jun 2020 13:21:50 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 02/13] audit: add container id Date: Sat, 27 Jun 2020 09:20:35 -0400 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Implement the proc fs write to set the audit container identifier of a process, emitting an AUDIT_CONTAINER_OP record to document the event. This is a write from the container orchestrator task to a proc entry of the form /proc/PID/audit_containerid where PID is the process ID of the newly created task that is to become the first task in a container, or an additional task added to a container. The write expects up to a u64 value (unset: 18446744073709551615). The writer must have capability CAP_AUDIT_CONTROL. This will produce a record such as this: type=CONTAINER_OP msg=audit(2018-06-06 12:39:29.636:26949) : op=set opid=2209 contid=123456 old-contid=18446744073709551615 The "op" field indicates an initial set. The "opid" field is the object's PID, the process being "contained". New and old audit container identifier values are given in the "contid" fields. It is not permitted to unset the audit container identifier. A child inherits its parent's audit container identifier. Store the audit container identifier in a refcounted kernel object that is added to the master list of audit container identifiers. This will allow multiple container orchestrators/engines to work on the same machine without danger of inadvertantly re-using an existing identifier. It will also allow an orchestrator to inject a process into an existing container by checking if the original container owner is the one injecting the task. A hash table list is used to optimize searches. Please see the github audit kernel issue for the main feature: https://github.com/linux-audit/audit-kernel/issues/90 Please see the github audit userspace issue for supporting additions: https://github.com/linux-audit/audit-userspace/issues/51 Please see the github audit testsuiite issue for the test case: https://github.com/linux-audit/audit-testsuite/issues/64 Please see the github audit wiki for the feature overview: https://github.com/linux-audit/audit-kernel/wiki/RFE-Audit-Container-ID Signed-off-by: Richard Guy Briggs Acked-by: Serge Hallyn Acked-by: Steve Grubb Acked-by: Neil Horman Reviewed-by: Ondrej Mosnacek --- fs/proc/base.c | 36 +++++++++++ include/linux/audit.h | 33 ++++++++++ include/uapi/linux/audit.h | 2 + kernel/audit.c | 148 +++++++++++++++++++++++++++++++++++++++++++++ kernel/audit.h | 8 +++ 5 files changed, 227 insertions(+) diff --git a/fs/proc/base.c b/fs/proc/base.c index d86c0afc8a85..6c17ab32e71b 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1317,6 +1317,40 @@ static ssize_t proc_sessionid_read(struct file * file, char __user * buf, .read = proc_sessionid_read, .llseek = generic_file_llseek, }; + +static ssize_t proc_contid_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file_inode(file); + u64 contid; + int rv; + struct task_struct *task = get_proc_task(inode); + + if (!task) + return -ESRCH; + if (*ppos != 0) { + /* No partial writes. */ + put_task_struct(task); + return -EINVAL; + } + + rv = kstrtou64_from_user(buf, count, 10, &contid); + if (rv < 0) { + put_task_struct(task); + return rv; + } + + rv = audit_set_contid(task, contid); + put_task_struct(task); + if (rv < 0) + return rv; + return count; +} + +static const struct file_operations proc_contid_operations = { + .write = proc_contid_write, + .llseek = generic_file_llseek, +}; #endif #ifdef CONFIG_FAULT_INJECTION @@ -3219,6 +3253,7 @@ static int proc_stack_depth(struct seq_file *m, struct pid_namespace *ns, #ifdef CONFIG_AUDIT REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), + REG("audit_containerid", S_IWUSR, proc_contid_operations), #endif #ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), @@ -3558,6 +3593,7 @@ static int proc_tid_comm_permission(struct inode *inode, int mask) #ifdef CONFIG_AUDIT REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), + REG("audit_containerid", S_IWUSR, proc_contid_operations), #endif #ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), diff --git a/include/linux/audit.h b/include/linux/audit.h index c2150415f9df..2800d4f1a2a8 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -100,9 +100,18 @@ enum audit_nfcfgop { AUDIT_XT_OP_UNREGISTER, }; +struct audit_contobj { + struct list_head list; + u64 id; + struct task_struct *owner; + refcount_t refcount; + struct rcu_head rcu; +}; + struct audit_task_info { kuid_t loginuid; unsigned int sessionid; + struct audit_contobj *cont; #ifdef CONFIG_AUDITSYSCALL struct audit_context *ctx; #endif @@ -204,6 +213,15 @@ static inline unsigned int audit_get_sessionid(struct task_struct *tsk) return tsk->audit->sessionid; } +extern int audit_set_contid(struct task_struct *tsk, u64 contid); + +static inline u64 audit_get_contid(struct task_struct *tsk) +{ + if (!tsk->audit || !tsk->audit->cont) + return AUDIT_CID_UNSET; + return tsk->audit->cont->id; +} + extern u32 audit_enabled; extern int audit_signal_info(int sig, struct task_struct *t); @@ -268,6 +286,11 @@ static inline unsigned int audit_get_sessionid(struct task_struct *tsk) return AUDIT_SID_UNSET; } +static inline u64 audit_get_contid(struct task_struct *tsk) +{ + return AUDIT_CID_UNSET; +} + #define audit_enabled AUDIT_OFF static inline int audit_signal_info(int sig, struct task_struct *t) @@ -692,6 +715,16 @@ static inline bool audit_loginuid_set(struct task_struct *tsk) return uid_valid(audit_get_loginuid(tsk)); } +static inline bool audit_contid_valid(u64 contid) +{ + return contid != AUDIT_CID_UNSET; +} + +static inline bool audit_contid_set(struct task_struct *tsk) +{ + return audit_contid_valid(audit_get_contid(tsk)); +} + static inline void audit_log_string(struct audit_buffer *ab, const char *buf) { audit_log_n_string(ab, buf, strlen(buf)); diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 9b6a973f4cc3..859382527210 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -71,6 +71,7 @@ #define AUDIT_TTY_SET 1017 /* Set TTY auditing status */ #define AUDIT_SET_FEATURE 1018 /* Turn an audit feature on or off */ #define AUDIT_GET_FEATURE 1019 /* Get which features are enabled */ +#define AUDIT_CONTAINER_OP 1020 /* Define the container id and info */ #define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */ #define AUDIT_USER_AVC 1107 /* We filter this differently */ @@ -491,6 +492,7 @@ struct audit_tty_status { #define AUDIT_UID_UNSET (unsigned int)-1 #define AUDIT_SID_UNSET ((unsigned int)-1) +#define AUDIT_CID_UNSET ((u64)-1) /* audit_rule_data supports filter rules with both integer and string * fields. It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and diff --git a/kernel/audit.c b/kernel/audit.c index 5d8147a29291..6d387793f702 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -138,6 +138,13 @@ struct auditd_connection { /* Hash for inode-based rules */ struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS]; +/* Hash for contid object lists */ +struct list_head audit_contid_hash[AUDIT_CONTID_BUCKETS]; +/* Lock all additions and deletions to the contid hash lists, assignment + * of container objects to tasks. There should be no need for + * interaction with tasklist_lock + */ +static DEFINE_SPINLOCK(audit_contobj_list_lock); static struct kmem_cache *audit_buffer_cache; @@ -212,6 +219,33 @@ void __init audit_task_init(void) 0, SLAB_PANIC, NULL); } +/* rcu_read_lock must be held by caller unless new */ +static struct audit_contobj *_audit_contobj_hold(struct audit_contobj *cont) +{ + if (cont) + refcount_inc(&cont->refcount); + return cont; +} + +static struct audit_contobj *_audit_contobj_get(struct task_struct *tsk) +{ + if (!tsk->audit) + return NULL; + return _audit_contobj_hold(tsk->audit->cont); +} + +/* rcu_read_lock must be held by caller */ +static void _audit_contobj_put(struct audit_contobj *cont) +{ + if (!cont) + return; + if (refcount_dec_and_test(&cont->refcount)) { + put_task_struct(cont->owner); + list_del_rcu(&cont->list); + kfree_rcu(cont, rcu); + } +} + /** * audit_alloc - allocate an audit info block for a task * @tsk: task @@ -232,6 +266,9 @@ int audit_alloc(struct task_struct *tsk) } info->loginuid = audit_get_loginuid(current); info->sessionid = audit_get_sessionid(current); + rcu_read_lock(); + info->cont = _audit_contobj_get(current); + rcu_read_unlock(); tsk->audit = info; ret = audit_alloc_syscall(tsk); @@ -246,6 +283,7 @@ int audit_alloc(struct task_struct *tsk) struct audit_task_info init_struct_audit = { .loginuid = INVALID_UID, .sessionid = AUDIT_SID_UNSET, + .cont = NULL, #ifdef CONFIG_AUDITSYSCALL .ctx = NULL, #endif @@ -262,6 +300,9 @@ void audit_free(struct task_struct *tsk) struct audit_task_info *info = tsk->audit; audit_free_syscall(tsk); + rcu_read_lock(); + _audit_contobj_put(tsk->audit->cont); + rcu_read_unlock(); /* Freeing the audit_task_info struct must be performed after * audit_log_exit() due to need for loginuid and sessionid. */ @@ -1709,6 +1750,9 @@ static int __init audit_init(void) for (i = 0; i < AUDIT_INODE_BUCKETS; i++) INIT_LIST_HEAD(&audit_inode_hash[i]); + for (i = 0; i < AUDIT_CONTID_BUCKETS; i++) + INIT_LIST_HEAD(&audit_contid_hash[i]); + mutex_init(&audit_cmd_mutex.lock); audit_cmd_mutex.owner = NULL; @@ -2410,6 +2454,110 @@ int audit_signal_info(int sig, struct task_struct *t) return audit_signal_info_syscall(t); } +/* + * audit_set_contid - set current task's audit contid + * @task: target task + * @contid: contid value + * + * Returns 0 on success, -EPERM on permission failure. + * + * If the original container owner goes away, no task injection is + * possible to an existing container. + * + * Called (set) from fs/proc/base.c::proc_contid_write(). + */ +int audit_set_contid(struct task_struct *task, u64 contid) +{ + int rc = 0; + struct audit_buffer *ab; + struct audit_contobj *oldcont = NULL; + + task_lock(task); + /* Can't set if audit disabled */ + if (!task->audit) { + task_unlock(task); + return -ENOPROTOOPT; + } + read_lock(&tasklist_lock); + /* Don't allow the contid to be unset */ + if (!audit_contid_valid(contid)) { + rc = -EINVAL; + goto unlock; + } + /* if we don't have caps, reject */ + if (!capable(CAP_AUDIT_CONTROL)) { + rc = -EPERM; + goto unlock; + } + /* if task has children or is not single-threaded, deny */ + if (!list_empty(&task->children) || + !(thread_group_leader(task) && thread_group_empty(task))) { + rc = -EBUSY; + goto unlock; + } + /* if contid is already set, deny */ + if (audit_contid_set(task)) + rc = -EEXIST; +unlock: + read_unlock(&tasklist_lock); + rcu_read_lock(); + oldcont = _audit_contobj_get(task); + if (!rc) { + struct audit_contobj *cont = NULL, *newcont = NULL; + int h = audit_hash_contid(contid); + + spin_lock(&audit_contobj_list_lock); + list_for_each_entry_rcu(cont, &audit_contid_hash[h], list) + if (cont->id == contid) { + /* task injection to existing container */ + if (current == cont->owner) { + _audit_contobj_hold(cont); + newcont = cont; + } else { + rc = -ENOTUNIQ; + spin_unlock(&audit_contobj_list_lock); + goto conterror; + } + break; + } + if (!newcont) { + newcont = kmalloc(sizeof(*newcont), GFP_ATOMIC); + if (newcont) { + INIT_LIST_HEAD(&newcont->list); + newcont->id = contid; + newcont->owner = get_task_struct(current); + refcount_set(&newcont->refcount, 1); + list_add_rcu(&newcont->list, + &audit_contid_hash[h]); + } else { + rc = -ENOMEM; + spin_unlock(&audit_contobj_list_lock); + goto conterror; + } + } + spin_unlock(&audit_contobj_list_lock); + task->audit->cont = newcont; + _audit_contobj_put(oldcont); + } +conterror: + task_unlock(task); + + if (!audit_enabled) + return rc; + + ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONTAINER_OP); + if (!ab) + return rc; + + audit_log_format(ab, + "op=set opid=%d contid=%llu old-contid=%llu", + task_tgid_nr(task), contid, oldcont ? oldcont->id : -1); + _audit_contobj_put(oldcont); + rcu_read_unlock(); + audit_log_end(ab); + return rc; +} + /** * audit_log_end - end one audit record * @ab: the audit_buffer diff --git a/kernel/audit.h b/kernel/audit.h index 9bee09757068..182fc76ea276 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -210,6 +210,14 @@ static inline int audit_hash_ino(u32 ino) return (ino & (AUDIT_INODE_BUCKETS-1)); } +#define AUDIT_CONTID_BUCKETS 32 +extern struct list_head audit_contid_hash[AUDIT_CONTID_BUCKETS]; + +static inline int audit_hash_contid(u64 contid) +{ + return (contid & (AUDIT_CONTID_BUCKETS-1)); +} + /* Indicates that audit should log the full pathname. */ #define AUDIT_NAME_FULL -1 From patchwork Sat Jun 27 13:20:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318317 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=KtrS+I9o; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDty2X2cz9sSS for ; Sat, 27 Jun 2020 23:22:18 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726721AbgF0NWQ (ORCPT ); Sat, 27 Jun 2020 09:22:16 -0400 Received: from us-smtp-2.mimecast.com ([207.211.31.81]:42973 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726712AbgF0NWQ (ORCPT ); Sat, 27 Jun 2020 09:22:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264134; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=ZmZQ6YpjDGuZOAaP7vN/saFkJHDkGblsgsww8zJHVz4=; b=KtrS+I9olPtqrhbZMr9DBnRoQBaSMIOcp50asexUcv8bJO0q9i17bdKOZYvyz2SH0OgAnM c4PFy4y88cDj4aXZJp0tnwUTcHgwartmj2CytWEDUs8km5sc9/ls87S2EdD8BRKvF26jCS Z6eFzATV1cyEjIDUw3RY+Glr8ydcQ4M= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-157-wnlBN0m0P9GJVdzwoU0N-g-1; Sat, 27 Jun 2020 09:22:10 -0400 X-MC-Unique: wnlBN0m0P9GJVdzwoU0N-g-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1ECED1800D4A; Sat, 27 Jun 2020 13:22:08 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id A818F7932A; Sat, 27 Jun 2020 13:22:03 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 03/13] audit: read container ID of a process Date: Sat, 27 Jun 2020 09:20:36 -0400 Message-Id: <37acbd05281e060abd868cc42663fe36d810aefd.1593198710.git.rgb@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Add support for reading the audit container identifier from the proc filesystem. This is a read from the proc entry of the form /proc/PID/audit_containerid where PID is the process ID of the task whose audit container identifier is sought. The read expects up to a u64 value (unset: 18446744073709551615). This read requires CAP_AUDIT_CONTROL. Signed-off-by: Richard Guy Briggs Acked-by: Serge Hallyn Acked-by: Neil Horman Reviewed-by: Ondrej Mosnacek --- fs/proc/base.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 6c17ab32e71b..794474cd8f35 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1234,7 +1234,7 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf, }; #ifdef CONFIG_AUDIT -#define TMPBUFLEN 11 +#define TMPBUFLEN 21 static ssize_t proc_loginuid_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) { @@ -1318,6 +1318,24 @@ static ssize_t proc_sessionid_read(struct file * file, char __user * buf, .llseek = generic_file_llseek, }; +static ssize_t proc_contid_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file_inode(file); + struct task_struct *task = get_proc_task(inode); + ssize_t length; + char tmpbuf[TMPBUFLEN]; + + if (!task) + return -ESRCH; + /* if we don't have caps, reject */ + if (!capable(CAP_AUDIT_CONTROL)) + return -EPERM; + length = scnprintf(tmpbuf, TMPBUFLEN, "%llu", audit_get_contid(task)); + put_task_struct(task); + return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); +} + static ssize_t proc_contid_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -1348,6 +1366,7 @@ static ssize_t proc_contid_write(struct file *file, const char __user *buf, } static const struct file_operations proc_contid_operations = { + .read = proc_contid_read, .write = proc_contid_write, .llseek = generic_file_llseek, }; @@ -3253,7 +3272,7 @@ static int proc_stack_depth(struct seq_file *m, struct pid_namespace *ns, #ifdef CONFIG_AUDIT REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), - REG("audit_containerid", S_IWUSR, proc_contid_operations), + REG("audit_containerid", S_IWUSR|S_IRUSR, proc_contid_operations), #endif #ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), @@ -3593,7 +3612,7 @@ static int proc_tid_comm_permission(struct inode *inode, int mask) #ifdef CONFIG_AUDIT REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), - REG("audit_containerid", S_IWUSR, proc_contid_operations), + REG("audit_containerid", S_IWUSR|S_IRUSR, proc_contid_operations), #endif #ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), From patchwork Sat Jun 27 13:20:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318320 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=KAYDIlvg; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDv85cZHz9sSS for ; Sat, 27 Jun 2020 23:22:28 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726724AbgF0NWV (ORCPT ); Sat, 27 Jun 2020 09:22:21 -0400 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:51216 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726731AbgF0NWU (ORCPT ); Sat, 27 Jun 2020 09:22:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264139; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=5daVVav2vz0gUbxpNuM5DjXpFZAkaJD7gM4Gto+ga3s=; b=KAYDIlvg4GzuE0lfs7gd5Jk3v5AipQB3zfJy1hgRbr1xb6+gb9MdrXY5/c8sZVqjVjOdi2 TPd4xTwz2XJa6avuRDmOpWGku572lOSPmmttv7tjffMbsYa7/6rGhnT1gx4VRnADpLZBp7 10N6VYEJ1nyljhrxgiCZivih3Z0TES0= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-370-8o6uA2f7NH-45B6dJFcCKA-1; Sat, 27 Jun 2020 09:22:14 -0400 X-MC-Unique: 8o6uA2f7NH-45B6dJFcCKA-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1F10D8015FD; Sat, 27 Jun 2020 13:22:13 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7FAC57932A; Sat, 27 Jun 2020 13:22:08 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 04/13] audit: log drop of contid on exit of last task Date: Sat, 27 Jun 2020 09:20:37 -0400 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Since we are tracking the life of each audit container indentifier, we can match the creation event with the destruction event. Log the destruction of the audit container identifier when the last process in that container exits. Signed-off-by: Richard Guy Briggs --- kernel/audit.c | 20 ++++++++++++++++++++ kernel/audit.h | 2 ++ kernel/auditsc.c | 2 ++ 3 files changed, 24 insertions(+) diff --git a/kernel/audit.c b/kernel/audit.c index 6d387793f702..9e0b38ce1ead 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -2558,6 +2558,26 @@ int audit_set_contid(struct task_struct *task, u64 contid) return rc; } +void audit_log_container_drop(void) +{ + struct audit_buffer *ab; + struct audit_contobj *cont; + + rcu_read_lock(); + cont = _audit_contobj_get(current); + _audit_contobj_put(cont); + if (!cont || refcount_read(&cont->refcount) > 1) + goto out; + ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONTAINER_OP); + if (!ab) + goto out; + audit_log_format(ab, "op=drop opid=%d contid=%llu old-contid=%llu", + task_tgid_nr(current), cont->id, cont->id); + audit_log_end(ab); +out: + rcu_read_unlock(); +} + /** * audit_log_end - end one audit record * @ab: the audit_buffer diff --git a/kernel/audit.h b/kernel/audit.h index 182fc76ea276..d07093903008 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -254,6 +254,8 @@ extern void audit_log_d_path_exe(struct audit_buffer *ab, extern struct tty_struct *audit_get_tty(void); extern void audit_put_tty(struct tty_struct *tty); +extern void audit_log_container_drop(void); + /* audit watch/mark/tree functions */ #ifdef CONFIG_AUDITSYSCALL extern unsigned int audit_serial(void); diff --git a/kernel/auditsc.c b/kernel/auditsc.c index f00c1da587ea..f03d3eb0752c 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1575,6 +1575,8 @@ static void audit_log_exit(void) audit_log_proctitle(); + audit_log_container_drop(); + /* Send end of event record to help user space know we are finished */ ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); if (ab) From patchwork Sat Jun 27 13:20:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318322 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=LPIbs2Ab; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDvS5tcLz9sR4 for ; Sat, 27 Jun 2020 23:22:44 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726784AbgF0NWh (ORCPT ); Sat, 27 Jun 2020 09:22:37 -0400 Received: from us-smtp-2.mimecast.com ([207.211.31.81]:40215 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726762AbgF0NWd (ORCPT ); Sat, 27 Jun 2020 09:22:33 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264150; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=6qtunjE5ws/F4Adj5tQCB/kH4v2kuL7jtyqe5YAUFwU=; b=LPIbs2AbNNMaxsUhXs5VgDAn009sqEaZ6v5hvxKLQx1yHpmRcZw0BsYgrZHnMWjzTByTDb CAQ23YdyYh2gX5PYpjp0k2IPZWimHUIEfWtV2kokJRx6HhA8RdJePs/uw7IBRO+MhNW64h Yu2LQ/f3gIETGWQOcj1DSDq4uHJH2hk= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-323-iExRSYVTOjm3bv2NNWNE1A-1; Sat, 27 Jun 2020 09:22:28 -0400 X-MC-Unique: iExRSYVTOjm3bv2NNWNE1A-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 860DE8031F6; Sat, 27 Jun 2020 13:22:26 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7EE857932A; Sat, 27 Jun 2020 13:22:13 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 05/13] audit: log container info of syscalls Date: Sat, 27 Jun 2020 09:20:38 -0400 Message-Id: <6e2e10432e1400f747918eeb93bf45029de2aa6c.1593198710.git.rgb@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Create a new audit record AUDIT_CONTAINER_ID to document the audit container identifier of a process if it is present. Called from audit_log_exit(), syscalls are covered. Include target_cid references from ptrace and signal. A sample raw event: type=SYSCALL msg=audit(1519924845.499:257): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=56374e1cef30 a2=241 a3=1b6 items=2 ppid=606 pid=635 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=3 comm="bash" exe="/usr/bin/bash" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="tmpcontainerid" type=CWD msg=audit(1519924845.499:257): cwd="/root" type=PATH msg=audit(1519924845.499:257): item=0 name="/tmp/" inode=13863 dev=00:27 mode=041777 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:tmp_t:s0 nametype= PARENT cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 type=PATH msg=audit(1519924845.499:257): item=1 name="/tmp/tmpcontainerid" inode=17729 dev=00:27 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_tmp_t:s0 nametype=CREATE cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 type=PROCTITLE msg=audit(1519924845.499:257): proctitle=62617368002D6300736C65657020313B206563686F2074657374203E202F746D702F746D70636F6E7461696E65726964 type=CONTAINER_ID msg=audit(1519924845.499:257): contid=123458 Please see the github audit kernel issue for the main feature: https://github.com/linux-audit/audit-kernel/issues/90 Please see the github audit userspace issue for supporting additions: https://github.com/linux-audit/audit-userspace/issues/51 Please see the github audit testsuiite issue for the test case: https://github.com/linux-audit/audit-testsuite/issues/64 Please see the github audit wiki for the feature overview: https://github.com/linux-audit/audit-kernel/wiki/RFE-Audit-Container-ID Signed-off-by: Richard Guy Briggs Acked-by: Serge Hallyn Acked-by: Steve Grubb Acked-by: Neil Horman Reviewed-by: Ondrej Mosnacek --- include/linux/audit.h | 7 +++++++ include/uapi/linux/audit.h | 1 + kernel/audit.c | 25 +++++++++++++++++++++++-- kernel/audit.h | 4 ++++ kernel/auditsc.c | 45 +++++++++++++++++++++++++++++++++++++++------ 5 files changed, 74 insertions(+), 8 deletions(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index 2800d4f1a2a8..5eeba0efffc2 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -222,6 +222,9 @@ static inline u64 audit_get_contid(struct task_struct *tsk) return tsk->audit->cont->id; } +extern void audit_log_container_id(struct audit_context *context, + struct audit_contobj *cont); + extern u32 audit_enabled; extern int audit_signal_info(int sig, struct task_struct *t); @@ -291,6 +294,10 @@ static inline u64 audit_get_contid(struct task_struct *tsk) return AUDIT_CID_UNSET; } +static inline void audit_log_container_id(struct audit_context *context, + struct audit_contobj *cont) +{ } + #define audit_enabled AUDIT_OFF static inline int audit_signal_info(int sig, struct task_struct *t) diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 859382527210..fd98460c983f 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -119,6 +119,7 @@ #define AUDIT_TIME_ADJNTPVAL 1333 /* NTP value adjustment */ #define AUDIT_BPF 1334 /* BPF subsystem */ #define AUDIT_EVENT_LISTENER 1335 /* Task joined multicast read socket */ +#define AUDIT_CONTAINER_ID 1336 /* Container ID */ #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ diff --git a/kernel/audit.c b/kernel/audit.c index 9e0b38ce1ead..a09f8f661234 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -227,7 +227,7 @@ static struct audit_contobj *_audit_contobj_hold(struct audit_contobj *cont) return cont; } -static struct audit_contobj *_audit_contobj_get(struct task_struct *tsk) +struct audit_contobj *_audit_contobj_get(struct task_struct *tsk) { if (!tsk->audit) return NULL; @@ -235,7 +235,7 @@ static struct audit_contobj *_audit_contobj_get(struct task_struct *tsk) } /* rcu_read_lock must be held by caller */ -static void _audit_contobj_put(struct audit_contobj *cont) +void _audit_contobj_put(struct audit_contobj *cont) { if (!cont) return; @@ -2211,6 +2211,27 @@ void audit_log_session_info(struct audit_buffer *ab) audit_log_format(ab, "auid=%u ses=%u", auid, sessionid); } +/* + * audit_log_container_id - report container info + * @context: task or local context for record + * @cont: container object to report + */ +void audit_log_container_id(struct audit_context *context, + struct audit_contobj *cont) +{ + struct audit_buffer *ab; + + if (!cont) + return; + /* Generate AUDIT_CONTAINER_ID record with container ID */ + ab = audit_log_start(context, GFP_KERNEL, AUDIT_CONTAINER_ID); + if (!ab) + return; + audit_log_format(ab, "contid=%llu", contid); + audit_log_end(ab); +} +EXPORT_SYMBOL(audit_log_container_id); + void audit_log_key(struct audit_buffer *ab, char *key) { audit_log_format(ab, " key="); diff --git a/kernel/audit.h b/kernel/audit.h index d07093903008..0c9446f8d52c 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -135,6 +135,7 @@ struct audit_context { kuid_t target_uid; unsigned int target_sessionid; u32 target_sid; + struct audit_contobj *target_cid; char target_comm[TASK_COMM_LEN]; struct audit_tree_refs *trees, *first_trees; @@ -218,6 +219,9 @@ static inline int audit_hash_contid(u64 contid) return (contid & (AUDIT_CONTID_BUCKETS-1)); } +extern struct audit_contobj *_audit_contobj_get(struct task_struct *tsk); +extern void _audit_contobj_put(struct audit_contobj *cont); + /* Indicates that audit should log the full pathname. */ #define AUDIT_NAME_FULL -1 diff --git a/kernel/auditsc.c b/kernel/auditsc.c index f03d3eb0752c..9e79645e5c0e 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -113,6 +113,7 @@ struct audit_aux_data_pids { kuid_t target_uid[AUDIT_AUX_PIDS]; unsigned int target_sessionid[AUDIT_AUX_PIDS]; u32 target_sid[AUDIT_AUX_PIDS]; + struct audit_contobj *target_cid[AUDIT_AUX_PIDS]; char target_comm[AUDIT_AUX_PIDS][TASK_COMM_LEN]; int pid_count; }; @@ -889,13 +890,20 @@ static inline void audit_free_names(struct audit_context *context) static inline void audit_free_aux(struct audit_context *context) { struct audit_aux_data *aux; + struct audit_aux_data_pids *axp; + _audit_contobj_put(context->target_cid); while ((aux = context->aux)) { context->aux = aux->next; kfree(aux); } while ((aux = context->aux_pids)) { + int i; + context->aux_pids = aux->next; + axp = (struct audit_aux_data_pids *)aux; + for (i = 0; i < axp->pid_count; i++) + _audit_contobj_put(axp->target_cid[i]); kfree(aux); } } @@ -1458,6 +1466,7 @@ static void audit_log_exit(void) struct audit_buffer *ab; struct audit_aux_data *aux; struct audit_names *n; + struct audit_contobj *cont; context->personality = current->personality; @@ -1541,7 +1550,7 @@ static void audit_log_exit(void) for (aux = context->aux_pids; aux; aux = aux->next) { struct audit_aux_data_pids *axs = (void *)aux; - for (i = 0; i < axs->pid_count; i++) + for (i = 0; i < axs->pid_count; i++) { if (audit_log_pid_context(context, axs->target_pid[i], axs->target_auid[i], axs->target_uid[i], @@ -1549,14 +1558,20 @@ static void audit_log_exit(void) axs->target_sid[i], axs->target_comm[i])) call_panic = 1; + audit_log_container_id(context, axs->target_cid[i]); + } } - if (context->target_pid && - audit_log_pid_context(context, context->target_pid, - context->target_auid, context->target_uid, - context->target_sessionid, - context->target_sid, context->target_comm)) + if (context->target_pid) { + if (audit_log_pid_context(context, context->target_pid, + context->target_auid, + context->target_uid, + context->target_sessionid, + context->target_sid, + context->target_comm)) call_panic = 1; + audit_log_container_id(context, context->target_cid); + } if (context->pwd.dentry && context->pwd.mnt) { ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD); @@ -1575,6 +1590,14 @@ static void audit_log_exit(void) audit_log_proctitle(); + rcu_read_lock(); + cont = _audit_contobj_get(current); + rcu_read_unlock(); + audit_log_container_id(context, cont); + rcu_read_lock(); + _audit_contobj_put(cont); + rcu_read_unlock(); + audit_log_container_drop(); /* Send end of event record to help user space know we are finished */ @@ -2385,6 +2408,10 @@ void __audit_ptrace(struct task_struct *t) context->target_uid = task_uid(t); context->target_sessionid = audit_get_sessionid(t); security_task_getsecid(t, &context->target_sid); + rcu_read_lock(); + _audit_contobj_put(context->target_cid); + context->target_cid = _audit_contobj_get(t); + rcu_read_unlock(); memcpy(context->target_comm, t->comm, TASK_COMM_LEN); } @@ -2412,6 +2439,9 @@ int audit_signal_info_syscall(struct task_struct *t) ctx->target_uid = t_uid; ctx->target_sessionid = audit_get_sessionid(t); security_task_getsecid(t, &ctx->target_sid); + rcu_read_lock(); + ctx->target_cid = _audit_contobj_get(t); + rcu_read_unlock(); memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN); return 0; } @@ -2433,6 +2463,9 @@ int audit_signal_info_syscall(struct task_struct *t) axp->target_uid[axp->pid_count] = t_uid; axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t); security_task_getsecid(t, &axp->target_sid[axp->pid_count]); + rcu_read_lock(); + axp->target_cid[axp->pid_count] = _audit_contobj_get(t); + rcu_read_unlock(); memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN); axp->pid_count++; From patchwork Sat Jun 27 13:20:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318326 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=YrIVWqxh; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDvp19nPz9sQx for ; Sat, 27 Jun 2020 23:23:02 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726805AbgF0NWn (ORCPT ); Sat, 27 Jun 2020 09:22:43 -0400 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:27607 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726794AbgF0NWm (ORCPT ); Sat, 27 Jun 2020 09:22:42 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264159; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=D/6L6twzheYSr88RdOaQC7di8PePUIyngyRcqG7vgpA=; b=YrIVWqxhOcntQIbuOhdpB9DWV+VLdz1krD3YZfj4skokTlDTx5/VZQHczq+xYqikLvGiXt wK3D05gFLABZFwhaUaVIUZgaEDQ7M9n0ZC14ofpFWDUt3CvHSixFrzVe3E/2uY8+Dbvxf/ kHiJ43Mcy3A4qkwYJGOm3NS7ZfaNvcg= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-144-u67sPryUM8-nmB7VjR08Jg-1; Sat, 27 Jun 2020 09:22:33 -0400 X-MC-Unique: u67sPryUM8-nmB7VjR08Jg-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id CEAC88031F8; Sat, 27 Jun 2020 13:22:31 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id E66548205F; Sat, 27 Jun 2020 13:22:26 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 06/13] audit: add contid support for signalling the audit daemon Date: Sat, 27 Jun 2020 09:20:39 -0400 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Add audit container identifier support to the action of signalling the audit daemon. Since this would need to add an element to the audit_sig_info struct, a new record type AUDIT_SIGNAL_INFO2 was created with a new audit_sig_info2 struct. Corresponding support is required in the userspace code to reflect the new record request and reply type. An older userspace won't break since it won't know to request this record type. Signed-off-by: Richard Guy Briggs --- include/linux/audit.h | 8 ++++ include/uapi/linux/audit.h | 1 + kernel/audit.c | 95 ++++++++++++++++++++++++++++++++++++++++++++- security/selinux/nlmsgtab.c | 1 + 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index 5eeba0efffc2..89cf7c66abe6 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -22,6 +22,13 @@ struct audit_sig_info { char ctx[]; }; +struct audit_sig_info2 { + uid_t uid; + pid_t pid; + u32 cid_len; + char data[]; +}; + struct audit_buffer; struct audit_context; struct inode; @@ -105,6 +112,7 @@ struct audit_contobj { u64 id; struct task_struct *owner; refcount_t refcount; + refcount_t sigflag; struct rcu_head rcu; }; diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index fd98460c983f..a56ad77069b9 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -72,6 +72,7 @@ #define AUDIT_SET_FEATURE 1018 /* Turn an audit feature on or off */ #define AUDIT_GET_FEATURE 1019 /* Get which features are enabled */ #define AUDIT_CONTAINER_OP 1020 /* Define the container id and info */ +#define AUDIT_SIGNAL_INFO2 1021 /* Get info auditd signal sender */ #define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */ #define AUDIT_USER_AVC 1107 /* We filter this differently */ diff --git a/kernel/audit.c b/kernel/audit.c index a09f8f661234..54dd2cb69402 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -126,6 +126,8 @@ struct auditd_connection { kuid_t audit_sig_uid = INVALID_UID; pid_t audit_sig_pid = -1; u32 audit_sig_sid = 0; +static struct audit_contobj *audit_sig_cid; +static struct task_struct *audit_sig_atsk; /* Records can be lost in several ways: 0) [suppressed in audit_alloc] @@ -239,7 +241,33 @@ void _audit_contobj_put(struct audit_contobj *cont) { if (!cont) return; - if (refcount_dec_and_test(&cont->refcount)) { + if (refcount_dec_and_test(&cont->refcount) && !refcount_read(&cont->sigflag)) { + put_task_struct(cont->owner); + list_del_rcu(&cont->list); + kfree_rcu(cont, rcu); + } +} + +/* rcu_read_lock must be held by caller unless new */ +static struct audit_contobj *_audit_contobj_get_sig(struct task_struct *tsk) +{ + struct audit_contobj *cont; + + if (!tsk->audit) + return NULL; + cont = tsk->audit->cont; + if (cont) + refcount_set(&cont->sigflag, 1); + return cont; +} + +/* rcu_read_lock must be held by caller */ +static void _audit_contobj_put_sig(struct audit_contobj *cont) +{ + if (!cont) + return; + refcount_set(&cont->sigflag, 0); + if (!refcount_read(&cont->refcount)) { put_task_struct(cont->owner); list_del_rcu(&cont->list); kfree_rcu(cont, rcu); @@ -309,6 +337,13 @@ void audit_free(struct task_struct *tsk) info = tsk->audit; tsk->audit = NULL; kmem_cache_free(audit_task_cache, info); + rcu_read_lock(); + if (audit_sig_atsk == tsk) { + _audit_contobj_put_sig(audit_sig_cid); + audit_sig_cid = NULL; + audit_sig_atsk = NULL; + } + rcu_read_unlock(); } /** @@ -1132,6 +1167,7 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type) case AUDIT_ADD_RULE: case AUDIT_DEL_RULE: case AUDIT_SIGNAL_INFO: + case AUDIT_SIGNAL_INFO2: case AUDIT_TTY_GET: case AUDIT_TTY_SET: case AUDIT_TRIM: @@ -1294,6 +1330,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) struct audit_buffer *ab; u16 msg_type = nlh->nlmsg_type; struct audit_sig_info *sig_data; + struct audit_sig_info2 *sig_data2; char *ctx = NULL; u32 len; @@ -1559,6 +1596,52 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) sig_data, sizeof(*sig_data) + len); kfree(sig_data); break; + case AUDIT_SIGNAL_INFO2: { + unsigned int contidstrlen = 0; + + len = 0; + if (audit_sig_sid) { + err = security_secid_to_secctx(audit_sig_sid, &ctx, + &len); + if (err) + return err; + } + if (audit_sig_cid) { + contidstr = kmalloc(21, GFP_KERNEL); + if (!contidstr) { + if (audit_sig_sid) + security_release_secctx(ctx, len); + return -ENOMEM; + } + contidstrlen = scnprintf(contidstr, 20, "%llu", audit_sig_cid->id); + } + sig_data2 = kmalloc(sizeof(*sig_data2) + contidstrlen + len, GFP_KERNEL); + if (!sig_data2) { + if (audit_sig_sid) + security_release_secctx(ctx, len); + kfree(contidstr); + return -ENOMEM; + } + sig_data2->uid = from_kuid(&init_user_ns, audit_sig_uid); + sig_data2->pid = audit_sig_pid; + if (audit_sig_cid) { + memcpy(sig_data2->data, contidstr, contidstrlen); + sig_data2->cid_len = contidstrlen; + kfree(contidstr); + } + if (audit_sig_sid) { + memcpy(sig_data2->data + contidstrlen, ctx, len); + security_release_secctx(ctx, len); + } + rcu_read_lock(); + _audit_contobj_put_sig(audit_sig_cid); + rcu_read_unlock(); + audit_sig_cid = NULL; + audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO2, 0, 0, + sig_data2, sizeof(*sig_data2) + contidstrlen + len); + kfree(sig_data2); + break; + } case AUDIT_TTY_GET: { struct audit_tty_status s; unsigned int t; @@ -2470,6 +2553,11 @@ int audit_signal_info(int sig, struct task_struct *t) else audit_sig_uid = uid; security_task_getsecid(current, &audit_sig_sid); + rcu_read_lock(); + _audit_contobj_put_sig(audit_sig_cid); + audit_sig_cid = _audit_contobj_get_sig(current); + rcu_read_unlock(); + audit_sig_atsk = t; } return audit_signal_info_syscall(t); @@ -2532,6 +2620,11 @@ int audit_set_contid(struct task_struct *task, u64 contid) if (cont->id == contid) { /* task injection to existing container */ if (current == cont->owner) { + if (!refcount_read(&cont->refcount)) { + rc = -ESHUTDOWN; + spin_unlock(&audit_contobj_list_lock); + goto conterror; + } _audit_contobj_hold(cont); newcont = cont; } else { diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index b69231918686..8303bb7a63d0 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -137,6 +137,7 @@ struct nlmsg_perm { { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ }, + { AUDIT_SIGNAL_INFO2, NETLINK_AUDIT_SOCKET__NLMSG_READ }, { AUDIT_TRIM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, { AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, From patchwork Sat Jun 27 13:20:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318324 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=N+FNinHG; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDvd37TSz9sQx for ; Sat, 27 Jun 2020 23:22:53 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726824AbgF0NWv (ORCPT ); Sat, 27 Jun 2020 09:22:51 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:37212 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726581AbgF0NWt (ORCPT ); Sat, 27 Jun 2020 09:22:49 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264168; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=Quiow2zvKmWErePkj6tgsO+t5+qVfVy/KDI+jkuHA2o=; b=N+FNinHGCuMmhwOwPt9otPmGmo5Fw4t80bWmVfUpUaoBuM5F7pVLeYF4shaTtxFq99AHrr xL/8WFJj3f62Zx1M3FjRJpL4kn9Uj+X7jCLOE5/LS9mZDUt2Un6a1UdrsnsdQeXL0eooDU jQMH0qMHumjkL//PbxCIvzC3C7EF4h8= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-359-3LdOcm5CMjaDh3VGTtGERg-1; Sat, 27 Jun 2020 09:22:46 -0400 X-MC-Unique: 3LdOcm5CMjaDh3VGTtGERg-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id D93C1107ACCA; Sat, 27 Jun 2020 13:22:44 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3AC5C71662; Sat, 27 Jun 2020 13:22:32 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 07/13] audit: add support for non-syscall auxiliary records Date: Sat, 27 Jun 2020 09:20:40 -0400 Message-Id: <21e6c4e1ac179c8dcf35803e603899ccfc69300a.1593198710.git.rgb@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Standalone audit records have the timestamp and serial number generated on the fly and as such are unique, making them standalone. This new function audit_alloc_local() generates a local audit context that will be used only for a standalone record and its auxiliary record(s). The context is discarded immediately after the local associated records are produced. Signed-off-by: Richard Guy Briggs Acked-by: Serge Hallyn Acked-by: Neil Horman Reviewed-by: Ondrej Mosnacek --- include/linux/audit.h | 8 ++++++++ kernel/audit.h | 1 + kernel/auditsc.c | 33 ++++++++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index 89cf7c66abe6..15d0defc5193 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -330,6 +330,8 @@ static inline int audit_signal_info(int sig, struct task_struct *t) /* These are defined in auditsc.c */ /* Public API */ +extern struct audit_context *audit_alloc_local(gfp_t gfpflags); +extern void audit_free_context(struct audit_context *context); 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); @@ -592,6 +594,12 @@ static inline void audit_log_nfcfg(const char *name, u8 af, extern int audit_n_rules; extern int audit_signals; #else /* CONFIG_AUDITSYSCALL */ +static inline struct audit_context *audit_alloc_local(gfp_t gfpflags) +{ + return NULL; +} +static inline void audit_free_context(struct audit_context *context) +{ } static inline void audit_syscall_entry(int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3) diff --git a/kernel/audit.h b/kernel/audit.h index 0c9446f8d52c..a7f88d76163f 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -98,6 +98,7 @@ struct audit_proctitle { struct audit_context { int dummy; /* must be the first element */ int in_syscall; /* 1 if task is in a syscall */ + bool local; /* local context needed */ 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 9e79645e5c0e..935eb3d2cde9 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -908,11 +908,13 @@ static inline void audit_free_aux(struct audit_context *context) } } -static inline struct audit_context *audit_alloc_context(enum audit_state state) +static inline struct audit_context *audit_alloc_context(enum audit_state state, + gfp_t gfpflags) { struct audit_context *context; - context = kzalloc(sizeof(*context), GFP_KERNEL); + /* We can be called in atomic context via audit_tg() */ + context = kzalloc(sizeof(*context), gfpflags); if (!context) return NULL; context->state = state; @@ -948,7 +950,8 @@ int audit_alloc_syscall(struct task_struct *tsk) return 0; } - if (!(context = audit_alloc_context(state))) { + context = audit_alloc_context(state, GFP_KERNEL); + if (!context) { kfree(key); audit_log_lost("out of memory in audit_alloc_syscall"); return -ENOMEM; @@ -960,8 +963,27 @@ int audit_alloc_syscall(struct task_struct *tsk) return 0; } -static inline void audit_free_context(struct audit_context *context) +struct audit_context *audit_alloc_local(gfp_t gfpflags) { + struct audit_context *context = NULL; + + context = audit_alloc_context(AUDIT_RECORD_CONTEXT, gfpflags); + if (!context) { + audit_log_lost("out of memory in audit_alloc_local"); + goto out; + } + context->serial = audit_serial(); + ktime_get_coarse_real_ts64(&context->ctime); + context->local = true; +out: + return context; +} +EXPORT_SYMBOL(audit_alloc_local); + +void audit_free_context(struct audit_context *context) +{ + if (!context) + return; audit_free_module(context); audit_free_names(context); unroll_tree_refs(context, NULL, 0); @@ -972,6 +994,7 @@ static inline void audit_free_context(struct audit_context *context) audit_proctitle_free(context); kfree(context); } +EXPORT_SYMBOL(audit_free_context); static int audit_log_pid_context(struct audit_context *context, pid_t pid, kuid_t auid, kuid_t uid, unsigned int sessionid, @@ -2204,7 +2227,7 @@ void __audit_inode_child(struct inode *parent, int auditsc_get_stamp(struct audit_context *ctx, struct timespec64 *t, unsigned int *serial) { - if (!ctx->in_syscall) + if (!ctx->in_syscall && !ctx->local) return 0; if (!ctx->serial) ctx->serial = audit_serial(); From patchwork Sat Jun 27 13:20:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318328 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=TeaK9T3q; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDw30sJnz9sQx for ; Sat, 27 Jun 2020 23:23:15 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726885AbgF0NXN (ORCPT ); Sat, 27 Jun 2020 09:23:13 -0400 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:39080 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726842AbgF0NXB (ORCPT ); Sat, 27 Jun 2020 09:23:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264180; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=tPpITunFHHYrcdgkS8NMc5qG45e+XjOoU0/iyAqJAFs=; b=TeaK9T3qGT9ZsBjmbBKAsI6NEimUpGzyAWHpKsSVtKXOdHbY955XXqN3V8yOYqoiPB6amg G2K+Hf9hRJhzlq3lwTvcI4GNOP4yQQp9E/fiv6qyFoHKqW1eTRSbpNWeKG8dEmlmC/WKmJ r+hDEew+tJA49vLcXx1Q1Vt6Gse8lso= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-282-qHRZtAcSO1e6JqqbOV4o6Q-1; Sat, 27 Jun 2020 09:22:58 -0400 X-MC-Unique: qHRZtAcSO1e6JqqbOV4o6Q-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 985B680058A; Sat, 27 Jun 2020 13:22:56 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5413C71662; Sat, 27 Jun 2020 13:22:45 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 08/13] audit: add containerid support for user records Date: Sat, 27 Jun 2020 09:20:41 -0400 Message-Id: <4a5019ed3cfab416aeb6549b791ac6d8cc9fb8b7.1593198710.git.rgb@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Add audit container identifier auxiliary record to user event standalone records. Signed-off-by: Richard Guy Briggs Acked-by: Neil Horman Reviewed-by: Ondrej Mosnacek --- kernel/audit.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/kernel/audit.c b/kernel/audit.c index 54dd2cb69402..997c34178ee8 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1212,12 +1212,6 @@ static void audit_log_common_recv_msg(struct audit_context *context, audit_log_task_context(*ab); } -static inline void audit_log_user_recv_msg(struct audit_buffer **ab, - u16 msg_type) -{ - audit_log_common_recv_msg(NULL, ab, msg_type); -} - int is_audit_feature_set(int i) { return af.features & AUDIT_FEATURE_TO_MASK(i); @@ -1486,6 +1480,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) err = audit_filter(msg_type, AUDIT_FILTER_USER); if (err == 1) { /* match or error */ char *str = data; + struct audit_context *context; + struct audit_contobj *cont; err = 0; if (msg_type == AUDIT_USER_TTY) { @@ -1493,7 +1489,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (err) break; } - audit_log_user_recv_msg(&ab, msg_type); + context = audit_alloc_local(GFP_KERNEL); + audit_log_common_recv_msg(context, &ab, msg_type); if (msg_type != AUDIT_USER_TTY) { /* ensure NULL termination */ str[data_len - 1] = '\0'; @@ -1507,6 +1504,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) audit_log_n_untrustedstring(ab, str, data_len); } audit_log_end(ab); + rcu_read_lock(); + cont = _audit_contobj_get(current); + rcu_read_unlock(); + audit_log_container_id(context, cont); + rcu_read_lock(); + _audit_contobj_put(cont); + rcu_read_unlock(); + audit_free_context(context); } break; case AUDIT_ADD_RULE: From patchwork Sat Jun 27 13:20:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318335 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=ZdAuEQig; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDwj3swBz9sR4 for ; Sat, 27 Jun 2020 23:23:49 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726904AbgF0NXc (ORCPT ); Sat, 27 Jun 2020 09:23:32 -0400 Received: from us-smtp-1.mimecast.com ([205.139.110.61]:49208 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726672AbgF0NXX (ORCPT ); Sat, 27 Jun 2020 09:23:23 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264201; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=TabxwYO5FJzN2Y5mg+1gJx1Jhp2y0LmF7+qh/iqVe0E=; b=ZdAuEQign2FIxjpLfGI9gPtPmttgn+GC57T3AX4ZYXReAXsoD1oLikR19JOjRE8JlCD6kJ v0oZvwCwwcVSQSxMQWdqKwPXbw1nG/01JIAC6qjuatpDhhKq8HgPw4y1YLEfle6hIC4liw Evo5wtje7xRlYd94sOnWinw45HCakpQ= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-262-QqYNox7hMZ2Y1NPdZsHkvg-1; Sat, 27 Jun 2020 09:23:15 -0400 X-MC-Unique: QqYNox7hMZ2Y1NPdZsHkvg-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 2A14B10059A4; Sat, 27 Jun 2020 13:23:14 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0456971662; Sat, 27 Jun 2020 13:22:56 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 09/13] audit: add containerid filtering Date: Sat, 27 Jun 2020 09:20:42 -0400 Message-Id: <6355038dbfc0b3fb41ba0f3ff9f34b044128f959.1593198710.git.rgb@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Implement audit container identifier filtering using the AUDIT_CONTID field name to send an 8-character string representing a u64 since the value field is only u32. Sending it as two u32 was considered, but gathering and comparing two fields was more complex. The feature indicator is AUDIT_FEATURE_BITMAP_CONTAINERID. Please see the github audit kernel issue for the contid filter feature: https://github.com/linux-audit/audit-kernel/issues/91 Please see the github audit userspace issue for filter additions: https://github.com/linux-audit/audit-userspace/issues/40 Please see the github audit testsuiite issue for the test case: https://github.com/linux-audit/audit-testsuite/issues/64 Please see the github audit wiki for the feature overview: https://github.com/linux-audit/audit-kernel/wiki/RFE-Audit-Container-ID Signed-off-by: Richard Guy Briggs Acked-by: Serge Hallyn Acked-by: Neil Horman Reviewed-by: Ondrej Mosnacek --- include/linux/audit.h | 1 + include/uapi/linux/audit.h | 5 ++++- kernel/audit.h | 1 + kernel/auditfilter.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/auditsc.c | 4 ++++ 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index 15d0defc5193..c4a755ae0d61 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -68,6 +68,7 @@ struct audit_field { u32 type; union { u32 val; + u64 val64; kuid_t uid; kgid_t gid; struct { diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index a56ad77069b9..831c12bdd235 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -271,6 +271,7 @@ #define AUDIT_LOGINUID_SET 24 #define AUDIT_SESSIONID 25 /* Session ID */ #define AUDIT_FSTYPE 26 /* FileSystem Type */ +#define AUDIT_CONTID 27 /* Container ID */ /* These are ONLY useful when checking * at syscall exit time (AUDIT_AT_EXIT). */ @@ -352,6 +353,7 @@ enum { #define AUDIT_FEATURE_BITMAP_SESSIONID_FILTER 0x00000010 #define AUDIT_FEATURE_BITMAP_LOST_RESET 0x00000020 #define AUDIT_FEATURE_BITMAP_FILTER_FS 0x00000040 +#define AUDIT_FEATURE_BITMAP_CONTAINERID 0x00000080 #define AUDIT_FEATURE_BITMAP_ALL (AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT | \ AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME | \ @@ -359,7 +361,8 @@ enum { AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND | \ AUDIT_FEATURE_BITMAP_SESSIONID_FILTER | \ AUDIT_FEATURE_BITMAP_LOST_RESET | \ - AUDIT_FEATURE_BITMAP_FILTER_FS) + AUDIT_FEATURE_BITMAP_FILTER_FS | \ + AUDIT_FEATURE_BITMAP_CONTAINERID) /* deprecated: AUDIT_VERSION_* */ #define AUDIT_VERSION_LATEST AUDIT_FEATURE_BITMAP_ALL diff --git a/kernel/audit.h b/kernel/audit.h index a7f88d76163f..34d8ec4bc6ef 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -228,6 +228,7 @@ static inline int audit_hash_contid(u64 contid) extern int audit_match_class(int class, unsigned syscall); extern int audit_comparator(const u32 left, const u32 op, const u32 right); +extern int audit_comparator64(const u64 left, const u32 op, const u64 right); extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); extern int parent_len(const char *path); diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index a10e2997aa6c..d812698efc1d 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -399,6 +399,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) case AUDIT_FILETYPE: case AUDIT_FIELD_COMPARE: case AUDIT_EXE: + case AUDIT_CONTID: /* only equal and not equal valid ops */ if (f->op != Audit_not_equal && f->op != Audit_equal) return -EINVAL; @@ -590,6 +591,14 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, entry->rule.buflen += f_val; entry->rule.exe = audit_mark; break; + case AUDIT_CONTID: + if (f_val != sizeof(u64)) + goto exit_free; + str = audit_unpack_string(&bufp, &remain, f_val); + if (IS_ERR(str)) + goto exit_free; + f->val64 = ((u64 *)str)[0]; + break; default: f->val = f_val; break; @@ -675,6 +684,11 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule) data->buflen += data->values[i] = audit_pack_string(&bufp, audit_mark_path(krule->exe)); break; + case AUDIT_CONTID: + data->buflen += data->values[i] = sizeof(u64); + memcpy(bufp, &f->val64, sizeof(u64)); + bufp += sizeof(u64); + break; case AUDIT_LOGINUID_SET: if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) { data->fields[i] = AUDIT_LOGINUID; @@ -761,6 +775,10 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b) if (!gid_eq(a->fields[i].gid, b->fields[i].gid)) return 1; break; + case AUDIT_CONTID: + if (a->fields[i].val64 != b->fields[i].val64) + return 1; + break; default: if (a->fields[i].val != b->fields[i].val) return 1; @@ -1216,6 +1234,30 @@ int audit_comparator(u32 left, u32 op, u32 right) } } +int audit_comparator64(u64 left, u32 op, u64 right) +{ + switch (op) { + case Audit_equal: + return (left == right); + case Audit_not_equal: + return (left != right); + case Audit_lt: + return (left < right); + case Audit_le: + return (left <= right); + case Audit_gt: + return (left > right); + case Audit_ge: + return (left >= right); + case Audit_bitmask: + return (left & right); + case Audit_bittest: + return ((left & right) == right); + default: + return 0; + } +} + int audit_uid_comparator(kuid_t left, u32 op, kuid_t right) { switch (op) { @@ -1350,6 +1392,10 @@ int audit_filter(int msgtype, unsigned int listtype) result = audit_comparator(audit_loginuid_set(current), f->op, f->val); break; + case AUDIT_CONTID: + result = audit_comparator64(audit_get_contid(current), + f->op, f->val64); + break; case AUDIT_MSGTYPE: result = audit_comparator(msgtype, f->op, f->val); break; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 935eb3d2cde9..baa5709590b4 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -640,6 +640,10 @@ static int audit_filter_rules(struct task_struct *tsk, result = audit_comparator(ctx->sockaddr->ss_family, f->op, f->val); break; + case AUDIT_CONTID: + result = audit_comparator64(audit_get_contid(tsk), + f->op, f->val64); + break; case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: From patchwork Sat Jun 27 13:20:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318340 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Q4zMdi0h; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDxG6RRFz9sR4 for ; Sat, 27 Jun 2020 23:24:18 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726646AbgF0NYL (ORCPT ); Sat, 27 Jun 2020 09:24:11 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:52431 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726895AbgF0NX2 (ORCPT ); Sat, 27 Jun 2020 09:23:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264205; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=CPP8DwxyP2nxU5T7VlnBBLby4pxWG218P+Lbpwd6l5M=; b=Q4zMdi0hHDdVtCiqyJzDPfJ7QwKjM4VQE8+4vVn7wHN0UOPydMVb1uBaElnqAB30iPPiMR VQD2aYmgdo0ivSG1O9HVsq8cs3tT2TT8W/X094K0y2c4X2RGHC8UNlZL7W0OAH7yXPzlCJ aXRReJGYsgH3hYu80aewWOTMWZu0a2g= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-109-Az1n9d3oNUGv4uftFmg6og-1; Sat, 27 Jun 2020 09:23:21 -0400 X-MC-Unique: Az1n9d3oNUGv4uftFmg6og-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 2A05A804003; Sat, 27 Jun 2020 13:23:19 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8A09D71662; Sat, 27 Jun 2020 13:23:14 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 10/13] audit: add support for containerid to network namespaces Date: Sat, 27 Jun 2020 09:20:43 -0400 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org This also adds support to qualify NETFILTER_PKT records. Audit events could happen in a network namespace outside of a task context due to packets received from the net that trigger an auditing rule prior to being associated with a running task. The network namespace could be in use by multiple containers by association to the tasks in that network namespace. We still want a way to attribute these events to any potential containers. Keep a list per network namespace to track these audit container identifiiers. Add/increment the audit container identifier on: - initial setting of the audit container identifier via /proc - clone/fork call that inherits an audit container identifier - unshare call that inherits an audit container identifier - setns call that inherits an audit container identifier Delete/decrement the audit container identifier on: - an inherited audit container identifier dropped when child set - process exit - unshare call that drops a net namespace - setns call that drops a net namespace Add audit container identifier auxiliary record(s) to NETFILTER_PKT event standalone records. Iterate through all potential audit container identifiers associated with a network namespace. Please see the github audit kernel issue for contid net support: https://github.com/linux-audit/audit-kernel/issues/92 Please see the github audit testsuiite issue for the test case: https://github.com/linux-audit/audit-testsuite/issues/64 Please see the github audit wiki for the feature overview: https://github.com/linux-audit/audit-kernel/wiki/RFE-Audit-Container-ID Signed-off-by: Richard Guy Briggs Acked-by: Neil Horman Reviewed-by: Ondrej Mosnacek --- include/linux/audit.h | 20 ++++++ kernel/audit.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++- kernel/nsproxy.c | 4 ++ net/netfilter/nft_log.c | 11 +++- net/netfilter/xt_AUDIT.c | 11 +++- 5 files changed, 195 insertions(+), 7 deletions(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index c4a755ae0d61..304fbb7c3c5b 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -128,6 +128,13 @@ struct audit_task_info { extern struct audit_task_info init_struct_audit; +struct audit_contobj_netns { + struct list_head list; + struct audit_contobj *obj; + int count; + struct rcu_head rcu; +}; + extern int is_audit_feature_set(int which); extern int __init audit_register_class(int class, unsigned *list); @@ -233,6 +240,11 @@ static inline u64 audit_get_contid(struct task_struct *tsk) extern void audit_log_container_id(struct audit_context *context, struct audit_contobj *cont); +extern void audit_copy_namespaces(struct net *net, struct task_struct *tsk); +extern void audit_switch_task_namespaces(struct nsproxy *ns, + struct task_struct *p); +extern void audit_log_netns_contid_list(struct net *net, + struct audit_context *context); extern u32 audit_enabled; @@ -306,6 +318,14 @@ static inline u64 audit_get_contid(struct task_struct *tsk) static inline void audit_log_container_id(struct audit_context *context, struct audit_contobj *cont) { } +static inline void audit_copy_namespaces(struct net *net, struct task_struct *tsk) +{ } +static inline void audit_switch_task_namespaces(struct nsproxy *ns, + struct task_struct *p) +{ } +static inline void audit_log_netns_contid_list(struct net *net, + struct audit_context *context) +{ } #define audit_enabled AUDIT_OFF diff --git a/kernel/audit.c b/kernel/audit.c index 997c34178ee8..a862721dfd9b 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -59,6 +59,7 @@ #include #include #include +#include #include "audit.h" @@ -86,9 +87,13 @@ /** * struct audit_net - audit private network namespace data * @sk: communication socket + * @contobj_list: audit container identifier list + * @contobj_list_lock audit container identifier list lock */ struct audit_net { struct sock *sk; + struct list_head contobj_list; + spinlock_t contobj_list_lock; }; /** @@ -214,6 +219,9 @@ struct audit_reply { static struct kmem_cache *audit_task_cache; +void audit_netns_contid_add(struct net *net, struct audit_contobj *cont); +void audit_netns_contid_del(struct net *net, struct audit_contobj *cont); + void __init audit_task_init(void) { audit_task_cache = kmem_cache_create("audit_task", @@ -326,10 +334,17 @@ struct audit_task_info init_struct_audit = { void audit_free(struct task_struct *tsk) { struct audit_task_info *info = tsk->audit; + struct nsproxy *ns = tsk->nsproxy; + struct audit_contobj *cont; audit_free_syscall(tsk); rcu_read_lock(); - _audit_contobj_put(tsk->audit->cont); + cont = _audit_contobj_get(tsk); + if (ns) { + audit_netns_contid_del(ns->net_ns, cont); + _audit_contobj_put(cont); + } + _audit_contobj_put(cont); rcu_read_unlock(); /* Freeing the audit_task_info struct must be performed after * audit_log_exit() due to need for loginuid and sessionid. @@ -437,6 +452,136 @@ static struct sock *audit_get_sk(const struct net *net) return aunet->sk; } +void audit_netns_contid_add(struct net *net, struct audit_contobj *cont) +{ + struct audit_net *aunet; + struct list_head *contobj_list; + struct audit_contobj_netns *contns; + + if (!net) + return; + if (!cont) + return; + aunet = net_generic(net, audit_net_id); + if (!aunet) + return; + contobj_list = &aunet->contobj_list; + rcu_read_lock(); + spin_lock(&aunet->contobj_list_lock); + list_for_each_entry_rcu(contns, contobj_list, list) + if (contns->obj == cont) { + contns->count++; + goto out; + } + contns = kmalloc(sizeof(*contns), GFP_ATOMIC); + if (contns) { + INIT_LIST_HEAD(&contns->list); + contns->obj = cont; + contns->count = 1; + list_add_rcu(&contns->list, contobj_list); + } +out: + spin_unlock(&aunet->contobj_list_lock); + rcu_read_unlock(); +} + +void audit_netns_contid_del(struct net *net, struct audit_contobj *cont) +{ + struct audit_net *aunet; + struct list_head *contobj_list; + struct audit_contobj_netns *contns = NULL; + + if (!net) + return; + if (!cont) + return; + aunet = net_generic(net, audit_net_id); + if (!aunet) + return; + contobj_list = &aunet->contobj_list; + rcu_read_lock(); + spin_lock(&aunet->contobj_list_lock); + list_for_each_entry_rcu(contns, contobj_list, list) + if (contns->obj == cont) { + contns->count--; + if (contns->count < 1) { + list_del_rcu(&contns->list); + kfree_rcu(contns, rcu); + } + break; + } + spin_unlock(&aunet->contobj_list_lock); + rcu_read_unlock(); +} + +void audit_copy_namespaces(struct net *net, struct task_struct *tsk) +{ + struct audit_contobj *cont; + + rcu_read_lock(); + cont = _audit_contobj_get(tsk); + audit_netns_contid_add(net, cont); + rcu_read_unlock(); +} + +void audit_switch_task_namespaces(struct nsproxy *ns, struct task_struct *p) +{ + struct audit_contobj *cont; + struct nsproxy *new = p->nsproxy; + + rcu_read_lock(); + cont = _audit_contobj_get(p); + if (!cont) + goto out; + audit_netns_contid_del(ns->net_ns, cont); + if (new) + audit_netns_contid_add(new->net_ns, cont); + else + _audit_contobj_put(cont); + _audit_contobj_put(cont); +out: + rcu_read_unlock(); +} + +/** + * audit_log_netns_contid_list - List contids for the given network namespace + * @net: the network namespace of interest + * @context: the audit context to use + * + * Description: + * Issues a CONTAINER_ID record with a CSV list of contids associated + * with a network namespace to accompany a NETFILTER_PKT record. + */ +void audit_log_netns_contid_list(struct net *net, struct audit_context *context) +{ + struct audit_buffer *ab = NULL; + struct audit_contobj_netns *cont; + struct audit_net *aunet; + + /* Generate AUDIT_CONTAINER_ID record with container ID CSV list */ + rcu_read_lock(); + aunet = net_generic(net, audit_net_id); + if (!aunet) + goto out; + list_for_each_entry_rcu(cont, &aunet->contobj_list, list) { + if (!ab) { + ab = audit_log_start(context, GFP_ATOMIC, + AUDIT_CONTAINER_ID); + if (!ab) { + audit_log_lost("out of memory in audit_log_netns_contid_list"); + goto out; + } + audit_log_format(ab, "contid="); + } else + audit_log_format(ab, ","); + audit_log_format(ab, "%llu", cont->obj->id); + } + audit_log_end(ab); +out: + rcu_read_unlock(); +} +EXPORT_SYMBOL(audit_log_netns_contid_list); + void audit_panic(const char *message) { switch (audit_failure) { @@ -1786,7 +1931,6 @@ static int __net_init audit_net_init(struct net *net) .flags = NL_CFG_F_NONROOT_RECV, .groups = AUDIT_NLGRP_MAX, }; - struct audit_net *aunet = net_generic(net, audit_net_id); aunet->sk = netlink_kernel_create(net, NETLINK_AUDIT, &cfg); @@ -1795,7 +1939,8 @@ static int __net_init audit_net_init(struct net *net) return -ENOMEM; } aunet->sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; - + INIT_LIST_HEAD(&aunet->contobj_list); + spin_lock_init(&aunet->contobj_list_lock); return 0; } @@ -2585,6 +2730,7 @@ int audit_set_contid(struct task_struct *task, u64 contid) int rc = 0; struct audit_buffer *ab; struct audit_contobj *oldcont = NULL; + struct net *net = task->nsproxy->net_ns; task_lock(task); /* Can't set if audit disabled */ @@ -2657,6 +2803,10 @@ int audit_set_contid(struct task_struct *task, u64 contid) spin_unlock(&audit_contobj_list_lock); task->audit->cont = newcont; _audit_contobj_put(oldcont); + audit_netns_contid_del(net, oldcont); + _audit_contobj_put(oldcont); + _audit_contobj_hold(newcont); + audit_netns_contid_add(net, newcont); } conterror: task_unlock(task); diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index b03df67621d0..5eddb3377049 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -26,6 +26,7 @@ #include #include #include +#include static struct kmem_cache *nsproxy_cachep; @@ -187,6 +188,8 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) } tsk->nsproxy = new_ns; + if (flags & CLONE_NEWNET) + audit_copy_namespaces(new_ns->net_ns, tsk); return 0; } @@ -249,6 +252,7 @@ void switch_task_namespaces(struct task_struct *p, struct nsproxy *new) ns = p->nsproxy; p->nsproxy = new; task_unlock(p); + audit_switch_task_namespaces(ns, p); if (ns && atomic_dec_and_test(&ns->count)) free_nsproxy(ns); diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c index fe4831f2258f..98d1e7e1a83c 100644 --- a/net/netfilter/nft_log.c +++ b/net/netfilter/nft_log.c @@ -66,13 +66,16 @@ static void nft_log_eval_audit(const struct nft_pktinfo *pkt) struct sk_buff *skb = pkt->skb; struct audit_buffer *ab; int fam = -1; + struct audit_context *context; + struct net *net; if (!audit_enabled) return; - ab = audit_log_start(NULL, GFP_ATOMIC, AUDIT_NETFILTER_PKT); + context = audit_alloc_local(GFP_ATOMIC); + ab = audit_log_start(context, GFP_ATOMIC, AUDIT_NETFILTER_PKT); if (!ab) - return; + goto errout; audit_log_format(ab, "mark=%#x", skb->mark); @@ -99,6 +102,10 @@ static void nft_log_eval_audit(const struct nft_pktinfo *pkt) audit_log_format(ab, " saddr=? daddr=? proto=-1"); audit_log_end(ab); + net = xt_net(&pkt->xt); + audit_log_netns_contid_list(net, context); +errout: + audit_free_context(context); } static void nft_log_eval(const struct nft_expr *expr, diff --git a/net/netfilter/xt_AUDIT.c b/net/netfilter/xt_AUDIT.c index 9cdc16b0d0d8..ecf868a1abde 100644 --- a/net/netfilter/xt_AUDIT.c +++ b/net/netfilter/xt_AUDIT.c @@ -68,10 +68,13 @@ static bool audit_ip6(struct audit_buffer *ab, struct sk_buff *skb) { struct audit_buffer *ab; int fam = -1; + struct audit_context *context; + struct net *net; if (audit_enabled == AUDIT_OFF) - goto errout; - ab = audit_log_start(NULL, GFP_ATOMIC, AUDIT_NETFILTER_PKT); + goto out; + context = audit_alloc_local(GFP_ATOMIC); + ab = audit_log_start(context, GFP_ATOMIC, AUDIT_NETFILTER_PKT); if (ab == NULL) goto errout; @@ -101,7 +104,11 @@ static bool audit_ip6(struct audit_buffer *ab, struct sk_buff *skb) audit_log_end(ab); + net = xt_net(par); + audit_log_netns_contid_list(net, context); errout: + audit_free_context(context); +out: return XT_CONTINUE; } From patchwork Sat Jun 27 13:20:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318334 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Z1+JGGet; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDwg59JXz9sR4 for ; Sat, 27 Jun 2020 23:23:47 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726937AbgF0NXp (ORCPT ); Sat, 27 Jun 2020 09:23:45 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:35938 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726916AbgF0NXh (ORCPT ); Sat, 27 Jun 2020 09:23:37 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264215; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=k1ut6WkTgl4dIR6Pt+/0ewyvawbqPYzltO79GX8YVNI=; b=Z1+JGGetd0GVmefPiioE1H/5dnnX41I3qhURfAcLV5B5fdkMNxEG7DOOvjQ3/215Tt8BAS iJZFaJkTVqfhYicNZTDYKibFtRczC3jvI5APUr/PaE5YOJ9vKnMZ7lbKq+KBoEHw4++OPq gw74Ifa6fvDRLbl6BboOduEUAqV3VBw= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-167-mnILldnlMISyoZ0KY_i4pg-1; Sat, 27 Jun 2020 09:23:31 -0400 X-MC-Unique: mnILldnlMISyoZ0KY_i4pg-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 9793618A0724; Sat, 27 Jun 2020 13:23:29 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8AE2C71662; Sat, 27 Jun 2020 13:23:19 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 11/13] audit: contid check descendancy and nesting Date: Sat, 27 Jun 2020 09:20:44 -0400 Message-Id: <01229b93733d9baf6ac9bb0cc243eeb08ad579cd.1593198710.git.rgb@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Require the target task to be a descendant of the container orchestrator/engine. You would only change the audit container ID from one set or inherited value to another if you were nesting containers. If changing the contid, the container orchestrator/engine must be a descendant and not same orchestrator as the one that set it so it is not possible to change the contid of another orchestrator's container. Since the task_is_descendant() function is used in YAMA and in audit, remove the duplication and pull the function into kernel/core/sched.c Signed-off-by: Richard Guy Briggs --- include/linux/sched.h | 3 +++ kernel/audit.c | 23 +++++++++++++++++++++-- kernel/sched/core.c | 33 +++++++++++++++++++++++++++++++++ security/yama/yama_lsm.c | 33 --------------------------------- 4 files changed, 57 insertions(+), 35 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 2213ac670386..06938d0b9e0c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2047,4 +2047,7 @@ static inline void rseq_syscall(struct pt_regs *regs) const struct cpumask *sched_trace_rd_span(struct root_domain *rd); +extern int task_is_descendant(struct task_struct *parent, + struct task_struct *child); + #endif diff --git a/kernel/audit.c b/kernel/audit.c index a862721dfd9b..efa65ec01239 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -2713,6 +2713,20 @@ int audit_signal_info(int sig, struct task_struct *t) return audit_signal_info_syscall(t); } +static bool audit_contid_isnesting(struct task_struct *tsk) +{ + bool isowner = false; + bool ownerisparent = false; + + rcu_read_lock(); + if (tsk->audit && tsk->audit->cont) { + isowner = current == tsk->audit->cont->owner; + ownerisparent = task_is_descendant(tsk->audit->cont->owner, current); + } + rcu_read_unlock(); + return !isowner && ownerisparent; +} + /* * audit_set_contid - set current task's audit contid * @task: target task @@ -2755,8 +2769,13 @@ int audit_set_contid(struct task_struct *task, u64 contid) rc = -EBUSY; goto unlock; } - /* if contid is already set, deny */ - if (audit_contid_set(task)) + /* if task is not descendant, block */ + if (task == current || !task_is_descendant(current, task)) { + rc = -EXDEV; + goto unlock; + } + /* only allow contid setting again if nesting */ + if (audit_contid_set(task) && !audit_contid_isnesting(task)) rc = -EEXIST; unlock: read_unlock(&tasklist_lock); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 8f360326861e..e6b24c52b3c3 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -8012,6 +8012,39 @@ void dump_cpu_task(int cpu) } /* + * task_is_descendant - walk up a process family tree looking for a match + * @parent: the process to compare against while walking up from child + * @child: the process to start from while looking upwards for parent + * + * Returns 1 if child is a descendant of parent, 0 if not. + */ +int task_is_descendant(struct task_struct *parent, + struct task_struct *child) +{ + int rc = 0; + struct task_struct *walker = child; + + if (!parent || !child) + return 0; + + rcu_read_lock(); + if (!thread_group_leader(parent)) + parent = rcu_dereference(parent->group_leader); + while (walker->pid > 0) { + if (!thread_group_leader(walker)) + walker = rcu_dereference(walker->group_leader); + if (walker == parent) { + rc = 1; + break; + } + walker = rcu_dereference(walker->real_parent); + } + rcu_read_unlock(); + + return rc; +} + +/* * Nice levels are multiplicative, with a gentle 10% change for every * nice level changed. I.e. when a CPU-bound task goes from nice 0 to * nice 1, it will get ~10% less CPU time than another CPU-bound task diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 536c99646f6a..24939f765df5 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -263,39 +263,6 @@ static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, } /** - * task_is_descendant - walk up a process family tree looking for a match - * @parent: the process to compare against while walking up from child - * @child: the process to start from while looking upwards for parent - * - * Returns 1 if child is a descendant of parent, 0 if not. - */ -static int task_is_descendant(struct task_struct *parent, - struct task_struct *child) -{ - int rc = 0; - struct task_struct *walker = child; - - if (!parent || !child) - return 0; - - rcu_read_lock(); - if (!thread_group_leader(parent)) - parent = rcu_dereference(parent->group_leader); - while (walker->pid > 0) { - if (!thread_group_leader(walker)) - walker = rcu_dereference(walker->group_leader); - if (walker == parent) { - rc = 1; - break; - } - walker = rcu_dereference(walker->real_parent); - } - rcu_read_unlock(); - - return rc; -} - -/** * ptracer_exception_found - tracer registered as exception for this tracee * @tracer: the task_struct of the process attempting ptrace * @tracee: the task_struct of the process to be ptraced From patchwork Sat Jun 27 13:20:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318336 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=M2dos+qS; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDwl3TvPz9sQx for ; Sat, 27 Jun 2020 23:23:51 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726946AbgF0NXu (ORCPT ); Sat, 27 Jun 2020 09:23:50 -0400 Received: from us-smtp-1.mimecast.com ([205.139.110.61]:53667 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726806AbgF0NXt (ORCPT ); Sat, 27 Jun 2020 09:23:49 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264226; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=xHQ23E0ubwuEGdr08pTjn1ZZAxTi7f5b6ScMm0bJY4c=; b=M2dos+qSdkdfThdqEhDIKsZdSRpUlnleRLz5SSLKDmUuScAOxPdi2rNPySNeARJxGC++JK f87tLOdac2N1CSd3wVCCz7mBf3JyzO1/VTTla2k7/UaFtdNA2jDWgl5RegxJyr4gyBbrSH MI5gyle//eXIEsAQ8PIP1qEdX0c4uc4= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-18-UOKJWxGZPmy5N6uVApuoTQ-1; Sat, 27 Jun 2020 09:23:44 -0400 X-MC-Unique: UOKJWxGZPmy5N6uVApuoTQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id DFCF2800C60; Sat, 27 Jun 2020 13:23:42 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0901871662; Sat, 27 Jun 2020 13:23:29 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 12/13] audit: track container nesting Date: Sat, 27 Jun 2020 09:20:45 -0400 Message-Id: <1d793e2fc60650de4bbc9f4bde3c736c94efe9a1.1593198710.git.rgb@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Track the parent container of a container to be able to filter and report nesting. Now that we have a way to track and check the parent container of a container, modify the contid field format to be able to report that nesting using a carrat ("^") modifier to indicate nesting. The original field format was "contid=" for task-associated records and "contid=[,[...]]" for network-namespace-associated records. The new field format is "contid=[,^[...]][,[...]]". Signed-off-by: Richard Guy Briggs --- include/linux/audit.h | 1 + kernel/audit.c | 60 ++++++++++++++++++++++++++++++++++++++++++--------- kernel/audit.h | 2 ++ kernel/auditfilter.c | 17 ++++++++++++++- kernel/auditsc.c | 2 +- 5 files changed, 70 insertions(+), 12 deletions(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index 304fbb7c3c5b..025b52ae8422 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -115,6 +115,7 @@ struct audit_contobj { refcount_t refcount; refcount_t sigflag; struct rcu_head rcu; + struct audit_contobj *parent; }; struct audit_task_info { diff --git a/kernel/audit.c b/kernel/audit.c index efa65ec01239..aaf74702e993 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -221,6 +221,7 @@ struct audit_reply { void audit_netns_contid_add(struct net *net, struct audit_contobj *cont); void audit_netns_contid_del(struct net *net, struct audit_contobj *cont); +void audit_log_contid(struct audit_buffer *ab, struct audit_contobj *cont); void __init audit_task_init(void) { @@ -277,6 +278,7 @@ static void _audit_contobj_put_sig(struct audit_contobj *cont) refcount_set(&cont->sigflag, 0); if (!refcount_read(&cont->refcount)) { put_task_struct(cont->owner); + _audit_contobj_put(cont->parent); list_del_rcu(&cont->list); kfree_rcu(cont, rcu); } @@ -574,7 +576,7 @@ void audit_log_netns_contid_list(struct net *net, struct audit_context *context) audit_log_format(ab, "contid="); } else audit_log_format(ab, ","); - audit_log_format(ab, "%llu", cont->obj->id); + audit_log_contid(ab, cont->obj); } audit_log_end(ab); out: @@ -1747,7 +1749,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) kfree(sig_data); break; case AUDIT_SIGNAL_INFO2: { + char *contidstr = NULL; unsigned int contidstrlen = 0; + struct audit_contobj *cont = audit_sig_cid; len = 0; if (audit_sig_sid) { @@ -1757,13 +1761,27 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return err; } if (audit_sig_cid) { - contidstr = kmalloc(21, GFP_KERNEL); + contidstr = kmalloc(AUDIT_MESSAGE_TEXT_MAX, GFP_KERNEL); if (!contidstr) { if (audit_sig_sid) security_release_secctx(ctx, len); return -ENOMEM; } - contidstrlen = scnprintf(contidstr, 20, "%llu", audit_sig_cid->id); + rcu_read_lock(); + while (cont) { + if (cont->parent) + contidstrlen += scnprintf(contidstr, + AUDIT_MESSAGE_TEXT_MAX - + contidstrlen, + "%llu,^", cont->id); + else + contidstrlen += scnprintf(contidstr, + AUDIT_MESSAGE_TEXT_MAX - + contidstrlen, + "%llu", cont->id); + cont = cont->parent; + } + rcu_read_unlock(); } sig_data2 = kmalloc(sizeof(*sig_data2) + contidstrlen + len, GFP_KERNEL); if (!sig_data2) { @@ -2444,6 +2462,23 @@ void audit_log_session_info(struct audit_buffer *ab) audit_log_format(ab, "auid=%u ses=%u", auid, sessionid); } +void audit_log_contid(struct audit_buffer *ab, struct audit_contobj *cont) +{ + if (!cont) { + audit_log_format(ab, "-1"); + return; + } + rcu_read_lock(); + while (cont) { + if (cont->parent) + audit_log_format(ab, "%llu,^", cont->id); + else + audit_log_format(ab, "%llu", cont->id); + cont = cont->parent; + } + rcu_read_unlock(); +} + /* * audit_log_container_id - report container info * @context: task or local context for record @@ -2460,7 +2495,8 @@ void audit_log_container_id(struct audit_context *context, ab = audit_log_start(context, GFP_KERNEL, AUDIT_CONTAINER_ID); if (!ab) return; - audit_log_format(ab, "contid=%llu", contid); + audit_log_format(ab, "contid="); + audit_log_contid(ab, cont); audit_log_end(ab); } EXPORT_SYMBOL(audit_log_container_id); @@ -2810,6 +2846,7 @@ int audit_set_contid(struct task_struct *task, u64 contid) INIT_LIST_HEAD(&newcont->list); newcont->id = contid; newcont->owner = get_task_struct(current); + newcont->parent = _audit_contobj_get(newcont->owner); refcount_set(&newcont->refcount, 1); list_add_rcu(&newcont->list, &audit_contid_hash[h]); @@ -2828,6 +2865,7 @@ int audit_set_contid(struct task_struct *task, u64 contid) audit_netns_contid_add(net, newcont); } conterror: + rcu_read_unlock(); task_unlock(task); if (!audit_enabled) @@ -2837,12 +2875,13 @@ int audit_set_contid(struct task_struct *task, u64 contid) if (!ab) return rc; - audit_log_format(ab, - "op=set opid=%d contid=%llu old-contid=%llu", - task_tgid_nr(task), contid, oldcont ? oldcont->id : -1); + audit_log_format(ab, "op=set opid=%d contid=%llu old-contid=", + task_tgid_nr(task), contid); + audit_log_contid(ab, oldcont); + audit_log_end(ab); + rcu_read_lock(); _audit_contobj_put(oldcont); rcu_read_unlock(); - audit_log_end(ab); return rc; } @@ -2859,8 +2898,9 @@ void audit_log_container_drop(void) ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONTAINER_OP); if (!ab) goto out; - audit_log_format(ab, "op=drop opid=%d contid=%llu old-contid=%llu", - task_tgid_nr(current), cont->id, cont->id); + audit_log_format(ab, "op=drop opid=%d contid=%llu old-contid=", + task_tgid_nr(current), AUDIT_CID_UNSET); + audit_log_contid(ab, cont); audit_log_end(ab); out: rcu_read_unlock(); diff --git a/kernel/audit.h b/kernel/audit.h index 34d8ec4bc6ef..7bea5b51124b 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -229,6 +229,8 @@ static inline int audit_hash_contid(u64 contid) extern int audit_match_class(int class, unsigned syscall); extern int audit_comparator(const u32 left, const u32 op, const u32 right); extern int audit_comparator64(const u64 left, const u32 op, const u64 right); +extern int audit_contid_comparator(const u64 left, const u32 op, + const u64 right); extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); extern int parent_len(const char *path); diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index d812698efc1d..981c72a8b863 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1302,6 +1302,21 @@ int audit_gid_comparator(kgid_t left, u32 op, kgid_t right) } } +int audit_contid_comparator(u64 left, u32 op, u64 right) +{ + struct audit_contobj *cont = NULL; + int h; + int result = 0; + + h = audit_hash_contid(left); + list_for_each_entry_rcu(cont, &audit_contid_hash[h], list) { + result = audit_comparator64(cont->id, op, right); + if (result) + break; + } + return result; +} + /** * parent_len - find the length of the parent portion of a pathname * @path: pathname of which to determine length @@ -1393,7 +1408,7 @@ int audit_filter(int msgtype, unsigned int listtype) f->op, f->val); break; case AUDIT_CONTID: - result = audit_comparator64(audit_get_contid(current), + result = audit_contid_comparator(audit_get_contid(current), f->op, f->val64); break; case AUDIT_MSGTYPE: diff --git a/kernel/auditsc.c b/kernel/auditsc.c index baa5709590b4..9198857ac721 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -641,7 +641,7 @@ static int audit_filter_rules(struct task_struct *tsk, f->op, f->val); break; case AUDIT_CONTID: - result = audit_comparator64(audit_get_contid(tsk), + result = audit_contid_comparator(audit_get_contid(tsk), f->op, f->val64); break; case AUDIT_SUBJ_USER: From patchwork Sat Jun 27 13:20:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Guy Briggs X-Patchwork-Id: 1318338 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=QwkEoKOX; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49vDx40FFYz9sSS for ; Sat, 27 Jun 2020 23:24:08 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726695AbgF0NYF (ORCPT ); Sat, 27 Jun 2020 09:24:05 -0400 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:58213 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726964AbgF0NX7 (ORCPT ); Sat, 27 Jun 2020 09:23:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1593264237; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:in-reply-to: references:references:references; bh=Vbsz74jx639O45NZJ//E5urMuCAJMJoLkV3YW2Jxk5M=; b=QwkEoKOXI14Cyj4uSi8GimqBkq1i3GmtiInD1DVMVfk+Ult6ic9GeXidl5OGHOjuU/KgOh W6IPWToESRCk8vNdYdMWf0WXo3iT8ZomQsj9zDk0ffTMzrFVp5eIMEXSUO0HM44P+1gHUs LgYF6HEGay7ISkbmurYV05rhu+pb9vQ= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-300-C3L9deshP0OUCzQ5IpSj0Q-1; Sat, 27 Jun 2020 09:23:55 -0400 X-MC-Unique: C3L9deshP0OUCzQ5IpSj0Q-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 8D191A0BD7; Sat, 27 Jun 2020 13:23:53 +0000 (UTC) Received: from madcap2.tricolour.ca (unknown [10.10.110.28]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5A07D8205F; Sat, 27 Jun 2020 13:23:43 +0000 (UTC) From: Richard Guy Briggs To: containers@lists.linux-foundation.org, linux-api@vger.kernel.org, Linux-Audit Mailing List , linux-fsdevel@vger.kernel.org, LKML , netdev@vger.kernel.org, netfilter-devel@vger.kernel.org Cc: Paul Moore , sgrubb@redhat.com, omosnace@redhat.com, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, nhorman@tuxdriver.com, dwalsh@redhat.com, mpatel@redhat.com, Richard Guy Briggs Subject: [PATCH ghak90 V9 13/13] audit: add capcontid to set contid outside init_user_ns Date: Sat, 27 Jun 2020 09:20:46 -0400 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Provide a mechanism similar to CAP_AUDIT_CONTROL to explicitly give a process in a non-init user namespace the capability to set audit container identifiers of individual children. Provide the /proc/$PID/audit_capcontid interface to capcontid. Valid values are: 1==enabled, 0==disabled Writing a "1" to this special file for the target process $PID will enable the target process to set audit container identifiers of its descendants. A process must already have CAP_AUDIT_CONTROL in the initial user namespace or have had audit_capcontid enabled by a previous use of this feature by its parent on this process in order to be able to enable it for another process. The target process must be a descendant of the calling process. Report this action in new message type AUDIT_SET_CAPCONTID 1022 with fields opid= capcontid= old-capcontid= Signed-off-by: Richard Guy Briggs --- fs/proc/base.c | 57 +++++++++++++++++++++++++++++++++++++++++++++- include/linux/audit.h | 14 ++++++++++++ include/uapi/linux/audit.h | 1 + kernel/audit.c | 38 ++++++++++++++++++++++++++++++- 4 files changed, 108 insertions(+), 2 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 794474cd8f35..1083db2ce345 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1329,7 +1329,7 @@ static ssize_t proc_contid_read(struct file *file, char __user *buf, if (!task) return -ESRCH; /* if we don't have caps, reject */ - if (!capable(CAP_AUDIT_CONTROL)) + if (!capable(CAP_AUDIT_CONTROL) && !audit_get_capcontid(current)) return -EPERM; length = scnprintf(tmpbuf, TMPBUFLEN, "%llu", audit_get_contid(task)); put_task_struct(task); @@ -1370,6 +1370,59 @@ static ssize_t proc_contid_write(struct file *file, const char __user *buf, .write = proc_contid_write, .llseek = generic_file_llseek, }; + +static ssize_t proc_capcontid_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file_inode(file); + struct task_struct *task = get_proc_task(inode); + ssize_t length; + char tmpbuf[TMPBUFLEN]; + + if (!task) + return -ESRCH; + /* if we don't have caps, reject */ + if (!capable(CAP_AUDIT_CONTROL) && !audit_get_capcontid(current)) + return -EPERM; + length = scnprintf(tmpbuf, TMPBUFLEN, "%u", audit_get_capcontid(task)); + put_task_struct(task); + return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); +} + +static ssize_t proc_capcontid_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file_inode(file); + u32 capcontid; + int rv; + struct task_struct *task = get_proc_task(inode); + + if (!task) + return -ESRCH; + if (*ppos != 0) { + /* No partial writes. */ + put_task_struct(task); + return -EINVAL; + } + + rv = kstrtou32_from_user(buf, count, 10, &capcontid); + if (rv < 0) { + put_task_struct(task); + return rv; + } + + rv = audit_set_capcontid(task, capcontid); + put_task_struct(task); + if (rv < 0) + return rv; + return count; +} + +static const struct file_operations proc_capcontid_operations = { + .read = proc_capcontid_read, + .write = proc_capcontid_write, + .llseek = generic_file_llseek, +}; #endif #ifdef CONFIG_FAULT_INJECTION @@ -3273,6 +3326,7 @@ static int proc_stack_depth(struct seq_file *m, struct pid_namespace *ns, REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), REG("audit_containerid", S_IWUSR|S_IRUSR, proc_contid_operations), + REG("audit_capcontainerid", S_IWUSR|S_IRUSR, proc_capcontid_operations), #endif #ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), @@ -3613,6 +3667,7 @@ static int proc_tid_comm_permission(struct inode *inode, int mask) REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), REG("audit_containerid", S_IWUSR|S_IRUSR, proc_contid_operations), + REG("audit_capcontainerid", S_IWUSR|S_IRUSR, proc_capcontid_operations), #endif #ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), diff --git a/include/linux/audit.h b/include/linux/audit.h index 025b52ae8422..2b3a2b6020ed 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -122,6 +122,7 @@ struct audit_task_info { kuid_t loginuid; unsigned int sessionid; struct audit_contobj *cont; + u32 capcontid; #ifdef CONFIG_AUDITSYSCALL struct audit_context *ctx; #endif @@ -230,6 +231,14 @@ static inline unsigned int audit_get_sessionid(struct task_struct *tsk) return tsk->audit->sessionid; } +static inline u32 audit_get_capcontid(struct task_struct *tsk) +{ + if (!tsk->audit) + return 0; + return tsk->audit->capcontid; +} + +extern int audit_set_capcontid(struct task_struct *tsk, u32 enable); extern int audit_set_contid(struct task_struct *tsk, u64 contid); static inline u64 audit_get_contid(struct task_struct *tsk) @@ -311,6 +320,11 @@ static inline unsigned int audit_get_sessionid(struct task_struct *tsk) return AUDIT_SID_UNSET; } +static inline u32 audit_get_capcontid(struct task_struct *tsk) +{ + return 0; +} + static inline u64 audit_get_contid(struct task_struct *tsk) { return AUDIT_CID_UNSET; diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 831c12bdd235..5e30f4c95dc2 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -73,6 +73,7 @@ #define AUDIT_GET_FEATURE 1019 /* Get which features are enabled */ #define AUDIT_CONTAINER_OP 1020 /* Define the container id and info */ #define AUDIT_SIGNAL_INFO2 1021 /* Get info auditd signal sender */ +#define AUDIT_SET_CAPCONTID 1022 /* Set cap_contid of a task */ #define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */ #define AUDIT_USER_AVC 1107 /* We filter this differently */ diff --git a/kernel/audit.c b/kernel/audit.c index aaf74702e993..454473f2e193 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -307,6 +307,7 @@ int audit_alloc(struct task_struct *tsk) rcu_read_lock(); info->cont = _audit_contobj_get(current); rcu_read_unlock(); + info->capcontid = 0; tsk->audit = info; ret = audit_alloc_syscall(tsk); @@ -322,6 +323,7 @@ struct audit_task_info init_struct_audit = { .loginuid = INVALID_UID, .sessionid = AUDIT_SID_UNSET, .cont = NULL, + .capcontid = 0, #ifdef CONFIG_AUDITSYSCALL .ctx = NULL, #endif @@ -2763,6 +2765,40 @@ static bool audit_contid_isnesting(struct task_struct *tsk) return !isowner && ownerisparent; } +int audit_set_capcontid(struct task_struct *task, u32 enable) +{ + u32 oldcapcontid; + int rc = 0; + struct audit_buffer *ab; + + if (!task->audit) + return -ENOPROTOOPT; + oldcapcontid = audit_get_capcontid(task); + /* if task is not descendant, block */ + if (task == current || !task_is_descendant(current, task)) + rc = -EXDEV; + else if (current_user_ns() == &init_user_ns) { + if (!capable(CAP_AUDIT_CONTROL) && + !audit_get_capcontid(current)) + rc = -EPERM; + } + if (!rc) + task->audit->capcontid = enable; + + if (!audit_enabled) + return rc; + + ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_SET_CAPCONTID); + if (!ab) + return rc; + + audit_log_format(ab, + "opid=%d capcontid=%u old-capcontid=%u", + task_tgid_nr(task), enable, oldcapcontid); + audit_log_end(ab); + return rc; +} + /* * audit_set_contid - set current task's audit contid * @task: target task @@ -2795,7 +2831,7 @@ int audit_set_contid(struct task_struct *task, u64 contid) goto unlock; } /* if we don't have caps, reject */ - if (!capable(CAP_AUDIT_CONTROL)) { + if (!capable(CAP_AUDIT_CONTROL) && !audit_get_capcontid(current)) { rc = -EPERM; goto unlock; }