From patchwork Tue Sep 14 03:32:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Moore X-Patchwork-Id: 12491543 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 61B94C4167B for ; Tue, 14 Sep 2021 03:33:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4D43860EE5 for ; Tue, 14 Sep 2021 03:33:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238987AbhINDe3 (ORCPT ); Mon, 13 Sep 2021 23:34:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55748 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238998AbhINDeR (ORCPT ); Mon, 13 Sep 2021 23:34:17 -0400 Received: from mail-qt1-x834.google.com (mail-qt1-x834.google.com [IPv6:2607:f8b0:4864:20::834]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4D4F4C061764 for ; Mon, 13 Sep 2021 20:33:00 -0700 (PDT) Received: by mail-qt1-x834.google.com with SMTP id d11so10185550qtw.3 for ; Mon, 13 Sep 2021 20:33:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paul-moore-com.20150623.gappssmtp.com; s=20150623; h=subject:from:to:date:message-id:in-reply-to:references:user-agent :mime-version:content-transfer-encoding; bh=hjdomjLS+lWCoI4Q9zTrrxKXKbyuhKjuXKKt6YGQU/s=; b=2I32F7kI8NcN75AIUX7vH2iHLKlojKRhKQoq+wBmSSLHkJtBBVVKEWymRsrR23aLSx u3syQRfyoqmzepzJWPuU9pIXFEP113vxOfcfWj8SClRuGa/7BQe+WIhxRC8JgDh0+GUN 4KzvLAamu1WaNi1yicLZ7fGDYjg/8zHCIir1JnLsN59pCotda7tmPFLSgfe0ncdtw9Gn IFpBFDMz1WixWk7+aYpemb1QEGy2XB8+VLYpiLJVmKDNTZzwbVVw4ImMZWwyX81zhkxj KgnkznAGYVMV2vbTDVPw40OAUe/v5S7Xfoy2hPkC8lCB1fcmUf9EMTHaaQQG+3H9HzJ2 QQWg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:subject:from:to:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=hjdomjLS+lWCoI4Q9zTrrxKXKbyuhKjuXKKt6YGQU/s=; b=vEelC0QOsvr1/usKP2FGG9EdRclrAxHNFJYKsuCgsz5qtU4Ww631Tw17BGAqIQx3Bp w1SH55b677/ofK+zX0mc86kBLC21Xi6qfMGbYY269ZAzJeTcK0U5mqQGMMQd/pZdnLQQ 4Xg4BKcqrPbCOFDMZzVQlLizSfz/AhW0BsH9pSmS6qNBRNI0LO3pJ/p23oGPoc5XgC7H iql/ZAWmmf53EUuRgNEdWpHhOyyBIDhJOkDPHPIpfgmD4KtGArzS8kWyjk25WrpkBzjI QguMYlMSWrVM1a37P1znujbemPe9PCHznVKIc/R43QgIAtMDaxoXDRpyTUx8Jy+nBL75 RmxA== X-Gm-Message-State: AOAM531ZUWXKXqNY9FNoU9dOw8RitMfq7fohMsZ6uhWdFUSQ7Xh0l6MB HJ7nyq2bM7Bp2lUmsL+LT/ZXMWBr4SJO X-Google-Smtp-Source: ABdhPJzCIDRHws4u4wW6vuxk9QLgP0U8sNKJCigNo3Zb+Y6gEYKRjosiAUzPNJqfjjkhk8Qroe4Gsw== X-Received: by 2002:a05:622a:34c:: with SMTP id r12mr2681660qtw.147.1631590378917; Mon, 13 Sep 2021 20:32:58 -0700 (PDT) Received: from localhost (pool-96-237-52-188.bstnma.fios.verizon.net. [96.237.52.188]) by smtp.gmail.com with ESMTPSA id i14sm5231195qtr.2.2021.09.13.20.32.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Sep 2021 20:32:58 -0700 (PDT) Subject: [PATCH v3 1/8] audit: prepare audit_context for use in calling contexts beyond syscalls From: Paul Moore To: linux-security-module@vger.kernel.org, selinux@vger.kernel.org, linux-audit@redhat.com, io-uring@vger.kernel.org, linux-fsdevel@vger.kernel.org, Jens Axboe , Pavel Begunkov , Kumar Kartikeya Dwivedi Date: Mon, 13 Sep 2021 23:32:57 -0400 Message-ID: <163159037772.470089.13410389222083978499.stgit@olly> In-Reply-To: <163159032713.470089.11728103630366176255.stgit@olly> References: <163159032713.470089.11728103630366176255.stgit@olly> User-Agent: StGit/1.1 MIME-Version: 1.0 Precedence: bulk List-ID: This patch cleans up some of our audit_context handling by abstracting out the reset and return code fixup handling to dedicated functions. Not only does this help make things easier to read and inspect, it allows for easier reuse by future patches. We also convert the simple audit_context->in_syscall flag into an enum which can be used to by future patches to indicate a calling context other than the syscall context. Thanks to Richard Guy Briggs for review and feedback. Acked-by: Richard Guy Briggs Signed-off-by: Paul Moore --- v3: - removed work-in-progress warning from the description v2: - no change v1: - initial draft --- kernel/audit.h | 5 + kernel/auditsc.c | 256 ++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 167 insertions(+), 94 deletions(-) diff --git a/kernel/audit.h b/kernel/audit.h index d6a2c899a8db..13abc48de0bd 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -100,7 +100,10 @@ struct audit_proctitle { /* The per-task audit context. */ struct audit_context { int dummy; /* must be the first element */ - int in_syscall; /* 1 if task is in a syscall */ + enum { + AUDIT_CTX_UNUSED, /* audit_context is currently unused */ + AUDIT_CTX_SYSCALL, /* in use by syscall */ + } context; 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 8dd73a64f921..c0383d554e61 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -915,10 +915,80 @@ static inline void audit_free_aux(struct audit_context *context) context->aux = aux->next; kfree(aux); } + context->aux = NULL; while ((aux = context->aux_pids)) { context->aux_pids = aux->next; kfree(aux); } + context->aux_pids = NULL; +} + +/** + * audit_reset_context - reset a audit_context structure + * @ctx: the audit_context to reset + * + * All fields in the audit_context will be reset to an initial state, all + * references held by fields will be dropped, and private memory will be + * released. When this function returns the audit_context will be suitable + * for reuse, so long as the passed context is not NULL or a dummy context. + */ +static void audit_reset_context(struct audit_context *ctx) +{ + if (!ctx) + return; + + /* if ctx is non-null, reset the "ctx->state" regardless */ + ctx->context = AUDIT_CTX_UNUSED; + if (ctx->dummy) + return; + + /* + * NOTE: It shouldn't matter in what order we release the fields, so + * release them in the order in which they appear in the struct; + * this gives us some hope of quickly making sure we are + * resetting the audit_context properly. + * + * Other things worth mentioning: + * - we don't reset "dummy" + * - we don't reset "state", we do reset "current_state" + * - we preserver "filterkey" if "state" is AUDIT_STATE_RECORD + * - much of this is likely overkill, but play it safe for now + * - we really need to work on improving the audit_context struct + */ + + ctx->current_state = ctx->state; + ctx->serial = 0; + ctx->major = 0; + ctx->ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 }; + memset(ctx->argv, 0, sizeof(ctx->argv)); + ctx->return_code = 0; + ctx->prio = (ctx->state == AUDIT_STATE_RECORD ? ~0ULL : 0); + ctx->return_valid = AUDITSC_INVALID; + audit_free_names(ctx); + if (ctx->state != AUDIT_STATE_RECORD) { + kfree(ctx->filterkey); + ctx->filterkey = NULL; + } + audit_free_aux(ctx); + kfree(ctx->sockaddr); + ctx->sockaddr = NULL; + ctx->sockaddr_len = 0; + ctx->pid = ctx->ppid = 0; + ctx->uid = ctx->euid = ctx->suid = ctx->fsuid = KUIDT_INIT(0); + ctx->gid = ctx->egid = ctx->sgid = ctx->fsgid = KGIDT_INIT(0); + ctx->personality = 0; + ctx->arch = 0; + ctx->target_pid = 0; + ctx->target_auid = ctx->target_uid = KUIDT_INIT(0); + ctx->target_sessionid = 0; + ctx->target_sid = 0; + ctx->target_comm[0] = '\0'; + unroll_tree_refs(ctx, NULL, 0); + WARN_ON(!list_empty(&ctx->killed_trees)); + ctx->type = 0; + audit_free_module(ctx); + ctx->fds[0] = -1; + audit_proctitle_free(ctx); } static inline struct audit_context *audit_alloc_context(enum audit_state state) @@ -928,6 +998,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state) context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return NULL; + context->context = AUDIT_CTX_UNUSED; context->state = state; context->prio = state == AUDIT_STATE_RECORD ? ~0ULL : 0; INIT_LIST_HEAD(&context->killed_trees); @@ -953,7 +1024,7 @@ int audit_alloc(struct task_struct *tsk) char *key = NULL; if (likely(!audit_ever_enabled)) - return 0; /* Return if not auditing. */ + return 0; state = audit_filter_task(tsk, &key); if (state == AUDIT_STATE_DISABLED) { @@ -975,14 +1046,10 @@ int audit_alloc(struct task_struct *tsk) static inline void audit_free_context(struct audit_context *context) { - audit_free_module(context); - audit_free_names(context); - unroll_tree_refs(context, NULL, 0); + /* resetting is extra work, but it is likely just noise */ + audit_reset_context(context); free_tree_refs(context); - audit_free_aux(context); kfree(context->filterkey); - kfree(context->sockaddr); - audit_proctitle_free(context); kfree(context); } @@ -1489,29 +1556,35 @@ static void audit_log_exit(void) context->personality = current->personality; - ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL); - if (!ab) - return; /* audit_panic has been called */ - audit_log_format(ab, "arch=%x syscall=%d", - context->arch, context->major); - if (context->personality != PER_LINUX) - audit_log_format(ab, " per=%lx", context->personality); - if (context->return_valid != AUDITSC_INVALID) - audit_log_format(ab, " success=%s exit=%ld", - (context->return_valid==AUDITSC_SUCCESS)?"yes":"no", - context->return_code); - - audit_log_format(ab, - " a0=%lx a1=%lx a2=%lx a3=%lx items=%d", - context->argv[0], - context->argv[1], - context->argv[2], - context->argv[3], - context->name_count); - - audit_log_task_info(ab); - audit_log_key(ab, context->filterkey); - audit_log_end(ab); + switch (context->context) { + case AUDIT_CTX_SYSCALL: + ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL); + if (!ab) + return; + audit_log_format(ab, "arch=%x syscall=%d", + context->arch, context->major); + if (context->personality != PER_LINUX) + audit_log_format(ab, " per=%lx", context->personality); + if (context->return_valid != AUDITSC_INVALID) + audit_log_format(ab, " success=%s exit=%ld", + (context->return_valid == AUDITSC_SUCCESS ? + "yes" : "no"), + context->return_code); + audit_log_format(ab, + " a0=%lx a1=%lx a2=%lx a3=%lx items=%d", + context->argv[0], + context->argv[1], + context->argv[2], + context->argv[3], + context->name_count); + audit_log_task_info(ab); + audit_log_key(ab, context->filterkey); + audit_log_end(ab); + break; + default: + BUG(); + break; + } for (aux = context->aux; aux; aux = aux->next) { @@ -1602,14 +1675,15 @@ static void audit_log_exit(void) audit_log_name(context, n, NULL, i++, &call_panic); } - audit_log_proctitle(); + if (context->context == AUDIT_CTX_SYSCALL) + audit_log_proctitle(); /* Send end of event record to help user space know we are finished */ ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); if (ab) audit_log_end(ab); if (call_panic) - audit_panic("error converting sid to string"); + audit_panic("error in audit_log_exit()"); } /** @@ -1625,6 +1699,7 @@ void __audit_free(struct task_struct *tsk) if (!context) return; + /* this may generate CONFIG_CHANGE records */ if (!list_empty(&context->killed_trees)) audit_kill_trees(context); @@ -1633,7 +1708,8 @@ void __audit_free(struct task_struct *tsk) * random task_struct that doesn't doesn't have any meaningful data we * need to log via audit_log_exit(). */ - if (tsk == current && !context->dummy && context->in_syscall) { + if (tsk == current && !context->dummy && + context->context == AUDIT_CTX_SYSCALL) { context->return_valid = AUDITSC_INVALID; context->return_code = 0; @@ -1647,6 +1723,34 @@ void __audit_free(struct task_struct *tsk) audit_free_context(context); } +/** + * audit_return_fixup - fixup the return codes in the audit_context + * @ctx: the audit_context + * @success: true/false value to indicate if the operation succeeded or not + * @code: operation return code + * + * We need to fixup the return code in the audit logs if the actual return + * codes are later going to be fixed by the arch specific signal handlers. + */ +static void audit_return_fixup(struct audit_context *ctx, + int success, long code) +{ + /* + * This is actually a test for: + * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) || + * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK) + * + * but is faster than a bunch of || + */ + if (unlikely(code <= -ERESTARTSYS) && + (code >= -ERESTART_RESTARTBLOCK) && + (code != -ENOIOCTLCMD)) + ctx->return_code = -EINTR; + else + ctx->return_code = code; + ctx->return_valid = (success ? AUDITSC_SUCCESS : AUDITSC_FAILURE); +} + /** * __audit_syscall_entry - fill in an audit record at syscall entry * @major: major syscall type (function) @@ -1672,7 +1776,12 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2, if (!audit_enabled || !context) return; - BUG_ON(context->in_syscall || context->name_count); + WARN_ON(context->context != AUDIT_CTX_UNUSED); + WARN_ON(context->name_count); + if (context->context != AUDIT_CTX_UNUSED || context->name_count) { + audit_panic("unrecoverable error in audit_syscall_entry()"); + return; + } state = context->state; if (state == AUDIT_STATE_DISABLED) @@ -1691,10 +1800,8 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2, context->argv[1] = a2; context->argv[2] = a3; context->argv[3] = a4; - context->serial = 0; - context->in_syscall = 1; + context->context = AUDIT_CTX_SYSCALL; context->current_state = state; - context->ppid = 0; ktime_get_coarse_real_ts64(&context->ctime); } @@ -1711,63 +1818,27 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2, */ void __audit_syscall_exit(int success, long return_code) { - struct audit_context *context; + struct audit_context *context = audit_context(); - context = audit_context(); - if (!context) - return; + if (!context || context->dummy || + context->context != AUDIT_CTX_SYSCALL) + goto out; + /* this may generate CONFIG_CHANGE records */ if (!list_empty(&context->killed_trees)) audit_kill_trees(context); - if (!context->dummy && context->in_syscall) { - if (success) - context->return_valid = AUDITSC_SUCCESS; - else - context->return_valid = AUDITSC_FAILURE; - - /* - * we need to fix up the return code in the audit logs if the - * actual return codes are later going to be fixed up by the - * arch specific signal handlers - * - * This is actually a test for: - * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) || - * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK) - * - * but is faster than a bunch of || - */ - if (unlikely(return_code <= -ERESTARTSYS) && - (return_code >= -ERESTART_RESTARTBLOCK) && - (return_code != -ENOIOCTLCMD)) - context->return_code = -EINTR; - else - context->return_code = return_code; - - audit_filter_syscall(current, context); - audit_filter_inodes(current, context); - if (context->current_state == AUDIT_STATE_RECORD) - audit_log_exit(); - } + /* run through both filters to ensure we set the filterkey properly */ + audit_filter_syscall(current, context); + audit_filter_inodes(current, context); + if (context->current_state < AUDIT_STATE_RECORD) + goto out; - context->in_syscall = 0; - context->prio = context->state == AUDIT_STATE_RECORD ? ~0ULL : 0; + audit_return_fixup(context, success, return_code); + audit_log_exit(); - audit_free_module(context); - audit_free_names(context); - unroll_tree_refs(context, NULL, 0); - audit_free_aux(context); - context->aux = NULL; - context->aux_pids = NULL; - context->target_pid = 0; - context->target_sid = 0; - context->sockaddr_len = 0; - context->type = 0; - context->fds[0] = -1; - if (context->state != AUDIT_STATE_RECORD) { - kfree(context->filterkey); - context->filterkey = NULL; - } +out: + audit_reset_context(context); } static inline void handle_one(const struct inode *inode) @@ -1919,7 +1990,7 @@ void __audit_getname(struct filename *name) struct audit_context *context = audit_context(); struct audit_names *n; - if (!context->in_syscall) + if (context->context == AUDIT_CTX_UNUSED) return; n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); @@ -1991,7 +2062,7 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS]; int i; - if (!context->in_syscall) + if (context->context == AUDIT_CTX_UNUSED) return; rcu_read_lock(); @@ -2109,7 +2180,7 @@ void __audit_inode_child(struct inode *parent, struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS]; int i; - if (!context->in_syscall) + if (context->context == AUDIT_CTX_UNUSED) return; rcu_read_lock(); @@ -2208,7 +2279,7 @@ EXPORT_SYMBOL_GPL(__audit_inode_child); int auditsc_get_stamp(struct audit_context *ctx, struct timespec64 *t, unsigned int *serial) { - if (!ctx->in_syscall) + if (ctx->context == AUDIT_CTX_UNUSED) return 0; if (!ctx->serial) ctx->serial = audit_serial(); @@ -2706,8 +2777,7 @@ void audit_seccomp_actions_logged(const char *names, const char *old_names, struct list_head *audit_killed_trees(void) { struct audit_context *ctx = audit_context(); - - if (likely(!ctx || !ctx->in_syscall)) + if (likely(!ctx || ctx->context == AUDIT_CTX_UNUSED)) return NULL; return &ctx->killed_trees; } From patchwork Tue Sep 14 03:33:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Moore X-Patchwork-Id: 12491545 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C89EFC433F5 for ; Tue, 14 Sep 2021 03:33:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id ADC0B60F24 for ; Tue, 14 Sep 2021 03:33:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238787AbhINDea (ORCPT ); Mon, 13 Sep 2021 23:34:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55778 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239141AbhINDeX (ORCPT ); Mon, 13 Sep 2021 23:34:23 -0400 Received: from mail-qt1-x82c.google.com (mail-qt1-x82c.google.com [IPv6:2607:f8b0:4864:20::82c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 947B3C061764 for ; Mon, 13 Sep 2021 20:33:06 -0700 (PDT) Received: by mail-qt1-x82c.google.com with SMTP id d11so10185824qtw.3 for ; Mon, 13 Sep 2021 20:33:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paul-moore-com.20150623.gappssmtp.com; s=20150623; h=subject:from:to:date:message-id:in-reply-to:references:user-agent :mime-version:content-transfer-encoding; bh=t9g7lwcAT63OmJcbTuIhhVl7/18uJfot7JKc7VxpTLM=; b=KAJ/YiLVYK1UchGEfENOfAoFfe5k1FTqpclI+V9RBs4YAU3DZNQJPjjzfHvJMHqUqd rHvi5zv3ykmPrkXtQ9a4G4ByeROkvDQ7NXhD+M03E53oKkLpTh42o3LbeU43VYWUFNmm 3tIu8eqQsdgxZk8LImpLudWgzpGK2ahpsryY8Kaand24D/igoiWwdt+MkI1O219yJGrH +tPD1CR3rak2NdzxF8ZFlIpgTv1lU6xdo6kwNt1dFeacmtBxqGFMGsEm7cIx6m5BB8Fr hk45M58hPj8ASgnaQPrecYMvX1yAfQ7i4oj0A6lXtabqImmT2W9tKcilg9wbHUIXMhie cldQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:subject:from:to:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=t9g7lwcAT63OmJcbTuIhhVl7/18uJfot7JKc7VxpTLM=; b=UY8p/r8J0nn1WRnSd4iSFnDoAF6/9dXmFUmL/ZyFLuFWKmwJu98y7MOtxiv4jO9tpE hss1z5Z70jG7LqYVtbiz9YN/V0429JsGsEsaek/SyYOzH7P3MRQRBkVr0oKxoKmTfKbX 5ykuXnpssU9utVGcdeucqNhEwBnxNhdjssGIuMkuEBsSv4bo039GAlALnBQsDw7QnUnZ EqPhGJA5LdRdDaVqgczsxYbfGGGs1FUqMp+KsYl44g//YQa8Q6Bgrfh1hCuN+wJ5ygPz OkfcuNWe9SorzB9u+b+g2AXwpoH2ZyELpgzpyWrYMh6CzQZpTQEHa6Hin6PBAN24KbH4 1dhg== X-Gm-Message-State: AOAM531tKBBz+NsjP3tObT9fpUC3rroUYGlkUoKnhaNrimOqxTOvUAB0 ly1a2+p55KB+2WrgAY0aZp9FfsKz6sr9 X-Google-Smtp-Source: ABdhPJzzsbE4Yvg5HMBfV3FFXU2yOIOCzWZ5ia1i6/cyAB3o9i8facu5oS19BIJnK9BaM++hUKiw4g== X-Received: by 2002:ac8:7c44:: with SMTP id o4mr2796915qtv.82.1631590385154; Mon, 13 Sep 2021 20:33:05 -0700 (PDT) Received: from localhost (pool-96-237-52-188.bstnma.fios.verizon.net. [96.237.52.188]) by smtp.gmail.com with ESMTPSA id t188sm6860143qkf.22.2021.09.13.20.33.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Sep 2021 20:33:04 -0700 (PDT) Subject: [PATCH v3 2/8] audit,io_uring,io-wq: add some basic audit support to io_uring From: Paul Moore To: linux-security-module@vger.kernel.org, selinux@vger.kernel.org, linux-audit@redhat.com, io-uring@vger.kernel.org, linux-fsdevel@vger.kernel.org, Jens Axboe , Pavel Begunkov , Kumar Kartikeya Dwivedi Date: Mon, 13 Sep 2021 23:33:04 -0400 Message-ID: <163159038402.470089.1406703360189547052.stgit@olly> In-Reply-To: <163159032713.470089.11728103630366176255.stgit@olly> References: <163159032713.470089.11728103630366176255.stgit@olly> User-Agent: StGit/1.1 MIME-Version: 1.0 Precedence: bulk List-ID: This patch adds basic auditing to io_uring operations, regardless of their context. This is accomplished by allocating audit_context structures for the io-wq worker and io_uring SQPOLL kernel threads as well as explicitly auditing the io_uring operations in io_issue_sqe(). Individual io_uring operations can bypass auditing through the "audit_skip" field in the struct io_op_def definition for the operation; although great care must be taken so that security relevant io_uring operations do not bypass auditing; please contact the audit mailing list (see the MAINTAINERS file) with any questions. The io_uring operations are audited using a new AUDIT_URINGOP record, an example is shown below: type=UNKNOWN[1336] msg=audit(1630523381.288:260): uring_op=19 success=yes exit=0 items=0 ppid=853 pid=1204 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) AUID="root" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root" Thanks to Richard Guy Briggs for review and feedback. Signed-off-by: Paul Moore --- v3: - removed work-in-progress warning from the description v2: - added dummy funcs for audit_uring_{entry,exit}() - replaced opcode checks in io_issue_sqe() with audit_skip checks - moved fastpath checks into audit_uring_{entry,exit}() - audit_log_uring() uses GFP_ATOMIC - don't record the arch in __audit_uring_entry() v1: - initial draft --- fs/io-wq.c | 4 + fs/io_uring.c | 55 ++++++++++++-- include/linux/audit.h | 26 +++++++ include/uapi/linux/audit.h | 1 kernel/audit.h | 2 + kernel/auditsc.c | 174 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 256 insertions(+), 6 deletions(-) diff --git a/fs/io-wq.c b/fs/io-wq.c index 6c55362c1f99..dac5c5961c9d 100644 --- a/fs/io-wq.c +++ b/fs/io-wq.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "io-wq.h" @@ -562,6 +563,8 @@ static int io_wqe_worker(void *data) snprintf(buf, sizeof(buf), "iou-wrk-%d", wq->task->pid); set_task_comm(current, buf); + audit_alloc_kernel(current); + while (!test_bit(IO_WQ_BIT_EXIT, &wq->state)) { long ret; @@ -601,6 +604,7 @@ static int io_wqe_worker(void *data) io_worker_handle_work(worker); } + audit_free(current); io_worker_exit(worker); return 0; } diff --git a/fs/io_uring.c b/fs/io_uring.c index 16fb7436043c..388754b24785 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -79,6 +79,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -917,6 +918,8 @@ struct io_op_def { unsigned needs_async_setup : 1; /* should block plug */ unsigned plug : 1; + /* skip auditing */ + unsigned audit_skip : 1; /* size of async data needed, if any */ unsigned short async_size; }; @@ -930,6 +933,7 @@ static const struct io_op_def io_op_defs[] = { .buffer_select = 1, .needs_async_setup = 1, .plug = 1, + .audit_skip = 1, .async_size = sizeof(struct io_async_rw), }, [IORING_OP_WRITEV] = { @@ -939,16 +943,19 @@ static const struct io_op_def io_op_defs[] = { .pollout = 1, .needs_async_setup = 1, .plug = 1, + .audit_skip = 1, .async_size = sizeof(struct io_async_rw), }, [IORING_OP_FSYNC] = { .needs_file = 1, + .audit_skip = 1, }, [IORING_OP_READ_FIXED] = { .needs_file = 1, .unbound_nonreg_file = 1, .pollin = 1, .plug = 1, + .audit_skip = 1, .async_size = sizeof(struct io_async_rw), }, [IORING_OP_WRITE_FIXED] = { @@ -957,15 +964,20 @@ static const struct io_op_def io_op_defs[] = { .unbound_nonreg_file = 1, .pollout = 1, .plug = 1, + .audit_skip = 1, .async_size = sizeof(struct io_async_rw), }, [IORING_OP_POLL_ADD] = { .needs_file = 1, .unbound_nonreg_file = 1, + .audit_skip = 1, + }, + [IORING_OP_POLL_REMOVE] = { + .audit_skip = 1, }, - [IORING_OP_POLL_REMOVE] = {}, [IORING_OP_SYNC_FILE_RANGE] = { .needs_file = 1, + .audit_skip = 1, }, [IORING_OP_SENDMSG] = { .needs_file = 1, @@ -983,18 +995,23 @@ static const struct io_op_def io_op_defs[] = { .async_size = sizeof(struct io_async_msghdr), }, [IORING_OP_TIMEOUT] = { + .audit_skip = 1, .async_size = sizeof(struct io_timeout_data), }, [IORING_OP_TIMEOUT_REMOVE] = { /* used by timeout updates' prep() */ + .audit_skip = 1, }, [IORING_OP_ACCEPT] = { .needs_file = 1, .unbound_nonreg_file = 1, .pollin = 1, }, - [IORING_OP_ASYNC_CANCEL] = {}, + [IORING_OP_ASYNC_CANCEL] = { + .audit_skip = 1, + }, [IORING_OP_LINK_TIMEOUT] = { + .audit_skip = 1, .async_size = sizeof(struct io_timeout_data), }, [IORING_OP_CONNECT] = { @@ -1009,14 +1026,19 @@ static const struct io_op_def io_op_defs[] = { }, [IORING_OP_OPENAT] = {}, [IORING_OP_CLOSE] = {}, - [IORING_OP_FILES_UPDATE] = {}, - [IORING_OP_STATX] = {}, + [IORING_OP_FILES_UPDATE] = { + .audit_skip = 1, + }, + [IORING_OP_STATX] = { + .audit_skip = 1, + }, [IORING_OP_READ] = { .needs_file = 1, .unbound_nonreg_file = 1, .pollin = 1, .buffer_select = 1, .plug = 1, + .audit_skip = 1, .async_size = sizeof(struct io_async_rw), }, [IORING_OP_WRITE] = { @@ -1025,39 +1047,50 @@ static const struct io_op_def io_op_defs[] = { .unbound_nonreg_file = 1, .pollout = 1, .plug = 1, + .audit_skip = 1, .async_size = sizeof(struct io_async_rw), }, [IORING_OP_FADVISE] = { .needs_file = 1, + .audit_skip = 1, }, [IORING_OP_MADVISE] = {}, [IORING_OP_SEND] = { .needs_file = 1, .unbound_nonreg_file = 1, .pollout = 1, + .audit_skip = 1, }, [IORING_OP_RECV] = { .needs_file = 1, .unbound_nonreg_file = 1, .pollin = 1, .buffer_select = 1, + .audit_skip = 1, }, [IORING_OP_OPENAT2] = { }, [IORING_OP_EPOLL_CTL] = { .unbound_nonreg_file = 1, + .audit_skip = 1, }, [IORING_OP_SPLICE] = { .needs_file = 1, .hash_reg_file = 1, .unbound_nonreg_file = 1, + .audit_skip = 1, + }, + [IORING_OP_PROVIDE_BUFFERS] = { + .audit_skip = 1, + }, + [IORING_OP_REMOVE_BUFFERS] = { + .audit_skip = 1, }, - [IORING_OP_PROVIDE_BUFFERS] = {}, - [IORING_OP_REMOVE_BUFFERS] = {}, [IORING_OP_TEE] = { .needs_file = 1, .hash_reg_file = 1, .unbound_nonreg_file = 1, + .audit_skip = 1, }, [IORING_OP_SHUTDOWN] = { .needs_file = 1, @@ -6591,6 +6624,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags) if ((req->flags & REQ_F_CREDS) && req->creds != current_cred()) creds = override_creds(req->creds); + if (!io_op_defs[req->opcode].audit_skip) + audit_uring_entry(req->opcode); + switch (req->opcode) { case IORING_OP_NOP: ret = io_nop(req, issue_flags); @@ -6706,6 +6742,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags) break; } + if (!io_op_defs[req->opcode].audit_skip) + audit_uring_exit(!ret, ret); + if (creds) revert_creds(creds); if (ret) @@ -7360,6 +7399,8 @@ static int io_sq_thread(void *data) set_cpus_allowed_ptr(current, cpu_online_mask); current->flags |= PF_NO_SETAFFINITY; + audit_alloc_kernel(current); + mutex_lock(&sqd->lock); while (1) { bool cap_entries, sqt_spin = false; @@ -7425,6 +7466,8 @@ static int io_sq_thread(void *data) io_run_task_work(); mutex_unlock(&sqd->lock); + audit_free(current); + complete(&sqd->exited); do_exit(0); } diff --git a/include/linux/audit.h b/include/linux/audit.h index 82b7c1116a85..d656a06dd909 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -286,7 +286,10 @@ 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 int audit_alloc_kernel(struct task_struct *task); extern void __audit_free(struct task_struct *task); +extern void __audit_uring_entry(u8 op); +extern void __audit_uring_exit(int success, long code); 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); @@ -323,6 +326,21 @@ static inline void audit_free(struct task_struct *task) if (unlikely(task->audit_context)) __audit_free(task); } +static inline void audit_uring_entry(u8 op) +{ + /* + * We intentionally check audit_context() before audit_enabled as most + * Linux systems (as of ~2021) rely on systemd which forces audit to + * be enabled regardless of the user's audit configuration. + */ + if (unlikely(audit_context() && audit_enabled)) + __audit_uring_entry(op); +} +static inline void audit_uring_exit(int success, long code) +{ + if (unlikely(!audit_dummy_context())) + __audit_uring_exit(success, code); +} static inline void audit_syscall_entry(int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3) @@ -554,8 +572,16 @@ static inline int audit_alloc(struct task_struct *task) { return 0; } +static inline int audit_alloc_kernel(struct task_struct *task) +{ + return 0; +} static inline void audit_free(struct task_struct *task) { } +static inline void audit_uring_entry(u8 op) +{ } +static inline void audit_uring_exit(int success, long code) +{ } static inline void audit_syscall_entry(int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3) diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index daa481729e9b..a1997697c8b1 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -118,6 +118,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_URINGOP 1336 /* io_uring operation */ #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ diff --git a/kernel/audit.h b/kernel/audit.h index 13abc48de0bd..d1161e3b83e2 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -103,10 +103,12 @@ struct audit_context { enum { AUDIT_CTX_UNUSED, /* audit_context is currently unused */ AUDIT_CTX_SYSCALL, /* in use by syscall */ + AUDIT_CTX_URING, /* in use by io_uring */ } context; enum audit_state state, current_state; unsigned int serial; /* serial number for record */ int major; /* syscall number */ + int uring_op; /* uring operation */ struct timespec64 ctime; /* time of syscall entry */ unsigned long argv[4]; /* syscall arguments */ long return_code;/* syscall return code */ diff --git a/kernel/auditsc.c b/kernel/auditsc.c index c0383d554e61..62fb502da3fc 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -959,6 +959,7 @@ static void audit_reset_context(struct audit_context *ctx) ctx->current_state = ctx->state; ctx->serial = 0; ctx->major = 0; + ctx->uring_op = 0; ctx->ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 }; memset(ctx->argv, 0, sizeof(ctx->argv)); ctx->return_code = 0; @@ -1044,6 +1045,31 @@ int audit_alloc(struct task_struct *tsk) return 0; } +/** + * audit_alloc_kernel - allocate an audit_context for a kernel task + * @tsk: the kernel task + * + * Similar to the audit_alloc() function, but intended for kernel private + * threads. Returns zero on success, negative values on failure. + */ +int audit_alloc_kernel(struct task_struct *tsk) +{ + /* + * At the moment we are just going to call into audit_alloc() to + * simplify the code, but there two things to keep in mind with this + * approach: + * + * 1. Filtering internal kernel tasks is a bit laughable in almost all + * cases, but there is at least one case where there is a benefit: + * the '-a task,never' case allows the admin to effectively disable + * task auditing at runtime. + * + * 2. The {set,clear}_task_syscall_work() ops likely have zero effect + * on these internal kernel tasks, but they probably don't hurt either. + */ + return audit_alloc(tsk); +} + static inline void audit_free_context(struct audit_context *context) { /* resetting is extra work, but it is likely just noise */ @@ -1546,6 +1572,52 @@ static void audit_log_proctitle(void) audit_log_end(ab); } +/** + * audit_log_uring - generate a AUDIT_URINGOP record + * @ctx: the audit context + */ +static void audit_log_uring(struct audit_context *ctx) +{ + struct audit_buffer *ab; + const struct cred *cred; + + /* + * TODO: What do we log here? I'm tossing in a few things to start the + * conversation, but additional thought needs to go into this. + */ + + ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_URINGOP); + if (!ab) + return; + cred = current_cred(); + audit_log_format(ab, "uring_op=%d", ctx->uring_op); + if (ctx->return_valid != AUDITSC_INVALID) + audit_log_format(ab, " success=%s exit=%ld", + (ctx->return_valid == AUDITSC_SUCCESS ? + "yes" : "no"), + ctx->return_code); + audit_log_format(ab, + " items=%d" + " ppid=%d pid=%d auid=%u uid=%u gid=%u" + " euid=%u suid=%u fsuid=%u" + " egid=%u sgid=%u fsgid=%u", + ctx->name_count, + task_ppid_nr(current), + task_tgid_nr(current), + from_kuid(&init_user_ns, audit_get_loginuid(current)), + from_kuid(&init_user_ns, cred->uid), + from_kgid(&init_user_ns, cred->gid), + from_kuid(&init_user_ns, cred->euid), + from_kuid(&init_user_ns, cred->suid), + from_kuid(&init_user_ns, cred->fsuid), + from_kgid(&init_user_ns, cred->egid), + from_kgid(&init_user_ns, cred->sgid), + from_kgid(&init_user_ns, cred->fsgid)); + audit_log_task_context(ab); + audit_log_key(ab, ctx->filterkey); + audit_log_end(ab); +} + static void audit_log_exit(void) { int i, call_panic = 0; @@ -1581,6 +1653,9 @@ static void audit_log_exit(void) audit_log_key(ab, context->filterkey); audit_log_end(ab); break; + case AUDIT_CTX_URING: + audit_log_uring(context); + break; default: BUG(); break; @@ -1751,6 +1826,105 @@ static void audit_return_fixup(struct audit_context *ctx, ctx->return_valid = (success ? AUDITSC_SUCCESS : AUDITSC_FAILURE); } +/** + * __audit_uring_entry - prepare the kernel task's audit context for io_uring + * @op: the io_uring opcode + * + * This is similar to audit_syscall_entry() but is intended for use by io_uring + * operations. This function should only ever be called from + * audit_uring_entry() as we rely on the audit context checking present in that + * function. + */ +void __audit_uring_entry(u8 op) +{ + struct audit_context *ctx = audit_context(); + + if (ctx->state == AUDIT_STATE_DISABLED) + return; + + /* + * NOTE: It's possible that we can be called from the process' context + * before it returns to userspace, and before audit_syscall_exit() + * is called. In this case there is not much to do, just record + * the io_uring details and return. + */ + ctx->uring_op = op; + if (ctx->context == AUDIT_CTX_SYSCALL) + return; + + ctx->dummy = !audit_n_rules; + if (!ctx->dummy && ctx->state == AUDIT_STATE_BUILD) + ctx->prio = 0; + + ctx->context = AUDIT_CTX_URING; + ctx->current_state = ctx->state; + ktime_get_coarse_real_ts64(&ctx->ctime); +} + +/** + * __audit_uring_exit - wrap up the kernel task's audit context after io_uring + * @success: true/false value to indicate if the operation succeeded or not + * @code: operation return code + * + * This is similar to audit_syscall_exit() but is intended for use by io_uring + * operations. This function should only ever be called from + * audit_uring_exit() as we rely on the audit context checking present in that + * function. + */ +void __audit_uring_exit(int success, long code) +{ + struct audit_context *ctx = audit_context(); + + /* + * TODO: At some point we will likely want to filter on io_uring ops + * and other things similar to what we do for syscalls, but that + * is something for another day; just record what we can here. + */ + + if (ctx->context == AUDIT_CTX_SYSCALL) { + /* + * NOTE: See the note in __audit_uring_entry() about the case + * where we may be called from process context before we + * return to userspace via audit_syscall_exit(). In this + * case we simply emit a URINGOP record and bail, the + * normal syscall exit handling will take care of + * everything else. + * It is also worth mentioning that when we are called, + * the current process creds may differ from the creds + * used during the normal syscall processing; keep that + * in mind if/when we move the record generation code. + */ + + /* + * We need to filter on the syscall info here to decide if we + * should emit a URINGOP record. I know it seems odd but this + * solves the problem where users have a filter to block *all* + * syscall records in the "exit" filter; we want to preserve + * the behavior here. + */ + audit_filter_syscall(current, ctx); + audit_filter_inodes(current, ctx); + if (ctx->current_state != AUDIT_STATE_RECORD) + return; + + audit_log_uring(ctx); + return; + } + + /* this may generate CONFIG_CHANGE records */ + if (!list_empty(&ctx->killed_trees)) + audit_kill_trees(ctx); + + audit_filter_inodes(current, ctx); + if (ctx->current_state != AUDIT_STATE_RECORD) + goto out; + audit_return_fixup(ctx, success, code); + audit_log_exit(); + +out: + audit_reset_context(ctx); +} + /** * __audit_syscall_entry - fill in an audit record at syscall entry * @major: major syscall type (function) From patchwork Tue Sep 14 03:33:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Moore X-Patchwork-Id: 12491547 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0EB1DC4167E for ; Tue, 14 Sep 2021 03:33:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EF84861159 for ; Tue, 14 Sep 2021 03:33:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238756AbhINDec (ORCPT ); Mon, 13 Sep 2021 23:34:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55810 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238906AbhINDe3 (ORCPT ); Mon, 13 Sep 2021 23:34:29 -0400 Received: from mail-qt1-x82b.google.com (mail-qt1-x82b.google.com [IPv6:2607:f8b0:4864:20::82b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AA47CC061574 for ; Mon, 13 Sep 2021 20:33:12 -0700 (PDT) Received: by mail-qt1-x82b.google.com with SMTP id r21so10135203qtw.11 for ; Mon, 13 Sep 2021 20:33:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paul-moore-com.20150623.gappssmtp.com; s=20150623; h=subject:from:to:date:message-id:in-reply-to:references:user-agent :mime-version:content-transfer-encoding; bh=vMfQCt+uLiO0djmjLUrPCnseEyBZjnenjfAhu7qlx0c=; b=DELMydZBjcy90XHQNhrcdYJK+dNl9s7myCh4iee3FoXNQTcewYIs7pPA+h+8CLJITi uDDyjDuqZHtMuCUaVz+KXwCocx6X//HZta2IaG6EdZgs7vz04Hj355uWD4Alzbeuc192 x7Bnvhh0Wj8lsR7kT0Y6soGJC1y5pfYT1z3tz07pvKbMgEvlQKQbIY1Z/jtDc0s6j6+N 5iSyQtxwMeY+ByidHXn2mbUKyKloCKMuCt2kUyBErVjpe82Z82B8zT0dupSFu8Z9u4t3 c6T7zSHMOZPMTAkV+2tqTctzK2uxl57jWHZzei170essgxv1D5CR9okx9a284y1ASK9q 9t5A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:subject:from:to:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=vMfQCt+uLiO0djmjLUrPCnseEyBZjnenjfAhu7qlx0c=; b=rniweFbJADs2nCSMp/FcB+Q7S3ht6BacbdNQZ0qVKfq/wTzHXchXdmDLSMmLUxgnd3 g0toV6Sk1zMVBjqsdlXYHTiBWSbB+M01suusfGxfbLfkgk30vhQSXfvNIlVK/PMWMoQK wkRDvs/OGTSUjAlG924rSoaXsu0njnwOWzL4fyFP8UHlMZUEhrRUNOQoEPgAut8Mx7i1 XV+Jlq4ADJlA/8b7/lHyjYaLqHEaR4VIGkIgPKzeUEwWmaN2KaN5p8qiJhuBRP8DDi/c 57zBR/W5NWyevwa8uwP1+KRO6ZNesKNwhUktE6uM9yGoOPNyfAl4O2MPWTiwq29SHvl0 ZKFA== X-Gm-Message-State: AOAM532Xhp8LtZ8zYrIVsMnzXJBrdhhosAYq+lJGSQH5HkRD3q12TCD0 z7+EeR11Y/eUOaOceNGjtfs/zhRwNChy X-Google-Smtp-Source: ABdhPJzHVPH6/dQ4CfMF8kWcsd/i6+k7cFmQWVNP6WoHx1hyTmgKpJ1LDwYfNyuZxdo259sPFpBGBQ== X-Received: by 2002:a05:622a:1911:: with SMTP id w17mr2845124qtc.228.1631590391328; Mon, 13 Sep 2021 20:33:11 -0700 (PDT) Received: from localhost (pool-96-237-52-188.bstnma.fios.verizon.net. [96.237.52.188]) by smtp.gmail.com with ESMTPSA id 21sm6682576qkk.51.2021.09.13.20.33.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Sep 2021 20:33:10 -0700 (PDT) Subject: [PATCH v3 3/8] audit: add filtering for io_uring records From: Paul Moore To: linux-security-module@vger.kernel.org, selinux@vger.kernel.org, linux-audit@redhat.com, io-uring@vger.kernel.org, linux-fsdevel@vger.kernel.org, Jens Axboe , Pavel Begunkov , Kumar Kartikeya Dwivedi Date: Mon, 13 Sep 2021 23:33:10 -0400 Message-ID: <163159039025.470089.10174083902520146275.stgit@olly> In-Reply-To: <163159032713.470089.11728103630366176255.stgit@olly> References: <163159032713.470089.11728103630366176255.stgit@olly> User-Agent: StGit/1.1 MIME-Version: 1.0 Precedence: bulk List-ID: This patch adds basic audit io_uring filtering, using as much of the existing audit filtering infrastructure as possible. In order to do this we reuse the audit filter rule's syscall mask for the io_uring operation and we create a new filter for io_uring operations as AUDIT_FILTER_URING_EXIT/audit_filter_list[7]. Thanks to Richard Guy Briggs for his review, feedback, and work on the corresponding audit userspace changes. Signed-off-by: Paul Moore --- v3: - removed work-in-progress warning from the description v2: - incorporate feedback from Richard v1: - initial draft --- include/uapi/linux/audit.h | 3 +- kernel/audit_tree.c | 3 +- kernel/audit_watch.c | 3 +- kernel/auditfilter.c | 15 +++++++++-- kernel/auditsc.c | 61 ++++++++++++++++++++++++++++++++++---------- 5 files changed, 65 insertions(+), 20 deletions(-) diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index a1997697c8b1..ecf1edd2affa 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -167,8 +167,9 @@ #define AUDIT_FILTER_EXCLUDE 0x05 /* Apply rule before record creation */ #define AUDIT_FILTER_TYPE AUDIT_FILTER_EXCLUDE /* obsolete misleading naming */ #define AUDIT_FILTER_FS 0x06 /* Apply rule at __audit_inode_child */ +#define AUDIT_FILTER_URING_EXIT 0x07 /* Apply rule at io_uring op exit */ -#define AUDIT_NR_FILTERS 7 +#define AUDIT_NR_FILTERS 8 #define AUDIT_FILTER_PREPEND 0x10 /* Prepend to front of list */ diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 2cd7b5694422..338c53a961c5 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -726,7 +726,8 @@ int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op) { if (pathname[0] != '/' || - rule->listnr != AUDIT_FILTER_EXIT || + (rule->listnr != AUDIT_FILTER_EXIT && + rule->listnr != AUDIT_FILTER_URING_EXIT) || op != Audit_equal || rule->inode_f || rule->watch || rule->tree) return -EINVAL; diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 2acf7ca49154..698b62b4a2ec 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -183,7 +183,8 @@ int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op) return -EOPNOTSUPP; if (path[0] != '/' || path[len-1] == '/' || - krule->listnr != AUDIT_FILTER_EXIT || + (krule->listnr != AUDIT_FILTER_EXIT && + krule->listnr != AUDIT_FILTER_URING_EXIT) || op != Audit_equal || krule->inode_f || krule->watch || krule->tree) return -EINVAL; diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index db2c6b59dfc3..d75acb014ccd 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -44,7 +44,8 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = { LIST_HEAD_INIT(audit_filter_list[4]), LIST_HEAD_INIT(audit_filter_list[5]), LIST_HEAD_INIT(audit_filter_list[6]), -#if AUDIT_NR_FILTERS != 7 + LIST_HEAD_INIT(audit_filter_list[7]), +#if AUDIT_NR_FILTERS != 8 #error Fix audit_filter_list initialiser #endif }; @@ -56,6 +57,7 @@ static struct list_head audit_rules_list[AUDIT_NR_FILTERS] = { LIST_HEAD_INIT(audit_rules_list[4]), LIST_HEAD_INIT(audit_rules_list[5]), LIST_HEAD_INIT(audit_rules_list[6]), + LIST_HEAD_INIT(audit_rules_list[7]), }; DEFINE_MUTEX(audit_filter_mutex); @@ -151,7 +153,8 @@ char *audit_unpack_string(void **bufp, size_t *remain, size_t len) static inline int audit_to_inode(struct audit_krule *krule, struct audit_field *f) { - if (krule->listnr != AUDIT_FILTER_EXIT || + if ((krule->listnr != AUDIT_FILTER_EXIT && + krule->listnr != AUDIT_FILTER_URING_EXIT) || krule->inode_f || krule->watch || krule->tree || (f->op != Audit_equal && f->op != Audit_not_equal)) return -EINVAL; @@ -248,6 +251,7 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data * pr_err("AUDIT_FILTER_ENTRY is deprecated\n"); goto exit_err; case AUDIT_FILTER_EXIT: + case AUDIT_FILTER_URING_EXIT: case AUDIT_FILTER_TASK: #endif case AUDIT_FILTER_USER: @@ -332,6 +336,10 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) if (entry->rule.listnr != AUDIT_FILTER_FS) return -EINVAL; break; + case AUDIT_PERM: + if (entry->rule.listnr == AUDIT_FILTER_URING_EXIT) + return -EINVAL; + break; } switch (entry->rule.listnr) { @@ -980,7 +988,8 @@ static inline int audit_add_rule(struct audit_entry *entry) } entry->rule.prio = ~0ULL; - if (entry->rule.listnr == AUDIT_FILTER_EXIT) { + if (entry->rule.listnr == AUDIT_FILTER_EXIT || + entry->rule.listnr == AUDIT_FILTER_URING_EXIT) { if (entry->rule.flags & AUDIT_FILTER_PREPEND) entry->rule.prio = ++prio_high; else diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 62fb502da3fc..3cbcc999aff6 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -805,6 +805,35 @@ static int audit_in_mask(const struct audit_krule *rule, unsigned long val) return rule->mask[word] & bit; } +/** + * audit_filter_uring - apply filters to an io_uring operation + * @tsk: associated task + * @ctx: audit context + */ +static void audit_filter_uring(struct task_struct *tsk, + struct audit_context *ctx) +{ + struct audit_entry *e; + enum audit_state state; + + if (auditd_test_task(tsk)) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_URING_EXIT], + list) { + if (audit_in_mask(&e->rule, ctx->uring_op) && + audit_filter_rules(tsk, &e->rule, ctx, NULL, &state, + false)) { + rcu_read_unlock(); + ctx->current_state = state; + return; + } + } + rcu_read_unlock(); + return; +} + /* At syscall exit time, this filter is called if the audit_state is * not low enough that auditing cannot take place, but is also not * high enough that we already know we have to write an audit record @@ -1765,7 +1794,7 @@ static void audit_log_exit(void) * __audit_free - free a per-task audit context * @tsk: task whose audit context block to free * - * Called from copy_process and do_exit + * Called from copy_process, do_exit, and the io_uring code */ void __audit_free(struct task_struct *tsk) { @@ -1783,15 +1812,21 @@ void __audit_free(struct task_struct *tsk) * random task_struct that doesn't doesn't have any meaningful data we * need to log via audit_log_exit(). */ - if (tsk == current && !context->dummy && - context->context == AUDIT_CTX_SYSCALL) { + if (tsk == current && !context->dummy) { context->return_valid = AUDITSC_INVALID; context->return_code = 0; - - audit_filter_syscall(tsk, context); - audit_filter_inodes(tsk, context); - if (context->current_state == AUDIT_STATE_RECORD) - audit_log_exit(); + if (context->context == AUDIT_CTX_SYSCALL) { + audit_filter_syscall(tsk, context); + audit_filter_inodes(tsk, context); + if (context->current_state == AUDIT_STATE_RECORD) + audit_log_exit(); + } else if (context->context == AUDIT_CTX_URING) { + /* TODO: verify this case is real and valid */ + audit_filter_uring(tsk, context); + audit_filter_inodes(tsk, context); + if (context->current_state == AUDIT_STATE_RECORD) + audit_log_uring(context); + } } audit_set_context(tsk, NULL); @@ -1875,12 +1910,6 @@ void __audit_uring_exit(int success, long code) { struct audit_context *ctx = audit_context(); - /* - * TODO: At some point we will likely want to filter on io_uring ops - * and other things similar to what we do for syscalls, but that - * is something for another day; just record what we can here. - */ - if (ctx->context == AUDIT_CTX_SYSCALL) { /* * NOTE: See the note in __audit_uring_entry() about the case @@ -1903,6 +1932,8 @@ void __audit_uring_exit(int success, long code) * the behavior here. */ audit_filter_syscall(current, ctx); + if (ctx->current_state != AUDIT_STATE_RECORD) + audit_filter_uring(current, ctx); audit_filter_inodes(current, ctx); if (ctx->current_state != AUDIT_STATE_RECORD) return; @@ -1915,6 +1946,8 @@ void __audit_uring_exit(int success, long code) if (!list_empty(&ctx->killed_trees)) audit_kill_trees(ctx); + /* run through both filters to ensure we set the filterkey properly */ + audit_filter_uring(current, ctx); audit_filter_inodes(current, ctx); if (ctx->current_state != AUDIT_STATE_RECORD) goto out; From patchwork Tue Sep 14 03:33:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Moore X-Patchwork-Id: 12491549 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 704E8C4332F for ; Tue, 14 Sep 2021 03:33:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5EB3960F12 for ; Tue, 14 Sep 2021 03:33:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239120AbhINDeh (ORCPT ); Mon, 13 Sep 2021 23:34:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239040AbhINDef (ORCPT ); Mon, 13 Sep 2021 23:34:35 -0400 Received: from mail-qt1-x82a.google.com (mail-qt1-x82a.google.com [IPv6:2607:f8b0:4864:20::82a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C31D8C0613C1 for ; Mon, 13 Sep 2021 20:33:18 -0700 (PDT) Received: by mail-qt1-x82a.google.com with SMTP id x5so10130040qtq.13 for ; Mon, 13 Sep 2021 20:33:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paul-moore-com.20150623.gappssmtp.com; s=20150623; h=subject:from:to:date:message-id:in-reply-to:references:user-agent :mime-version:content-transfer-encoding; bh=yIvUop3P/60QYLtm8bDVCxAY3B7HwxRQ7AkWTc9jkh8=; b=UgU+ZGMcIRDHUazzWyvjbnYgPk38HeUD054UfCNUk/5P8rMXNbD5DbpJzY2/NwJnbk B+FrHS7LvYvCnLVPoGMgntRSQFOsg9Nl2QuKfmRRuwVlVHaPeLR3hTpWCAdxJD1Tqjxx fKv8n0cbftyErcP0rY5NC1WMglM9KHmxLUXmHHwrTVoapBa6SN75vlNjd8L601C/hW+E K23NCl8EpLdbAFG+GCr1uW2f2QeqmRPnnT4V3q/Da25J1ItCbI4ajKE4Y6jAo10guLnV s7/cYgSka8Q9cSrCPWDyvf+FBqMVkoscIqz/iiVoX61wrdHFN5316lXkBzpQ1De4hVXQ TDtA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:subject:from:to:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=yIvUop3P/60QYLtm8bDVCxAY3B7HwxRQ7AkWTc9jkh8=; b=FEH+DXf5qTamOZBR1LJDvsJf18DUPZxb3d/pyzk+dsqf4HRt0jMSudxy47Fq2QZhhA R5vIu1ps9DHVQjgi5TYF69bzANZ1MAFCM9sEnWw2nxSjDtC7VXPfEj4k/yJxFHYKBVmP oUzqNIQO/zg0Eo+6FcM22CgHKq87/qjL3P/B3AdKeWn7BelCmZ8jFvHYFnNcdRUEhXpI ClK3WmTaXvoh2vv64ynh/mKc/MbSjkDxdWM7mZgvYWNooNJEFSDK0B4Ud8gK1a+Wfj8D DQddn+FQ2Eeg7gVSVAgb9m7Yjs3PkrQJvIX+IM3KH66r0Bms580/1iqS77eid5EKcDqW Q0vA== X-Gm-Message-State: AOAM533GaH4uNw8dpNfxLiHW7LRGPFp08PD3nbs0de2B+jWmgf1AItMT 5xg2dMxHSysOFn5ypEF9KB56Hm09Kv5o X-Google-Smtp-Source: ABdhPJyBLgu6nnMNu0XNtQrmb84WAJq+QQFJ7unI1AirZRKDx5A8vQSop0c3lfor668lSPDvc9ZMMA== X-Received: by 2002:a05:622a:1c6:: with SMTP id t6mr2748253qtw.390.1631590397433; Mon, 13 Sep 2021 20:33:17 -0700 (PDT) Received: from localhost (pool-96-237-52-188.bstnma.fios.verizon.net. [96.237.52.188]) by smtp.gmail.com with ESMTPSA id u7sm5288981qtc.75.2021.09.13.20.33.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Sep 2021 20:33:17 -0700 (PDT) Subject: [PATCH v3 4/8] fs: add anon_inode_getfile_secure() similar to anon_inode_getfd_secure() From: Paul Moore To: linux-security-module@vger.kernel.org, selinux@vger.kernel.org, linux-audit@redhat.com, io-uring@vger.kernel.org, linux-fsdevel@vger.kernel.org, Jens Axboe , Pavel Begunkov , Kumar Kartikeya Dwivedi Date: Mon, 13 Sep 2021 23:33:16 -0400 Message-ID: <163159039643.470089.15401020922378832012.stgit@olly> In-Reply-To: <163159032713.470089.11728103630366176255.stgit@olly> References: <163159032713.470089.11728103630366176255.stgit@olly> User-Agent: StGit/1.1 MIME-Version: 1.0 Precedence: bulk List-ID: Extending the secure anonymous inode support to other subsystems requires that we have a secure anon_inode_getfile() variant in addition to the existing secure anon_inode_getfd() variant. Thankfully we can reuse the existing __anon_inode_getfile() function and just wrap it with the proper arguments. Acked-by: Mickaël Salaün Signed-off-by: Paul Moore --- v3: - no change v2: - no change v1: - initial draft --- fs/anon_inodes.c | 29 +++++++++++++++++++++++++++++ include/linux/anon_inodes.h | 4 ++++ 2 files changed, 33 insertions(+) diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index a280156138ed..e0c3e33c4177 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -148,6 +148,35 @@ struct file *anon_inode_getfile(const char *name, } EXPORT_SYMBOL_GPL(anon_inode_getfile); +/** + * anon_inode_getfile_secure - Like anon_inode_getfile(), but creates a new + * !S_PRIVATE anon inode rather than reuse the + * singleton anon inode and calls the + * inode_init_security_anon() LSM hook. This + * allows for both the inode to have its own + * security context and for the LSM to enforce + * policy on the inode's creation. + * + * @name: [in] name of the "class" of the new file + * @fops: [in] file operations for the new file + * @priv: [in] private data for the new file (will be file's private_data) + * @flags: [in] flags + * @context_inode: + * [in] the logical relationship with the new inode (optional) + * + * The LSM may use @context_inode in inode_init_security_anon(), but a + * reference to it is not held. Returns the newly created file* or an error + * pointer. See the anon_inode_getfile() documentation for more information. + */ +struct file *anon_inode_getfile_secure(const char *name, + const struct file_operations *fops, + void *priv, int flags, + const struct inode *context_inode) +{ + return __anon_inode_getfile(name, fops, priv, flags, + context_inode, true); +} + static int __anon_inode_getfd(const char *name, const struct file_operations *fops, void *priv, int flags, diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h index 71881a2b6f78..5deaddbd7927 100644 --- a/include/linux/anon_inodes.h +++ b/include/linux/anon_inodes.h @@ -15,6 +15,10 @@ struct inode; struct file *anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags); +struct file *anon_inode_getfile_secure(const char *name, + const struct file_operations *fops, + void *priv, int flags, + const struct inode *context_inode); int anon_inode_getfd(const char *name, const struct file_operations *fops, void *priv, int flags); int anon_inode_getfd_secure(const char *name, From patchwork Tue Sep 14 03:33:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Moore X-Patchwork-Id: 12491599 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 63D4FC433F5 for ; Tue, 14 Sep 2021 03:33:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 519AF60F12 for ; Tue, 14 Sep 2021 03:33:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239099AbhINDfG (ORCPT ); Mon, 13 Sep 2021 23:35:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55880 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239165AbhINDel (ORCPT ); Mon, 13 Sep 2021 23:34:41 -0400 Received: from mail-qk1-x72a.google.com (mail-qk1-x72a.google.com [IPv6:2607:f8b0:4864:20::72a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C5E4CC0613C1 for ; Mon, 13 Sep 2021 20:33:24 -0700 (PDT) Received: by mail-qk1-x72a.google.com with SMTP id a10so13183324qka.12 for ; Mon, 13 Sep 2021 20:33:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paul-moore-com.20150623.gappssmtp.com; s=20150623; h=subject:from:to:date:message-id:in-reply-to:references:user-agent :mime-version:content-transfer-encoding; bh=pFa7GQIxXWl0c/uM3483yackGoLHK0NgaO+2cmzz5Nw=; b=wEpIkxBpc62PNnC88chQDJ6zl25RE56F/I9noxOjWlQLPwUG7cqnrdLMG7Wlk/LPnd Zm0E4bQI9M4k1UtZNyWF7wCSNgsKxaMFD4UNfcxkXMMfDVnjGPQ8M62e5Dnj6Jc6BrpB b5LKHdaK4Fq8cywiuL0lJxpzyTt+UP8nP/hFKMZkdqvbul8SNTDL4H34hOfutmA0ICb1 /410R7ECIcMMAC+kBO8BDZ0co8cHwwCm/YNfySjIvLgDLCHHnV/01gNm1lxD9uFNhedX 2J9FAsPgQ8h6ts8zlKrCJQXt626+kaQdlnB5snN96wzL4diruTl78Bl8L70wplAugZoJ KfMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:subject:from:to:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=pFa7GQIxXWl0c/uM3483yackGoLHK0NgaO+2cmzz5Nw=; b=yFGOOa6aNKFcOh8HRXLK4+rY2uPTIhIe9WrehNi2QRPazUfKL/aNmPwA3rUCd2nFfL M2KHe8QGxii5FI3fEw82BkoQcEw1ILLbo09xt+MkeUHP6TPHLhngYWWWz1Os574ziU28 IYTiYSwQ37gv34uqFpAa4lsJRYPazk2aVcda/uDTnKy92yG2/RdLGQqRfH0b9idXQd4l Xy9LbJWNSlZzVVdV9GGJKbL0qAaYhctHumxKmEdrmPJE9oAkTf61Eb4t025qyx7xe3aW u4rIcDW8N7vuJinGhqEPup1JjTTdBCeOYSMjGx34B6mZbQvNipi3GGmSEJiE0dOh8zyb 7ovg== X-Gm-Message-State: AOAM530dkxakzTzTkXWFY1i4dg1s8WbOZR57EpO4EWIwoa5ZCNSVsC0S o5Mlh5LfRNym6w1FE4EZZ0JDM9/OjizV X-Google-Smtp-Source: ABdhPJw+Gqp/QaKJUPx+eMnsA6HZ3RZzmRCYKVzNF9XtqTZeCyQUZcicJKwDykSIlKMgYCUZ69zReA== X-Received: by 2002:a05:620a:448e:: with SMTP id x14mr2935347qkp.526.1631590403616; Mon, 13 Sep 2021 20:33:23 -0700 (PDT) Received: from localhost (pool-96-237-52-188.bstnma.fios.verizon.net. [96.237.52.188]) by smtp.gmail.com with ESMTPSA id t26sm6530426qkm.0.2021.09.13.20.33.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Sep 2021 20:33:23 -0700 (PDT) Subject: [PATCH v3 5/8] io_uring: convert io_uring to the secure anon inode interface From: Paul Moore To: linux-security-module@vger.kernel.org, selinux@vger.kernel.org, linux-audit@redhat.com, io-uring@vger.kernel.org, linux-fsdevel@vger.kernel.org, Jens Axboe , Pavel Begunkov , Kumar Kartikeya Dwivedi Date: Mon, 13 Sep 2021 23:33:22 -0400 Message-ID: <163159040254.470089.7192304410101378968.stgit@olly> In-Reply-To: <163159032713.470089.11728103630366176255.stgit@olly> References: <163159032713.470089.11728103630366176255.stgit@olly> User-Agent: StGit/1.1 MIME-Version: 1.0 Precedence: bulk List-ID: Converting io_uring's anonymous inode to the secure anon inode API enables LSMs to enforce policy on the io_uring anonymous inodes if they chose to do so. This is an important first step towards providing the necessary mechanisms so that LSMs can apply security policy to io_uring operations. Signed-off-by: Paul Moore --- v3: - no change v2: - no change v1: - initial draft --- fs/io_uring.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/io_uring.c b/fs/io_uring.c index 388754b24785..56cc9aba0d01 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -10155,8 +10155,8 @@ static struct file *io_uring_get_file(struct io_ring_ctx *ctx) return ERR_PTR(ret); #endif - file = anon_inode_getfile("[io_uring]", &io_uring_fops, ctx, - O_RDWR | O_CLOEXEC); + file = anon_inode_getfile_secure("[io_uring]", &io_uring_fops, ctx, + O_RDWR | O_CLOEXEC, NULL); #if defined(CONFIG_UNIX) if (IS_ERR(file)) { sock_release(ctx->ring_sock); From patchwork Tue Sep 14 03:33:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Moore X-Patchwork-Id: 12491601 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5A97DC4332F for ; Tue, 14 Sep 2021 03:33:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4498C60EE7 for ; Tue, 14 Sep 2021 03:33:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239030AbhINDfM (ORCPT ); Mon, 13 Sep 2021 23:35:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55926 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239175AbhINDet (ORCPT ); Mon, 13 Sep 2021 23:34:49 -0400 Received: from mail-qt1-x833.google.com (mail-qt1-x833.google.com [IPv6:2607:f8b0:4864:20::833]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 285EFC0613E0 for ; Mon, 13 Sep 2021 20:33:31 -0700 (PDT) Received: by mail-qt1-x833.google.com with SMTP id s15so10137662qta.10 for ; Mon, 13 Sep 2021 20:33:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paul-moore-com.20150623.gappssmtp.com; s=20150623; h=subject:from:to:date:message-id:in-reply-to:references:user-agent :mime-version:content-transfer-encoding; bh=44m8YfPMzWXdTq/gfRdFGlc5TMy4yJ/NKyjhjSqGlf8=; b=s9KwB6zj2FfJUCokRSuEb8hBW9DV0tc7SQWtsy//fAgiwhfFS3H/kf5/juhjcneM4a RYf6rhZzA5ft/7L/5mbUjiwc5EtReMTnsqvGu1c7Bu6kasgchNYWomGOminCn3ioNK7R CIS32FxqF7FcZ9UYsg4i6S+438cWU6Ecz5jeQSOF6nvFky5pyMK0H8GXZ9dxDdCIn3DB hslu3UVhhOyJBONJi4dFoRnx7zEKIO4+TGUJVHUBEKPKe+sQFPpttPceTouI2kDLjx7N DsxM4bX41q39HbpdjAkUWEUoIQCjZQ77zosPirnXCQH42N8k7fodt4P4PguG/rNnwIPb 1RuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:subject:from:to:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=44m8YfPMzWXdTq/gfRdFGlc5TMy4yJ/NKyjhjSqGlf8=; b=Hr4F4H+smr4LYYHPTrswKjCM67zl/ZjmCwqo++6uh7IM/TUcq7mu2NcqXtU2o9tizf RPaQzyFmC+ec0JkGFPFS0/cekBs06l/N8zx0ulIZuqEfubSbdwO76kRUsFUSnCp1CFc8 mjdT/4jKZQEGUa0qEWnxbe1FtlmN+Z5ekXgT/ofeHRxzA3Z/ZF2HxBB7CbAOFLlhKkdN DMbGZW3Urj2NxAXVJ35mysGskd0tdFp9QvZ9gFsbWfM1sYXWr+t2MWt66YeOKeBfENGp ZQ+Whwfz+t+Sec42LXFTomcFge9vEAMTwzVQdvZCjKUjTrJk9R4svqhkFkmvenAyJYIj W5AQ== X-Gm-Message-State: AOAM5332xvnV/ssuc4RY6GENQpFWxfCetmK/woYjNI6VxVAJKyJ2lOhx xEzqeaOdeGMTpS2Q3jJXGbUbSM+TY/ib X-Google-Smtp-Source: ABdhPJwVIqGWSZwbX+Go0aGdD7JTOnckXWG8p8h6PN81TBFq4M3jox9+PBjvYZrW8+uSOTwYav2mqQ== X-Received: by 2002:ac8:7042:: with SMTP id y2mr2798819qtm.48.1631590409892; Mon, 13 Sep 2021 20:33:29 -0700 (PDT) Received: from localhost (pool-96-237-52-188.bstnma.fios.verizon.net. [96.237.52.188]) by smtp.gmail.com with ESMTPSA id 9sm6534734qkc.52.2021.09.13.20.33.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Sep 2021 20:33:29 -0700 (PDT) Subject: [PATCH v3 6/8] lsm,io_uring: add LSM hooks to io_uring From: Paul Moore To: linux-security-module@vger.kernel.org, selinux@vger.kernel.org, linux-audit@redhat.com, io-uring@vger.kernel.org, linux-fsdevel@vger.kernel.org, Jens Axboe , Pavel Begunkov , Kumar Kartikeya Dwivedi Date: Mon, 13 Sep 2021 23:33:28 -0400 Message-ID: <163159040872.470089.8173538586765911676.stgit@olly> In-Reply-To: <163159032713.470089.11728103630366176255.stgit@olly> References: <163159032713.470089.11728103630366176255.stgit@olly> User-Agent: StGit/1.1 MIME-Version: 1.0 Precedence: bulk List-ID: A full expalantion of io_uring is beyond the scope of this commit description, but in summary it is an asynchronous I/O mechanism which allows for I/O requests and the resulting data to be queued in memory mapped "rings" which are shared between the kernel and userspace. Optionally, io_uring offers the ability for applications to spawn kernel threads to dequeue I/O requests from the ring and submit the requests in the kernel, helping to minimize the syscall overhead. Rings are accessed in userspace by memory mapping a file descriptor provided by the io_uring_setup(2), and can be shared between applications as one might do with any open file descriptor. Finally, process credentials can be registered with a given ring and any process with access to that ring can submit I/O requests using any of the registered credentials. While the io_uring functionality is widely recognized as offering a vastly improved, and high performing asynchronous I/O mechanism, its ability to allow processes to submit I/O requests with credentials other than its own presents a challenge to LSMs. When a process creates a new io_uring ring the ring's credentials are inhertied from the calling process; if this ring is shared with another process operating with different credentials there is the potential to bypass the LSMs security policy. Similarly, registering credentials with a given ring allows any process with access to that ring to submit I/O requests with those credentials. In an effort to allow LSMs to apply security policy to io_uring I/O operations, this patch adds two new LSM hooks. These hooks, in conjunction with the LSM anonymous inode support previously submitted, allow an LSM to apply access control policy to the sharing of io_uring rings as well as any io_uring credential changes requested by a process. The new LSM hooks are described below: * int security_uring_override_creds(cred) Controls if the current task, executing an io_uring operation, is allowed to override it's credentials with @cred. In cases where the current task is a user application, the current credentials will be those of the user application. In cases where the current task is a kernel thread servicing io_uring requests the current credentials will be those of the io_uring ring (inherited from the process that created the ring). * int security_uring_sqpoll(void) Controls if the current task is allowed to create an io_uring polling thread (IORING_SETUP_SQPOLL). Without a SQPOLL thread in the kernel processes must submit I/O requests via io_uring_enter(2) which allows us to compare any requested credential changes against the application making the request. With a SQPOLL thread, we can no longer compare requested credential changes against the application making the request, the comparison is made against the ring's credentials. Signed-off-by: Paul Moore --- v3: - removed work-in-progress warning from the description v2: - no change v1: - initial draft --- fs/io_uring.c | 10 ++++++++++ include/linux/lsm_hook_defs.h | 5 +++++ include/linux/lsm_hooks.h | 13 +++++++++++++ include/linux/security.h | 16 ++++++++++++++++ security/security.c | 12 ++++++++++++ 5 files changed, 56 insertions(+) diff --git a/fs/io_uring.c b/fs/io_uring.c index 56cc9aba0d01..f89d00af3a67 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -80,6 +80,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -7070,6 +7071,11 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req, if (!req->creds) return -EINVAL; get_cred(req->creds); + ret = security_uring_override_creds(req->creds); + if (ret) { + put_cred(req->creds); + return ret; + } req->flags |= REQ_F_CREDS; } state = &ctx->submit_state; @@ -8566,6 +8572,10 @@ static int io_sq_offload_create(struct io_ring_ctx *ctx, struct io_sq_data *sqd; bool attached; + ret = security_uring_sqpoll(); + if (ret) + return ret; + sqd = io_get_sq_data(p, &attached); if (IS_ERR(sqd)) { ret = PTR_ERR(sqd); diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 2adeea44c0d5..b3c525353769 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -402,3 +402,8 @@ LSM_HOOK(void, LSM_RET_VOID, perf_event_free, struct perf_event *event) LSM_HOOK(int, 0, perf_event_read, struct perf_event *event) LSM_HOOK(int, 0, perf_event_write, struct perf_event *event) #endif /* CONFIG_PERF_EVENTS */ + +#ifdef CONFIG_IO_URING +LSM_HOOK(int, 0, uring_override_creds, const struct cred *new) +LSM_HOOK(int, 0, uring_sqpoll, void) +#endif /* CONFIG_IO_URING */ diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 5c4c5c0602cb..0eb0ae95c4c4 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1557,6 +1557,19 @@ * Read perf_event security info if allowed. * @perf_event_write: * Write perf_event security info if allowed. + * + * Security hooks for io_uring + * + * @uring_override_creds: + * Check if the current task, executing an io_uring operation, is allowed + * to override it's credentials with @new. + * + * @new: the new creds to use + * + * @uring_sqpoll: + * Check whether the current task is allowed to spawn a io_uring polling + * thread (IORING_SETUP_SQPOLL). + * */ union security_list_options { #define LSM_HOOK(RET, DEFAULT, NAME, ...) RET (*NAME)(__VA_ARGS__); diff --git a/include/linux/security.h b/include/linux/security.h index 5b7288521300..7979b9629a42 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2038,4 +2038,20 @@ static inline int security_perf_event_write(struct perf_event *event) #endif /* CONFIG_SECURITY */ #endif /* CONFIG_PERF_EVENTS */ +#ifdef CONFIG_IO_URING +#ifdef CONFIG_SECURITY +extern int security_uring_override_creds(const struct cred *new); +extern int security_uring_sqpoll(void); +#else +static inline int security_uring_override_creds(const struct cred *new) +{ + return 0; +} +static inline int security_uring_sqpoll(void) +{ + return 0; +} +#endif /* CONFIG_SECURITY */ +#endif /* CONFIG_IO_URING */ + #endif /* ! __LINUX_SECURITY_H */ diff --git a/security/security.c b/security/security.c index 9ffa9e9c5c55..c49a2c0cc1c1 100644 --- a/security/security.c +++ b/security/security.c @@ -2625,3 +2625,15 @@ int security_perf_event_write(struct perf_event *event) return call_int_hook(perf_event_write, 0, event); } #endif /* CONFIG_PERF_EVENTS */ + +#ifdef CONFIG_IO_URING +int security_uring_override_creds(const struct cred *new) +{ + return call_int_hook(uring_override_creds, 0, new); +} + +int security_uring_sqpoll(void) +{ + return call_int_hook(uring_sqpoll, 0); +} +#endif /* CONFIG_IO_URING */ From patchwork Tue Sep 14 03:33:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Moore X-Patchwork-Id: 12491603 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A5409C433EF for ; Tue, 14 Sep 2021 03:33:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 90C6E60F12 for ; Tue, 14 Sep 2021 03:33:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239071AbhINDfN (ORCPT ); Mon, 13 Sep 2021 23:35:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55948 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239115AbhINDex (ORCPT ); Mon, 13 Sep 2021 23:34:53 -0400 Received: from mail-qt1-x82a.google.com (mail-qt1-x82a.google.com [IPv6:2607:f8b0:4864:20::82a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 30561C0613E1 for ; Mon, 13 Sep 2021 20:33:37 -0700 (PDT) Received: by mail-qt1-x82a.google.com with SMTP id m9so7303290qtk.4 for ; Mon, 13 Sep 2021 20:33:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paul-moore-com.20150623.gappssmtp.com; s=20150623; h=subject:from:to:date:message-id:in-reply-to:references:user-agent :mime-version:content-transfer-encoding; bh=1hmr6L0fVcZTcmxPJPnof4mx/iAEjJvjvO8eEYK9GTY=; b=qPuX5/vw585Sn8sXxfV2jhjIJA+UeiZ6GNll27zSXPvWdTNB/vHf1WD4O0bzXD5NHi icq+MFF3VqBIDNRenVQhoK4YYfRP7v4Xd5jT8GkjpEszP8GKefKDvmOeQ/QW0eNhMntv RkRLnQurKrgiOV36gV2Feb0lsqgzrxnSq8KOwhfk1/eSd4/9FOu36mqbeRdmyaKHB+et DQxU3EySubFgliQLhDeVf2qbufZvRVqUOXTduk1ZmS6iZkhwnsLU2PB/LSl+YBpYvodr WIaQD27zb601BeNL6ba0DzQb/wSyfzg0oxJKFGW/SV2rrWSvJxXii1hFRj5dpMK/EvJt XRHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:subject:from:to:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=1hmr6L0fVcZTcmxPJPnof4mx/iAEjJvjvO8eEYK9GTY=; b=oJy2QncVU20EdvYmhv4yqvAGvkMbXS0k+97Hp/7ID8DsjsDv1jFmyqr5zynB7yxOGK WPwr/xgt/ton9Mq68UW6JHjDoVD0WX1OX3dv6c/lyCoAMK7hRFElhh9tjzRKIV/GfJN8 mYNeqLzeAGFwXSvMvAnq8K7RxJuwT0RcdFOyX1U/mBnnamfoL/ch+KH8j/oRMa8yyDk3 hNdlppzQUQ8zxq4Ql2+MA+cr7JVwSFceUpqOvvTMQF74C4z9FBJAZ89Qb+wzdd1MheND xF32asoumcyqlAT0ToraaeMtaIYbEcZD/2e0IvWo+41icjuo3V7QbaP9pDIcjRYOBXSi lFdA== X-Gm-Message-State: AOAM533NrUHUoj2kqvFlJH66XC2DOJpZkqZy98TTuJtJQ5JnmXQvBWXs ApMeLplKkTNalVfipNV9g0B3Zl+eFog5 X-Google-Smtp-Source: ABdhPJyIyp1hiwJfZDPM7fHYpgOdMt/MoPWfVS5fj481zKGK2WbXUsP0NNJpdTxyHYf8LDUGODkTwg== X-Received: by 2002:ac8:7090:: with SMTP id y16mr2821209qto.19.1631590415998; Mon, 13 Sep 2021 20:33:35 -0700 (PDT) Received: from localhost (pool-96-237-52-188.bstnma.fios.verizon.net. [96.237.52.188]) by smtp.gmail.com with ESMTPSA id g13sm6740138qkk.110.2021.09.13.20.33.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Sep 2021 20:33:35 -0700 (PDT) Subject: [PATCH v3 7/8] selinux: add support for the io_uring access controls From: Paul Moore To: linux-security-module@vger.kernel.org, selinux@vger.kernel.org, linux-audit@redhat.com, io-uring@vger.kernel.org, linux-fsdevel@vger.kernel.org, Jens Axboe , Pavel Begunkov , Kumar Kartikeya Dwivedi Date: Mon, 13 Sep 2021 23:33:35 -0400 Message-ID: <163159041500.470089.11310853524829799938.stgit@olly> In-Reply-To: <163159032713.470089.11728103630366176255.stgit@olly> References: <163159032713.470089.11728103630366176255.stgit@olly> User-Agent: StGit/1.1 MIME-Version: 1.0 Precedence: bulk List-ID: This patch implements two new io_uring access controls, specifically support for controlling the io_uring "personalities" and IORING_SETUP_SQPOLL. Controlling the sharing of io_urings themselves is handled via the normal file/inode labeling and sharing mechanisms. The io_uring { override_creds } permission restricts which domains the subject domain can use to override it's own credentials. Granting a domain the io_uring { override_creds } permission allows it to impersonate another domain in io_uring operations. The io_uring { sqpoll } permission restricts which domains can create asynchronous io_uring polling threads. This is important from a security perspective as operations queued by this asynchronous thread inherit the credentials of the thread creator by default; if an io_uring is shared across process/domain boundaries this could result in one domain impersonating another. Controlling the creation of sqpoll threads, and the sharing of io_urings across processes, allow policy authors to restrict the ability of one domain to impersonate another via io_uring. As a quick summary, this patch adds a new object class with two permissions: io_uring { override_creds sqpoll } These permissions can be seen in the two simple policy statements below: allow domA_t domB_t : io_uring { override_creds }; allow domA_t self : io_uring { sqpoll }; Signed-off-by: Paul Moore --- v3: - removed work-in-progress warning from the description v2: - made the selinux_uring_* funcs static - removed the debugging code v1: - initial draft --- security/selinux/hooks.c | 34 ++++++++++++++++++++++++++++++++++ security/selinux/include/classmap.h | 2 ++ 2 files changed, 36 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6517f221d52c..012e8504ed9e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -7111,6 +7111,35 @@ static int selinux_perf_event_write(struct perf_event *event) } #endif +#ifdef CONFIG_IO_URING +/** + * selinux_uring_override_creds - check the requested cred override + * @new: the target creds + * + * Check to see if the current task is allowed to override it's credentials + * to service an io_uring operation. + */ +static int selinux_uring_override_creds(const struct cred *new) +{ + return avc_has_perm(&selinux_state, current_sid(), cred_sid(new), + SECCLASS_IO_URING, IO_URING__OVERRIDE_CREDS, NULL); +} + +/** + * selinux_uring_sqpoll - check if a io_uring polling thread can be created + * + * Check to see if the current task is allowed to create a new io_uring + * kernel polling thread. + */ +static int selinux_uring_sqpoll(void) +{ + int sid = current_sid(); + + return avc_has_perm(&selinux_state, sid, sid, + SECCLASS_IO_URING, IO_URING__SQPOLL, NULL); +} +#endif /* CONFIG_IO_URING */ + /* * IMPORTANT NOTE: When adding new hooks, please be careful to keep this order: * 1. any hooks that don't belong to (2.) or (3.) below, @@ -7349,6 +7378,11 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write), #endif +#ifdef CONFIG_IO_URING + LSM_HOOK_INIT(uring_override_creds, selinux_uring_override_creds), + LSM_HOOK_INIT(uring_sqpoll, selinux_uring_sqpoll), +#endif + LSM_HOOK_INIT(locked_down, selinux_lockdown), /* diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 084757ff4390..698ccfdaf82d 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -254,6 +254,8 @@ struct security_class_mapping secclass_map[] = { { "integrity", "confidentiality", NULL } }, { "anon_inode", { COMMON_FILE_PERMS, NULL } }, + { "io_uring", + { "override_creds", "sqpoll", NULL } }, { NULL } }; From patchwork Tue Sep 14 03:33:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Moore X-Patchwork-Id: 12491605 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CBC02C433EF for ; Tue, 14 Sep 2021 03:34:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B8B80610EA for ; Tue, 14 Sep 2021 03:34:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239115AbhINDfP (ORCPT ); Mon, 13 Sep 2021 23:35:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55982 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239179AbhINDfC (ORCPT ); Mon, 13 Sep 2021 23:35:02 -0400 Received: from mail-qk1-x72b.google.com (mail-qk1-x72b.google.com [IPv6:2607:f8b0:4864:20::72b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 55EB5C0613E4 for ; Mon, 13 Sep 2021 20:33:43 -0700 (PDT) Received: by mail-qk1-x72b.google.com with SMTP id ay33so13174895qkb.10 for ; Mon, 13 Sep 2021 20:33:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paul-moore-com.20150623.gappssmtp.com; s=20150623; h=subject:from:to:date:message-id:in-reply-to:references:user-agent :mime-version:content-transfer-encoding; bh=54Sbzge3G+aat3VcychMMrLelhIpqQAZp6yuJG+ykt8=; b=aZ6thOvMHLr+wxTevjEA1i5Ht/W/KrKBQJDrsm43lV+2/eSbhr0/w/m5LaTbRZv97v 13VV/f6a5EZn+YwNo+evAqqV68Rk0Q3ZSZ7p66Z50xOHLmTvSRidUUAQqWKoRmufA//s TRdH5DrwLc8h6Fex7ElS7A8hxXq9SCFZnCMT2WXwEZFLdqa6eaRHhZuYOqmQZA+UPyb8 U6kNemODgsXPNN7mcEVByROU8emfLbr8Vnk/Yuyf9KR1xQgvIKEYcEbjkCJLJqdNEz8k K9dZzuNqP701EebgEt1oQ05r+hhjxT6DR0Y1fY8t9nmU0Lbxbb7cA5vBOG5ann40QGgU C7rg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:subject:from:to:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=54Sbzge3G+aat3VcychMMrLelhIpqQAZp6yuJG+ykt8=; b=rxlPpsS9fa7vYcguFdUR/lUfkPBwWI50fXFAQU7O1D13P+lh7CNyqREMgyQuCMzCyI W+b4oXRCHt/zYA4nw6uSvDH0Bza+PKSdsS2OifkdBRMJ3kKAzYCR49Rzv/TdFF1UAQ6G p7C6iVkPit6BZ1FCgFSdbuIHZEOViiHn7GArHGvew6sEXY2ssx8P4ilrx4xg1H6q7/rv +ZDM/MHvghU9hLmfVAptcuuZxi9PJBUqOENI4dibacZiRqw/s117DVCRgoqLX3VvObwe TyapaVuduszB0NESVWt6YKpGDFnqOfFIU/bgo686W6K1tsK5Ltnhje/JbodX/Lnkx++K Tbmw== X-Gm-Message-State: AOAM530HoZvFanFAoTXIj9rFFDYVgpxmds24pMbUqxBJOHNPeaDTFdNj axOl/8PPO7c6WcwBzCzNQyjdloJSSw/n X-Google-Smtp-Source: ABdhPJxCTwAyD5dWI5ou1pL9SVHqbRt3WXQyP3KXoalYRryIJkcZ1TtZ+jPi+4HNVU0jJ4AhyxpGgA== X-Received: by 2002:a37:6691:: with SMTP id a139mr2900014qkc.310.1631590422163; Mon, 13 Sep 2021 20:33:42 -0700 (PDT) Received: from localhost (pool-96-237-52-188.bstnma.fios.verizon.net. [96.237.52.188]) by smtp.gmail.com with ESMTPSA id b1sm5212672qtj.76.2021.09.13.20.33.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Sep 2021 20:33:41 -0700 (PDT) Subject: [PATCH v3 8/8] Smack: Brutalist io_uring support with debug From: Paul Moore To: linux-security-module@vger.kernel.org, selinux@vger.kernel.org, linux-audit@redhat.com, io-uring@vger.kernel.org, linux-fsdevel@vger.kernel.org, Jens Axboe , Pavel Begunkov , Kumar Kartikeya Dwivedi Date: Mon, 13 Sep 2021 23:33:41 -0400 Message-ID: <163159042110.470089.9405201508228711833.stgit@olly> In-Reply-To: <163159032713.470089.11728103630366176255.stgit@olly> References: <163159032713.470089.11728103630366176255.stgit@olly> User-Agent: StGit/1.1 MIME-Version: 1.0 Precedence: bulk List-ID: From: Casey Schaufler Add Smack privilege checks for io_uring. Use CAP_MAC_OVERRIDE for the override_creds case and CAP_MAC_ADMIN for creating a polling thread. These choices are based on conjecture regarding the intent of the surrounding code. Signed-off-by: Casey Schaufler [PM: make the smack_uring_* funcs static, remove debug code] Signed-off-by: Paul Moore --- v3: - removed debug code v2: - made the smack_uring_* funcs static v1: - initial draft --- security/smack/smack_lsm.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index cacbe7518519..f90ab1efeb6d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -4691,6 +4691,48 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, return 0; } +#ifdef CONFIG_IO_URING +/** + * smack_uring_override_creds - Is io_uring cred override allowed? + * @new: the target creds + * + * Check to see if the current task is allowed to override it's credentials + * to service an io_uring operation. + */ +static int smack_uring_override_creds(const struct cred *new) +{ + struct task_smack *tsp = smack_cred(current_cred()); + struct task_smack *nsp = smack_cred(new); + + /* + * Allow the degenerate case where the new Smack value is + * the same as the current Smack value. + */ + if (tsp->smk_task == nsp->smk_task) + return 0; + + if (smack_privileged_cred(CAP_MAC_OVERRIDE, current_cred())) + return 0; + + return -EPERM; +} + +/** + * smack_uring_sqpoll - check if a io_uring polling thread can be created + * + * Check to see if the current task is allowed to create a new io_uring + * kernel polling thread. + */ +static int smack_uring_sqpoll(void) +{ + if (smack_privileged_cred(CAP_MAC_ADMIN, current_cred())) + return 0; + + return -EPERM; +} + +#endif /* CONFIG_IO_URING */ + struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { .lbs_cred = sizeof(struct task_smack), .lbs_file = sizeof(struct smack_known *), @@ -4843,6 +4885,10 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(inode_copy_up, smack_inode_copy_up), LSM_HOOK_INIT(inode_copy_up_xattr, smack_inode_copy_up_xattr), LSM_HOOK_INIT(dentry_create_files_as, smack_dentry_create_files_as), +#ifdef CONFIG_IO_URING + LSM_HOOK_INIT(uring_override_creds, smack_uring_override_creds), + LSM_HOOK_INIT(uring_sqpoll, smack_uring_sqpoll), +#endif };