From patchwork Wed Jul 29 17:58:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691579 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7B82E913 for ; Wed, 29 Jul 2020 18:00:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 64CB62083B for ; Wed, 29 Jul 2020 18:00:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ecnAksZk" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727112AbgG2R6z (ORCPT ); Wed, 29 Jul 2020 13:58:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35658 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726857AbgG2R6z (ORCPT ); Wed, 29 Jul 2020 13:58:55 -0400 Received: from mail-pg1-x541.google.com (mail-pg1-x541.google.com [IPv6:2607:f8b0:4864:20::541]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3B1D2C0619D2 for ; Wed, 29 Jul 2020 10:58:55 -0700 (PDT) Received: by mail-pg1-x541.google.com with SMTP id l12so3599998pgt.13 for ; Wed, 29 Jul 2020 10:58:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=DgMrXVVefzee5XLvUUvLofSlFR2vFY36qKFP1IS3s/M=; b=ecnAksZk8u482WqjHzXgmErEsJOgZFCFls0F0FtO7QmdHTAAGDaWiu+nlxfcYYLD/d vOqlPliWbWinlSxtuqmjAy7Ruxwd6be6qQHWGBiByabdvGPPs65frNOVSJCZRjLZGs7F RFwB+vTeBV8v3277ad97fHgeSGQl8zzdLnaqs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=DgMrXVVefzee5XLvUUvLofSlFR2vFY36qKFP1IS3s/M=; b=qCkDaXVDtRRVHaeih/IjW5mhp8DJ2TSqRgL0iht8FFwFuRzr5d2L9KT7rL89GLVscS Ftq2SjOi6osQAzSNzk70TigKe6E0EhB/Y8gKDMBPGGPXD9NDV4TzQV3p07iWVkpcY+Ax /3f9TLxhpjwGlS4nnKX7x3f4J81DvhN47Qv17W8IPYiZzdyYZesZu5RqjW85N1IDUiTk +tZuLtD3LwDyfFLjPttjmNJCIO7Q+qhjgxPzR5aYf14GyVgTz13OXR/I8ztjb9bckdon YpYMEpN/FuSh4VTfekg72eeSYrHBMLAO2F5HRrBcvhJVnMjG7ZvRpo9Rn1LXn0WmBzgA mTHA== X-Gm-Message-State: AOAM5328+gHQcYNYzNCQ6vFgxWMS1juskeimlftHc4pV3QIJFaum8gri t18llN48BGnjNgc2t7R8Wcwl2Q== X-Google-Smtp-Source: ABdhPJxhdO2MgDtr62Uppf9UbFVzy8Bb9dXdsSesClNEHtIm2RElCtl0XV+rgMZUKEUflFVUEOGjEg== X-Received: by 2002:a63:5349:: with SMTP id t9mr2901760pgl.204.1596045534650; Wed, 29 Jul 2020 10:58:54 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id b82sm3185975pfb.215.2020.07.29.10.58.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:53 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , stable@vger.kernel.org, Scott Branden , Luis Chamberlain , Mimi Zohar , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 01/17] test_firmware: Test platform fw loading on non-EFI systems Date: Wed, 29 Jul 2020 10:58:29 -0700 Message-Id: <20200729175845.1745471-2-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org On non-EFI systems, it wasn't possible to test the platform firmware loader because it will have never set "checked_fw" during __init. Instead, allow the test code to override this check. Additionally split the declarations into a private header file so it there is greater enforcement of the symbol visibility. Fixes: 548193cba2a7 ("test_firmware: add support for firmware_request_platform") Cc: stable@vger.kernel.org Acked-by: Scott Branden Reviewed-by: Luis Chamberlain Signed-off-by: Kees Cook --- drivers/firmware/efi/embedded-firmware.c | 21 ++++++++++++++++----- drivers/firmware/efi/embedded-firmware.h | 21 +++++++++++++++++++++ include/linux/efi_embedded_fw.h | 13 ------------- lib/test_firmware.c | 5 +++++ 4 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 drivers/firmware/efi/embedded-firmware.h diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c index a1b199de9006..0fb03cd0a5a2 100644 --- a/drivers/firmware/efi/embedded-firmware.c +++ b/drivers/firmware/efi/embedded-firmware.c @@ -14,11 +14,22 @@ #include #include +#include "embedded-firmware.h" + +#ifdef CONFIG_TEST_FIRMWARE +# define EFI_EMBEDDED_FW_VISIBILITY +#else +# define EFI_EMBEDDED_FW_VISIBILITY static +#endif + +EFI_EMBEDDED_FW_VISIBILITY LIST_HEAD(efi_embedded_fw_list); +EFI_EMBEDDED_FW_VISIBILITY bool efi_embedded_fw_checked; + /* Exported for use by lib/test_firmware.c only */ -LIST_HEAD(efi_embedded_fw_list); +#ifdef CONFIG_TEST_FIRMWARE EXPORT_SYMBOL_GPL(efi_embedded_fw_list); - -static bool checked_for_fw; +EXPORT_SYMBOL_GPL(efi_embedded_fw_checked); +#endif static const struct dmi_system_id * const embedded_fw_table[] = { #ifdef CONFIG_TOUCHSCREEN_DMI @@ -119,14 +130,14 @@ void __init efi_check_for_embedded_firmwares(void) } } - checked_for_fw = true; + efi_embedded_fw_checked = true; } int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size) { struct efi_embedded_fw *iter, *fw = NULL; - if (!checked_for_fw) { + if (!efi_embedded_fw_checked) { pr_warn("Warning %s called while we did not check for embedded fw\n", __func__); return -ENOENT; diff --git a/drivers/firmware/efi/embedded-firmware.h b/drivers/firmware/efi/embedded-firmware.h new file mode 100644 index 000000000000..bb894eae0906 --- /dev/null +++ b/drivers/firmware/efi/embedded-firmware.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _EFI_EMBEDDED_FW_INTERNAL_H_ +#define _EFI_EMBEDDED_FW_INTERNAL_H_ + +/* + * This struct and efi_embedded_fw_list are private to the efi-embedded fw + * implementation they only in separate header for use by lib/test_firmware.c. + */ +struct efi_embedded_fw { + struct list_head list; + const char *name; + const u8 *data; + size_t length; +}; + +#ifdef CONFIG_TEST_FIRMWARE +extern struct list_head efi_embedded_fw_list; +extern bool efi_embedded_fw_checked; +#endif + +#endif /* _EFI_EMBEDDED_FW_INTERNAL_H_ */ diff --git a/include/linux/efi_embedded_fw.h b/include/linux/efi_embedded_fw.h index 57eac5241303..4ad5db9f5312 100644 --- a/include/linux/efi_embedded_fw.h +++ b/include/linux/efi_embedded_fw.h @@ -7,19 +7,6 @@ #define EFI_EMBEDDED_FW_PREFIX_LEN 8 -/* - * This struct and efi_embedded_fw_list are private to the efi-embedded fw - * implementation they are in this header for use by lib/test_firmware.c only! - */ -struct efi_embedded_fw { - struct list_head list; - const char *name; - const u8 *data; - size_t length; -}; - -extern struct list_head efi_embedded_fw_list; - /** * struct efi_embedded_fw_desc - This struct is used by the EFI embedded-fw * code to search for embedded firmwares. diff --git a/lib/test_firmware.c b/lib/test_firmware.c index 9fee2b93a8d1..62af792e151c 100644 --- a/lib/test_firmware.c +++ b/lib/test_firmware.c @@ -489,6 +489,7 @@ static ssize_t trigger_request_store(struct device *dev, static DEVICE_ATTR_WO(trigger_request); #ifdef CONFIG_EFI_EMBEDDED_FIRMWARE +#include "../drivers/firmware/efi/embedded-firmware.h" static ssize_t trigger_request_platform_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -501,6 +502,7 @@ static ssize_t trigger_request_platform_store(struct device *dev, }; struct efi_embedded_fw efi_embedded_fw; const struct firmware *firmware = NULL; + bool saved_efi_embedded_fw_checked; char *name; int rc; @@ -513,6 +515,8 @@ static ssize_t trigger_request_platform_store(struct device *dev, efi_embedded_fw.data = (void *)test_data; efi_embedded_fw.length = sizeof(test_data); list_add(&efi_embedded_fw.list, &efi_embedded_fw_list); + saved_efi_embedded_fw_checked = efi_embedded_fw_checked; + efi_embedded_fw_checked = true; pr_info("loading '%s'\n", name); rc = firmware_request_platform(&firmware, name, dev); @@ -530,6 +534,7 @@ static ssize_t trigger_request_platform_store(struct device *dev, rc = count; out: + efi_embedded_fw_checked = saved_efi_embedded_fw_checked; release_firmware(firmware); list_del(&efi_embedded_fw.list); kfree(name); From patchwork Wed Jul 29 17:58:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691573 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E1D7F913 for ; Wed, 29 Jul 2020 18:00:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C57FD2083B for ; Wed, 29 Jul 2020 18:00:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="OVFs0/QE" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727803AbgG2SAW (ORCPT ); Wed, 29 Jul 2020 14:00:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35676 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727801AbgG2R65 (ORCPT ); Wed, 29 Jul 2020 13:58:57 -0400 Received: from mail-pf1-x444.google.com (mail-pf1-x444.google.com [IPv6:2607:f8b0:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 19735C0619D6 for ; Wed, 29 Jul 2020 10:58:57 -0700 (PDT) Received: by mail-pf1-x444.google.com with SMTP id y206so3038585pfb.10 for ; Wed, 29 Jul 2020 10:58:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=sRl4ArXnrOISqSTXzK0jAGG1Z2MSdUd0jkgKdeOKsWo=; b=OVFs0/QEPGPkJIRpGLowyTSnvHw90HePMKoo09KDUP6e7gj2tShVpC/LWsDXppwrjZ 6Dm/3VqkkErwtheuMRqUDLwgcw3BdxmZnv2/Bo0jTT8K/Vgf6ykJ8fRlPb/6DX1y4gdE oV/ADepCE3C/448pcUPyBnv+OWaP0iAaVBVbI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=sRl4ArXnrOISqSTXzK0jAGG1Z2MSdUd0jkgKdeOKsWo=; b=HUeouQpeRp6GuzGn8tdfgqk0SqcPZ5NJL86/vg7MOAf9RbiAenGUA4WPBO+/EiNnf7 lWhFauZGG2npu2ZWR8oL3JxB81jE8VXBnIdZa4QYTzgg5tgBJohG518b8bLYkI5EdLkm ePSnc3f080FD+T/jsQN55RqxfDTeRsqeWk+W8tRxG5B7kzNECzFgw0WMlIchxwHigm8e LlVJV1oSgW7XglJoIhTkGhOhgUx4Z9mmNFnd50XtLdmSboyW91dnLZdWJBzt1brx51oj kFWzUvPallZag3lGVghha6W/e/3bkvpHcbAVN7KJoh2whkgFy30dsRqVLPi0aqa/SllC lDCg== X-Gm-Message-State: AOAM533eUKNwWaejDqr/riDYGLToKILNED5n4iVCZ9mJFKMORismfSrn cIQ+Q2gI3edX8rMBvnnKM96aCA== X-Google-Smtp-Source: ABdhPJz6OTbitFp/F/2/sFwilVSoYMJOcQRfio7ZcSDH8I98D5PznOsDG891T47KZvZGtlOQly4Hcw== X-Received: by 2002:a62:1713:: with SMTP id 19mr18949716pfx.115.1596045536530; Wed, 29 Jul 2020 10:58:56 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id u21sm2866085pjn.27.2020.07.29.10.58.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:53 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , stable@vger.kernel.org, Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 02/17] fs/kernel_read_file: Remove FIRMWARE_PREALLOC_BUFFER enum Date: Wed, 29 Jul 2020 10:58:30 -0700 Message-Id: <20200729175845.1745471-3-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org FIRMWARE_PREALLOC_BUFFER is a "how", not a "what", and confuses the LSMs that are interested in filtering between types of things. The "how" should be an internal detail made uninteresting to the LSMs. Fixes: a098ecd2fa7d ("firmware: support loading into a pre-allocated buffer") Fixes: fd90bc559bfb ("ima: based on policy verify firmware signatures (pre-allocated buffer)") Fixes: 4f0496d8ffa3 ("ima: based on policy warn about loading firmware (pre-allocated buffer)") Cc: stable@vger.kernel.org Acked-by: Scott Branden Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Signed-off-by: Kees Cook --- To aid in backporting, this change is made before moving kernel_read_file() to separate header/source files. --- drivers/base/firmware_loader/main.c | 5 ++--- fs/exec.c | 7 ++++--- include/linux/fs.h | 2 +- kernel/module.c | 2 +- security/integrity/digsig.c | 2 +- security/integrity/ima/ima_fs.c | 2 +- security/integrity/ima/ima_main.c | 6 ++---- 7 files changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 9da0c9d5f538..fe68ae278201 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -465,14 +465,12 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, int i, len; int rc = -ENOENT; char *path; - enum kernel_read_file_id id = READING_FIRMWARE; size_t msize = INT_MAX; void *buffer = NULL; /* Already populated data member means we're loading into a buffer */ if (!decompress && fw_priv->data) { buffer = fw_priv->data; - id = READING_FIRMWARE_PREALLOC_BUFFER; msize = fw_priv->allocated_size; } @@ -496,7 +494,8 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, /* load firmware files from the mount namespace of init */ rc = kernel_read_file_from_path_initns(path, &buffer, - &size, msize, id); + &size, msize, + READING_FIRMWARE); if (rc) { if (rc != -ENOENT) dev_warn(device, "loading %s failed with error %d\n", diff --git a/fs/exec.c b/fs/exec.c index e6e8a9a70327..2bf549757ce7 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -927,6 +927,7 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, { loff_t i_size, pos; ssize_t bytes = 0; + void *allocated = NULL; int ret; if (!S_ISREG(file_inode(file)->i_mode) || max_size < 0) @@ -950,8 +951,8 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, goto out; } - if (id != READING_FIRMWARE_PREALLOC_BUFFER) - *buf = vmalloc(i_size); + if (!*buf) + *buf = allocated = vmalloc(i_size); if (!*buf) { ret = -ENOMEM; goto out; @@ -980,7 +981,7 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, out_free: if (ret < 0) { - if (id != READING_FIRMWARE_PREALLOC_BUFFER) { + if (allocated) { vfree(*buf); *buf = NULL; } diff --git a/include/linux/fs.h b/include/linux/fs.h index f5abba86107d..f34d47ba49de 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2993,10 +2993,10 @@ static inline void i_readcount_inc(struct inode *inode) #endif extern int do_pipe_flags(int *, int); +/* This is a list of *what* is being read, not *how*. */ #define __kernel_read_file_id(id) \ id(UNKNOWN, unknown) \ id(FIRMWARE, firmware) \ - id(FIRMWARE_PREALLOC_BUFFER, firmware) \ id(FIRMWARE_EFI_EMBEDDED, firmware) \ id(MODULE, kernel-module) \ id(KEXEC_IMAGE, kexec-image) \ diff --git a/kernel/module.c b/kernel/module.c index aa183c9ac0a2..d2d12c299dd8 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3991,7 +3991,7 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) { struct load_info info = { }; loff_t size; - void *hdr; + void *hdr = NULL; int err; err = may_init_module(); diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index e9cbadade74b..ac02b7632353 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -169,7 +169,7 @@ int __init integrity_add_key(const unsigned int id, const void *data, int __init integrity_load_x509(const unsigned int id, const char *path) { - void *data; + void *data = NULL; loff_t size; int rc; key_perm_t perm; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index e3fcad871861..15a44c5022f7 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -272,7 +272,7 @@ static const struct file_operations ima_ascii_measurements_ops = { static ssize_t ima_read_policy(char *path) { - void *data; + void *data = NULL; char *datap; loff_t size; int rc, pathlen = strlen(path); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index c1583d98c5e5..f80ee4ce4669 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -611,19 +611,17 @@ void ima_post_path_mknod(struct dentry *dentry) int ima_read_file(struct file *file, enum kernel_read_file_id read_id) { /* - * READING_FIRMWARE_PREALLOC_BUFFER - * * Do devices using pre-allocated memory run the risk of the * firmware being accessible to the device prior to the completion * of IMA's signature verification any more than when using two - * buffers? + * buffers? It may be desirable to include the buffer address + * in this API and walk all the dma_map_single() mappings to check. */ return 0; } const int read_idmap[READING_MAX_ID] = { [READING_FIRMWARE] = FIRMWARE_CHECK, - [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK, [READING_MODULE] = MODULE_CHECK, [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK, [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK, From patchwork Wed Jul 29 17:58:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691577 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 54D1B6C1 for ; Wed, 29 Jul 2020 18:00:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3DD8C21883 for ; Wed, 29 Jul 2020 18:00:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="JouYoLib" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727796AbgG2SA1 (ORCPT ); Wed, 29 Jul 2020 14:00:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35672 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727098AbgG2R6z (ORCPT ); Wed, 29 Jul 2020 13:58:55 -0400 Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9BF59C0619D4 for ; Wed, 29 Jul 2020 10:58:55 -0700 (PDT) Received: by mail-pl1-x643.google.com with SMTP id k13so4339035plk.13 for ; Wed, 29 Jul 2020 10:58:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=8HjX3I6MUip4Fi6mrcrqGUTu4mjaatj7TaSRJ7Kpnbs=; b=JouYoLibHzxGq9Tia/G2XKM0Pb5E4nYUOUqYs+MPZGp5GijUgb3iUjYeu+cELUFDdt H303xAy/Z1MSIR/9N8m0lErdSoQqpTF5RIVZtd8SuoBzkXTHkDJMSLw+61XEXxzNcQZi cw+HoU5EWlrF4bw436jtimiB3q8pMUyiGckyU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=8HjX3I6MUip4Fi6mrcrqGUTu4mjaatj7TaSRJ7Kpnbs=; b=e8B7g3wio3FZeyX+Ft9klqPCm5wr6ujCktRzRiXRpixzsm083RZ6OhFaVJYsAYX+cU YZHH8um6Sv0Kb89r4XcHJOwt77qJYbOeCu1uhfpubx+wm7GusNCJQQ3LBGv65L+3pNIQ PsfZWuQ67sK13nu8E9yVdjj2LqED+gpocXKMhR2IJI2makL2KKo8vKtrkqc9j25Y3yLn pRaGc4sxNAh5LMyUvQ2cAr2A7cmpTaIItG2vm9eRgbY3RAEeXd1pWsu8ZMQxLEUodTtA p9bXVHb8A3OS6K2RtZF5BHL5yuUtx2+HD4x+nRcZnFapLMUXuk2yIfxIBnEsHe0jDIiM gzvA== X-Gm-Message-State: AOAM53347RP75iwzDQYI80sbYdyOz27K2cgm7lCcmbFmxy7yDHcY/2Lu 2X3SHIS04NBOgQ5Ia69Q30+xXw== X-Google-Smtp-Source: ABdhPJzOQSPyPPbca4bdXvhVQPbDmuxdTaAXuuAwi3ioxNYnjv4nD6uGvsUE0we+fUNaZtSsT0xvhQ== X-Received: by 2002:a17:90a:f2d7:: with SMTP id gt23mr11119581pjb.0.1596045535204; Wed, 29 Jul 2020 10:58:55 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id y196sm3166458pfc.202.2020.07.29.10.58.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:53 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , stable@vger.kernel.org, Scott Branden , Luis Chamberlain , Mimi Zohar , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 03/17] fs/kernel_read_file: Remove FIRMWARE_EFI_EMBEDDED enum Date: Wed, 29 Jul 2020 10:58:31 -0700 Message-Id: <20200729175845.1745471-4-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org The "FIRMWARE_EFI_EMBEDDED" enum is a "where", not a "what". It should not be distinguished separately from just "FIRMWARE", as this confuses the LSMs about what is being loaded. Additionally, there was no actual validation of the firmware contents happening. Fixes: e4c2c0ff00ec ("firmware: Add new platform fallback mechanism and firmware_request_platform()") Cc: stable@vger.kernel.org Acked-by: Scott Branden Reviewed-by: Luis Chamberlain Signed-off-by: Kees Cook --- To aid in backporting, this change is made before moving kernel_read_file() to separate header/source files. --- drivers/base/firmware_loader/fallback_platform.c | 2 +- include/linux/fs.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/base/firmware_loader/fallback_platform.c b/drivers/base/firmware_loader/fallback_platform.c index 685edb7dd05a..6958ab1a8059 100644 --- a/drivers/base/firmware_loader/fallback_platform.c +++ b/drivers/base/firmware_loader/fallback_platform.c @@ -17,7 +17,7 @@ int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags) if (!(opt_flags & FW_OPT_FALLBACK_PLATFORM)) return -ENOENT; - rc = security_kernel_load_data(LOADING_FIRMWARE_EFI_EMBEDDED); + rc = security_kernel_load_data(LOADING_FIRMWARE); if (rc) return rc; diff --git a/include/linux/fs.h b/include/linux/fs.h index f34d47ba49de..0d4f7aacf286 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2993,11 +2993,10 @@ static inline void i_readcount_inc(struct inode *inode) #endif extern int do_pipe_flags(int *, int); -/* This is a list of *what* is being read, not *how*. */ +/* This is a list of *what* is being read, not *how* nor *where*. */ #define __kernel_read_file_id(id) \ id(UNKNOWN, unknown) \ id(FIRMWARE, firmware) \ - id(FIRMWARE_EFI_EMBEDDED, firmware) \ id(MODULE, kernel-module) \ id(KEXEC_IMAGE, kexec-image) \ id(KEXEC_INITRAMFS, kexec-initramfs) \ From patchwork Wed Jul 29 17:58:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691553 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 32F971392 for ; Wed, 29 Jul 2020 18:00:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0D02E20838 for ; Wed, 29 Jul 2020 18:00:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="Lhc6LBu1" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727823AbgG2SAM (ORCPT ); Wed, 29 Jul 2020 14:00:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35702 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727816AbgG2R67 (ORCPT ); Wed, 29 Jul 2020 13:58:59 -0400 Received: from mail-pf1-x441.google.com (mail-pf1-x441.google.com [IPv6:2607:f8b0:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9BD90C0619E2 for ; Wed, 29 Jul 2020 10:58:58 -0700 (PDT) Received: by mail-pf1-x441.google.com with SMTP id s26so13324125pfm.4 for ; Wed, 29 Jul 2020 10:58:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=4uV1XDtVSjazxMGWXkVCcYQMNDbl2DJVvo2LtALrREA=; b=Lhc6LBu1WJJJ+87Zn0qG5QOQdj+FrzEUj6ZsFzbd4STPUPlpqtIxImFaWHFhvsZSie Qp5MPPRWGIpkQJyc0JRVUCdMLZaYFB1w90UVVn1JJ4juLpL9XtwN0VzzSUnH+fSV34HK E6lHF4oSVQOVQ0e5larml7/p1l0eaygQRJUCM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=4uV1XDtVSjazxMGWXkVCcYQMNDbl2DJVvo2LtALrREA=; b=Pm1yQyi7ADwnemVZGz31E3+Bpk/c1JvL0iTDTHn9QOwXvxOF0xAleXAkKc/ED2wBHf gPe62TUFMOwRhD0gzvUg2Rvs43VUGQOgICVa9W+sUuBPUTN7mNudtcqMTh638y3scD9p t28FgAiIO1GCKC4Oo8Tb8LOv+ZnjvyQBvc8HymeUMNZ6qWzvxC6UUGuf+gFJhHbvzqfi /XPXPDAVGJWmU7jjiGFRAvdkguZHkQ98RbwNLRBjqMkotWPkdwNrAYoSmVqhbcotk+Nw Ht3hbCSjnOqCzYaF6kLtV9AukqpHeh3TNrb/gF+/AI6mnt1HzV0QUU+oyGG0XptaVODi MbOQ== X-Gm-Message-State: AOAM5330KrHgftnbV7sVtM9c0ddLaCb43Wu/oQSYfSruFHwUKQQkrTt9 fL0S/E2OoHNGpkpGoAW3TvwDtA== X-Google-Smtp-Source: ABdhPJzCmitUK5Jw54enRFPGZe9MPAp5TN+IqzGkzP4JfNz6NYqZygd7sAETSxy3t9CLmp2mU/USdQ== X-Received: by 2002:a63:f91d:: with SMTP id h29mr30192710pgi.185.1596045537925; Wed, 29 Jul 2020 10:58:57 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id g28sm3060399pfr.70.2020.07.29.10.58.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:53 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Christoph Hellwig , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 04/17] fs/kernel_read_file: Split into separate include file Date: Wed, 29 Jul 2020 10:58:32 -0700 Message-Id: <20200729175845.1745471-5-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Scott Branden Move kernel_read_file* out of linux/fs.h to its own linux/kernel_read_file.h include file. That header gets pulled in just about everywhere and doesn't really need functions not related to the general fs interface. Suggested-by: Christoph Hellwig Signed-off-by: Scott Branden Reviewed-by: Christoph Hellwig Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20200706232309.12010-2-scott.branden@broadcom.com Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Signed-off-by: Kees Cook Acked-by: James Morris --- drivers/base/firmware_loader/main.c | 1 + fs/exec.c | 1 + include/linux/fs.h | 38 --------------------- include/linux/ima.h | 1 + include/linux/kernel_read_file.h | 51 +++++++++++++++++++++++++++++ include/linux/security.h | 1 + kernel/kexec_file.c | 1 + kernel/module.c | 1 + security/integrity/digsig.c | 1 + security/integrity/ima/ima_fs.c | 1 + security/integrity/ima/ima_main.c | 1 + security/integrity/ima/ima_policy.c | 1 + security/loadpin/loadpin.c | 1 + security/security.c | 1 + security/selinux/hooks.c | 1 + 15 files changed, 64 insertions(+), 38 deletions(-) create mode 100644 include/linux/kernel_read_file.h diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index fe68ae278201..7fd677281806 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/fs/exec.c b/fs/exec.c index 2bf549757ce7..07a7fe9ac5be 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -23,6 +23,7 @@ * formats. */ +#include #include #include #include diff --git a/include/linux/fs.h b/include/linux/fs.h index 0d4f7aacf286..76283ff04d37 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2993,44 +2993,6 @@ static inline void i_readcount_inc(struct inode *inode) #endif extern int do_pipe_flags(int *, int); -/* This is a list of *what* is being read, not *how* nor *where*. */ -#define __kernel_read_file_id(id) \ - id(UNKNOWN, unknown) \ - id(FIRMWARE, firmware) \ - id(MODULE, kernel-module) \ - id(KEXEC_IMAGE, kexec-image) \ - id(KEXEC_INITRAMFS, kexec-initramfs) \ - id(POLICY, security-policy) \ - id(X509_CERTIFICATE, x509-certificate) \ - id(MAX_ID, ) - -#define __fid_enumify(ENUM, dummy) READING_ ## ENUM, -#define __fid_stringify(dummy, str) #str, - -enum kernel_read_file_id { - __kernel_read_file_id(__fid_enumify) -}; - -static const char * const kernel_read_file_str[] = { - __kernel_read_file_id(__fid_stringify) -}; - -static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id) -{ - if ((unsigned)id >= READING_MAX_ID) - return kernel_read_file_str[READING_UNKNOWN]; - - return kernel_read_file_str[id]; -} - -extern int kernel_read_file(struct file *, void **, loff_t *, loff_t, - enum kernel_read_file_id); -extern int kernel_read_file_from_path(const char *, void **, loff_t *, loff_t, - enum kernel_read_file_id); -extern int kernel_read_file_from_path_initns(const char *, void **, loff_t *, loff_t, - enum kernel_read_file_id); -extern int kernel_read_file_from_fd(int, void **, loff_t *, loff_t, - enum kernel_read_file_id); extern ssize_t kernel_read(struct file *, void *, size_t, loff_t *); ssize_t __kernel_read(struct file *file, void *buf, size_t count, loff_t *pos); extern ssize_t kernel_write(struct file *, const void *, size_t, loff_t *); diff --git a/include/linux/ima.h b/include/linux/ima.h index 9164e1534ec9..148636bfcc8f 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -7,6 +7,7 @@ #ifndef _LINUX_IMA_H #define _LINUX_IMA_H +#include #include #include #include diff --git a/include/linux/kernel_read_file.h b/include/linux/kernel_read_file.h new file mode 100644 index 000000000000..78cf3d7dc835 --- /dev/null +++ b/include/linux/kernel_read_file.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_KERNEL_READ_FILE_H +#define _LINUX_KERNEL_READ_FILE_H + +#include +#include + +/* This is a list of *what* is being read, not *how* nor *where*. */ +#define __kernel_read_file_id(id) \ + id(UNKNOWN, unknown) \ + id(FIRMWARE, firmware) \ + id(MODULE, kernel-module) \ + id(KEXEC_IMAGE, kexec-image) \ + id(KEXEC_INITRAMFS, kexec-initramfs) \ + id(POLICY, security-policy) \ + id(X509_CERTIFICATE, x509-certificate) \ + id(MAX_ID, ) + +#define __fid_enumify(ENUM, dummy) READING_ ## ENUM, +#define __fid_stringify(dummy, str) #str, + +enum kernel_read_file_id { + __kernel_read_file_id(__fid_enumify) +}; + +static const char * const kernel_read_file_str[] = { + __kernel_read_file_id(__fid_stringify) +}; + +static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id) +{ + if ((unsigned int)id >= READING_MAX_ID) + return kernel_read_file_str[READING_UNKNOWN]; + + return kernel_read_file_str[id]; +} + +int kernel_read_file(struct file *file, + void **buf, loff_t *size, loff_t max_size, + enum kernel_read_file_id id); +int kernel_read_file_from_path(const char *path, + void **buf, loff_t *size, loff_t max_size, + enum kernel_read_file_id id); +int kernel_read_file_from_path_initns(const char *path, + void **buf, loff_t *size, loff_t max_size, + enum kernel_read_file_id id); +int kernel_read_file_from_fd(int fd, + void **buf, loff_t *size, loff_t max_size, + enum kernel_read_file_id id); + +#endif /* _LINUX_KERNEL_READ_FILE_H */ diff --git a/include/linux/security.h b/include/linux/security.h index 0a0a03b36a3b..42df0d9b4c37 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -23,6 +23,7 @@ #ifndef __LINUX_SECURITY_H #define __LINUX_SECURITY_H +#include #include #include #include diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 09cc78df53c6..1358069ce9e9 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "kexec_internal.h" diff --git a/kernel/module.c b/kernel/module.c index d2d12c299dd8..cc8d83841568 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index ac02b7632353..f8869be45d8f 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 15a44c5022f7..e13ffece3726 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index f80ee4ce4669..dab4a13221cf 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index e493063a3c34..f8390f6081f0 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index ee5cb944f4ad..81bc95127f92 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include diff --git a/security/security.c b/security/security.c index 70a7ad357bc6..19d3150f68f4 100644 --- a/security/security.c +++ b/security/security.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index efa6108b1ce9..5de45010fb1a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include From patchwork Wed Jul 29 17:58:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691549 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 62BEF1392 for ; Wed, 29 Jul 2020 18:00:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 47FB520809 for ; Wed, 29 Jul 2020 18:00:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="Uy1qxMG9" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727840AbgG2SAF (ORCPT ); Wed, 29 Jul 2020 14:00:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35688 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727837AbgG2R7A (ORCPT ); Wed, 29 Jul 2020 13:59:00 -0400 Received: from mail-pl1-x641.google.com (mail-pl1-x641.google.com [IPv6:2607:f8b0:4864:20::641]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 44273C0619D5 for ; Wed, 29 Jul 2020 10:59:00 -0700 (PDT) Received: by mail-pl1-x641.google.com with SMTP id o1so12168041plk.1 for ; Wed, 29 Jul 2020 10:59:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=s8pBSpCBzAxEXSHFMED25Y5ODq87rGH8b/wr0X9QC7I=; b=Uy1qxMG9Wk7KhOJd3h1FBwTDF5og6PjBAQI16Z27ZpZm2EIrFW3BdRtpDli8mZi1t6 2NNjargrYHFlYLP8pNZ29iVEsGle8JrqmrtsHwy/+EiM9ae/EoP6+HBD5yz/FBTmfY5o YT+z+TKhc/UG0zOYcimMA/QrptC9N69IWpT60= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=s8pBSpCBzAxEXSHFMED25Y5ODq87rGH8b/wr0X9QC7I=; b=G8ro70sK0acA2le7rNL/P9jfvKKUIC7o1K/TTxRoyClkYFHt8UWBpzQJjdtPyJJ7RK CZrMFM47dUhsUZtFNRuB8EZ+Ig/Uz+I9QHcsOvnIcICT8U/JQXySFkSQO+o+nS08PuGC w9gjJ65BrZbSnSuMxIl+V4nQLBQM0p/5okAV4Kr9EsYeQY9kG3nJzKkqhhhA1yKvodEI 3g0kd7ohBEvCQ/zg2niK/xJlzXx7iqNgCgG2pMg5g62DHZUZo/xcIrR1KhrE8t7b5Ecu AyRBZl+Wy3o91IOpCK6huFZqcylNxDgp1Eo6xIm/XBDge95P7LexoDw45jOE0pALIcb+ 2kQA== X-Gm-Message-State: AOAM531XyNNRNoW9OQbKvi2/0YeKnuJA6BV5Xhu+E7AtbJdocF5MY1qk IvI2IcPs4IGGgX7UqqRbdagTtA== X-Google-Smtp-Source: ABdhPJzo9IxoT9gvuXx2GpK4yoZzBFJYjOX4Gn6EU8vWiGKG8RTXVOjsQFEjv28d+YZFT5W01YafVw== X-Received: by 2002:a17:902:7086:: with SMTP id z6mr27406701plk.4.1596045539786; Wed, 29 Jul 2020 10:58:59 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id u2sm3138576pfl.21.2020.07.29.10.58.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:58 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 05/17] fs/kernel_read_file: Split into separate source file Date: Wed, 29 Jul 2020 10:58:33 -0700 Message-Id: <20200729175845.1745471-6-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org These routines are used in places outside of exec(2), so in preparation for refactoring them, move them into a separate source file, fs/kernel_read_file.c. Acked-by: Scott Branden Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Signed-off-by: Kees Cook --- fs/Makefile | 3 +- fs/exec.c | 132 ---------------------------------------- fs/kernel_read_file.c | 138 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 133 deletions(-) create mode 100644 fs/kernel_read_file.c diff --git a/fs/Makefile b/fs/Makefile index 2ce5112b02c8..a05fc247b2a7 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -13,7 +13,8 @@ obj-y := open.o read_write.o file_table.o super.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ pnode.o splice.o sync.o utimes.o d_path.o \ stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \ - fs_types.o fs_context.o fs_parser.o fsopen.o + fs_types.o fs_context.o fs_parser.o fsopen.o \ + kernel_read_file.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o block_dev.o direct-io.o mpage.o diff --git a/fs/exec.c b/fs/exec.c index 07a7fe9ac5be..d619b79aab30 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -923,138 +923,6 @@ struct file *open_exec(const char *name) } EXPORT_SYMBOL(open_exec); -int kernel_read_file(struct file *file, void **buf, loff_t *size, - loff_t max_size, enum kernel_read_file_id id) -{ - loff_t i_size, pos; - ssize_t bytes = 0; - void *allocated = NULL; - int ret; - - if (!S_ISREG(file_inode(file)->i_mode) || max_size < 0) - return -EINVAL; - - ret = deny_write_access(file); - if (ret) - return ret; - - ret = security_kernel_read_file(file, id); - if (ret) - goto out; - - i_size = i_size_read(file_inode(file)); - if (i_size <= 0) { - ret = -EINVAL; - goto out; - } - if (i_size > SIZE_MAX || (max_size > 0 && i_size > max_size)) { - ret = -EFBIG; - goto out; - } - - if (!*buf) - *buf = allocated = vmalloc(i_size); - if (!*buf) { - ret = -ENOMEM; - goto out; - } - - pos = 0; - while (pos < i_size) { - bytes = kernel_read(file, *buf + pos, i_size - pos, &pos); - if (bytes < 0) { - ret = bytes; - goto out_free; - } - - if (bytes == 0) - break; - } - - if (pos != i_size) { - ret = -EIO; - goto out_free; - } - - ret = security_kernel_post_read_file(file, *buf, i_size, id); - if (!ret) - *size = pos; - -out_free: - if (ret < 0) { - if (allocated) { - vfree(*buf); - *buf = NULL; - } - } - -out: - allow_write_access(file); - return ret; -} -EXPORT_SYMBOL_GPL(kernel_read_file); - -int kernel_read_file_from_path(const char *path, void **buf, loff_t *size, - loff_t max_size, enum kernel_read_file_id id) -{ - struct file *file; - int ret; - - if (!path || !*path) - return -EINVAL; - - file = filp_open(path, O_RDONLY, 0); - if (IS_ERR(file)) - return PTR_ERR(file); - - ret = kernel_read_file(file, buf, size, max_size, id); - fput(file); - return ret; -} -EXPORT_SYMBOL_GPL(kernel_read_file_from_path); - -int kernel_read_file_from_path_initns(const char *path, void **buf, - loff_t *size, loff_t max_size, - enum kernel_read_file_id id) -{ - struct file *file; - struct path root; - int ret; - - if (!path || !*path) - return -EINVAL; - - task_lock(&init_task); - get_fs_root(init_task.fs, &root); - task_unlock(&init_task); - - file = file_open_root(root.dentry, root.mnt, path, O_RDONLY, 0); - path_put(&root); - if (IS_ERR(file)) - return PTR_ERR(file); - - ret = kernel_read_file(file, buf, size, max_size, id); - fput(file); - return ret; -} -EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns); - -int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size, - enum kernel_read_file_id id) -{ - struct fd f = fdget(fd); - int ret = -EBADF; - - if (!f.file) - goto out; - - ret = kernel_read_file(f.file, buf, size, max_size, id); -out: - fdput(f); - return ret; -} -EXPORT_SYMBOL_GPL(kernel_read_file_from_fd); - #if defined(CONFIG_HAVE_AOUT) || defined(CONFIG_BINFMT_FLAT) || \ defined(CONFIG_BINFMT_ELF_FDPIC) ssize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len) diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c new file mode 100644 index 000000000000..54d972d4befc --- /dev/null +++ b/fs/kernel_read_file.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include + +int kernel_read_file(struct file *file, void **buf, loff_t *size, + loff_t max_size, enum kernel_read_file_id id) +{ + loff_t i_size, pos; + ssize_t bytes = 0; + void *allocated = NULL; + int ret; + + if (!S_ISREG(file_inode(file)->i_mode) || max_size < 0) + return -EINVAL; + + ret = deny_write_access(file); + if (ret) + return ret; + + ret = security_kernel_read_file(file, id); + if (ret) + goto out; + + i_size = i_size_read(file_inode(file)); + if (i_size <= 0) { + ret = -EINVAL; + goto out; + } + if (i_size > SIZE_MAX || (max_size > 0 && i_size > max_size)) { + ret = -EFBIG; + goto out; + } + + if (!*buf) + *buf = allocated = vmalloc(i_size); + if (!*buf) { + ret = -ENOMEM; + goto out; + } + + pos = 0; + while (pos < i_size) { + bytes = kernel_read(file, *buf + pos, i_size - pos, &pos); + if (bytes < 0) { + ret = bytes; + goto out_free; + } + + if (bytes == 0) + break; + } + + if (pos != i_size) { + ret = -EIO; + goto out_free; + } + + ret = security_kernel_post_read_file(file, *buf, i_size, id); + if (!ret) + *size = pos; + +out_free: + if (ret < 0) { + if (allocated) { + vfree(*buf); + *buf = NULL; + } + } + +out: + allow_write_access(file); + return ret; +} +EXPORT_SYMBOL_GPL(kernel_read_file); + +int kernel_read_file_from_path(const char *path, void **buf, loff_t *size, + loff_t max_size, enum kernel_read_file_id id) +{ + struct file *file; + int ret; + + if (!path || !*path) + return -EINVAL; + + file = filp_open(path, O_RDONLY, 0); + if (IS_ERR(file)) + return PTR_ERR(file); + + ret = kernel_read_file(file, buf, size, max_size, id); + fput(file); + return ret; +} +EXPORT_SYMBOL_GPL(kernel_read_file_from_path); + +int kernel_read_file_from_path_initns(const char *path, void **buf, + loff_t *size, loff_t max_size, + enum kernel_read_file_id id) +{ + struct file *file; + struct path root; + int ret; + + if (!path || !*path) + return -EINVAL; + + task_lock(&init_task); + get_fs_root(init_task.fs, &root); + task_unlock(&init_task); + + file = file_open_root(root.dentry, root.mnt, path, O_RDONLY, 0); + path_put(&root); + if (IS_ERR(file)) + return PTR_ERR(file); + + ret = kernel_read_file(file, buf, size, max_size, id); + fput(file); + return ret; +} +EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns); + +int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size, + enum kernel_read_file_id id) +{ + struct fd f = fdget(fd); + int ret = -EBADF; + + if (!f.file) + goto out; + + ret = kernel_read_file(f.file, buf, size, max_size, id); +out: + fdput(f); + return ret; +} +EXPORT_SYMBOL_GPL(kernel_read_file_from_fd); From patchwork Wed Jul 29 17:58:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691503 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 07C2A913 for ; Wed, 29 Jul 2020 17:59:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DA6802083B for ; Wed, 29 Jul 2020 17:59:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="UzScXCUf" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727898AbgG2R7F (ORCPT ); Wed, 29 Jul 2020 13:59:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35710 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727854AbgG2R7B (ORCPT ); Wed, 29 Jul 2020 13:59:01 -0400 Received: from mail-pj1-x1044.google.com (mail-pj1-x1044.google.com [IPv6:2607:f8b0:4864:20::1044]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DA37FC0619DD for ; Wed, 29 Jul 2020 10:59:00 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id k1so2233400pjt.5 for ; Wed, 29 Jul 2020 10:59:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Jj3CP3i5cgoxLiTKNpwRPq3sBRUYUJpaElXSIRjx/rQ=; b=UzScXCUfDVXTTBp5qy4zl1tY00zoFCZD/2tBzyBIXR7dGtL79z7icddeT2H6hFIVfj 0s/jzv57HN1dgxIt4UC65BpzhrpbqPxKwQ5PXEp7Sp8A0vy/D9/0IwtAZaAek26x5MA1 xaB+FTZ2anX1w3P3Iz09bEVIub1yrVIdrQP2U= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Jj3CP3i5cgoxLiTKNpwRPq3sBRUYUJpaElXSIRjx/rQ=; b=imuI09PxswGI5I+Y/RPZYRimrquc1E87BBITpFRi2yYpErCA6AsVySsAyhLPEOPyUo ouPo4nIwVRwSZo1P0FDv+7XTIp737i9MJ+725zdHkwrSutHfiG3f0aXXJYXCfRWLKZac BF/8rwyQ9bYSD+HOp2p4mVUvYaztcp8JyY9Q/Ij3NxynOCqAaEY1sFzbdjNGGrVbPFfH qjYwJAU5pKiNXskiibLU3Y4codAyfYgx31HUC+e0gXCSfN3ZDu2+GBTexjs0Ssleen9j 2q/E/umy6KJNs75v65hVcL+CBug9E/17btVKjfP6WA8B31GAIuqhNcpKtDhV2oKU4FJk A59w== X-Gm-Message-State: AOAM533m+ujn4VyT3Sajv3xFlXOnyFV9/yiItjxtWy5FOKXGmw7QOWSF VYW2bnYFgYeA0f61Mwv4heCcEQ== X-Google-Smtp-Source: ABdhPJwEb6H8zu/aaMoTf0U6bEuNVQmzJSRKxIr0X80bcUmeTmexwxEl2CPjvVEZamIB3wn+HipEdw== X-Received: by 2002:a17:902:8e87:: with SMTP id bg7mr28468621plb.19.1596045540322; Wed, 29 Jul 2020 10:59:00 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id v128sm942299pfc.14.2020.07.29.10.58.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:58 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 06/17] fs/kernel_read_file: Remove redundant size argument Date: Wed, 29 Jul 2020 10:58:34 -0700 Message-Id: <20200729175845.1745471-7-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org In preparation for refactoring kernel_read_file*(), remove the redundant "size" argument which is not needed: it can be included in the return code, with callers adjusted. (VFS reads already cannot be larger than INT_MAX.) Acked-by: Scott Branden Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Signed-off-by: Kees Cook Reviewed-by: James Morris --- drivers/base/firmware_loader/main.c | 10 ++++++---- fs/kernel_read_file.c | 20 +++++++++----------- include/linux/kernel_read_file.h | 8 ++++---- kernel/kexec_file.c | 14 +++++++------- kernel/module.c | 7 +++---- security/integrity/digsig.c | 5 +++-- security/integrity/ima/ima_fs.c | 6 ++++-- 7 files changed, 36 insertions(+), 34 deletions(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 7fd677281806..9b425437afe6 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -462,7 +462,7 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, size_t in_size, const void *in_buffer)) { - loff_t size; + size_t size; int i, len; int rc = -ENOENT; char *path; @@ -494,10 +494,9 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, fw_priv->size = 0; /* load firmware files from the mount namespace of init */ - rc = kernel_read_file_from_path_initns(path, &buffer, - &size, msize, + rc = kernel_read_file_from_path_initns(path, &buffer, msize, READING_FIRMWARE); - if (rc) { + if (rc < 0) { if (rc != -ENOENT) dev_warn(device, "loading %s failed with error %d\n", path, rc); @@ -506,6 +505,9 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, path); continue; } + size = rc; + rc = 0; + dev_dbg(device, "Loading firmware from %s\n", path); if (decompress) { dev_dbg(device, "f/w decompressing %s\n", diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c index 54d972d4befc..dc28a8def597 100644 --- a/fs/kernel_read_file.c +++ b/fs/kernel_read_file.c @@ -5,7 +5,7 @@ #include #include -int kernel_read_file(struct file *file, void **buf, loff_t *size, +int kernel_read_file(struct file *file, void **buf, loff_t max_size, enum kernel_read_file_id id) { loff_t i_size, pos; @@ -29,7 +29,7 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, ret = -EINVAL; goto out; } - if (i_size > SIZE_MAX || (max_size > 0 && i_size > max_size)) { + if (i_size > INT_MAX || (max_size > 0 && i_size > max_size)) { ret = -EFBIG; goto out; } @@ -59,8 +59,6 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, } ret = security_kernel_post_read_file(file, *buf, i_size, id); - if (!ret) - *size = pos; out_free: if (ret < 0) { @@ -72,11 +70,11 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, out: allow_write_access(file); - return ret; + return ret == 0 ? pos : ret; } EXPORT_SYMBOL_GPL(kernel_read_file); -int kernel_read_file_from_path(const char *path, void **buf, loff_t *size, +int kernel_read_file_from_path(const char *path, void **buf, loff_t max_size, enum kernel_read_file_id id) { struct file *file; @@ -89,14 +87,14 @@ int kernel_read_file_from_path(const char *path, void **buf, loff_t *size, if (IS_ERR(file)) return PTR_ERR(file); - ret = kernel_read_file(file, buf, size, max_size, id); + ret = kernel_read_file(file, buf, max_size, id); fput(file); return ret; } EXPORT_SYMBOL_GPL(kernel_read_file_from_path); int kernel_read_file_from_path_initns(const char *path, void **buf, - loff_t *size, loff_t max_size, + loff_t max_size, enum kernel_read_file_id id) { struct file *file; @@ -115,13 +113,13 @@ int kernel_read_file_from_path_initns(const char *path, void **buf, if (IS_ERR(file)) return PTR_ERR(file); - ret = kernel_read_file(file, buf, size, max_size, id); + ret = kernel_read_file(file, buf, max_size, id); fput(file); return ret; } EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns); -int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size, +int kernel_read_file_from_fd(int fd, void **buf, loff_t max_size, enum kernel_read_file_id id) { struct fd f = fdget(fd); @@ -130,7 +128,7 @@ int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size, if (!f.file) goto out; - ret = kernel_read_file(f.file, buf, size, max_size, id); + ret = kernel_read_file(f.file, buf, max_size, id); out: fdput(f); return ret; diff --git a/include/linux/kernel_read_file.h b/include/linux/kernel_read_file.h index 78cf3d7dc835..0ca0bdbed1bd 100644 --- a/include/linux/kernel_read_file.h +++ b/include/linux/kernel_read_file.h @@ -36,16 +36,16 @@ static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id) } int kernel_read_file(struct file *file, - void **buf, loff_t *size, loff_t max_size, + void **buf, loff_t max_size, enum kernel_read_file_id id); int kernel_read_file_from_path(const char *path, - void **buf, loff_t *size, loff_t max_size, + void **buf, loff_t max_size, enum kernel_read_file_id id); int kernel_read_file_from_path_initns(const char *path, - void **buf, loff_t *size, loff_t max_size, + void **buf, loff_t max_size, enum kernel_read_file_id id); int kernel_read_file_from_fd(int fd, - void **buf, loff_t *size, loff_t max_size, + void **buf, loff_t max_size, enum kernel_read_file_id id); #endif /* _LINUX_KERNEL_READ_FILE_H */ diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 1358069ce9e9..eda19ca256a3 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -220,13 +220,12 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, { int ret; void *ldata; - loff_t size; ret = kernel_read_file_from_fd(kernel_fd, &image->kernel_buf, - &size, INT_MAX, READING_KEXEC_IMAGE); - if (ret) + INT_MAX, READING_KEXEC_IMAGE); + if (ret < 0) return ret; - image->kernel_buf_len = size; + image->kernel_buf_len = ret; /* Call arch image probe handlers */ ret = arch_kexec_kernel_image_probe(image, image->kernel_buf, @@ -243,11 +242,12 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, /* It is possible that there no initramfs is being loaded */ if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { ret = kernel_read_file_from_fd(initrd_fd, &image->initrd_buf, - &size, INT_MAX, + INT_MAX, READING_KEXEC_INITRAMFS); - if (ret) + if (ret < 0) goto out; - image->initrd_buf_len = size; + image->initrd_buf_len = ret; + ret = 0; } if (cmdline_len) { diff --git a/kernel/module.c b/kernel/module.c index cc8d83841568..0792ce3bf643 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3991,7 +3991,6 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) { struct load_info info = { }; - loff_t size; void *hdr = NULL; int err; @@ -4005,12 +4004,12 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) |MODULE_INIT_IGNORE_VERMAGIC)) return -EINVAL; - err = kernel_read_file_from_fd(fd, &hdr, &size, INT_MAX, + err = kernel_read_file_from_fd(fd, &hdr, INT_MAX, READING_MODULE); - if (err) + if (err < 0) return err; info.hdr = hdr; - info.len = size; + info.len = err; return load_module(&info, uargs, flags); } diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index f8869be45d8f..97661ffabc4e 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -171,16 +171,17 @@ int __init integrity_add_key(const unsigned int id, const void *data, int __init integrity_load_x509(const unsigned int id, const char *path) { void *data = NULL; - loff_t size; + size_t size; int rc; key_perm_t perm; - rc = kernel_read_file_from_path(path, &data, &size, 0, + rc = kernel_read_file_from_path(path, &data, 0, READING_X509_CERTIFICATE); if (rc < 0) { pr_err("Unable to open file: %s (%d)", path, rc); return rc; } + size = rc; perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index e13ffece3726..602f52717757 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -275,7 +275,7 @@ static ssize_t ima_read_policy(char *path) { void *data = NULL; char *datap; - loff_t size; + size_t size; int rc, pathlen = strlen(path); char *p; @@ -284,11 +284,13 @@ static ssize_t ima_read_policy(char *path) datap = path; strsep(&datap, "\n"); - rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY); + rc = kernel_read_file_from_path(path, &data, 0, READING_POLICY); if (rc < 0) { pr_err("Unable to open file: %s (%d)", path, rc); return rc; } + size = rc; + rc = 0; datap = data; while (size > 0 && (p = strsep(&datap, "\n"))) { From patchwork Wed Jul 29 17:58:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691533 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 75CFD913 for ; Wed, 29 Jul 2020 17:59:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5D1C82084D for ; Wed, 29 Jul 2020 17:59:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="BmjVjoWK" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727877AbgG2R76 (ORCPT ); Wed, 29 Jul 2020 13:59:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35682 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727871AbgG2R7C (ORCPT ); Wed, 29 Jul 2020 13:59:02 -0400 Received: from mail-pg1-x544.google.com (mail-pg1-x544.google.com [IPv6:2607:f8b0:4864:20::544]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6642EC08C5C0 for ; Wed, 29 Jul 2020 10:59:02 -0700 (PDT) Received: by mail-pg1-x544.google.com with SMTP id z5so14684594pgb.6 for ; Wed, 29 Jul 2020 10:59:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=8FXcJVqBHjcgT1Agm86XnnWSLKBXkfAqvFnOxkisTqQ=; b=BmjVjoWKA8kMgg8+hHzQgXql4nM5ujsG2sEYnBcdy7xaNlTgyBePPNTGBEbQ6MDFV1 d6Y9Z0cuDbncD+mzS7Rl6gxkg/qiz/DE9kVm7QK1iCHYoKpCxAHaYXBt+o9T0bXhMFay k2FzeyjXJC9jz/eqoAjjdLxVY02VrroizS3K8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=8FXcJVqBHjcgT1Agm86XnnWSLKBXkfAqvFnOxkisTqQ=; b=D5eh+rpC/LgWHQ+UvLVFc1xDaOf2gzFI+5/hoaWG70oGiRHgQiZ/LIUwst9qfFctma +mWetUbZUvW8HwT1kqhTwiFAWfV8jc25mDIzLctvwakwQ2a3wEm0VlDN27hpPOf9pJwn HQ/oT17T2NXZBmHYZygYBGA6fPTpYBbZ+g+HRl/mwQpy8SmSRSYRXGUphI4Puu8hoDpL 7q/wvTpHkivJT/oJ6hy0lzeu/XOHlrNEcBDmICLPIujPpLsj1FBzINXFDij8b/EmktgF 4d68YsMtvQG7fl0ba0A2zVG3ekbMZR2bqfSxAcsVPffHxPxkujfjHv4LLXnBXsr/tTVT o2cA== X-Gm-Message-State: AOAM530Xgk6tGVzj2nPYZSba8yBMpbGwPL8YNvyQwBCZf/mlSC3a2qE8 ZIhdnWdmne2PCJoAIWNPrSbi7A== X-Google-Smtp-Source: ABdhPJx8EX4pc8bYnKpIrYzoFGT5+7PS/5s/buTOZrRuN/iRGO620gNUO5macxBQPeRbg/cVCrULPg== X-Received: by 2002:a05:6a00:7ca:: with SMTP id n10mr18901795pfu.129.1596045541943; Wed, 29 Jul 2020 10:59:01 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id l16sm2981366pff.167.2020.07.29.10.58.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:58 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 07/17] fs/kernel_read_file: Switch buffer size arg to size_t Date: Wed, 29 Jul 2020 10:58:35 -0700 Message-Id: <20200729175845.1745471-8-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org In preparation for further refactoring of kernel_read_file*(), rename the "max_size" argument to the more accurate "buf_size", and correct its type to size_t. Add kerndoc to explain the specifics of how the arguments will be used. Note that with buf_size now size_t, it can no longer be negative (and was never called with a negative value). Adjust callers to use it as a "maximum size" when *buf is NULL. Acked-by: Scott Branden Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Signed-off-by: Kees Cook Reviewed-by: James Morris --- fs/kernel_read_file.c | 34 +++++++++++++++++++++++--------- include/linux/kernel_read_file.h | 8 ++++---- security/integrity/digsig.c | 2 +- security/integrity/ima/ima_fs.c | 2 +- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c index dc28a8def597..e21a76001fff 100644 --- a/fs/kernel_read_file.c +++ b/fs/kernel_read_file.c @@ -5,15 +5,31 @@ #include #include +/** + * kernel_read_file() - read file contents into a kernel buffer + * + * @file file to read from + * @buf pointer to a "void *" buffer for reading into (if + * *@buf is NULL, a buffer will be allocated, and + * @buf_size will be ignored) + * @buf_size size of buf, if already allocated. If @buf not + * allocated, this is the largest size to allocate. + * @id the kernel_read_file_id identifying the type of + * file contents being read (for LSMs to examine) + * + * Returns number of bytes read (no single read will be bigger + * than INT_MAX), or negative on error. + * + */ int kernel_read_file(struct file *file, void **buf, - loff_t max_size, enum kernel_read_file_id id) + size_t buf_size, enum kernel_read_file_id id) { loff_t i_size, pos; ssize_t bytes = 0; void *allocated = NULL; int ret; - if (!S_ISREG(file_inode(file)->i_mode) || max_size < 0) + if (!S_ISREG(file_inode(file)->i_mode)) return -EINVAL; ret = deny_write_access(file); @@ -29,7 +45,7 @@ int kernel_read_file(struct file *file, void **buf, ret = -EINVAL; goto out; } - if (i_size > INT_MAX || (max_size > 0 && i_size > max_size)) { + if (i_size > INT_MAX || i_size > buf_size) { ret = -EFBIG; goto out; } @@ -75,7 +91,7 @@ int kernel_read_file(struct file *file, void **buf, EXPORT_SYMBOL_GPL(kernel_read_file); int kernel_read_file_from_path(const char *path, void **buf, - loff_t max_size, enum kernel_read_file_id id) + size_t buf_size, enum kernel_read_file_id id) { struct file *file; int ret; @@ -87,14 +103,14 @@ int kernel_read_file_from_path(const char *path, void **buf, if (IS_ERR(file)) return PTR_ERR(file); - ret = kernel_read_file(file, buf, max_size, id); + ret = kernel_read_file(file, buf, buf_size, id); fput(file); return ret; } EXPORT_SYMBOL_GPL(kernel_read_file_from_path); int kernel_read_file_from_path_initns(const char *path, void **buf, - loff_t max_size, + size_t buf_size, enum kernel_read_file_id id) { struct file *file; @@ -113,13 +129,13 @@ int kernel_read_file_from_path_initns(const char *path, void **buf, if (IS_ERR(file)) return PTR_ERR(file); - ret = kernel_read_file(file, buf, max_size, id); + ret = kernel_read_file(file, buf, buf_size, id); fput(file); return ret; } EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns); -int kernel_read_file_from_fd(int fd, void **buf, loff_t max_size, +int kernel_read_file_from_fd(int fd, void **buf, size_t buf_size, enum kernel_read_file_id id) { struct fd f = fdget(fd); @@ -128,7 +144,7 @@ int kernel_read_file_from_fd(int fd, void **buf, loff_t max_size, if (!f.file) goto out; - ret = kernel_read_file(f.file, buf, max_size, id); + ret = kernel_read_file(f.file, buf, buf_size, id); out: fdput(f); return ret; diff --git a/include/linux/kernel_read_file.h b/include/linux/kernel_read_file.h index 0ca0bdbed1bd..910039e7593e 100644 --- a/include/linux/kernel_read_file.h +++ b/include/linux/kernel_read_file.h @@ -36,16 +36,16 @@ static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id) } int kernel_read_file(struct file *file, - void **buf, loff_t max_size, + void **buf, size_t buf_size, enum kernel_read_file_id id); int kernel_read_file_from_path(const char *path, - void **buf, loff_t max_size, + void **buf, size_t buf_size, enum kernel_read_file_id id); int kernel_read_file_from_path_initns(const char *path, - void **buf, loff_t max_size, + void **buf, size_t buf_size, enum kernel_read_file_id id); int kernel_read_file_from_fd(int fd, - void **buf, loff_t max_size, + void **buf, size_t buf_size, enum kernel_read_file_id id); #endif /* _LINUX_KERNEL_READ_FILE_H */ diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 97661ffabc4e..04f779c4f5ed 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -175,7 +175,7 @@ int __init integrity_load_x509(const unsigned int id, const char *path) int rc; key_perm_t perm; - rc = kernel_read_file_from_path(path, &data, 0, + rc = kernel_read_file_from_path(path, &data, INT_MAX, READING_X509_CERTIFICATE); if (rc < 0) { pr_err("Unable to open file: %s (%d)", path, rc); diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 602f52717757..692b83e82edf 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -284,7 +284,7 @@ static ssize_t ima_read_policy(char *path) datap = path; strsep(&datap, "\n"); - rc = kernel_read_file_from_path(path, &data, 0, READING_POLICY); + rc = kernel_read_file_from_path(path, &data, INT_MAX, READING_POLICY); if (rc < 0) { pr_err("Unable to open file: %s (%d)", path, rc); return rc; From patchwork Wed Jul 29 17:58:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691457 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 724361392 for ; Wed, 29 Jul 2020 17:59:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5B8E92083B for ; Wed, 29 Jul 2020 17:59:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="cfJA1yoL" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727909AbgG2R7F (ORCPT ); Wed, 29 Jul 2020 13:59:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35676 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727865AbgG2R7C (ORCPT ); Wed, 29 Jul 2020 13:59:02 -0400 Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C5DFDC0619E2 for ; Wed, 29 Jul 2020 10:59:01 -0700 (PDT) Received: by mail-pl1-x643.google.com with SMTP id k13so4339185plk.13 for ; Wed, 29 Jul 2020 10:59:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=jU2VJx8QGZyxpfIxF1fo6TrEFAt4UxU1npx7vrAKnZ8=; b=cfJA1yoLRS1EuKB6SD/UZbVHyHN2opnYoF3ty8DxzWqNZIqnI10tluoUMCaXOaLBuQ +UqNF0lhPk6ughdqC/jshZTZ0iLCkahWZgnil8QJ2Q/jgcCqlWZN9Ehlh1yFsO8+qmhK xWfmFj9xY99va9E6S8WpZMcLDlcIrEat3nR7o= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=jU2VJx8QGZyxpfIxF1fo6TrEFAt4UxU1npx7vrAKnZ8=; b=RSN8u2txTj73sN7cBuiW1J5TsrQPxT+/E95Kx5BAvNw/06+raY+aBIs9k/+G/unur1 ZpxaHovHlIArQShYWQhblylrI6yL4yDrcTGnRoCsN7/I5SKHzZiqdTQ79mYiWgcI38oj Ep39zcPc/TEg2tg5/zxeCBJ9tZNCbhnuTWbbe2STe9fcSt5Tq/ZXa6AXu4F1G+MKYrcf Uq15FMBLLEQwz7aPboHxeYIgHYaguEN4MlpVyON8UEg/4Nf+4QW55Waro9ApXrno6ZUD qh9X+p0om4+H1iDsM7TeiSYDm87MrtpwYETICDp3wc+UOmDV4Ct6ZldAO21CAD5WzEs3 oN0A== X-Gm-Message-State: AOAM531aH7ZWveTWCxZuuYb+qEtdzlnUaQQuTaQqYW5wkN8fcvuopHTX xCRSPZ2D1gCyM0qoE1tqQeH7SA== X-Google-Smtp-Source: ABdhPJy6PwoNCyC8rVomCYFtW5CtQ1E6nIw60akd0htXreCsvmisuIrvcMKK3sC9okq9AG7t/KI7oA== X-Received: by 2002:a17:902:ea8c:: with SMTP id x12mr15675315plb.60.1596045541329; Wed, 29 Jul 2020 10:59:01 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id z13sm3142496pfq.220.2020.07.29.10.58.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:58 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 08/17] fs/kernel_read_file: Add file_size output argument Date: Wed, 29 Jul 2020 10:58:36 -0700 Message-Id: <20200729175845.1745471-9-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org In preparation for adding partial read support, add an optional output argument to kernel_read_file*() that reports the file size so callers can reason more easily about their reading progress. Acked-by: Scott Branden Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Signed-off-by: Kees Cook Reviewed-by: James Morris --- drivers/base/firmware_loader/main.c | 1 + fs/kernel_read_file.c | 19 +++++++++++++------ include/linux/kernel_read_file.h | 4 ++++ kernel/kexec_file.c | 4 ++-- kernel/module.c | 2 +- security/integrity/digsig.c | 2 +- security/integrity/ima/ima_fs.c | 2 +- 7 files changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 9b425437afe6..6a5d407279e3 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -495,6 +495,7 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, /* load firmware files from the mount namespace of init */ rc = kernel_read_file_from_path_initns(path, &buffer, msize, + NULL, READING_FIRMWARE); if (rc < 0) { if (rc != -ENOENT) diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c index e21a76001fff..2e29c38eb4df 100644 --- a/fs/kernel_read_file.c +++ b/fs/kernel_read_file.c @@ -14,6 +14,8 @@ * @buf_size will be ignored) * @buf_size size of buf, if already allocated. If @buf not * allocated, this is the largest size to allocate. + * @file_size if non-NULL, the full size of @file will be + * written here. * @id the kernel_read_file_id identifying the type of * file contents being read (for LSMs to examine) * @@ -22,7 +24,8 @@ * */ int kernel_read_file(struct file *file, void **buf, - size_t buf_size, enum kernel_read_file_id id) + size_t buf_size, size_t *file_size, + enum kernel_read_file_id id) { loff_t i_size, pos; ssize_t bytes = 0; @@ -49,6 +52,8 @@ int kernel_read_file(struct file *file, void **buf, ret = -EFBIG; goto out; } + if (file_size) + *file_size = i_size; if (!*buf) *buf = allocated = vmalloc(i_size); @@ -91,7 +96,8 @@ int kernel_read_file(struct file *file, void **buf, EXPORT_SYMBOL_GPL(kernel_read_file); int kernel_read_file_from_path(const char *path, void **buf, - size_t buf_size, enum kernel_read_file_id id) + size_t buf_size, size_t *file_size, + enum kernel_read_file_id id) { struct file *file; int ret; @@ -103,14 +109,14 @@ int kernel_read_file_from_path(const char *path, void **buf, if (IS_ERR(file)) return PTR_ERR(file); - ret = kernel_read_file(file, buf, buf_size, id); + ret = kernel_read_file(file, buf, buf_size, file_size, id); fput(file); return ret; } EXPORT_SYMBOL_GPL(kernel_read_file_from_path); int kernel_read_file_from_path_initns(const char *path, void **buf, - size_t buf_size, + size_t buf_size, size_t *file_size, enum kernel_read_file_id id) { struct file *file; @@ -129,13 +135,14 @@ int kernel_read_file_from_path_initns(const char *path, void **buf, if (IS_ERR(file)) return PTR_ERR(file); - ret = kernel_read_file(file, buf, buf_size, id); + ret = kernel_read_file(file, buf, buf_size, file_size, id); fput(file); return ret; } EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns); int kernel_read_file_from_fd(int fd, void **buf, size_t buf_size, + size_t *file_size, enum kernel_read_file_id id) { struct fd f = fdget(fd); @@ -144,7 +151,7 @@ int kernel_read_file_from_fd(int fd, void **buf, size_t buf_size, if (!f.file) goto out; - ret = kernel_read_file(f.file, buf, buf_size, id); + ret = kernel_read_file(f.file, buf, buf_size, file_size, id); out: fdput(f); return ret; diff --git a/include/linux/kernel_read_file.h b/include/linux/kernel_read_file.h index 910039e7593e..023293eaf948 100644 --- a/include/linux/kernel_read_file.h +++ b/include/linux/kernel_read_file.h @@ -37,15 +37,19 @@ static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id) int kernel_read_file(struct file *file, void **buf, size_t buf_size, + size_t *file_size, enum kernel_read_file_id id); int kernel_read_file_from_path(const char *path, void **buf, size_t buf_size, + size_t *file_size, enum kernel_read_file_id id); int kernel_read_file_from_path_initns(const char *path, void **buf, size_t buf_size, + size_t *file_size, enum kernel_read_file_id id); int kernel_read_file_from_fd(int fd, void **buf, size_t buf_size, + size_t *file_size, enum kernel_read_file_id id); #endif /* _LINUX_KERNEL_READ_FILE_H */ diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index eda19ca256a3..878ca684a3a1 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -222,7 +222,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, void *ldata; ret = kernel_read_file_from_fd(kernel_fd, &image->kernel_buf, - INT_MAX, READING_KEXEC_IMAGE); + INT_MAX, NULL, READING_KEXEC_IMAGE); if (ret < 0) return ret; image->kernel_buf_len = ret; @@ -242,7 +242,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, /* It is possible that there no initramfs is being loaded */ if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { ret = kernel_read_file_from_fd(initrd_fd, &image->initrd_buf, - INT_MAX, + INT_MAX, NULL, READING_KEXEC_INITRAMFS); if (ret < 0) goto out; diff --git a/kernel/module.c b/kernel/module.c index 0792ce3bf643..16558bc842de 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -4004,7 +4004,7 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) |MODULE_INIT_IGNORE_VERMAGIC)) return -EINVAL; - err = kernel_read_file_from_fd(fd, &hdr, INT_MAX, + err = kernel_read_file_from_fd(fd, &hdr, INT_MAX, NULL, READING_MODULE); if (err < 0) return err; diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 04f779c4f5ed..8a523dfd7fd7 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -175,7 +175,7 @@ int __init integrity_load_x509(const unsigned int id, const char *path) int rc; key_perm_t perm; - rc = kernel_read_file_from_path(path, &data, INT_MAX, + rc = kernel_read_file_from_path(path, &data, INT_MAX, NULL, READING_X509_CERTIFICATE); if (rc < 0) { pr_err("Unable to open file: %s (%d)", path, rc); diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 692b83e82edf..5fc56ccb6678 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -284,7 +284,7 @@ static ssize_t ima_read_policy(char *path) datap = path; strsep(&datap, "\n"); - rc = kernel_read_file_from_path(path, &data, INT_MAX, READING_POLICY); + rc = kernel_read_file_from_path(path, &data, INT_MAX, NULL, READING_POLICY); if (rc < 0) { pr_err("Unable to open file: %s (%d)", path, rc); return rc; From patchwork Wed Jul 29 17:58:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691505 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A4BCD1392 for ; Wed, 29 Jul 2020 17:59:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 836892083B for ; Wed, 29 Jul 2020 17:59:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="MeMTEVZM" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728024AbgG2R7l (ORCPT ); Wed, 29 Jul 2020 13:59:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35716 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727896AbgG2R7E (ORCPT ); Wed, 29 Jul 2020 13:59:04 -0400 Received: from mail-pj1-x1044.google.com (mail-pj1-x1044.google.com [IPv6:2607:f8b0:4864:20::1044]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A6EAAC0619D2 for ; Wed, 29 Jul 2020 10:59:04 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id f9so2418579pju.4 for ; Wed, 29 Jul 2020 10:59:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=j1rK6VB3/t6r0bDwVuIBlz/fGniErwQNG3K4S4eQ1vg=; b=MeMTEVZMrvI2ihI8pPW8HR1Lf3x3/zVT7fJCxush8MQJ64QnLVl4dQJo4tGqcOmTWU 1rYEJmRqrrtk1Zx79XNvhAcxC9RrSrhW3Y90LRJZNW2gYIogBKOUCpV65cG1i4hMMH00 obLT/+SyE5//b4HPEi0w2PPrkPfcDfIKFQfdU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=j1rK6VB3/t6r0bDwVuIBlz/fGniErwQNG3K4S4eQ1vg=; b=hybmtqRCuBkFoWARNQR88WyYFYIXM08v2hLtz/IoV6ITxi7cqXWfQFq+7hx0MG2uyW d355PrP1TfhwGjFcqUfI7YuShe++/UuT92v1KVRaJYpAFC8eWo73kh6OmrV0Wk9NU5Cp uccQ3Eo3mTVPlxGyvM7bPfKqZsdECrKtNqDOYAnl5UyCgxe1Z4FuGiXQpK+NKz8RQaE3 P49BIIVjohLS8kdrvrcC60zRoKvodRFG06qeYNmPO+wTa3qyIDVZBoBjbkDG0CnQdavM BbLhsAF327ly4IsKPOwtXULD+/AgmNKWXIHmp7UQiNT96qaUCYk7Y2vL8ApYr+SfK+39 +WNg== X-Gm-Message-State: AOAM532JKa73Qrel08pIZloIBe5Srb+omvBAQadDWqf/azNcxQA1p92c kam+0Ij9Zwko2tzJuUR85gTGYw== X-Google-Smtp-Source: ABdhPJwA8FKdst3jI8sC5OVe2Q0MUeNhzLJsRQnsD98HjcampeIR6qqTWDa4ZGIGlCAB6pl409RCtA== X-Received: by 2002:a17:90a:71c1:: with SMTP id m1mr3376328pjs.163.1596045544081; Wed, 29 Jul 2020 10:59:04 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id v28sm3226131pgn.81.2020.07.29.10.58.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:58 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 09/17] LSM: Introduce kernel_post_load_data() hook Date: Wed, 29 Jul 2020 10:58:37 -0700 Message-Id: <20200729175845.1745471-10-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org There are a few places in the kernel where LSMs would like to have visibility into the contents of a kernel buffer that has been loaded or read. While security_kernel_post_read_file() (which includes the buffer) exists as a pairing for security_kernel_read_file(), no such hook exists to pair with security_kernel_load_data(). Earlier proposals for just using security_kernel_post_read_file() with a NULL file argument were rejected (i.e. "file" should always be valid for the security_..._file hooks, but it appears at least one case was left in the kernel during earlier refactoring. (This will be fixed in a subsequent patch.) Since not all cases of security_kernel_load_data() can have a single contiguous buffer made available to the LSM hook (e.g. kexec image segments are separately loaded), there needs to be a way for the LSM to reason about its expectations of the hook coverage. In order to handle this, add a "contents" argument to the "kernel_load_data" hook that indicates if the newly added "kernel_post_load_data" hook will be called with the full contents once loaded. That way, LSMs requiring full contents can choose to unilaterally reject "kernel_load_data" with contents=false (which is effectively the existing hook coverage), but when contents=true they can allow it and later evaluate the "kernel_post_load_data" hook once the buffer is loaded. With this change, LSMs can gain coverage over non-file-backed data loads (e.g. init_module(2) and firmware userspace helper), which will happen in subsequent patches. Additionally prepare IMA to start processing these cases. Signed-off-by: Kees Cook Reviewed-by: KP Singh --- drivers/base/firmware_loader/fallback.c | 2 +- .../base/firmware_loader/fallback_platform.c | 2 +- include/linux/ima.h | 12 +++++++++-- include/linux/lsm_hook_defs.h | 4 +++- include/linux/lsm_hooks.h | 9 ++++++++ include/linux/security.h | 12 +++++++++-- kernel/kexec.c | 2 +- kernel/module.c | 2 +- security/integrity/ima/ima_main.c | 21 ++++++++++++++++++- security/loadpin/loadpin.c | 2 +- security/security.c | 18 +++++++++++++--- security/selinux/hooks.c | 2 +- 12 files changed, 73 insertions(+), 15 deletions(-) diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index 5327bfc6ba71..a196aacce22c 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -613,7 +613,7 @@ static bool fw_run_sysfs_fallback(u32 opt_flags) return false; /* Also permit LSMs and IMA to fail firmware sysfs fallback */ - ret = security_kernel_load_data(LOADING_FIRMWARE); + ret = security_kernel_load_data(LOADING_FIRMWARE, false); if (ret < 0) return false; diff --git a/drivers/base/firmware_loader/fallback_platform.c b/drivers/base/firmware_loader/fallback_platform.c index 6958ab1a8059..a12c79d47efc 100644 --- a/drivers/base/firmware_loader/fallback_platform.c +++ b/drivers/base/firmware_loader/fallback_platform.c @@ -17,7 +17,7 @@ int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags) if (!(opt_flags & FW_OPT_FALLBACK_PLATFORM)) return -ENOENT; - rc = security_kernel_load_data(LOADING_FIRMWARE); + rc = security_kernel_load_data(LOADING_FIRMWARE, false); if (rc) return rc; diff --git a/include/linux/ima.h b/include/linux/ima.h index 148636bfcc8f..502e36ad7804 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -20,7 +20,9 @@ extern void ima_post_create_tmpfile(struct inode *inode); extern void ima_file_free(struct file *file); extern int ima_file_mmap(struct file *file, unsigned long prot); extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot); -extern int ima_load_data(enum kernel_load_data_id id); +extern int ima_load_data(enum kernel_load_data_id id, bool contents); +extern int ima_post_load_data(char *buf, loff_t size, + enum kernel_load_data_id id); extern int ima_read_file(struct file *file, enum kernel_read_file_id id); extern int ima_post_read_file(struct file *file, void *buf, loff_t size, enum kernel_read_file_id id); @@ -78,7 +80,13 @@ static inline int ima_file_mprotect(struct vm_area_struct *vma, return 0; } -static inline int ima_load_data(enum kernel_load_data_id id) +static inline int ima_load_data(enum kernel_load_data_id id, bool contents) +{ + return 0; +} + +static inline int ima_post_load_data(char *buf, loff_t size, + enum kernel_load_data_id id) { return 0; } diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index af998f93d256..7ed5d31ac9cc 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -184,7 +184,9 @@ LSM_HOOK(void, LSM_RET_VOID, cred_getsecid, const struct cred *c, u32 *secid) LSM_HOOK(int, 0, kernel_act_as, struct cred *new, u32 secid) LSM_HOOK(int, 0, kernel_create_files_as, struct cred *new, struct inode *inode) LSM_HOOK(int, 0, kernel_module_request, char *kmod_name) -LSM_HOOK(int, 0, kernel_load_data, enum kernel_load_data_id id) +LSM_HOOK(int, 0, kernel_load_data, enum kernel_load_data_id id, bool contents) +LSM_HOOK(int, 0, kernel_post_load_data, char *buf, loff_t size, + enum kernel_read_file_id id) LSM_HOOK(int, 0, kernel_read_file, struct file *file, enum kernel_read_file_id id) LSM_HOOK(int, 0, kernel_post_read_file, struct file *file, char *buf, diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 95b7c1d32062..812d626195fc 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -635,7 +635,16 @@ * @kernel_load_data: * Load data provided by userspace. * @id kernel load data identifier + * @contents if a subsequent @kernel_post_load_data will be called. * Return 0 if permission is granted. + * @kernel_post_load_data: + * Load data provided by a non-file source (usually userspace buffer). + * @buf pointer to buffer containing the data contents. + * @size length of the data contents. + * @id kernel load data identifier + * Return 0 if permission is granted. + * This must be paired with a prior @kernel_load_data call that had + * @contents set to true. * @kernel_read_file: * Read a file specified by userspace. * @file contains the file structure pointing to the file being read diff --git a/include/linux/security.h b/include/linux/security.h index 42df0d9b4c37..e748974c707b 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -387,7 +387,9 @@ void security_cred_getsecid(const struct cred *c, u32 *secid); int security_kernel_act_as(struct cred *new, u32 secid); int security_kernel_create_files_as(struct cred *new, struct inode *inode); int security_kernel_module_request(char *kmod_name); -int security_kernel_load_data(enum kernel_load_data_id id); +int security_kernel_load_data(enum kernel_load_data_id id, bool contents); +int security_kernel_post_load_data(char *buf, loff_t size, + enum kernel_load_data_id id); int security_kernel_read_file(struct file *file, enum kernel_read_file_id id); int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id); @@ -1014,7 +1016,13 @@ static inline int security_kernel_module_request(char *kmod_name) return 0; } -static inline int security_kernel_load_data(enum kernel_load_data_id id) +static inline int security_kernel_load_data(enum kernel_load_data_id id, bool contents) +{ + return 0; +} + +static inline int security_kernel_post_load_data(char *buf, loff_t size, + enum kernel_load_data_id id) { return 0; } diff --git a/kernel/kexec.c b/kernel/kexec.c index f977786fe498..c82c6c06f051 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -205,7 +205,7 @@ static inline int kexec_load_check(unsigned long nr_segments, return -EPERM; /* Permit LSMs and IMA to fail the kexec */ - result = security_kernel_load_data(LOADING_KEXEC_IMAGE); + result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); if (result < 0) return result; diff --git a/kernel/module.c b/kernel/module.c index 16558bc842de..d773f32f8dfd 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2970,7 +2970,7 @@ static int copy_module_from_user(const void __user *umod, unsigned long len, if (info->len < sizeof(*(info->hdr))) return -ENOEXEC; - err = security_kernel_load_data(LOADING_MODULE); + err = security_kernel_load_data(LOADING_MODULE, false); if (err) return err; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index dab4a13221cf..85000dc8595c 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -676,6 +676,8 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, /** * ima_load_data - appraise decision based on policy * @id: kernel load data caller identifier + * @contents: whether the full contents will be available in a later + * call to ima_post_load_data(). * * Callers of this LSM hook can not measure, appraise, or audit the * data provided by userspace. Enforce policy rules requring a file @@ -683,7 +685,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, * * For permission return 0, otherwise return -EACCES. */ -int ima_load_data(enum kernel_load_data_id id) +int ima_load_data(enum kernel_load_data_id id, bool contents) { bool ima_enforce, sig_enforce; @@ -723,6 +725,23 @@ int ima_load_data(enum kernel_load_data_id id) return 0; } +/** + * ima_post_load_data - appraise decision based on policy + * @buf: pointer to in memory file contents + * @size: size of in memory file contents + * @id: kernel load data caller identifier + * + * Measure/appraise/audit in memory buffer based on policy. Policy rules + * are written in terms of a policy identifier. + * + * On success return 0. On integrity appraisal error, assuming the file + * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. + */ +int ima_post_load_data(char *buf, loff_t size, enum kernel_load_data_id load_id) +{ + return 0; +} + /* * process_buffer_measurement - Measure the buffer to ima log. * @buf: pointer to the buffer that needs to be added to the log. diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index 81bc95127f92..db320a43f42e 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -176,7 +176,7 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id) return 0; } -static int loadpin_load_data(enum kernel_load_data_id id) +static int loadpin_load_data(enum kernel_load_data_id id, bool contents) { return loadpin_read_file(NULL, (enum kernel_read_file_id) id); } diff --git a/security/security.c b/security/security.c index 19d3150f68f4..568bb77e84f4 100644 --- a/security/security.c +++ b/security/security.c @@ -1695,17 +1695,29 @@ int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, } EXPORT_SYMBOL_GPL(security_kernel_post_read_file); -int security_kernel_load_data(enum kernel_load_data_id id) +int security_kernel_load_data(enum kernel_load_data_id id, bool contents) { int ret; - ret = call_int_hook(kernel_load_data, 0, id); + ret = call_int_hook(kernel_load_data, 0, id, contents); if (ret) return ret; - return ima_load_data(id); + return ima_load_data(id, contents); } EXPORT_SYMBOL_GPL(security_kernel_load_data); +int security_kernel_post_load_data(char *buf, loff_t size, + enum kernel_load_data_id id) +{ + int ret; + + ret = call_int_hook(kernel_post_load_data, 0, buf, size, id); + if (ret) + return ret; + return ima_post_load_data(buf, size, id); +} +EXPORT_SYMBOL_GPL(security_kernel_post_load_data); + int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5de45010fb1a..1a5c68196faf 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4019,7 +4019,7 @@ static int selinux_kernel_read_file(struct file *file, return rc; } -static int selinux_kernel_load_data(enum kernel_load_data_id id) +static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents) { int rc = 0; From patchwork Wed Jul 29 17:58:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691513 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 73AF91392 for ; Wed, 29 Jul 2020 17:59:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5CA5122BEA for ; Wed, 29 Jul 2020 17:59:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="DWupj1kf" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727887AbgG2R7l (ORCPT ); Wed, 29 Jul 2020 13:59:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35678 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727883AbgG2R7E (ORCPT ); Wed, 29 Jul 2020 13:59:04 -0400 Received: from mail-pg1-x543.google.com (mail-pg1-x543.google.com [IPv6:2607:f8b0:4864:20::543]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 24373C08C5E0 for ; Wed, 29 Jul 2020 10:59:03 -0700 (PDT) Received: by mail-pg1-x543.google.com with SMTP id o13so14698620pgf.0 for ; Wed, 29 Jul 2020 10:59:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=dge98+d3xjbY9IP5mQNDSECkvDjG9MOM+lU6BMHPuiA=; b=DWupj1kfarktDDqW8iV0U0Fl3rATkLnX92mmTciLVaQ0w0R4To89zPvTkL5ShbA8fz tLlRIKyxnoLPkrvn1FsKnQaFih1tMYIURcsugtNYl3v5j6qr4MgIjN1Uq4BtkK+V4C/r urPM2vEjgWKrA6FlUJFOGO2XKguldg1gijli8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=dge98+d3xjbY9IP5mQNDSECkvDjG9MOM+lU6BMHPuiA=; b=hOlujyddMYvhFO7uUEwJSP+eXEj/rLRERr6Czj0mUjBV2eXVb1O/79PLkwm+SbGLhp pHVWRz3xa1WntB4T/G+Rm7mUFV4NeFBh3xCKyW9P8aFnEnitXgeKvm3lX7GEWmdjxaRg wPE+slx6Po1S3/OIcSdbaQaWITQTyzNQZAePdslqQj3ijXg79LT+aS1fm6xLDTOi0bjs oPro7NuD1r3qc/iOCSYAWzOtaNz0abc1UuxvRt9FGOfulLESJ46feVgcgTBCX+odqFUw 0pW9EZPUNOVxgcyR/+qKqWJVy7GXpH90HfjN0Rp+eSmKi7HUabUwKbFxZ4ccv0zt4h1N Vvtg== X-Gm-Message-State: AOAM531M/rVVJo2cMQXSjDt+bj3uzYB28fhIMTBfAVZVgTT0VBehlOSt J+AWTbsxdKAfmpw7vLzAoia9sQ== X-Google-Smtp-Source: ABdhPJzAjwYdqsQeLe2KNGjZnjR0XNZcsw5+JYPFJ80D6EHfefx62MFfkXPoJG3B9uAD4Jux3P7Grw== X-Received: by 2002:a63:6cd:: with SMTP id 196mr30212447pgg.169.1596045542650; Wed, 29 Jul 2020 10:59:02 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id j19sm2771099pjy.40.2020.07.29.10.58.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:58 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 10/17] firmware_loader: Use security_post_load_data() Date: Wed, 29 Jul 2020 10:58:38 -0700 Message-Id: <20200729175845.1745471-11-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Now that security_post_load_data() is wired up, use it instead of the NULL file argument style of security_post_read_file(), and update the security_kernel_load_data() call to indicate that a security_kernel_post_load_data() call is expected. Wire up the IMA check to match earlier logic. Perhaps a generalized change to ima_post_load_data() might look something like this: return process_buffer_measurement(buf, size, kernel_load_data_id_str(load_id), read_idmap[load_id] ?: FILE_CHECK, 0, NULL); Signed-off-by: Kees Cook Reviewed-by: Mimi Zohar --- drivers/base/firmware_loader/fallback.c | 8 ++++---- .../base/firmware_loader/fallback_platform.c | 7 ++++++- security/integrity/ima/ima_main.c | 20 +++++++++---------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index a196aacce22c..7cfdfdcb819c 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -272,9 +272,9 @@ static ssize_t firmware_loading_store(struct device *dev, dev_err(dev, "%s: map pages failed\n", __func__); else - rc = security_kernel_post_read_file(NULL, - fw_priv->data, fw_priv->size, - READING_FIRMWARE); + rc = security_kernel_post_load_data(fw_priv->data, + fw_priv->size, + LOADING_FIRMWARE); /* * Same logic as fw_load_abort, only the DONE bit @@ -613,7 +613,7 @@ static bool fw_run_sysfs_fallback(u32 opt_flags) return false; /* Also permit LSMs and IMA to fail firmware sysfs fallback */ - ret = security_kernel_load_data(LOADING_FIRMWARE, false); + ret = security_kernel_load_data(LOADING_FIRMWARE, true); if (ret < 0) return false; diff --git a/drivers/base/firmware_loader/fallback_platform.c b/drivers/base/firmware_loader/fallback_platform.c index a12c79d47efc..4d1157af0e86 100644 --- a/drivers/base/firmware_loader/fallback_platform.c +++ b/drivers/base/firmware_loader/fallback_platform.c @@ -17,7 +17,7 @@ int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags) if (!(opt_flags & FW_OPT_FALLBACK_PLATFORM)) return -ENOENT; - rc = security_kernel_load_data(LOADING_FIRMWARE, false); + rc = security_kernel_load_data(LOADING_FIRMWARE, true); if (rc) return rc; @@ -27,6 +27,11 @@ int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags) if (fw_priv->data && size > fw_priv->allocated_size) return -ENOMEM; + + rc = security_kernel_post_load_data((u8 *)data, size, LOADING_FIRMWARE); + if (rc) + return rc; + if (!fw_priv->data) fw_priv->data = vmalloc(size); if (!fw_priv->data) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 85000dc8595c..1a7bc4c7437d 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -648,15 +648,6 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, enum ima_hooks func; u32 secid; - if (!file && read_id == READING_FIRMWARE) { - if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && - (ima_appraise & IMA_APPRAISE_ENFORCE)) { - pr_err("Prevent firmware loading_store.\n"); - return -EACCES; /* INTEGRITY_UNKNOWN */ - } - return 0; - } - /* permit signed certs */ if (!file && read_id == READING_X509_CERTIFICATE) return 0; @@ -706,7 +697,7 @@ int ima_load_data(enum kernel_load_data_id id, bool contents) } break; case LOADING_FIRMWARE: - if (ima_enforce && (ima_appraise & IMA_APPRAISE_FIRMWARE)) { + if (ima_enforce && (ima_appraise & IMA_APPRAISE_FIRMWARE) && !contents) { pr_err("Prevent firmware sysfs fallback loading.\n"); return -EACCES; /* INTEGRITY_UNKNOWN */ } @@ -739,6 +730,15 @@ int ima_load_data(enum kernel_load_data_id id, bool contents) */ int ima_post_load_data(char *buf, loff_t size, enum kernel_load_data_id load_id) { + if (load_id == LOADING_FIRMWARE) { + if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && + (ima_appraise & IMA_APPRAISE_ENFORCE)) { + pr_err("Prevent firmware loading_store.\n"); + return -EACCES; /* INTEGRITY_UNKNOWN */ + } + return 0; + } + return 0; } From patchwork Wed Jul 29 17:58:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691497 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A752017C5 for ; Wed, 29 Jul 2020 17:59:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 90D062173E for ; Wed, 29 Jul 2020 17:59:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="PeYr3jVB" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727921AbgG2R7d (ORCPT ); Wed, 29 Jul 2020 13:59:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727915AbgG2R7G (ORCPT ); Wed, 29 Jul 2020 13:59:06 -0400 Received: from mail-pf1-x444.google.com (mail-pf1-x444.google.com [IPv6:2607:f8b0:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D82EC0619DB for ; Wed, 29 Jul 2020 10:59:05 -0700 (PDT) Received: by mail-pf1-x444.google.com with SMTP id r11so5428221pfl.11 for ; Wed, 29 Jul 2020 10:59:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=2dckHYDBSef92hBk0hdLw37DCCWMtjung/PzGLRIGlQ=; b=PeYr3jVB7W6UcW212/oJZmLRi4czVPcQjfijK3aeH7rdxGYPMC62JtlyIoOxj7gwy5 c2dWpHJMjKgNg5+GOs7lE5ptFlJbitvkjzFCMkK2BuSsglPWQHHRYHbZXOmZVOOvVeL9 AXbaJuHNrbC7ktjkX3HyAY7OqVwqAjEvn/WKk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2dckHYDBSef92hBk0hdLw37DCCWMtjung/PzGLRIGlQ=; b=R60FOdv5ObfXFpwdfRE+Zy2vH7f6Ju01fmmaXIG/rZCzZsMMmYeLBbn4fxnmd4FFqu hvUAPNDLKSTo4dML0vlbxtx4HtZz1HKE0QhA/cOYI0DaGqdVPzT0yP3tO5mrO19G+2+x Y8KDylm6pt8D/pS6QXZs1Ux2ExULVu2uxcrdDuU4r+W8RJio7CWyPYQDvcQI9Ve/MrMe eyn+moihfMjh2hfqbFks4bBug6+4PsPi5SLTacP/sjt5Da7/gfhawH3IMHa3ZdUHiIDO 60QtwFufZt1Q7EKFcy81jwO3PUgkKqqXsewG29zPDQ6pIEOdKE0KFmadJEjWYvLapMcy DkDQ== X-Gm-Message-State: AOAM53086GRpKB5O6PkV3zB0AmR7nlpXFn00OF2fGaW9PAsVYYU52GjV +DTWOX0qbYFAi/7vbOdvfcfbhg== X-Google-Smtp-Source: ABdhPJx0d4Pms05JWWdUqTfjeGaSa2h+B6c1vOgjK6stye4AbmKSEHfAQSNgfmrRFdWMcscCi/9fDQ== X-Received: by 2002:a65:64c5:: with SMTP id t5mr30425186pgv.28.1596045544724; Wed, 29 Jul 2020 10:59:04 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id t73sm3172293pfc.78.2020.07.29.10.58.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:58 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Jessica Yu , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 11/17] module: Call security_kernel_post_load_data() Date: Wed, 29 Jul 2020 10:58:39 -0700 Message-Id: <20200729175845.1745471-12-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Now that there is an API for checking loaded contents for modules loaded without a file, call into the LSM hooks. Cc: Jessica Yu Signed-off-by: Kees Cook Acked-by: Jessica Yu Reviewed-by: KP Singh --- kernel/module.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index d773f32f8dfd..72e33e25d7b9 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2970,7 +2970,7 @@ static int copy_module_from_user(const void __user *umod, unsigned long len, if (info->len < sizeof(*(info->hdr))) return -ENOEXEC; - err = security_kernel_load_data(LOADING_MODULE, false); + err = security_kernel_load_data(LOADING_MODULE, true); if (err) return err; @@ -2980,11 +2980,17 @@ static int copy_module_from_user(const void __user *umod, unsigned long len, return -ENOMEM; if (copy_chunked_from_user(info->hdr, umod, info->len) != 0) { - vfree(info->hdr); - return -EFAULT; + err = -EFAULT; + goto out; } - return 0; + err = security_kernel_post_load_data((char *)info->hdr, info->len, + LOADING_MODULE); +out: + if (err) + vfree(info->hdr); + + return err; } static void free_copy(struct load_info *info) From patchwork Wed Jul 29 17:58:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691511 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 41E32913 for ; Wed, 29 Jul 2020 17:59:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2AE3920838 for ; Wed, 29 Jul 2020 17:59:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="M2UD4yWR" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727893AbgG2R7l (ORCPT ); Wed, 29 Jul 2020 13:59:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35710 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727887AbgG2R7E (ORCPT ); Wed, 29 Jul 2020 13:59:04 -0400 Received: from mail-pl1-x641.google.com (mail-pl1-x641.google.com [IPv6:2607:f8b0:4864:20::641]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C6B66C08C5F3 for ; Wed, 29 Jul 2020 10:59:03 -0700 (PDT) Received: by mail-pl1-x641.google.com with SMTP id u10so2659867plr.7 for ; Wed, 29 Jul 2020 10:59:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=2xUsRXnbLux6qdeU+pa7NDiD7kg6YP/2d6cCFbbVK74=; b=M2UD4yWRvt6I0iEzMEsXP+yL3/MoTJX4tb39Y1yjRy1i8ktFeHU4P7m2rRiVey0bue lh/+xGTlCztDozFgYb21YMIgwnfp8JCm5BAXr75LWPgB/p//fjwtk4tUkQV4D/hKzVSV 3nvpzoPMKgAcKKsjN/qC8hiMYDXsrQdbE5GLI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2xUsRXnbLux6qdeU+pa7NDiD7kg6YP/2d6cCFbbVK74=; b=c+cBDBickFwDBSySj4CQezT6W/NMDLbVohV1V5W+ZHQ0BcerfCBaDT2JzGKxU/yCsu JiNxvceav/qvKP8yrTefxQeKGi35OI0r+rUZ7who97xCpZM9lXFAOzrc14/tkMvRBHrk 23cJUS2b5FVsvNcaGQd6D93goNMq1M69E0/0IzZiOqFru41Jgf1PPGGGGaqT4BaJU62w vFlLe0R7WnMjWJGqmmXsG744pZHkIPDDBd1K0oX5RvhF3q+U3p4EK3wdv5qCP2v+l10J F/LrUaBcRN6guG9kKrXHS9oBXGKQ4D+1y9QmAA7JeYBzCwoI+rTqAiXyMafV4fLJOnAt Egkg== X-Gm-Message-State: AOAM531EEl8Nz34KaFoFAO89DgYNUvWgWs/o8HTcq1brRlPBs0ptYR4O RCUMoIGJ/AxUMvf0HCQJypwiiQOaZdY= X-Google-Smtp-Source: ABdhPJyi1wpi983u8TuB+A6QdDocyhpityC2XUY1mpslc539rFiRO36v0okvDsM0vtEVtPnrgqzjlw== X-Received: by 2002:a17:90a:e511:: with SMTP id t17mr10821360pjy.189.1596045543265; Wed, 29 Jul 2020 10:59:03 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id y11sm3375092pfp.73.2020.07.29.10.58.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:58:58 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 12/17] LSM: Add "contents" flag to kernel_read_file hook Date: Wed, 29 Jul 2020 10:58:40 -0700 Message-Id: <20200729175845.1745471-13-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org As with the kernel_load_data LSM hook, add a "contents" flag to the kernel_read_file LSM hook that indicates whether the LSM can expect a matching call to the kernel_post_read_file LSM hook with the full contents of the file. With the coming addition of partial file read support for kernel_read_file*() API, the LSM will no longer be able to always see the entire contents of a file during the read calls. For cases where the LSM must read examine the complete file contents, it will need to do so on its own every time the kernel_read_file hook is called with contents=false (or reject such cases). Adjust all existing LSMs to retain existing behavior. Signed-off-by: Kees Cook Reviewed-by: Mimi Zohar --- fs/kernel_read_file.c | 2 +- include/linux/ima.h | 6 ++++-- include/linux/lsm_hook_defs.h | 2 +- include/linux/lsm_hooks.h | 3 +++ include/linux/security.h | 6 ++++-- security/integrity/ima/ima_main.c | 10 +++++++++- security/loadpin/loadpin.c | 14 ++++++++++++-- security/security.c | 7 ++++--- security/selinux/hooks.c | 5 +++-- 9 files changed, 41 insertions(+), 14 deletions(-) diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c index 2e29c38eb4df..d73bc3fa710a 100644 --- a/fs/kernel_read_file.c +++ b/fs/kernel_read_file.c @@ -39,7 +39,7 @@ int kernel_read_file(struct file *file, void **buf, if (ret) return ret; - ret = security_kernel_read_file(file, id); + ret = security_kernel_read_file(file, id, true); if (ret) goto out; diff --git a/include/linux/ima.h b/include/linux/ima.h index 502e36ad7804..259023039dc9 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -23,7 +23,8 @@ extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot); extern int ima_load_data(enum kernel_load_data_id id, bool contents); extern int ima_post_load_data(char *buf, loff_t size, enum kernel_load_data_id id); -extern int ima_read_file(struct file *file, enum kernel_read_file_id id); +extern int ima_read_file(struct file *file, enum kernel_read_file_id id, + bool contents); extern int ima_post_read_file(struct file *file, void *buf, loff_t size, enum kernel_read_file_id id); extern void ima_post_path_mknod(struct dentry *dentry); @@ -91,7 +92,8 @@ static inline int ima_post_load_data(char *buf, loff_t size, return 0; } -static inline int ima_read_file(struct file *file, enum kernel_read_file_id id) +static inline int ima_read_file(struct file *file, enum kernel_read_file_id id, + bool contents) { return 0; } diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 7ed5d31ac9cc..f953aa938eaf 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -188,7 +188,7 @@ LSM_HOOK(int, 0, kernel_load_data, enum kernel_load_data_id id, bool contents) LSM_HOOK(int, 0, kernel_post_load_data, char *buf, loff_t size, enum kernel_read_file_id id) LSM_HOOK(int, 0, kernel_read_file, struct file *file, - enum kernel_read_file_id id) + enum kernel_read_file_id id, bool contents) LSM_HOOK(int, 0, kernel_post_read_file, struct file *file, char *buf, loff_t size, enum kernel_read_file_id id) LSM_HOOK(int, 0, task_fix_setuid, struct cred *new, const struct cred *old, diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 812d626195fc..b66433b5aa15 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -650,6 +650,7 @@ * @file contains the file structure pointing to the file being read * by the kernel. * @id kernel read file identifier + * @contents if a subsequent @kernel_post_read_file will be called. * Return 0 if permission is granted. * @kernel_post_read_file: * Read a file specified by userspace. @@ -658,6 +659,8 @@ * @buf pointer to buffer containing the file contents. * @size length of the file contents. * @id kernel read file identifier + * This must be paired with a prior @kernel_read_file call that had + * @contents set to true. * Return 0 if permission is granted. * @task_fix_setuid: * Update the module's state after setting one or more of the user diff --git a/include/linux/security.h b/include/linux/security.h index e748974c707b..a5d66b89cd6c 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -390,7 +390,8 @@ int security_kernel_module_request(char *kmod_name); int security_kernel_load_data(enum kernel_load_data_id id, bool contents); int security_kernel_post_load_data(char *buf, loff_t size, enum kernel_load_data_id id); -int security_kernel_read_file(struct file *file, enum kernel_read_file_id id); +int security_kernel_read_file(struct file *file, enum kernel_read_file_id id, + bool contents); int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id); int security_task_fix_setuid(struct cred *new, const struct cred *old, @@ -1028,7 +1029,8 @@ static inline int security_kernel_post_load_data(char *buf, loff_t size, } static inline int security_kernel_read_file(struct file *file, - enum kernel_read_file_id id) + enum kernel_read_file_id id, + bool contents) { return 0; } diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 1a7bc4c7437d..dc4f90660aa6 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -602,6 +602,7 @@ void ima_post_path_mknod(struct dentry *dentry) * ima_read_file - pre-measure/appraise hook decision based on policy * @file: pointer to the file to be measured/appraised/audit * @read_id: caller identifier + * @contents: whether a subsequent call will be made to ima_post_read_file() * * Permit reading a file based on policy. The policy rules are written * in terms of the policy identifier. Appraising the integrity of @@ -609,8 +610,15 @@ void ima_post_path_mknod(struct dentry *dentry) * * For permission return 0, otherwise return -EACCES. */ -int ima_read_file(struct file *file, enum kernel_read_file_id read_id) +int ima_read_file(struct file *file, enum kernel_read_file_id read_id, + bool contents) { + /* Reject all partial reads during appraisal. */ + if (!contents) { + if (ima_appraise & IMA_APPRAISE_ENFORCE) + return -EACCES; + } + /* * Do devices using pre-allocated memory run the risk of the * firmware being accessible to the device prior to the completion diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index db320a43f42e..a1778ebef137 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -117,11 +117,21 @@ static void loadpin_sb_free_security(struct super_block *mnt_sb) } } -static int loadpin_read_file(struct file *file, enum kernel_read_file_id id) +static int loadpin_read_file(struct file *file, enum kernel_read_file_id id, + bool contents) { struct super_block *load_root; const char *origin = kernel_read_file_id_str(id); + /* + * If we will not know that we'll be seeing the full contents + * then we cannot trust a load will be complete and unchanged + * off disk. Treat all contents=false hooks as if there were + * no associated file struct. + */ + if (!contents) + file = NULL; + /* If the file id is excluded, ignore the pinning. */ if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) && ignore_read_file_id[id]) { @@ -178,7 +188,7 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id) static int loadpin_load_data(enum kernel_load_data_id id, bool contents) { - return loadpin_read_file(NULL, (enum kernel_read_file_id) id); + return loadpin_read_file(NULL, (enum kernel_read_file_id) id, contents); } static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = { diff --git a/security/security.c b/security/security.c index 568bb77e84f4..6a38fc533a5a 100644 --- a/security/security.c +++ b/security/security.c @@ -1672,14 +1672,15 @@ int security_kernel_module_request(char *kmod_name) return integrity_kernel_module_request(kmod_name); } -int security_kernel_read_file(struct file *file, enum kernel_read_file_id id) +int security_kernel_read_file(struct file *file, enum kernel_read_file_id id, + bool contents) { int ret; - ret = call_int_hook(kernel_read_file, 0, file, id); + ret = call_int_hook(kernel_read_file, 0, file, id, contents); if (ret) return ret; - return ima_read_file(file, id); + return ima_read_file(file, id, contents); } EXPORT_SYMBOL_GPL(security_kernel_read_file); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 1a5c68196faf..6d183bbc12a6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4004,13 +4004,14 @@ static int selinux_kernel_module_from_file(struct file *file) } static int selinux_kernel_read_file(struct file *file, - enum kernel_read_file_id id) + enum kernel_read_file_id id, + bool contents) { int rc = 0; switch (id) { case READING_MODULE: - rc = selinux_kernel_module_from_file(file); + rc = selinux_kernel_module_from_file(contents ? file : NULL); break; default: break; From patchwork Wed Jul 29 17:58:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691471 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 24175138C for ; Wed, 29 Jul 2020 17:59:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0C20720838 for ; Wed, 29 Jul 2020 17:59:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ZZB5JK//" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727914AbgG2R7J (ORCPT ); Wed, 29 Jul 2020 13:59:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35664 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727930AbgG2R7H (ORCPT ); Wed, 29 Jul 2020 13:59:07 -0400 Received: from mail-pf1-x442.google.com (mail-pf1-x442.google.com [IPv6:2607:f8b0:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C7457C0619E1 for ; Wed, 29 Jul 2020 10:59:06 -0700 (PDT) Received: by mail-pf1-x442.google.com with SMTP id 74so5066115pfx.13 for ; Wed, 29 Jul 2020 10:59:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=d+cxh7Adx01Lz+PZ0BqdBZD0tuhqHe+fIcb3T8VVshI=; b=ZZB5JK//OYdCgnZb/fU8QzTjp427UrGSGiw79T8stn6rtJuQa9EpnWg2nqhPKWluxW W6G5fG+ztYpEQLf1lCq0MlQ9zNk4q/Y5m3gxLuSfvTXmmiKW5Rv4D1MaN0sW3Ja7Djt+ EOHWd0VX606jZjeyOdUtx/H0g56YaQIalcg6A= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=d+cxh7Adx01Lz+PZ0BqdBZD0tuhqHe+fIcb3T8VVshI=; b=WV2O7objozwqOG1L7SZkYie+h+z1O65CVvTgZd9MLwhm0mls5oKftmifJU1MCdn/yb d4ebdWYfYRnv88w9ET/VWHlud+MS04dYLs77dseCxv/JGa7ZOkE1LLBI/LT6CihIfn8J awI/FlmQfcbLayqmO3fwzKn1Aza9S0SJR+bxEfu6H4wOegBzQ/swMxTa8s5/6ZRQoB8v p0WFtuqXscQC+dFZqbO6omoiFjsqIU/i6GCqowCMTaqsGGWanXABEtqKAIJ8Jx+GbZml QspdNJ1gh5PDT/pyX0n6ewp/tVdYtezgYO23/PO+Dd1nIgqwf0y4fs1+mIoYX1yK4wWO jLgA== X-Gm-Message-State: AOAM5321LlRtUneC97usZMHd+JvF6i1f4H44XYtu0mhDaWB8snDUbZ3r 5gR9WCiZARIx5hPNdv8+CtALcA== X-Google-Smtp-Source: ABdhPJzwV8yZ+vHoQE7rb6HkYEvIykxXV/ucl+4R0uhyvLJBDEppIOQPIpaDe7F8tvEjOO8IV+mKow== X-Received: by 2002:a63:ce41:: with SMTP id r1mr31178572pgi.203.1596045546377; Wed, 29 Jul 2020 10:59:06 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id y10sm3081590pff.187.2020.07.29.10.58.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:59:04 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 13/17] IMA: Add support for file reads without contents Date: Wed, 29 Jul 2020 10:58:41 -0700 Message-Id: <20200729175845.1745471-14-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Scott Branden When the kernel_read_file LSM hook is called with contents=false, IMA can appraise the file directly, without requiring a filled buffer. When such a buffer is available, though, IMA can continue to use it instead of forcing a double read here. Signed-off-by: Scott Branden Link: https://lore.kernel.org/lkml/20200706232309.12010-10-scott.branden@broadcom.com/ Reviewed-by: Mimi Zohar Signed-off-by: Kees Cook --- security/integrity/ima/ima_main.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index dc4f90660aa6..de57fce5bced 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -613,11 +613,8 @@ void ima_post_path_mknod(struct dentry *dentry) int ima_read_file(struct file *file, enum kernel_read_file_id read_id, bool contents) { - /* Reject all partial reads during appraisal. */ - if (!contents) { - if (ima_appraise & IMA_APPRAISE_ENFORCE) - return -EACCES; - } + enum ima_hooks func; + u32 secid; /* * Do devices using pre-allocated memory run the risk of the @@ -626,7 +623,20 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id, * buffers? It may be desirable to include the buffer address * in this API and walk all the dma_map_single() mappings to check. */ - return 0; + + /* + * There will be a call made to ima_post_read_file() with + * a filled buffer, so we don't need to perform an extra + * read early here. + */ + if (contents) + return 0; + + /* Read entire file for all partial reads. */ + func = read_idmap[read_id] ?: FILE_CHECK; + security_task_getsecid(current, &secid); + return process_measurement(file, current_cred(), secid, NULL, + 0, MAY_READ, func); } const int read_idmap[READING_MAX_ID] = { From patchwork Wed Jul 29 17:58:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691475 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D635A913 for ; Wed, 29 Jul 2020 17:59:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B8E6E2083B for ; Wed, 29 Jul 2020 17:59:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="M7Mhxd0V" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728001AbgG2R7X (ORCPT ); Wed, 29 Jul 2020 13:59:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727956AbgG2R7J (ORCPT ); Wed, 29 Jul 2020 13:59:09 -0400 Received: from mail-pj1-x1041.google.com (mail-pj1-x1041.google.com [IPv6:2607:f8b0:4864:20::1041]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D787C08C5DF for ; Wed, 29 Jul 2020 10:59:08 -0700 (PDT) Received: by mail-pj1-x1041.google.com with SMTP id il6so2427815pjb.0 for ; Wed, 29 Jul 2020 10:59:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=O6dxMTnC8mm7wVLUL1y7lUu+yrbj06Q1SoL75qZmOEE=; b=M7Mhxd0VHTaCjwpeLi8bb8xRTEAHLRq1LaJcOFS7AmQH3RfeiwHFguYalSwk9UPXaM X4RpeIahd/8iTvKzIzAeBx58iaUbdKCRMrRhBy6MMLQKbK+ea2rWxsus3vf11lbiBFFc g9WlKEhCezbVivOz/NVWRQm51DCrYN4cYBXYY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=O6dxMTnC8mm7wVLUL1y7lUu+yrbj06Q1SoL75qZmOEE=; b=FAVcYAJna84JH12C8jstbia5mLkdTW1b/aVOhg7mhk9ClPKMJ9fXVt37zsVaGuybFn SR0dBHMBblEGL445PQiiMzPtS9gCLtIu1oUli0S9deajGKDBmVz/icWQjwEzOrIIX0rR 4jbl6ZY+ijTDUwiogb5ZHzw0szOyMS8seUmOO70y/+Cn3Evhy2O9uicywLodf/Yd6Tvq sPHK2v5HIHMv9maeNPQuCG71/ds59g4OP3KKGX2uG9/LzTb4KnvVikbAzlDAYm+lsVAb raGXuXQn2+hiTmSFKAbNJ6QjViLwhr/m6Ah/JapE4TKSacviIiIS2JyUrsCI+5WYhmUQ C+qA== X-Gm-Message-State: AOAM530T1Ok7sQH2mHtRt9Iv+78K03hxEuI068rKsvy47YfCr/k1RFgQ N6nO+cdzXxFQsDp4iU/EBkIPyA== X-Google-Smtp-Source: ABdhPJzd+GNo2MQY1vzIWQ6bA0AmjVMNq/K11NFESpj+C1FM+CA/agEp1qz6/BytDXhQGCqkERCRrw== X-Received: by 2002:a17:90a:d081:: with SMTP id k1mr10817500pju.177.1596045547560; Wed, 29 Jul 2020 10:59:07 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id g10sm3096851pfb.82.2020.07.29.10.58.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:59:04 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 14/17] fs/kernel_file_read: Add "offset" arg for partial reads Date: Wed, 29 Jul 2020 10:58:42 -0700 Message-Id: <20200729175845.1745471-15-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org To perform partial reads, callers of kernel_read_file*() must have a non-NULL file_size argument and a preallocated buffer. The new "offset" argument can then be used to seek to specific locations in the file to fill the buffer to, at most, "buf_size" per call. Where possible, the LSM hooks can report whether a full file has been read or not so that the contents can be reasoned about. Signed-off-by: Kees Cook --- drivers/base/firmware_loader/main.c | 2 +- fs/kernel_read_file.c | 78 ++++++++++++++++++++--------- include/linux/kernel_read_file.h | 8 +-- kernel/kexec_file.c | 4 +- kernel/module.c | 2 +- security/integrity/digsig.c | 2 +- security/integrity/ima/ima_fs.c | 3 +- 7 files changed, 65 insertions(+), 34 deletions(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 6a5d407279e3..ff1808ed7547 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -494,7 +494,7 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, fw_priv->size = 0; /* load firmware files from the mount namespace of init */ - rc = kernel_read_file_from_path_initns(path, &buffer, msize, + rc = kernel_read_file_from_path_initns(path, 0, &buffer, msize, NULL, READING_FIRMWARE); if (rc < 0) { diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c index d73bc3fa710a..90d255fbdd9b 100644 --- a/fs/kernel_read_file.c +++ b/fs/kernel_read_file.c @@ -9,6 +9,7 @@ * kernel_read_file() - read file contents into a kernel buffer * * @file file to read from + * @offset where to start reading from (see below). * @buf pointer to a "void *" buffer for reading into (if * *@buf is NULL, a buffer will be allocated, and * @buf_size will be ignored) @@ -19,19 +20,31 @@ * @id the kernel_read_file_id identifying the type of * file contents being read (for LSMs to examine) * + * @offset must be 0 unless both @buf and @file_size are non-NULL + * (i.e. the caller must be expecting to read partial file contents + * via an already-allocated @buf, in at most @buf_size chunks, and + * will be able to determine when the entire file was read by + * checking @file_size). This isn't a recommended way to read a + * file, though, since it is possible that the contents might + * change between calls to kernel_read_file(). + * * Returns number of bytes read (no single read will be bigger * than INT_MAX), or negative on error. * */ -int kernel_read_file(struct file *file, void **buf, +int kernel_read_file(struct file *file, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id) { loff_t i_size, pos; - ssize_t bytes = 0; + size_t copied; void *allocated = NULL; + bool whole_file; int ret; + if (offset != 0 && (!*buf || !file_size)) + return -EINVAL; + if (!S_ISREG(file_inode(file)->i_mode)) return -EINVAL; @@ -39,19 +52,27 @@ int kernel_read_file(struct file *file, void **buf, if (ret) return ret; - ret = security_kernel_read_file(file, id, true); - if (ret) - goto out; - i_size = i_size_read(file_inode(file)); if (i_size <= 0) { ret = -EINVAL; goto out; } - if (i_size > INT_MAX || i_size > buf_size) { + /* The file is too big for sane activities. */ + if (i_size > INT_MAX) { + ret = -EFBIG; + goto out; + } + /* The entire file cannot be read in one buffer. */ + if (!file_size && offset == 0 && i_size > buf_size) { ret = -EFBIG; goto out; } + + whole_file = (offset == 0 && i_size <= buf_size); + ret = security_kernel_read_file(file, id, whole_file); + if (ret) + goto out; + if (file_size) *file_size = i_size; @@ -62,9 +83,14 @@ int kernel_read_file(struct file *file, void **buf, goto out; } - pos = 0; - while (pos < i_size) { - bytes = kernel_read(file, *buf + pos, i_size - pos, &pos); + pos = offset; + copied = 0; + while (copied < buf_size) { + ssize_t bytes; + size_t wanted = min_t(size_t, buf_size - copied, + i_size - pos); + + bytes = kernel_read(file, *buf + copied, wanted, &pos); if (bytes < 0) { ret = bytes; goto out_free; @@ -72,14 +98,17 @@ int kernel_read_file(struct file *file, void **buf, if (bytes == 0) break; + copied += bytes; } - if (pos != i_size) { - ret = -EIO; - goto out_free; - } + if (whole_file) { + if (pos != i_size) { + ret = -EIO; + goto out_free; + } - ret = security_kernel_post_read_file(file, *buf, i_size, id); + ret = security_kernel_post_read_file(file, *buf, i_size, id); + } out_free: if (ret < 0) { @@ -91,11 +120,11 @@ int kernel_read_file(struct file *file, void **buf, out: allow_write_access(file); - return ret == 0 ? pos : ret; + return ret == 0 ? copied : ret; } EXPORT_SYMBOL_GPL(kernel_read_file); -int kernel_read_file_from_path(const char *path, void **buf, +int kernel_read_file_from_path(const char *path, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id) { @@ -109,14 +138,15 @@ int kernel_read_file_from_path(const char *path, void **buf, if (IS_ERR(file)) return PTR_ERR(file); - ret = kernel_read_file(file, buf, buf_size, file_size, id); + ret = kernel_read_file(file, offset, buf, buf_size, file_size, id); fput(file); return ret; } EXPORT_SYMBOL_GPL(kernel_read_file_from_path); -int kernel_read_file_from_path_initns(const char *path, void **buf, - size_t buf_size, size_t *file_size, +int kernel_read_file_from_path_initns(const char *path, loff_t offset, + void **buf, size_t buf_size, + size_t *file_size, enum kernel_read_file_id id) { struct file *file; @@ -135,14 +165,14 @@ int kernel_read_file_from_path_initns(const char *path, void **buf, if (IS_ERR(file)) return PTR_ERR(file); - ret = kernel_read_file(file, buf, buf_size, file_size, id); + ret = kernel_read_file(file, offset, buf, buf_size, file_size, id); fput(file); return ret; } EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns); -int kernel_read_file_from_fd(int fd, void **buf, size_t buf_size, - size_t *file_size, +int kernel_read_file_from_fd(int fd, loff_t offset, void **buf, + size_t buf_size, size_t *file_size, enum kernel_read_file_id id) { struct fd f = fdget(fd); @@ -151,7 +181,7 @@ int kernel_read_file_from_fd(int fd, void **buf, size_t buf_size, if (!f.file) goto out; - ret = kernel_read_file(f.file, buf, buf_size, file_size, id); + ret = kernel_read_file(f.file, offset, buf, buf_size, file_size, id); out: fdput(f); return ret; diff --git a/include/linux/kernel_read_file.h b/include/linux/kernel_read_file.h index 023293eaf948..575ffa1031d3 100644 --- a/include/linux/kernel_read_file.h +++ b/include/linux/kernel_read_file.h @@ -35,19 +35,19 @@ static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id) return kernel_read_file_str[id]; } -int kernel_read_file(struct file *file, +int kernel_read_file(struct file *file, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id); -int kernel_read_file_from_path(const char *path, +int kernel_read_file_from_path(const char *path, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id); -int kernel_read_file_from_path_initns(const char *path, +int kernel_read_file_from_path_initns(const char *path, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id); -int kernel_read_file_from_fd(int fd, +int kernel_read_file_from_fd(int fd, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id); diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 878ca684a3a1..45726bc8f6ce 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -221,7 +221,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, int ret; void *ldata; - ret = kernel_read_file_from_fd(kernel_fd, &image->kernel_buf, + ret = kernel_read_file_from_fd(kernel_fd, 0, &image->kernel_buf, INT_MAX, NULL, READING_KEXEC_IMAGE); if (ret < 0) return ret; @@ -241,7 +241,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, #endif /* It is possible that there no initramfs is being loaded */ if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { - ret = kernel_read_file_from_fd(initrd_fd, &image->initrd_buf, + ret = kernel_read_file_from_fd(initrd_fd, 0, &image->initrd_buf, INT_MAX, NULL, READING_KEXEC_INITRAMFS); if (ret < 0) diff --git a/kernel/module.c b/kernel/module.c index 72e33e25d7b9..a89900adeb6c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -4010,7 +4010,7 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) |MODULE_INIT_IGNORE_VERMAGIC)) return -EINVAL; - err = kernel_read_file_from_fd(fd, &hdr, INT_MAX, NULL, + err = kernel_read_file_from_fd(fd, 0, &hdr, INT_MAX, NULL, READING_MODULE); if (err < 0) return err; diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 8a523dfd7fd7..0f518dcfde05 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -175,7 +175,7 @@ int __init integrity_load_x509(const unsigned int id, const char *path) int rc; key_perm_t perm; - rc = kernel_read_file_from_path(path, &data, INT_MAX, NULL, + rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL, READING_X509_CERTIFICATE); if (rc < 0) { pr_err("Unable to open file: %s (%d)", path, rc); diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 5fc56ccb6678..ea8ff8a07b36 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -284,7 +284,8 @@ static ssize_t ima_read_policy(char *path) datap = path; strsep(&datap, "\n"); - rc = kernel_read_file_from_path(path, &data, INT_MAX, NULL, READING_POLICY); + rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL, + READING_POLICY); if (rc < 0) { pr_err("Unable to open file: %s (%d)", path, rc); return rc; From patchwork Wed Jul 29 17:58:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691463 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8812B1392 for ; Wed, 29 Jul 2020 17:59:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6882920838 for ; Wed, 29 Jul 2020 17:59:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="VmCpSLRl" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727923AbgG2R7S (ORCPT ); Wed, 29 Jul 2020 13:59:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35664 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727961AbgG2R7J (ORCPT ); Wed, 29 Jul 2020 13:59:09 -0400 Received: from mail-pl1-x644.google.com (mail-pl1-x644.google.com [IPv6:2607:f8b0:4864:20::644]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0C412C0619DC for ; Wed, 29 Jul 2020 10:59:09 -0700 (PDT) Received: by mail-pl1-x644.google.com with SMTP id r4so1519898pls.2 for ; Wed, 29 Jul 2020 10:59:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=lWcAww6uJ01YuNLJeOQrqV6g1rafs6Sro4nLkyLVL3E=; b=VmCpSLRlzhGxSusWQkaM5UvMc829z68Yb/v6IWvG9umwYq20BCokHFg1l9f2y42gW5 7/odZ+3sjmoEi1KaB0hx4W9vzg0vMgIc6WsNuIrGp29+dy31tCcbFXLUYaHVLkLeUQ4L PKDNeqzuZUiKhZVlIe5hXIXVHIqEhNsr5hKDI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=lWcAww6uJ01YuNLJeOQrqV6g1rafs6Sro4nLkyLVL3E=; b=jUtfFRk3uzxfeky7KLRDCFKix4ylBzAqT6O4/Sx+LZ8PXx7t8Mhxr5x/nNbQ/nkA81 TiJ7vv/RmSpjdLWHNyTe0GkDef3B4zbsRnLoNGlVbSYMvo5Od1/4X0qD+s1MhBj0RgkN 8+j6tab2sC3AyJJPDh0mG3+dwJd1N2vDTUU0yHO1DrQc+Yt1ZB2pdEbw7hjTxOlezREr Tey/P+q7YxvDk+jR6g6/RwcXwnWuCGd52jmkP9Y/0h7jsORX6XYdBzlGbEgA7teAI7Y5 0+qRLGuTCkDSnaia7bbjlWiopyQc3SiL5j9SzFmlK3rrC1gZtkADgBrt9c3F9MLcPBpq jXMw== X-Gm-Message-State: AOAM531Y2wWFStjhDWOoGSMWnFEtzzSZBTdd3RGD0vDJ+wgEccefJfQO 7lySXmhnDFB7Eg87tBHjUjOORQ== X-Google-Smtp-Source: ABdhPJy6Yl7Lrov8yv8Do50u41KJqMXcq89CcCeJlL9nAm+R9n16rkazCDlBChTjoFuQhadZ5eX7yg== X-Received: by 2002:a17:90a:c094:: with SMTP id o20mr10399557pjs.12.1596045548534; Wed, 29 Jul 2020 10:59:08 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id r4sm2704205pji.37.2020.07.29.10.59.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:59:04 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 15/17] firmware: Store opt_flags in fw_priv Date: Wed, 29 Jul 2020 10:58:43 -0700 Message-Id: <20200729175845.1745471-16-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Instead of passing opt_flags around so much, store it in the private structure so it can be examined by internals without needing to add more arguments to functions. Co-developed-by: Scott Branden Signed-off-by: Scott Branden Signed-off-by: Kees Cook --- drivers/base/firmware_loader/fallback.c | 11 +++----- drivers/base/firmware_loader/fallback.h | 5 ++-- .../base/firmware_loader/fallback_platform.c | 4 +-- drivers/base/firmware_loader/firmware.h | 3 ++- drivers/base/firmware_loader/main.c | 25 +++++++++++-------- 5 files changed, 25 insertions(+), 23 deletions(-) diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index 7cfdfdcb819c..0a94c8739959 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -490,13 +490,11 @@ fw_create_instance(struct firmware *firmware, const char *fw_name, /** * fw_load_sysfs_fallback() - load a firmware via the sysfs fallback mechanism * @fw_sysfs: firmware sysfs information for the firmware to load - * @opt_flags: flags of options, FW_OPT_* * @timeout: timeout to wait for the load * * In charge of constructing a sysfs fallback interface for firmware loading. **/ -static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, - u32 opt_flags, long timeout) +static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, long timeout) { int retval = 0; struct device *f_dev = &fw_sysfs->dev; @@ -518,7 +516,7 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, list_add(&fw_priv->pending_list, &pending_fw_head); mutex_unlock(&fw_lock); - if (opt_flags & FW_OPT_UEVENT) { + if (fw_priv->opt_flags & FW_OPT_UEVENT) { fw_priv->need_uevent = true; dev_set_uevent_suppress(f_dev, false); dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_name); @@ -580,10 +578,10 @@ static int fw_load_from_user_helper(struct firmware *firmware, } fw_sysfs->fw_priv = firmware->priv; - ret = fw_load_sysfs_fallback(fw_sysfs, opt_flags, timeout); + ret = fw_load_sysfs_fallback(fw_sysfs, timeout); if (!ret) - ret = assign_fw(firmware, device, opt_flags); + ret = assign_fw(firmware, device); out_unlock: usermodehelper_read_unlock(); @@ -625,7 +623,6 @@ static bool fw_run_sysfs_fallback(u32 opt_flags) * @fw: pointer to firmware image * @name: name of firmware file to look for * @device: device for which firmware is being loaded - * @opt_flags: options to control firmware loading behaviour * @ret: return value from direct lookup which triggered the fallback mechanism * * This function is called if direct lookup for the firmware failed, it enables diff --git a/drivers/base/firmware_loader/fallback.h b/drivers/base/firmware_loader/fallback.h index 2afdb6adb23f..3af7205b302f 100644 --- a/drivers/base/firmware_loader/fallback.h +++ b/drivers/base/firmware_loader/fallback.h @@ -67,10 +67,9 @@ static inline void unregister_sysfs_loader(void) #endif /* CONFIG_FW_LOADER_USER_HELPER */ #ifdef CONFIG_EFI_EMBEDDED_FIRMWARE -int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags); +int firmware_fallback_platform(struct fw_priv *fw_priv); #else -static inline int firmware_fallback_platform(struct fw_priv *fw_priv, - u32 opt_flags) +static inline int firmware_fallback_platform(struct fw_priv *fw_priv) { return -ENOENT; } diff --git a/drivers/base/firmware_loader/fallback_platform.c b/drivers/base/firmware_loader/fallback_platform.c index 4d1157af0e86..38de68d7e973 100644 --- a/drivers/base/firmware_loader/fallback_platform.c +++ b/drivers/base/firmware_loader/fallback_platform.c @@ -8,13 +8,13 @@ #include "fallback.h" #include "firmware.h" -int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags) +int firmware_fallback_platform(struct fw_priv *fw_priv) { const u8 *data; size_t size; int rc; - if (!(opt_flags & FW_OPT_FALLBACK_PLATFORM)) + if (!(fw_priv->opt_flags & FW_OPT_FALLBACK_PLATFORM)) return -ENOENT; rc = security_kernel_load_data(LOADING_FIRMWARE, true); diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h index 933e2192fbe8..7ad5fe52bc72 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -68,6 +68,7 @@ struct fw_priv { void *data; size_t size; size_t allocated_size; + u32 opt_flags; #ifdef CONFIG_FW_LOADER_PAGED_BUF bool is_paged_buf; struct page **pages; @@ -136,7 +137,7 @@ static inline void fw_state_done(struct fw_priv *fw_priv) __fw_state_set(fw_priv, FW_STATUS_DONE); } -int assign_fw(struct firmware *fw, struct device *device, u32 opt_flags); +int assign_fw(struct firmware *fw, struct device *device); #ifdef CONFIG_FW_LOADER_PAGED_BUF void fw_free_paged_buf(struct fw_priv *fw_priv); diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index ff1808ed7547..67d8afa91ae0 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -168,7 +168,9 @@ static int fw_cache_piggyback_on_request(const char *name); static struct fw_priv *__allocate_fw_priv(const char *fw_name, struct firmware_cache *fwc, - void *dbuf, size_t size) + void *dbuf, + size_t size, + u32 opt_flags) { struct fw_priv *fw_priv; @@ -186,6 +188,7 @@ static struct fw_priv *__allocate_fw_priv(const char *fw_name, fw_priv->fwc = fwc; fw_priv->data = dbuf; fw_priv->allocated_size = size; + fw_priv->opt_flags = opt_flags; fw_state_init(fw_priv); #ifdef CONFIG_FW_LOADER_USER_HELPER INIT_LIST_HEAD(&fw_priv->pending_list); @@ -210,8 +213,10 @@ static struct fw_priv *__lookup_fw_priv(const char *fw_name) /* Returns 1 for batching firmware requests with the same name */ static int alloc_lookup_fw_priv(const char *fw_name, struct firmware_cache *fwc, - struct fw_priv **fw_priv, void *dbuf, - size_t size, u32 opt_flags) + struct fw_priv **fw_priv, + void *dbuf, + size_t size, + u32 opt_flags) { struct fw_priv *tmp; @@ -227,7 +232,7 @@ static int alloc_lookup_fw_priv(const char *fw_name, } } - tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size); + tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size, opt_flags); if (tmp) { INIT_LIST_HEAD(&tmp->list); if (!(opt_flags & FW_OPT_NOCACHE)) @@ -635,7 +640,7 @@ static int fw_add_devm_name(struct device *dev, const char *name) } #endif -int assign_fw(struct firmware *fw, struct device *device, u32 opt_flags) +int assign_fw(struct firmware *fw, struct device *device) { struct fw_priv *fw_priv = fw->priv; int ret; @@ -654,8 +659,8 @@ int assign_fw(struct firmware *fw, struct device *device, u32 opt_flags) * should be fixed in devres or driver core. */ /* don't cache firmware handled without uevent */ - if (device && (opt_flags & FW_OPT_UEVENT) && - !(opt_flags & FW_OPT_NOCACHE)) { + if (device && (fw_priv->opt_flags & FW_OPT_UEVENT) && + !(fw_priv->opt_flags & FW_OPT_NOCACHE)) { ret = fw_add_devm_name(device, fw_priv->fw_name); if (ret) { mutex_unlock(&fw_lock); @@ -667,7 +672,7 @@ int assign_fw(struct firmware *fw, struct device *device, u32 opt_flags) * After caching firmware image is started, let it piggyback * on request firmware. */ - if (!(opt_flags & FW_OPT_NOCACHE) && + if (!(fw_priv->opt_flags & FW_OPT_NOCACHE) && fw_priv->fwc->state == FW_LOADER_START_CACHE) { if (fw_cache_piggyback_on_request(fw_priv->fw_name)) kref_get(&fw_priv->ref); @@ -778,7 +783,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name, #endif if (ret == -ENOENT) - ret = firmware_fallback_platform(fw->priv, opt_flags); + ret = firmware_fallback_platform(fw->priv); if (ret) { if (!(opt_flags & FW_OPT_NO_WARN)) @@ -787,7 +792,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name, name, ret); ret = firmware_fallback_sysfs(fw, name, device, opt_flags, ret); } else - ret = assign_fw(fw, device, opt_flags); + ret = assign_fw(fw, device); out: if (ret < 0) { From patchwork Wed Jul 29 17:58:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691483 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 02F88913 for ; Wed, 29 Jul 2020 17:59:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D48B822B47 for ; Wed, 29 Jul 2020 17:59:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="hp7mbpgp" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727909AbgG2R7d (ORCPT ); Wed, 29 Jul 2020 13:59:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35716 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727939AbgG2R7H (ORCPT ); Wed, 29 Jul 2020 13:59:07 -0400 Received: from mail-pf1-x444.google.com (mail-pf1-x444.google.com [IPv6:2607:f8b0:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7BDB2C08C5DB for ; Wed, 29 Jul 2020 10:59:07 -0700 (PDT) Received: by mail-pf1-x444.google.com with SMTP id d188so7279251pfd.2 for ; Wed, 29 Jul 2020 10:59:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=+NaGsZ6LkqLP7N90n/8Avv/y2oDkj/LqGy0xmUe3sQI=; b=hp7mbpgpzEbT4hmsg/0VefWpKjWuMD8517bITA0szXsxyzLErrtYxEne3GSIfYyf1a TbEZZ3NQ3QLjzbI0vCoMwVy4hBW0R6Gd9ppCmdX5jDyH5QP8CHt+Ed6X8dJ6iSEQDMqP qZ+HawSNZSCQwfzbfxd8luxWK5q5OVS5vXT1o= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=+NaGsZ6LkqLP7N90n/8Avv/y2oDkj/LqGy0xmUe3sQI=; b=FqLQykehnfFapVobe6y72u7bqGi6PuNF1A7M2XIch0dKL455myEQ9jQcN7xbwy2Mgu OuBaRnsQbhyS2QneEo3DBGBDZM0J5LAmo72z1G1Yu/zDNk66o7IahI2AIgK5zGG+K/Zu R0tJXsblnMDsR4hHuaHXZk6d+OsSY2Z348pmGjNvLhcrnmYZdK+zEzI0ReY3ULcMVTDa dG19VQ/RkvxM3JjZokfjrhWi6eVnMNrhIZhTzWWE1A9Qd4Q4MhtG6gF5OLjomEubBuS3 gwHc0Z0IpccxWHkd4/5vH3XfWAX+QYzBW4ijmHvoXn+aLPc3qPw9L98LlhfqcalLeNvM 0IQg== X-Gm-Message-State: AOAM533O85AdMU9hX+px869SY7k7dcCDoDBwacDLLxmEDpQP+76as1Ny gDbkVlo80wO2SZ6s43Mo741auA== X-Google-Smtp-Source: ABdhPJxyBV4lMmdEC9afNAeBvnS7qOJJXJuf2R/sr7FyvukYVdfczUkitscrueNwT/Og6LWrh8CU+g== X-Received: by 2002:a62:7705:: with SMTP id s5mr12985932pfc.52.1596045546921; Wed, 29 Jul 2020 10:59:06 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id s125sm1247882pfc.63.2020.07.29.10.59.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 10:59:04 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 16/17] firmware: Add request_partial_firmware_into_buf() Date: Wed, 29 Jul 2020 10:58:44 -0700 Message-Id: <20200729175845.1745471-17-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Scott Branden Add request_partial_firmware_into_buf() to allow for portions of a firmware file to be read into a buffer. This is needed when large firmware must be loaded in portions from a file on memory constrained systems. Signed-off-by: Scott Branden Co-developed-by: Kees Cook Signed-off-by: Kees Cook --- drivers/base/firmware_loader/firmware.h | 4 + drivers/base/firmware_loader/main.c | 101 +++++++++++++++++++----- include/linux/firmware.h | 12 +++ 3 files changed, 99 insertions(+), 18 deletions(-) diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h index 7ad5fe52bc72..3f6eda46b3a2 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -32,6 +32,8 @@ * @FW_OPT_FALLBACK_PLATFORM: Enable fallback to device fw copy embedded in * the platform's main firmware. If both this fallback and the sysfs * fallback are enabled, then this fallback will be tried first. + * @FW_OPT_PARTIAL: Allow partial read of firmware instead of needing to read + * entire file. */ enum fw_opt { FW_OPT_UEVENT = BIT(0), @@ -41,6 +43,7 @@ enum fw_opt { FW_OPT_NOCACHE = BIT(4), FW_OPT_NOFALLBACK_SYSFS = BIT(5), FW_OPT_FALLBACK_PLATFORM = BIT(6), + FW_OPT_PARTIAL = BIT(7), }; enum fw_status { @@ -68,6 +71,7 @@ struct fw_priv { void *data; size_t size; size_t allocated_size; + size_t offset; u32 opt_flags; #ifdef CONFIG_FW_LOADER_PAGED_BUF bool is_paged_buf; diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 67d8afa91ae0..54c5d57b6327 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -170,10 +170,19 @@ static struct fw_priv *__allocate_fw_priv(const char *fw_name, struct firmware_cache *fwc, void *dbuf, size_t size, + size_t offset, u32 opt_flags) { struct fw_priv *fw_priv; + /* For a partial read, the buffer must be preallocated. */ + if ((opt_flags & FW_OPT_PARTIAL) && !dbuf) + return NULL; + + /* Only partial reads are allowed to use an offset. */ + if (offset != 0 && !(opt_flags & FW_OPT_PARTIAL)) + return NULL; + fw_priv = kzalloc(sizeof(*fw_priv), GFP_ATOMIC); if (!fw_priv) return NULL; @@ -188,6 +197,7 @@ static struct fw_priv *__allocate_fw_priv(const char *fw_name, fw_priv->fwc = fwc; fw_priv->data = dbuf; fw_priv->allocated_size = size; + fw_priv->offset = offset; fw_priv->opt_flags = opt_flags; fw_state_init(fw_priv); #ifdef CONFIG_FW_LOADER_USER_HELPER @@ -216,12 +226,17 @@ static int alloc_lookup_fw_priv(const char *fw_name, struct fw_priv **fw_priv, void *dbuf, size_t size, + size_t offset, u32 opt_flags) { struct fw_priv *tmp; spin_lock(&fwc->lock); - if (!(opt_flags & FW_OPT_NOCACHE)) { + /* + * Do not merge requests that are marked to be non-cached or + * are performing partial reads. + */ + if (!(opt_flags & (FW_OPT_NOCACHE | FW_OPT_PARTIAL))) { tmp = __lookup_fw_priv(fw_name); if (tmp) { kref_get(&tmp->ref); @@ -232,7 +247,7 @@ static int alloc_lookup_fw_priv(const char *fw_name, } } - tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size, opt_flags); + tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size, offset, opt_flags); if (tmp) { INIT_LIST_HEAD(&tmp->list); if (!(opt_flags & FW_OPT_NOCACHE)) @@ -485,6 +500,9 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, return -ENOMEM; for (i = 0; i < ARRAY_SIZE(fw_path); i++) { + size_t file_size = 0; + size_t *file_size_ptr = NULL; + /* skip the unset customized path */ if (!fw_path[i][0]) continue; @@ -498,9 +516,18 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, fw_priv->size = 0; + /* + * The total file size is only examined when doing a partial + * read; the "full read" case needs to fail if the whole + * firmware was not completely loaded. + */ + if ((fw_priv->opt_flags & FW_OPT_PARTIAL) && buffer) + file_size_ptr = &file_size; + /* load firmware files from the mount namespace of init */ - rc = kernel_read_file_from_path_initns(path, 0, &buffer, msize, - NULL, + rc = kernel_read_file_from_path_initns(path, fw_priv->offset, + &buffer, msize, + file_size_ptr, READING_FIRMWARE); if (rc < 0) { if (rc != -ENOENT) @@ -691,7 +718,7 @@ int assign_fw(struct firmware *fw, struct device *device) static int _request_firmware_prepare(struct firmware **firmware_p, const char *name, struct device *device, void *dbuf, size_t size, - u32 opt_flags) + size_t offset, u32 opt_flags) { struct firmware *firmware; struct fw_priv *fw_priv; @@ -710,7 +737,7 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name, } ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, dbuf, size, - opt_flags); + offset, opt_flags); /* * bind with 'priv' now to avoid warning in failure path @@ -757,9 +784,10 @@ static void fw_abort_batch_reqs(struct firmware *fw) static int _request_firmware(const struct firmware **firmware_p, const char *name, struct device *device, void *buf, size_t size, - u32 opt_flags) + size_t offset, u32 opt_flags) { struct firmware *fw = NULL; + bool nondirect = false; int ret; if (!firmware_p) @@ -771,18 +799,22 @@ _request_firmware(const struct firmware **firmware_p, const char *name, } ret = _request_firmware_prepare(&fw, name, device, buf, size, - opt_flags); + offset, opt_flags); if (ret <= 0) /* error or already assigned */ goto out; ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL); + + /* Only full reads can support decompression, platform, and sysfs. */ + if (!(opt_flags & FW_OPT_PARTIAL)) + nondirect = true; + #ifdef CONFIG_FW_LOADER_COMPRESS - if (ret == -ENOENT) + if (ret == -ENOENT && nondirect) ret = fw_get_filesystem_firmware(device, fw->priv, ".xz", fw_decompress_xz); #endif - - if (ret == -ENOENT) + if (ret == -ENOENT && nondirect) ret = firmware_fallback_platform(fw->priv); if (ret) { @@ -790,7 +822,9 @@ _request_firmware(const struct firmware **firmware_p, const char *name, dev_warn(device, "Direct firmware load for %s failed with error %d\n", name, ret); - ret = firmware_fallback_sysfs(fw, name, device, opt_flags, ret); + if (nondirect) + ret = firmware_fallback_sysfs(fw, name, device, + opt_flags, ret); } else ret = assign_fw(fw, device); @@ -833,7 +867,7 @@ request_firmware(const struct firmware **firmware_p, const char *name, /* Need to pin this module until return */ __module_get(THIS_MODULE); - ret = _request_firmware(firmware_p, name, device, NULL, 0, + ret = _request_firmware(firmware_p, name, device, NULL, 0, 0, FW_OPT_UEVENT); module_put(THIS_MODULE); return ret; @@ -860,7 +894,7 @@ int firmware_request_nowarn(const struct firmware **firmware, const char *name, /* Need to pin this module until return */ __module_get(THIS_MODULE); - ret = _request_firmware(firmware, name, device, NULL, 0, + ret = _request_firmware(firmware, name, device, NULL, 0, 0, FW_OPT_UEVENT | FW_OPT_NO_WARN); module_put(THIS_MODULE); return ret; @@ -884,7 +918,7 @@ int request_firmware_direct(const struct firmware **firmware_p, int ret; __module_get(THIS_MODULE); - ret = _request_firmware(firmware_p, name, device, NULL, 0, + ret = _request_firmware(firmware_p, name, device, NULL, 0, 0, FW_OPT_UEVENT | FW_OPT_NO_WARN | FW_OPT_NOFALLBACK_SYSFS); module_put(THIS_MODULE); @@ -909,7 +943,7 @@ int firmware_request_platform(const struct firmware **firmware, /* Need to pin this module until return */ __module_get(THIS_MODULE); - ret = _request_firmware(firmware, name, device, NULL, 0, + ret = _request_firmware(firmware, name, device, NULL, 0, 0, FW_OPT_UEVENT | FW_OPT_FALLBACK_PLATFORM); module_put(THIS_MODULE); return ret; @@ -965,13 +999,44 @@ request_firmware_into_buf(const struct firmware **firmware_p, const char *name, return -EOPNOTSUPP; __module_get(THIS_MODULE); - ret = _request_firmware(firmware_p, name, device, buf, size, + ret = _request_firmware(firmware_p, name, device, buf, size, 0, FW_OPT_UEVENT | FW_OPT_NOCACHE); module_put(THIS_MODULE); return ret; } EXPORT_SYMBOL(request_firmware_into_buf); +/** + * request_partial_firmware_into_buf() - load partial firmware into a previously allocated buffer + * @firmware_p: pointer to firmware image + * @name: name of firmware file + * @device: device for which firmware is being loaded and DMA region allocated + * @buf: address of buffer to load firmware into + * @size: size of buffer + * @offset: offset into file to read + * + * This function works pretty much like request_firmware_into_buf except + * it allows a partial read of the file. + */ +int +request_partial_firmware_into_buf(const struct firmware **firmware_p, + const char *name, struct device *device, + void *buf, size_t size, size_t offset) +{ + int ret; + + if (fw_cache_is_setup(device, name)) + return -EOPNOTSUPP; + + __module_get(THIS_MODULE); + ret = _request_firmware(firmware_p, name, device, buf, size, offset, + FW_OPT_UEVENT | FW_OPT_NOCACHE | + FW_OPT_PARTIAL); + module_put(THIS_MODULE); + return ret; +} +EXPORT_SYMBOL(request_partial_firmware_into_buf); + /** * release_firmware() - release the resource associated with a firmware image * @fw: firmware resource to release @@ -1004,7 +1069,7 @@ static void request_firmware_work_func(struct work_struct *work) fw_work = container_of(work, struct firmware_work, work); - _request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0, + _request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0, 0, fw_work->opt_flags); fw_work->cont(fw, fw_work->context); put_device(fw_work->device); /* taken in request_firmware_nowait() */ diff --git a/include/linux/firmware.h b/include/linux/firmware.h index cb3e2c06ed8a..c15acadc6cf4 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h @@ -53,6 +53,9 @@ int request_firmware_direct(const struct firmware **fw, const char *name, struct device *device); int request_firmware_into_buf(const struct firmware **firmware_p, const char *name, struct device *device, void *buf, size_t size); +int request_partial_firmware_into_buf(const struct firmware **firmware_p, + const char *name, struct device *device, + void *buf, size_t size, size_t offset); void release_firmware(const struct firmware *fw); #else @@ -102,6 +105,15 @@ static inline int request_firmware_into_buf(const struct firmware **firmware_p, return -EINVAL; } +static inline int request_partial_firmware_into_buf + (const struct firmware **firmware_p, + const char *name, + struct device *device, + void *buf, size_t size, size_t offset) +{ + return -EINVAL; +} + #endif int firmware_request_cache(struct device *device, const char *name); From patchwork Wed Jul 29 17:58:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11691593 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3DAB36C1 for ; Wed, 29 Jul 2020 18:08:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1B8602075F for ; Wed, 29 Jul 2020 18:08:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="NvT8VXou" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727791AbgG2SIy (ORCPT ); Wed, 29 Jul 2020 14:08:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37240 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726825AbgG2SIu (ORCPT ); Wed, 29 Jul 2020 14:08:50 -0400 Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3B17AC0619D7 for ; Wed, 29 Jul 2020 11:08:50 -0700 (PDT) Received: by mail-pl1-x643.google.com with SMTP id d1so12166652plr.8 for ; Wed, 29 Jul 2020 11:08:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=yHo9JWZzUyjBazerQ4BEANBUtQtdpP9atcQMB9aajac=; b=NvT8VXoujTZ0Hj5eqlf9jwL52OCMFhndos/nuWgslFO5jsHrdJ+euSuji8sSq6MGTE 9bdxX24HOJgiw32VpiFb2Ogi9cTWzFi89Yja1P46LAEVVsmBkg4ipNrzaLwk5f+SLIG+ 3Gek5p342VvarO/kZVcuTzVDF6NRDxs355NlU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=yHo9JWZzUyjBazerQ4BEANBUtQtdpP9atcQMB9aajac=; b=WtglKgVa2Y+5DLd//dL68CqUJ+MEKEV95yxIMhkLFsk9201Lk1sqnjkMN5XHpmCCdw OO4weKZtyDpZBxq9kkUd3gWMLPVegFBEcL0mjVNsUmPMNhx8r64L8XCPp7DCzVf7NIT3 BgGHXOkEfZFkPD9AWssuxIFa0vovlUhAnZfB9VDUZvCEyYTNypiXNBpykn6dq6Upo4Nm t2ZpI120twCleEtySAI80ESsNycsXyS4MzdY7s/nAAj1SN+5CVlFIEOng+Eyg2HuM56f T+xw9c5oAp6V2rfz26QAZnNfA03PSETGLxnmisTyZf5CrJ5tU8pV/78z7KXo9yUxr0ma M73A== X-Gm-Message-State: AOAM532PC9t5kx9dIRcXAQMI5ObWzyhVVCXno4WqCGCoTUreeDBodPHB Fa7801n39M1HTHuGA4TNnVcxbg== X-Google-Smtp-Source: ABdhPJxCXFyAXbDqIabQ4k/mW+HoDdIBwjXl7/WETODepWvJ4iIAmA3BDJKmHWMB5w2xD1QIrM5OFg== X-Received: by 2002:a17:90a:d583:: with SMTP id v3mr10867142pju.33.1596046129542; Wed, 29 Jul 2020 11:08:49 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id b25sm454550pft.134.2020.07.29.11.08.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jul 2020 11:08:48 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Mimi Zohar , Luis Chamberlain , Takashi Iwai , Jessica Yu , SeongJae Park , KP Singh , linux-efi@vger.kernel.org, linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 17/17] test_firmware: Test partial read support Date: Wed, 29 Jul 2020 10:58:45 -0700 Message-Id: <20200729175845.1745471-18-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200729175845.1745471-1-keescook@chromium.org> References: <20200729175845.1745471-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Scott Branden Add additional hooks to test_firmware to pass in support for partial file read using request_firmware_into_buf(): buf_size: size of buffer to request firmware into partial: indicates that a partial file request is being made file_offset: to indicate offset into file to request Also update firmware selftests to use the new partial read test API. Signed-off-by: Scott Branden Co-developed-by: Kees Cook Signed-off-by: Kees Cook --- lib/test_firmware.c | 154 ++++++++++++++++-- .../selftests/firmware/fw_filesystem.sh | 91 +++++++++++ 2 files changed, 233 insertions(+), 12 deletions(-) diff --git a/lib/test_firmware.c b/lib/test_firmware.c index 62af792e151c..387acb94eeea 100644 --- a/lib/test_firmware.c +++ b/lib/test_firmware.c @@ -50,6 +50,9 @@ struct test_batched_req { * @name: the name of the firmware file to look for * @into_buf: when the into_buf is used if this is true * request_firmware_into_buf() will be used instead. + * @buf_size: size of buf to allocate when into_buf is true + * @file_offset: file offset to request when calling request_firmware_into_buf + * @partial: partial read opt when calling request_firmware_into_buf * @sync_direct: when the sync trigger is used if this is true * request_firmware_direct() will be used instead. * @send_uevent: whether or not to send a uevent for async requests @@ -89,6 +92,9 @@ struct test_batched_req { struct test_config { char *name; bool into_buf; + size_t buf_size; + size_t file_offset; + bool partial; bool sync_direct; bool send_uevent; u8 num_requests; @@ -183,6 +189,9 @@ static int __test_firmware_config_init(void) test_fw_config->num_requests = TEST_FIRMWARE_NUM_REQS; test_fw_config->send_uevent = true; test_fw_config->into_buf = false; + test_fw_config->buf_size = TEST_FIRMWARE_BUF_SIZE; + test_fw_config->file_offset = 0; + test_fw_config->partial = false; test_fw_config->sync_direct = false; test_fw_config->req_firmware = request_firmware; test_fw_config->test_result = 0; @@ -236,28 +245,35 @@ static ssize_t config_show(struct device *dev, dev_name(dev)); if (test_fw_config->name) - len += scnprintf(buf+len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "name:\t%s\n", test_fw_config->name); else - len += scnprintf(buf+len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "name:\tEMTPY\n"); - len += scnprintf(buf+len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "num_requests:\t%u\n", test_fw_config->num_requests); - len += scnprintf(buf+len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "send_uevent:\t\t%s\n", test_fw_config->send_uevent ? "FW_ACTION_HOTPLUG" : "FW_ACTION_NOHOTPLUG"); - len += scnprintf(buf+len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "into_buf:\t\t%s\n", test_fw_config->into_buf ? "true" : "false"); - len += scnprintf(buf+len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, + "buf_size:\t%zu\n", test_fw_config->buf_size); + len += scnprintf(buf + len, PAGE_SIZE - len, + "file_offset:\t%zu\n", test_fw_config->file_offset); + len += scnprintf(buf + len, PAGE_SIZE - len, + "partial:\t\t%s\n", + test_fw_config->partial ? "true" : "false"); + len += scnprintf(buf + len, PAGE_SIZE - len, "sync_direct:\t\t%s\n", test_fw_config->sync_direct ? "true" : "false"); - len += scnprintf(buf+len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "read_fw_idx:\t%u\n", test_fw_config->read_fw_idx); mutex_unlock(&test_fw_mutex); @@ -315,6 +331,30 @@ static ssize_t test_dev_config_show_bool(char *buf, bool val) return snprintf(buf, PAGE_SIZE, "%d\n", val); } +static int test_dev_config_update_size_t(const char *buf, + size_t size, + size_t *cfg) +{ + int ret; + long new; + + ret = kstrtol(buf, 10, &new); + if (ret) + return ret; + + mutex_lock(&test_fw_mutex); + *(size_t *)cfg = new; + mutex_unlock(&test_fw_mutex); + + /* Always return full write size even if we didn't consume all */ + return size; +} + +static ssize_t test_dev_config_show_size_t(char *buf, size_t val) +{ + return snprintf(buf, PAGE_SIZE, "%zu\n", val); +} + static ssize_t test_dev_config_show_int(char *buf, int val) { return snprintf(buf, PAGE_SIZE, "%d\n", val); @@ -400,6 +440,83 @@ static ssize_t config_into_buf_show(struct device *dev, } static DEVICE_ATTR_RW(config_into_buf); +static ssize_t config_buf_size_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + + mutex_lock(&test_fw_mutex); + if (test_fw_config->reqs) { + pr_err("Must call release_all_firmware prior to changing config\n"); + rc = -EINVAL; + mutex_unlock(&test_fw_mutex); + goto out; + } + mutex_unlock(&test_fw_mutex); + + rc = test_dev_config_update_size_t(buf, count, + &test_fw_config->buf_size); + +out: + return rc; +} + +static ssize_t config_buf_size_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return test_dev_config_show_size_t(buf, test_fw_config->buf_size); +} +static DEVICE_ATTR_RW(config_buf_size); + +static ssize_t config_file_offset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + + mutex_lock(&test_fw_mutex); + if (test_fw_config->reqs) { + pr_err("Must call release_all_firmware prior to changing config\n"); + rc = -EINVAL; + mutex_unlock(&test_fw_mutex); + goto out; + } + mutex_unlock(&test_fw_mutex); + + rc = test_dev_config_update_size_t(buf, count, + &test_fw_config->file_offset); + +out: + return rc; +} + +static ssize_t config_file_offset_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return test_dev_config_show_size_t(buf, test_fw_config->file_offset); +} +static DEVICE_ATTR_RW(config_file_offset); + +static ssize_t config_partial_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return test_dev_config_update_bool(buf, + count, + &test_fw_config->partial); +} + +static ssize_t config_partial_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return test_dev_config_show_bool(buf, test_fw_config->partial); +} +static DEVICE_ATTR_RW(config_partial); + static ssize_t config_sync_direct_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -655,11 +772,21 @@ static int test_fw_run_batch_request(void *data) if (!test_buf) return -ENOSPC; - req->rc = request_firmware_into_buf(&req->fw, - req->name, - req->dev, - test_buf, - TEST_FIRMWARE_BUF_SIZE); + if (test_fw_config->partial) + req->rc = request_partial_firmware_into_buf + (&req->fw, + req->name, + req->dev, + test_buf, + test_fw_config->buf_size, + test_fw_config->file_offset); + else + req->rc = request_firmware_into_buf + (&req->fw, + req->name, + req->dev, + test_buf, + test_fw_config->buf_size); if (!req->fw) kfree(test_buf); } else { @@ -932,6 +1059,9 @@ static struct attribute *test_dev_attrs[] = { TEST_FW_DEV_ATTR(config_name), TEST_FW_DEV_ATTR(config_num_requests), TEST_FW_DEV_ATTR(config_into_buf), + TEST_FW_DEV_ATTR(config_buf_size), + TEST_FW_DEV_ATTR(config_file_offset), + TEST_FW_DEV_ATTR(config_partial), TEST_FW_DEV_ATTR(config_sync_direct), TEST_FW_DEV_ATTR(config_send_uevent), TEST_FW_DEV_ATTR(config_read_fw_idx), diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh index fcc281373b4d..c2a2a100114b 100755 --- a/tools/testing/selftests/firmware/fw_filesystem.sh +++ b/tools/testing/selftests/firmware/fw_filesystem.sh @@ -149,6 +149,26 @@ config_unset_into_buf() echo 0 > $DIR/config_into_buf } +config_set_buf_size() +{ + echo $1 > $DIR/config_buf_size +} + +config_set_file_offset() +{ + echo $1 > $DIR/config_file_offset +} + +config_set_partial() +{ + echo 1 > $DIR/config_partial +} + +config_unset_partial() +{ + echo 0 > $DIR/config_partial +} + config_set_sync_direct() { echo 1 > $DIR/config_sync_direct @@ -207,6 +227,35 @@ read_firmwares() done } +read_partial_firmwares() +{ + if [ "$(cat $DIR/config_into_buf)" == "1" ]; then + fwfile="${FW_INTO_BUF}" + else + fwfile="${FW}" + fi + + if [ "$1" = "xzonly" ]; then + fwfile="${fwfile}-orig" + fi + + # Strip fwfile down to match partial offset and length + partial_data="$(cat $fwfile)" + partial_data="${partial_data:$2:$3}" + + for i in $(seq 0 3); do + config_set_read_fw_idx $i + + read_firmware="$(cat $DIR/read_firmware)" + + # Verify the contents are what we expect. + if [ $read_firmware != $partial_data ]; then + echo "request #$i: partial firmware was not loaded" >&2 + exit 1 + fi + done +} + read_firmwares_expect_nofile() { for i in $(seq 0 3); do @@ -242,6 +291,21 @@ test_batched_request_firmware_into_buf_nofile() echo "OK" } +test_request_partial_firmware_into_buf_nofile() +{ + echo -n "Test request_partial_firmware_into_buf() off=$1 size=$2 nofile: " + config_reset + config_set_name nope-test-firmware.bin + config_set_into_buf + config_set_partial + config_set_buf_size $2 + config_set_file_offset $1 + config_trigger_sync + read_firmwares_expect_nofile + release_all_firmware + echo "OK" +} + test_batched_request_firmware_direct_nofile() { echo -n "Batched request_firmware_direct() nofile try #$1: " @@ -356,6 +420,21 @@ test_request_firmware_nowait_custom() echo "OK" } +test_request_partial_firmware_into_buf() +{ + echo -n "Test request_partial_firmware_into_buf() off=$1 size=$2: " + config_reset + config_set_name $TEST_FIRMWARE_INTO_BUF_FILENAME + config_set_into_buf + config_set_partial + config_set_buf_size $2 + config_set_file_offset $1 + config_trigger_sync + read_partial_firmwares normal $1 $2 + release_all_firmware + echo "OK" +} + # Only continue if batched request triggers are present on the # test-firmware driver test_config_present @@ -383,6 +462,12 @@ for i in $(seq 1 5); do test_request_firmware_nowait_custom $i normal done +# Partial loads cannot use fallback, so do not repeat tests. +test_request_partial_firmware_into_buf 0 10 +test_request_partial_firmware_into_buf 0 5 +test_request_partial_firmware_into_buf 1 6 +test_request_partial_firmware_into_buf 2 10 + # Test for file not found, errors are expected, the failure would be # a hung task, which would require a hard reset. echo @@ -407,6 +492,12 @@ for i in $(seq 1 5); do test_request_firmware_nowait_custom_nofile $i done +# Partial loads cannot use fallback, so do not repeat tests. +test_request_partial_firmware_into_buf_nofile 0 10 +test_request_partial_firmware_into_buf_nofile 0 5 +test_request_partial_firmware_into_buf_nofile 1 6 +test_request_partial_firmware_into_buf_nofile 2 10 + test "$HAS_FW_LOADER_COMPRESS" != "yes" && exit 0 # test with both files present