Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp30959imm; Tue, 31 Jul 2018 13:13:52 -0700 (PDT) X-Google-Smtp-Source: AAOMgpfjO0aZ/zkD5dsLN35vJ9/sXh3wIhlG1cHnaA6YDWl8d/KEDrsIcaI9HjJEt2Mu2xvETM8f X-Received: by 2002:a63:4283:: with SMTP id p125-v6mr22098558pga.142.1533068032727; Tue, 31 Jul 2018 13:13:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1533068032; cv=none; d=google.com; s=arc-20160816; b=zvw5ySSP+sr3kltkbzCSDAX/0r+nherkmV8MKiM7fWawSOsD6TVrTuCWhmLBaFwj57 mkpZPvIMgnP05Yht7qmdyZNMYtLBtjN2sMuN3+ope3MBZorvOc5/xLzpjvzm/MfwIe/r KRE/dR1QJItkSmARv03cbdaRyUjJwPC+9BmnEjFBwFWlBKdTgUevA8W0F+BGgUYv3Nmp 3IBV7z2qvhnvHCT+4bXkxJH6RVVfKhzjKjHnp+h/O3sKNaIRgODkqHEXSjRjjMi3beYn MKrTCvf/huCkBAKmJMya+sXTvYwK5rNuLjwRqazmp0qmL7Ktqda83ilZ8vtJIWh2N5Yh 0eqA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=XHPumJLnH7caYs50ZVcJsxY2hOJ59VWaxxP+PF8Lv40=; b=bNjo2kOF4mKG5Ms50BHcdxkno21MJNpR83bIsfTJz/9Hc008YsfqO9yntsOOPjre8m MM2TtG2TjSfzjLiUKo2h2GzTQqMdKyMYqjVAkUUc/L3hy9CDkkoRHWw8iJaE51radiqO ATnZCmWRa4qmUt8uL5NWrlnAnZxa2WkatpTkKaDQxfz4Dk1PHh8fMo0TZiKK5J4gZGMY 3EL2B72XofrsxSKJI/L3bfcDdiHrokEClRD03C+KFMkVsNLrttanQ8p0HO6qc0RnH9bZ 9lF9f2FtMD/jIpM4HqKwGa1Bnkxh/Z27bZi7CAlKnw17fYQToTdE/5MM+0IkjOYx4uNp 0F1A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t14-v6si12697630plo.48.2018.07.31.13.13.34; Tue, 31 Jul 2018 13:13:52 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732266AbeGaVx0 (ORCPT + 99 others); Tue, 31 Jul 2018 17:53:26 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:56476 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726580AbeGaVx0 (ORCPT ); Tue, 31 Jul 2018 17:53:26 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 79FB340216E3; Tue, 31 Jul 2018 20:11:26 +0000 (UTC) Received: from madcap2.tricolour.ca (ovpn-112-17.rdu2.redhat.com [10.10.112.17]) by smtp.corp.redhat.com (Postfix) with ESMTP id 795692026D7E; Tue, 31 Jul 2018 20:11:23 +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: luto@kernel.org, carlos@redhat.com, viro@zeniv.linux.org.uk, dhowells@redhat.com, simo@redhat.com, eparis@parisplace.org, serge@hallyn.com, ebiederm@xmission.com, Richard Guy Briggs Subject: [PATCH ghak90 (was ghak32) V4 02/10] audit: add container id Date: Tue, 31 Jul 2018 16:07:37 -0400 Message-Id: <12396e378a78ee8dd38c75f7730d67d8fbb08e02.1533065887.git.rgb@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 31 Jul 2018 20:11:26 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 31 Jul 2018 20:11:26 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'rgb@redhat.com' RCPT:'' Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@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_ID msg=audit(2018-06-06 12:39:29.636:26949) : op=set opid=2209 old-contid=18446744073709551615 contid=123456 pid=628 auid=root uid=root tty=ttyS0 ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 comm=bash exe=/usr/bin/bash res=yes The "op" field indicates an initial set. The "pid" to "ses" fields are the orchestrator while the "opid" field is the object's PID, the process being "contained". Old and new audit container identifier values are given in the "contid" fields, while res indicates its success. It is not permitted to unset the audit container identifier. A child inherits its parent's audit container identifier. See: https://github.com/linux-audit/audit-kernel/issues/90 See: https://github.com/linux-audit/audit-userspace/issues/51 See: https://github.com/linux-audit/audit-testsuite/issues/64 See: 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 --- fs/proc/base.c | 37 +++++++++++++++++++++++++ include/linux/audit.h | 24 ++++++++++++++++ include/uapi/linux/audit.h | 2 ++ kernel/auditsc.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+) diff --git a/fs/proc/base.c b/fs/proc/base.c index b657294..1b3cda1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1260,6 +1260,41 @@ 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 @@ -2952,6 +2987,7 @@ static int proc_pid_patch_state(struct seq_file *m, struct pid_namespace *ns, #ifdef CONFIG_AUDITSYSCALL 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), @@ -3337,6 +3373,7 @@ static int proc_tid_comm_permission(struct inode *inode, int mask) #ifdef CONFIG_AUDITSYSCALL 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 8964332..71a6fc6 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -222,6 +222,7 @@ static inline void audit_log_task_info(struct audit_buffer *ab, struct audit_task_info { kuid_t loginuid; unsigned int sessionid; + u64 contid; struct audit_context *ctx; }; extern struct audit_task_info init_struct_audit; @@ -334,6 +335,7 @@ static inline void audit_ptrace(struct task_struct *t) extern int auditsc_get_stamp(struct audit_context *ctx, struct timespec64 *t, unsigned int *serial); extern int audit_set_loginuid(kuid_t loginuid); +extern int audit_set_contid(struct task_struct *tsk, u64 contid); static inline kuid_t audit_get_loginuid(struct task_struct *tsk) { @@ -351,6 +353,14 @@ 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) +{ + if (!tsk->audit) + return AUDIT_CID_UNSET; + else + return tsk->audit->contid; +} + extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp); extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode); extern void __audit_bprm(struct linux_binprm *bprm); @@ -545,6 +555,10 @@ static inline unsigned int audit_get_sessionid(struct task_struct *tsk) { return AUDIT_SID_UNSET; } +static inline kuid_t audit_get_contid(struct task_struct *tsk) +{ + return AUDIT_CID_UNSET; +} static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) { } static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, @@ -609,6 +623,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 4e3eaba..3474f57 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 information */ #define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */ #define AUDIT_USER_AVC 1107 /* We filter this differently */ @@ -468,6 +469,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/auditsc.c b/kernel/auditsc.c index 88779a7..6125cef 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -956,6 +956,7 @@ int audit_alloc(struct task_struct *tsk) return -ENOMEM; info->loginuid = audit_get_loginuid(current); info->sessionid = audit_get_sessionid(current); + info->contid = audit_get_contid(current); tsk->audit = info; if (likely(!audit_ever_enabled)) @@ -985,6 +986,7 @@ int audit_alloc(struct task_struct *tsk) struct audit_task_info init_struct_audit = { .loginuid = INVALID_UID, .sessionid = AUDIT_SID_UNSET, + .contid = AUDIT_CID_UNSET, .ctx = NULL, }; @@ -2112,6 +2114,72 @@ int audit_set_loginuid(kuid_t loginuid) } /** + * audit_set_contid - set current task's audit_context contid + * @contid: contid value + * + * Returns 0 on success, -EPERM on permission failure. + * + * Called (set) from fs/proc/base.c::proc_contid_write(). + */ +int audit_set_contid(struct task_struct *task, u64 contid) +{ + u64 oldcontid; + int rc = 0; + struct audit_buffer *ab; + uid_t uid; + struct tty_struct *tty; + char comm[sizeof(current->comm)]; + + task_lock(task); + /* Can't set if audit disabled */ + if (!task->audit) { + task_unlock(task); + return -ENOPROTOOPT; + } + oldcontid = audit_get_contid(task); + read_lock(&tasklist_lock); + /* Don't allow the audit containerid to be unset */ + if (!audit_contid_valid(contid)) + rc = -EINVAL; + /* if we don't have caps, reject */ + else if (!capable(CAP_AUDIT_CONTROL)) + rc = -EPERM; + /* if task has children or is not single-threaded, deny */ + else if (!list_empty(&task->children)) + rc = -EBUSY; + else if (!(thread_group_leader(task) && thread_group_empty(task))) + rc = -EALREADY; + read_unlock(&tasklist_lock); + if (!rc) + task->audit->contid = contid; + task_unlock(task); + + if (!audit_enabled) + return rc; + + ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONTAINER_OP); + if (!ab) + return rc; + + uid = from_kuid(&init_user_ns, task_uid(current)); + tty = audit_get_tty(current); + audit_log_format(ab, "op=set opid=%d old-contid=%llu contid=%llu pid=%d uid=%u auid=%u tty=%s ses=%u", + task_tgid_nr(task), oldcontid, contid, + task_tgid_nr(current), uid, + from_kuid(&init_user_ns, audit_get_loginuid(current)), + tty ? tty_name(tty) : "(none)", + audit_get_sessionid(current)); + audit_put_tty(tty); + audit_log_task_context(ab); + audit_log_format(ab, " comm="); + audit_log_untrustedstring(ab, get_task_comm(comm, current)); + audit_log_d_path_exe(ab, current->mm); + audit_log_format(ab, " res=%d", !rc); + audit_log_end(ab); + return rc; +} + +/** * __audit_mq_open - record audit data for a POSIX MQ open * @oflag: open flag * @mode: mode bits -- 1.8.3.1