From patchwork Fri Oct 2 17:38:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814203 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 7CD196CB for ; Fri, 2 Oct 2020 17:38:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 590AC208C7 for ; Fri, 2 Oct 2020 17:38:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="P86pB/HX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388316AbgJBRie (ORCPT ); Fri, 2 Oct 2020 13:38:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55754 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726224AbgJBRie (ORCPT ); Fri, 2 Oct 2020 13:38:34 -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 7E56DC0613E3 for ; Fri, 2 Oct 2020 10:38:34 -0700 (PDT) Received: by mail-pf1-x441.google.com with SMTP id e10so1192870pfj.1 for ; Fri, 02 Oct 2020 10:38:34 -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=zaz5SJSv7A3XIuY8irUlDYqrESCe7gCcbO5tyaj03YU=; b=P86pB/HXvB1w66ujMKVlopbZUXuUA9r/mPIuYxOvuiet70Gi6UIgoN+Kxio24CM2/7 JfgmdRD8tgSfN3CFJ4Y75Bc4bn3m64UX/3OdRDLmD2nFCO6GweQosA22/MJXNgddI2Ip 1C480tVdsX9QUYYwIHMsDzV2XEJnCWfTsf7Xc= 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=zaz5SJSv7A3XIuY8irUlDYqrESCe7gCcbO5tyaj03YU=; b=dHNEPuWbYJN5Rde1+vyN2aVErdatfl5Y3CxfhXyBx84UfdeyaWyvySDrY8mHBRKOWm lsouWcSqJh8YEHiOvpiuI7JsKEPe+l2x44KoXGcGuD05hRlikY+hpNjsNE9oqI1cnaNB gRGiZi8ALLOYrg25AadOnmdkqytCfjbXdO/ud3B2ZVam6aWH2dV33aj8cgcHMIDL94e9 YM4+tYb0muMZfXnaKkrs3/2cYbMEqpnzt0y9rDFZxsbbCJ/F0LQ+6L1/dv6R7nafidgx C1lzHw5p7SBKKNmK5qHvIkQocNAS6dZX8dOQHBbgTe9bJ4UMbA9efh6mEvszdYlXNhnX wkRA== X-Gm-Message-State: AOAM533LRwwvEBxWLKcgX7kDnAEpEnXbV8drghrGQr6Ts/pppwrFQMM6 4EmulFC7beCP6qiKe50RF2vCfw== X-Google-Smtp-Source: ABdhPJxJZ5x2VgwvjB+CQFTtiG0FWPNxJc97Kyr4F/xETn9n8wWrhHY845HJDJm4z1m1PHBe9jXOTw== X-Received: by 2002:a63:121f:: with SMTP id h31mr3361167pgl.274.1601660313889; Fri, 02 Oct 2020 10:38:33 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id j25sm2609285pfn.212.2020.10.02.10.38.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:33 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Mimi Zohar , Luis Chamberlain , Scott Branden , stable@vger.kernel.org, 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 v5 01/16] fs/kernel_read_file: Remove FIRMWARE_PREALLOC_BUFFER enum Date: Fri, 2 Oct 2020 10:38:13 -0700 Message-Id: <20201002173828.2099543-2-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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)") Signed-off-by: Kees Cook Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Acked-by: Scott Branden Cc: stable@vger.kernel.org Reviewed-by: James Morris --- 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 63b9714a0154..b0ec2721f55d 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -470,14 +470,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; } @@ -501,7 +499,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 a91003e28eaa..9233cd50dc4c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -954,6 +954,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) @@ -977,8 +978,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; @@ -1007,7 +1008,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 7519ae003a08..7336e22d0c5d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2858,10 +2858,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 1c5cff34d9f2..b2808acac46b 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -4035,7 +4035,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 8a91711ca79b..2f187784c5bc 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 Fri Oct 2 17:38:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814211 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 A8B78618 for ; Fri, 2 Oct 2020 17:38:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8AEBC2137B for ; Fri, 2 Oct 2020 17:38:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="mnMnlTBe" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388362AbgJBRii (ORCPT ); Fri, 2 Oct 2020 13:38:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55766 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388320AbgJBRif (ORCPT ); Fri, 2 Oct 2020 13:38:35 -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 3F2DEC0613E6 for ; Fri, 2 Oct 2020 10:38:35 -0700 (PDT) Received: by mail-pg1-x543.google.com with SMTP id q18so1233069pgk.7 for ; Fri, 02 Oct 2020 10:38:35 -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=ITw/V5vvWbmjAkuPXqZiQMYCEzK7qNPFAgC/5GybC34=; b=mnMnlTBePU+ZIOCMpEfiJzwA0U+m1TsFSW5jtKCdhoXIMbDSLBPviw1u+W9/ozY6E3 /ObiQ6ze428VgPCEIz+x9+eJ7lGcPJtEkPMsTMOa12g2pvNDu2c8GeSX6nbMuKRT8p3z zdX82s3sdcApmphDrUQvIa0QlEOYLHZbS5P90= 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=ITw/V5vvWbmjAkuPXqZiQMYCEzK7qNPFAgC/5GybC34=; b=kS7fXgD6OevAlQ7/2oM0CN6tLemT4In6VPWOBVVe9++2evTVIsQKJ1qFaApesj3mv1 jp5/26TeWK901bQNqRejFflX6+L/4BkrkB9WXP67ETRZ6c3i7+sPxQm1RLichR1COJUk +Pw4rrQ+BbMiQTRdeyESBO83cPswiRQFVJJfSo6ye8JjtOHnb4YmdNIDOZjtP+WaI9Lu nVMjO7NqB9QqEIDJ+vUHVCLG+rXZbpA61LIjHrVhnjCoH1UmFa36oMFk0ZR5o2Ku4XKg yf7pQuXRMGsdjNn6Uyd20Z0Mue4Esl8P1Ukf5ZrylVv+BlLzygvltTrjNXbA4Z1f/Rhx WB7A== X-Gm-Message-State: AOAM530x8mL35bSlUs+cUTxcubJXHQyFgCtiFoyQJV5NcxjYeQsqQVxj 1SBxBgPC1f8+GFNHra/Pt5Sg+g== X-Google-Smtp-Source: ABdhPJwjBHjCgXl95SNKnk+LoWgbNy0ZNrd7Ms1/liceqETgNqR70ddLYqa8sjgokcAf8zr+gSU8xQ== X-Received: by 2002:aa7:941a:0:b029:142:2501:35d1 with SMTP id x26-20020aa7941a0000b0290142250135d1mr3970058pfo.49.1601660314475; Fri, 02 Oct 2020 10:38:34 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id 124sm2478687pfd.132.2020.10.02.10.38.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:33 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Luis Chamberlain , Scott Branden , stable@vger.kernel.org, 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 v5 02/16] fs/kernel_read_file: Remove FIRMWARE_EFI_EMBEDDED enum Date: Fri, 2 Oct 2020 10:38:14 -0700 Message-Id: <20201002173828.2099543-3-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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()") Signed-off-by: Kees Cook Reviewed-by: Luis Chamberlain Acked-by: Scott Branden Cc: stable@vger.kernel.org --- 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 7336e22d0c5d..3fb7af12d033 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2858,11 +2858,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 Fri Oct 2 17:38:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814309 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 306D3175A for ; Fri, 2 Oct 2020 17:39:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 14F43206CA for ; Fri, 2 Oct 2020 17:39:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="fG7iaIi/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388364AbgJBRjv (ORCPT ); Fri, 2 Oct 2020 13:39:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55760 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388347AbgJBRii (ORCPT ); Fri, 2 Oct 2020 13:38:38 -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 D5974C0613B3 for ; Fri, 2 Oct 2020 10:38:36 -0700 (PDT) Received: by mail-pg1-x544.google.com with SMTP id q18so1233106pgk.7 for ; Fri, 02 Oct 2020 10:38:36 -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=oHyyy0ZSHaOUioCUVDRjNSsPX3gvfN1E9+TUE31KLYU=; b=fG7iaIi/EkiRrDp3S/3jPDCdiKVQFg4CWGQCh/JJxSzGnrmPPkXhNymzkDpt4fGY4v y0lVJsGJ3CaPLaR8bZuV++9JOEe/0k4lIgn/f3eOzCK7C/e4CuTLeLCGvbUaRDrzaAXo L+OluWT/ieOL7lGWFAIrFuCtnJhbQHJ+oEgsg= 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=oHyyy0ZSHaOUioCUVDRjNSsPX3gvfN1E9+TUE31KLYU=; b=JVIOGPwAs3nm/a4BTL18hcwOIKCZ/yhq7X+wA2/X7/gjrgy7WObh2BX5ct9fnhEwbm 44+sSsZd0AmWltCl4S2Gzy1KiJJP8m8dJWR0f5C/j+yyz83khqzzd0S9LKYztRfuYW6w eiF57nibTuBo1j8Z6KATZOI/nhxhBKFSr9XVypWUkad7B5CMnaGb+SUfyFtASsnzu9Tc as3O3Xr+Vi9RRQ/6zXUUfmjTIFhrOVAMWVrS3MHJ4fYbSZz44NT8qSNZfaeGEDPaBj+J BDDp9BZDmYFMGw91mkLCSk5u7AfdkqaCjlUcNGxhrEwiHHWfO+6L0e1TfAubPHm7kx0L tY8Q== X-Gm-Message-State: AOAM533h+dmcWwlEaCUBoVV1j2gcfcT9unEdkbB1aD1TImsuA6b9AyIU 7iPhFPY5HYX93AAKYTmWPAgEQg== X-Google-Smtp-Source: ABdhPJxmEnnWLJW5a4HJU+tTjLEjsXGykEgIGWl+0XUOfTar1+/CpbL7p/bRLg/E5PqUZSxLsj42sg== X-Received: by 2002:a63:1016:: with SMTP id f22mr3227571pgl.226.1601660316347; Fri, 02 Oct 2020 10:38:36 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id s8sm2169969pjm.7.2020.10.02.10.38.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:33 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Scott Branden , Christoph Hellwig , Mimi Zohar , Luis Chamberlain , James Morris , 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 v5 03/16] fs/kernel_read_file: Split into separate include file Date: Fri, 2 Oct 2020 10:38:15 -0700 Message-Id: <20201002173828.2099543-4-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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 Signed-off-by: Kees Cook Reviewed-by: Christoph Hellwig Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Acked-by: Greg Kroah-Hartman Acked-by: James Morris Link: https://lore.kernel.org/r/20200706232309.12010-2-scott.branden@broadcom.com --- 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 b0ec2721f55d..8c6ea389afcf 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 9233cd50dc4c..c454af329413 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 3fb7af12d033..0885d53afb11 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2858,44 +2858,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 d15100de6cdd..64804f78408b 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 ca40bef75a61..1cc82557f4c1 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 b2808acac46b..4218abd272ee 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 2f187784c5bc..5f89970c5ab7 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 b4de33074b37..3b0b43e18ecf 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 670a1aebb8a1..163c48216d13 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 a340986aa92e..96f5f8b3b9f0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include From patchwork Fri Oct 2 17:38:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814321 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 B7B6592C for ; Fri, 2 Oct 2020 17:39:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9D1B7206CA for ; Fri, 2 Oct 2020 17:39:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="Fa1+kpky" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388535AbgJBRj4 (ORCPT ); Fri, 2 Oct 2020 13:39:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55768 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388330AbgJBRih (ORCPT ); Fri, 2 Oct 2020 13:38:37 -0400 Received: from mail-pj1-x1042.google.com (mail-pj1-x1042.google.com [IPv6:2607:f8b0:4864:20::1042]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 836BBC061787 for ; Fri, 2 Oct 2020 10:38:35 -0700 (PDT) Received: by mail-pj1-x1042.google.com with SMTP id a17so575250pju.1 for ; Fri, 02 Oct 2020 10:38:35 -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=MqCu1ZX3AyLQ2vV5pdqQHPUd5k1PtZXNO4rLUl2DsAc=; b=Fa1+kpkykeFSwotBKaUhSCt6EUI9L9UZDp8Mcc/Tk+rIh6nvLPqKq66QHkPhQKmqHS KKHW+WI5V4B8vdik79XG6H+40mGyt6NiwqX1N+jKHCc2O3xV4QGunHRUPPIIvYu1sxmj 1LQzZ77GWGoxfVAiZDdWv0m5zAKvalCLJO2Bw= 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=MqCu1ZX3AyLQ2vV5pdqQHPUd5k1PtZXNO4rLUl2DsAc=; b=Od6pE5wKL6mDyXgDmPu9eaH+4Tsf8QkXs6B/AAKNyVN8BZeBnYVy8f4HhCBY3fKCYl Y/QOrXmXW4VnGNuJT7vCGzTArZG+UihH7VymDHUTIsPPrwcq7FcVgnz3zUSIuOy1qH9E hjbeeeky4qaQBHko6Hvp5AQyTL+dk+h6NRLliagyk0SwM4wCT49agIaZYSx2OntVFS7W XGW2EhqvW5WxZqnIVdyatYrwj0xPLqBTlEUPB8u11bMq8gKQJSSKPEaBQO8ZqYWaaWm5 aPRbZhD8aaQGv7r6+SGSUYFLdfkBWD7HXJ99n+Qo2fW6AaSSRTKTLl48Xv7DSw4X7gjp Jdug== X-Gm-Message-State: AOAM530dI/ILRKnL4jZcIchTSf6CSyiH74vKkcF1njdJAhGbGY9kWX2A pokrFF4FnxXrj7I6vNaYn4aQzA== X-Google-Smtp-Source: ABdhPJxhiBbfvmXyBnGdtdXmsEgxOV/rva06BsW7dLnCt65Cg/BPKnR441EU624drgIyW4k0ZyYU9Q== X-Received: by 2002:a17:90a:3848:: with SMTP id l8mr3824347pjf.163.1601660315030; Fri, 02 Oct 2020 10:38:35 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id ca6sm2086832pjb.53.2020.10.02.10.38.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:33 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Mimi Zohar , Luis Chamberlain , Scott Branden , 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 v5 04/16] fs/kernel_read_file: Split into separate source file Date: Fri, 2 Oct 2020 10:38:16 -0700 Message-Id: <20201002173828.2099543-5-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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. Signed-off-by: Kees Cook Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Acked-by: Scott Branden Reviewed-by: James Morris --- 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 1c7b0e3f6daa..40c19ff3d570 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 init.o + fs_types.o fs_context.o fs_parser.o fsopen.o init.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 c454af329413..9f094406ea82 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -950,138 +950,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 Fri Oct 2 17:38:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814221 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 4A635618 for ; Fri, 2 Oct 2020 17:38:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 277B42085B for ; Fri, 2 Oct 2020 17:38:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="dhTPr3Hf" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388385AbgJBRij (ORCPT ); Fri, 2 Oct 2020 13:38:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55782 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388375AbgJBRii (ORCPT ); Fri, 2 Oct 2020 13:38:38 -0400 Received: from mail-pf1-x443.google.com (mail-pf1-x443.google.com [IPv6:2607:f8b0:4864:20::443]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A43B0C0613E7 for ; Fri, 2 Oct 2020 10:38:38 -0700 (PDT) Received: by mail-pf1-x443.google.com with SMTP id x22so1729276pfo.12 for ; Fri, 02 Oct 2020 10:38:38 -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=lZhM0u1Ixh6Kh+HXvNSm8TOvqXs6GWG/DhLCwiIZPAQ=; b=dhTPr3HfrcE87niKjHnrsTeF1TcXrwE3MtOzEVE6zgIgOvNW2rTQI9z3LOdcFoyVDM SBGNwTYXUuqJM/f0GmpP0X0+JEVgSuETIXvn6XfOmQ/TeXGBd3DyqhtRg4DFLO1+L2Mr i558wv0fKdwpBIUsFJJ9VnuXXiUIkFoFIk9vk= 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=lZhM0u1Ixh6Kh+HXvNSm8TOvqXs6GWG/DhLCwiIZPAQ=; b=Lo2jeXYDiU37yrbBwC8ptLMRMJW0n5EbYYeIFPzwjV8xLSxk1HT4HRvmtiNI/bPlLP KV+xFDRfa+Zpg7aZke1tBxyaEW4edttSciR3OTbQMZNk3tUUM7HPFlsL1frNjL22XgFu DoBtYrWlvpqf2487BeLVLK6KyAYpTyYPtlVHvaaip5VWTXt4qxvPVO2dBXYOeEk1tgRn uPKC7pIH6g/Zwj82TyldnjCv/Ttzj2YumaBX8Q6XPiuzQtm7qLB2kcgpsllvr2iN2lic 409GbM5mIFwD5OwCcKIgu88eAFq/qeUdtdgebbfzPOezkyrgfJ0FvBSd9heyLp9fntf1 AOsg== X-Gm-Message-State: AOAM530izLLn25GaCfj2llEgYnrEa1AsuJixp5EIeP3BDM/Zg+wN3Sjd LJ0pfPv1ON9KHtFDJcf2IqXDDw== X-Google-Smtp-Source: ABdhPJwaD4NElc+GQ4IINbv7oc2YCpYC1zsjIXxVz9EyAd0B1Cyyi5Hk2RJaUftxrf7tj37r6wGe1A== X-Received: by 2002:a62:3382:0:b029:150:bde9:d408 with SMTP id z124-20020a6233820000b0290150bde9d408mr4200055pfz.12.1601660318157; Fri, 02 Oct 2020 10:38:38 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id l10sm2157310pgp.25.2020.10.02.10.38.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:36 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Mimi Zohar , Luis Chamberlain , James Morris , Scott Branden , 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 v5 05/16] fs/kernel_read_file: Remove redundant size argument Date: Fri, 2 Oct 2020 10:38:17 -0700 Message-Id: <20201002173828.2099543-6-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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.) Signed-off-by: Kees Cook Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Reviewed-by: James Morris Acked-by: Scott Branden --- 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 8c6ea389afcf..6df1bdcfeb9d 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -467,7 +467,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; @@ -499,10 +499,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); @@ -511,6 +510,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 1cc82557f4c1..b20cfde8a01d 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 4218abd272ee..9faa6322f17b 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -4035,7 +4035,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; @@ -4049,12 +4048,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 Fri Oct 2 17:38:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814303 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 900A56CB for ; Fri, 2 Oct 2020 17:39:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7137320795 for ; Fri, 2 Oct 2020 17:39:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="VpU7xchN" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388297AbgJBRju (ORCPT ); Fri, 2 Oct 2020 13:39:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55790 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388360AbgJBRii (ORCPT ); Fri, 2 Oct 2020 13:38:38 -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 F018EC0613E4 for ; Fri, 2 Oct 2020 10:38:37 -0700 (PDT) Received: by mail-pg1-x544.google.com with SMTP id 7so1220405pgm.11 for ; Fri, 02 Oct 2020 10:38:37 -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=8Hp+7iC/qpDxM5Z+ih9Obdekn7D1QoZOPNj787JbbJI=; b=VpU7xchNgw6cw9oGZU5/CcpnqfEzBAL4Dvzshosnb4RzP+PA9ABf1JrbQKjbHsZTim OrtlcKNnqYHuSSeJxhZTnYYKv3w9PPfnzGqG/LqeB+xUpxHhmSJOlWulOuZFMAKFvXfW 7XcxuZK1TsW8mfDaTioIGtzU2mT6QC/K3m2CQ= 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=8Hp+7iC/qpDxM5Z+ih9Obdekn7D1QoZOPNj787JbbJI=; b=PWT2rRefMlDasnfw27xYcA5X+hpi4he/5ZH+uF2R5/6TPzyg9pIiTXSFASC+aV8YmB 2t36+Id/j7GQAybwuO/2UyvSKeFOY9GrwT6i5VCbQkCNXmNK6RvT4dwtHEq9sQu/TFR6 syrnmnioAIRs7bXOxMqTjRYY8cPNHWsLKK/+fYuf4q7gNGGmpxe0vQm5fJM3ie2UTbXe xnqcpEpKQ5Pj1Seocduq9rU2vRwRcGL+30nAe5Q0qCGeLRxoOzyQkO6plRXaOk9bbgz1 QKB2E/U0ac6CXvIMofRNg5kzwabKRlxZ52urKBkNSEJZYlpDTkhwC6puDb8BA/1ACdy+ 2iPg== X-Gm-Message-State: AOAM533M2JIt+OqBf/+BD5nEO+x9kPUtvMd11F6gkqR5pcQNw6RnbBmj YRjEWvIHsIBbL/6SjnWl2y0QQA== X-Google-Smtp-Source: ABdhPJy/BntAQKEnY5lvIusq1+xqLOvqEevT1O9eAGCzO9CsbBGzxwSBnuHX0A5VWfaOdB3pDAq2wg== X-Received: by 2002:a62:52ce:0:b029:13e:50c8:499b with SMTP id g197-20020a6252ce0000b029013e50c8499bmr3969231pfb.14.1601660317504; Fri, 02 Oct 2020 10:38:37 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id a2sm2826330pfr.104.2020.10.02.10.38.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:36 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Mimi Zohar , Luis Chamberlain , James Morris , Scott Branden , 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 v5 06/16] fs/kernel_read_file: Switch buffer size arg to size_t Date: Fri, 2 Oct 2020 10:38:18 -0700 Message-Id: <20201002173828.2099543-7-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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. Signed-off-by: Kees Cook Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Reviewed-by: James Morris Acked-by: Scott Branden --- 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 Fri Oct 2 17:38:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814281 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 ACAF4618 for ; Fri, 2 Oct 2020 17:39:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 88F8B20758 for ; Fri, 2 Oct 2020 17:39:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ZXP+q7Pn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388264AbgJBRjS (ORCPT ); Fri, 2 Oct 2020 13:39:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55810 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388376AbgJBRik (ORCPT ); Fri, 2 Oct 2020 13:38:40 -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 47804C0613A9 for ; Fri, 2 Oct 2020 10:38:40 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id p21so1309771pju.0 for ; Fri, 02 Oct 2020 10:38:40 -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=UZNhkp+Ex7uixUZwdnKtRZuboVANPTY0Sz5Zyi22yrg=; b=ZXP+q7PnzQa6LfR5IqDwOiL+3aiyalH+lzrSji6XGSuLCygmO87wN8h/T1+VwRCrXo 7l7zYzj8s9k1eycRAjGu0x2I4aY3HHR7HGBZU3XvySusni+7g+k1sm0CcCgX7Grls47g +/qsf06fs6BW7V8Nkk5YDWMp6ANViowBcWYDM= 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=UZNhkp+Ex7uixUZwdnKtRZuboVANPTY0Sz5Zyi22yrg=; b=SlgoqfEdL3HwWukkNtR8TWjs3nzAfE4/dyCbg/ivGV427NkiFyvIi9YXGG8QkcQ+Ip gpNtHnIlhyx3T5fYdFr+PJ0Wvth9nw99u07pN51MBJaaiJssZkcqdZEq+/PKWn7C8xzT 0GfSKtdLHFMp+tKmvhpq1+zFmmuYPisRu5YMzPrtu9I+RCLDYIJ3mlpYEznIuWqnEfes +Fqo2jjOklx/gen3fsV0ii1DnJxbF5jzodN+nxMGFDpfBdxp90C97sBll8ZkUlh0IJ0Z 0x+4VbPQBj8o+xDVYGeVNwhQbfz0Y3WUeV0kkewxMJxLLTHlNnHAZ8WIY4lhVHh9ZP1j zlzg== X-Gm-Message-State: AOAM530vjt1VAKGD6WtOBJWec+QzcbnWufiau8dtJ/ZkwQbQ172WcamJ LaLjpsVjHzhqRsmUtDVxDqE54A== X-Google-Smtp-Source: ABdhPJyor6I0OBDlhptSmA2CTw2A2FOz16orpOA1LJDZY8gyfQKIOZ86O1WsL37+jRrDp43R8+pnlA== X-Received: by 2002:a17:90a:1b45:: with SMTP id q63mr2160961pjq.21.1601660319816; Fri, 02 Oct 2020 10:38:39 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id z7sm2747869pfj.75.2020.10.02.10.38.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:36 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Mimi Zohar , Luis Chamberlain , James Morris , Scott Branden , 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 v5 07/16] fs/kernel_read_file: Add file_size output argument Date: Fri, 2 Oct 2020 10:38:19 -0700 Message-Id: <20201002173828.2099543-8-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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. Signed-off-by: Kees Cook Reviewed-by: Mimi Zohar Reviewed-by: Luis Chamberlain Reviewed-by: James Morris Acked-by: Scott Branden --- 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 6df1bdcfeb9d..d9a180148c4b 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -500,6 +500,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 b20cfde8a01d..ee51c1028658 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 9faa6322f17b..0f11eaed047e 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -4048,7 +4048,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 Fri Oct 2 17:38:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814287 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 DA14392C for ; Fri, 2 Oct 2020 17:39:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BC63A206CA for ; Fri, 2 Oct 2020 17:39:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="EkUakFPi" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388397AbgJBRjX (ORCPT ); Fri, 2 Oct 2020 13:39:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55794 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388393AbgJBRik (ORCPT ); Fri, 2 Oct 2020 13:38:40 -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 5674DC0613E7 for ; Fri, 2 Oct 2020 10:38:39 -0700 (PDT) Received: by mail-pj1-x1041.google.com with SMTP id p21so1309737pju.0 for ; Fri, 02 Oct 2020 10:38:39 -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=/K2vbxHcCuzbq3sjR/rWmD4bsCHJIDz9hKxoTonXhFg=; b=EkUakFPirgEHphE/CEdYgZkBHLqYceFOyCHe3YH7O10Zem/lCGVTtu9aintmXEdVo4 pMndBgaEY+25nAsHg1htLqHnRaBRZMLpIUDDn5A1pixBLvYZy82uhczmVeDj624bUWQN KY1wJyq61ozMyNOToiXb+MuyOxbNzLECOBDAs= 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=/K2vbxHcCuzbq3sjR/rWmD4bsCHJIDz9hKxoTonXhFg=; b=Ss2WeR6CI+gMlQ1z/S84zmr8qPYoaHIlwg0ch3vfOBvuGh85nK5O5PPX8lmLBz9ugy jfZIXnIgF1WUmmfOZzCu36LfAucJcKCxTyINxWrT16Z+QkUgOpZ5py7X+9iHBShD5Bvx 6Wqdx49fpw+pGH44v3kyA+arDozINJa6U/ENGXedLClJ8a6gEJlj915Enm/++Z1+1bm4 O01yigket+LNdId7rYI+15pcStfRa0ESQkyd6+ziZMGm/zzfNJR+Ms5KR5AnqHJbJd/6 N6UpXcT0TyNUS6ppTh34Xjqp6kbEFd3z/jSR5vZNn7FrzYtSoTO/K3DPnyW1GC1ncB43 Ln+Q== X-Gm-Message-State: AOAM5324FH89TfIdw0PE9KUJr2z7rWuSMy0aN7jB98k+u2Z9DSSv4hSu SCKjLe3JMFamhBtj/o6dAGGkDw== X-Google-Smtp-Source: ABdhPJwTjniVf2r8bEN3g+i0of7d1egPqTtv99FQjZYsLi51YRUppoZHrbkE8DsRbwK8KxmxQdJI8w== X-Received: by 2002:a17:90b:104f:: with SMTP id gq15mr3803958pjb.215.1601660318833; Fri, 02 Oct 2020 10:38:38 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id k2sm2580343pfi.169.2020.10.02.10.38.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:36 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , KP Singh , 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 v5 08/16] LSM: Introduce kernel_post_load_data() hook Date: Fri, 2 Oct 2020 10:38:20 -0700 Message-Id: <20201002173828.2099543-9-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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 | 13 ++++++++-- include/linux/lsm_hook_defs.h | 4 +++- include/linux/lsm_hooks.h | 10 ++++++++ include/linux/security.h | 14 +++++++++-- kernel/kexec.c | 2 +- kernel/module.c | 2 +- security/integrity/ima/ima_main.c | 24 ++++++++++++++++++- security/loadpin/loadpin.c | 2 +- security/security.c | 20 +++++++++++++--- security/selinux/hooks.c | 2 +- 12 files changed, 82 insertions(+), 15 deletions(-) diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index 283ca2de76d4..bff4717cc6b5 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 64804f78408b..af9fb8c5f16a 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, char *description); 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,14 @@ 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, + char *description) { return 0; } diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 2a8c74d99015..83c6f1f5cc1e 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, char *description) 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 9e2e3e63719d..6bb4f1a0158c 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -635,7 +635,17 @@ * @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 + * @description a text description of what was loaded, @id-specific + * 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..51c8e4e6b7cc 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -387,7 +387,10 @@ 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, + char *description); 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 +1017,14 @@ 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, + char *description) { 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 0f11eaed047e..f47209e0fde6 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3014,7 +3014,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 5f89970c5ab7..9dd9c5f4d736 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,26 @@ 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 + * @description: @id-specific description of contents + * + * 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, + char *description) +{ + return 0; +} + /* * process_buffer_measurement - Measure the buffer to ima log. * @inode: inode associated with the object being measured (NULL for KEY_CHECK) diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index 163c48216d13..28782412febb 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -177,7 +177,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..531b855826fc 100644 --- a/security/security.c +++ b/security/security.c @@ -1695,17 +1695,31 @@ 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, + char *description) +{ + int ret; + + ret = call_int_hook(kernel_post_load_data, 0, buf, size, id, + description); + if (ret) + return ret; + return ima_post_load_data(buf, size, id, description); +} +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 96f5f8b3b9f0..558beee97d8d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4018,7 +4018,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 Fri Oct 2 17:38:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814269 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 A0FE192C for ; Fri, 2 Oct 2020 17:39:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8668120795 for ; Fri, 2 Oct 2020 17:39:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="gIp5YUPO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388415AbgJBRjK (ORCPT ); Fri, 2 Oct 2020 13:39:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55822 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388414AbgJBRio (ORCPT ); Fri, 2 Oct 2020 13:38:44 -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 261DEC0613BF for ; Fri, 2 Oct 2020 10:38:43 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id i3so1227160pjz.4 for ; Fri, 02 Oct 2020 10:38:43 -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=qJcmVj+L5ner65w+xYxx1+RLP+ut9GxY3p4hCl1LqMA=; b=gIp5YUPO7PD3ieTusA8eENYMVQ+bK/n83HWEw+rMd0/t8bJ+GMNU1nfo8pmHLBGbey H5JyYlqUskPhuVlpO9NQs3bVG1i7dBKQITRy7QTRKpOIYsYmg1kUj4GmG2GV8J6vT6HB 0O1wQzHOr+TuqSP1UO1FvcIwzyDVBM0jrcqkw= 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=qJcmVj+L5ner65w+xYxx1+RLP+ut9GxY3p4hCl1LqMA=; b=LEBHfevDSIKGcRUDTYkW3WUcQp+60gI+6WWTofAEWyhV3Ab3T6od/YBncTnA8bQmGH ZO4XUVW1eMzQGv99AvKgGSS8sqbLEPYe1WHygT+o77Zn/eRhn9HMn7yHXT5+s5xQOmXk D1LXYjH5qbJ4PHAVM8Xpwi5o+Gd3kURJDKZktG5HCVv3N8q5P54POJHdHELTl5ks2Xnr ROu1ZSIwLafay9zfdke3M9dwqQFM/3jIi2JWmolduVJa1uUXEoIDH4xjL78yXPO8gklQ zpLS+t7B9XEqPYgWSrzeUhS5dsE/I5+aI32pCQnIwPFmMGnxtSLmUbhZqPtOj/EZK/ZW R/vg== X-Gm-Message-State: AOAM531QTTMINvv4OcO8RDBN8NVnh+AFehrGMWV4NpJWqrvgw4XfaBgT EC0zukVrwfj7KCm+qyRAfp900g== X-Google-Smtp-Source: ABdhPJzBWNvPO4VGKoipwgCa0vomjqtbhEwBldg9Xy+e2FhhYXBi1vlX/kGVu0Jis+yqO1+GeMgDig== X-Received: by 2002:a17:90a:69e3:: with SMTP id s90mr3814287pjj.130.1601660322701; Fri, 02 Oct 2020 10:38:42 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id q8sm2480298pfu.173.2020.10.02.10.38.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:36 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Mimi Zohar , Scott Branden , 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 v5 09/16] firmware_loader: Use security_post_load_data() Date: Fri, 2 Oct 2020 10:38:21 -0700 Message-Id: <20201002173828.2099543-10-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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 | 8 +++++++- security/integrity/ima/ima_main.c | 20 +++++++++---------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index bff4717cc6b5..251d92fc8bae 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, "blob"); /* * 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..8bdf88043079 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,12 @@ 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, + "platform"); + 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 9dd9c5f4d736..6f2b8352573a 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 */ } @@ -742,6 +733,15 @@ int ima_post_load_data(char *buf, loff_t size, enum kernel_load_data_id load_id, char *description) { + 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 Fri Oct 2 17:38:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814255 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 D16CE618 for ; Fri, 2 Oct 2020 17:39:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B659E20758 for ; Fri, 2 Oct 2020 17:39:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="Mfumh5tR" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388421AbgJBRjJ (ORCPT ); Fri, 2 Oct 2020 13:39:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388419AbgJBRio (ORCPT ); Fri, 2 Oct 2020 13:38:44 -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 53AC2C0613B8 for ; Fri, 2 Oct 2020 10:38:42 -0700 (PDT) Received: by mail-pf1-x441.google.com with SMTP id n14so1753446pff.6 for ; Fri, 02 Oct 2020 10:38:42 -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=NRNkvGI2Ff9BjWU3dffE18oblDO1Opoo7ReByCIGKwI=; b=Mfumh5tRxy4skOQP6OGVehMnWKDcGfbBGXiWQ720eRb5OVAh6dC5RBijHQgpZPj/Y4 YQXKfqFXUF679RfBa37dgjcpUP7MkM6k3757Sg6ZOw3gczyWHedDnJ9IiYxY6rw+0L2I WiL4xchzU3Ld30sxaoGGExLRw2vgpeVSEkQCU= 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=NRNkvGI2Ff9BjWU3dffE18oblDO1Opoo7ReByCIGKwI=; b=CfLrFdYV/B0cek8c8SURrPN8+XqGZcZ5vfmE2BaHVCnkBNvYKP1qch12Jp5rzLQRek srXjMmcObETcdkpihng2QxEk6d1CMNdQlMcCBE9ySyQugWwUeJWFU0CxwTeGEsn4Tn9D PHKxhAZKHhsINDmxKZt77ULeJ175c1zKwJKit0aH0wtVKingPPOh0OQZIsFWm+FMZRPz s/Z/qAQhF8DxCEW9Sn+eX041ffomC5BEN16nHHv8pvwxlcoKcQqWCkmwqNPvMjbBem6B HuAZeppl7YjhUqU8ZP8OtNvhaV594hg6f7n9xuMtfJiDAcxOc2YYSz5CsOmcN2vfNZNv I8hQ== X-Gm-Message-State: AOAM533JvVqwv2xNYT01z8tIXf98eg5OyK4Bh0QePMdhYCbO5GZ4OnEd bTPme82NT6XjlmNEm6otNGs/CQ== X-Google-Smtp-Source: ABdhPJwwS7Nbs517CZEc++bRCN5UnGB0D5kqLBspE9m/jC8b6k7oNPzx/9EjCuSoJzqxzl4G5yJT6A== X-Received: by 2002:a63:c547:: with SMTP id g7mr3156527pgd.234.1601660321870; Fri, 02 Oct 2020 10:38:41 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id g1sm2650900pfm.124.2020.10.02.10.38.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:36 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , KP Singh , 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 v5 10/16] module: Call security_kernel_post_load_data() Date: Fri, 2 Oct 2020 10:38:22 -0700 Message-Id: <20201002173828.2099543-11-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org Now that there is an API for checking loaded contents for modules loaded without a file, call into the LSM hooks. Signed-off-by: Kees Cook Reviewed-by: KP Singh Acked-by: Jessica Yu Reviewed-by: James Morris --- kernel/module.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index f47209e0fde6..adfa21dd3842 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3014,7 +3014,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; @@ -3024,11 +3024,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, "init_module"); +out: + if (err) + vfree(info->hdr); + + return err; } static void free_copy(struct load_info *info) From patchwork Fri Oct 2 17:38:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814275 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 2C951618 for ; Fri, 2 Oct 2020 17:39:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0AFEC20758 for ; Fri, 2 Oct 2020 17:39:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="D85k7ABO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388412AbgJBRjP (ORCPT ); Fri, 2 Oct 2020 13:39:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55792 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388401AbgJBRin (ORCPT ); Fri, 2 Oct 2020 13:38:43 -0400 Received: from mail-pj1-x1043.google.com (mail-pj1-x1043.google.com [IPv6:2607:f8b0:4864:20::1043]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A73BEC0613B1 for ; Fri, 2 Oct 2020 10:38:41 -0700 (PDT) Received: by mail-pj1-x1043.google.com with SMTP id a17so575423pju.1 for ; Fri, 02 Oct 2020 10:38:41 -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=iS/6sG1Z4X2NGBdo1TTYRLUvbymOQKdrvWIO+/geSmU=; b=D85k7ABO+aDlKXNecga+ObrsZiD9SSJ+Chan4tQllXSgijtmuecq0jaN6JmfURzU+L 4SAZYX11D7rvIpgoOAIoNHbnkfAFDQwHITHBSz8Pk6tl6XzIwnY7GWgcXA+//h99i749 M0/wZRDSBG/053iJi6nD1TXm+S33QV9BTmovE= 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=iS/6sG1Z4X2NGBdo1TTYRLUvbymOQKdrvWIO+/geSmU=; b=GRN9LxJ/xmx/LV/ypwIvpTAPNa5gECofMzEF78byqga/PkqKYkmlj5LBBZqP4Ihkz2 f69BTtdgm5OedF36f9BMOvXsbHcHGjQR6JrsBUx8Dqu/lMuoJpa8p97ULRRgLxTDdsU+ T2hV7LwK0SOGYzWQuFbFrOiHJFVSGz7hgp/+IFdfJklk6W3yDKR44ikQFWzZzCWFnsg7 HwkJAWFUuNpkrajTk4WFYO6urkEb+daAAsypRv+WVPe3BE+tMiChuyKR9/xSuQOheTIV 3QmMInZfnf+pBp5idmFNFg2cMAO9ovV8xLlrEYRfuFSDXSrtR9QPzkICiHrp4e5tKSYQ k79w== X-Gm-Message-State: AOAM532RybfYVLoh4pTWbaBPo9oFYmza+ZEIOuC0EBxjI05TAerMjQnn WiUdSAixGH2um+MVHWll8iTCHQ== X-Google-Smtp-Source: ABdhPJy9M0P3qffN5JZsx5TaefpHfSqkP+NCo5gHXu1SJZ9SL5f69WoQNxy2LGkHywryrC80KiB+Fw== X-Received: by 2002:a17:90b:3444:: with SMTP id lj4mr3769724pjb.78.1601660321165; Fri, 02 Oct 2020 10:38:41 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id g4sm2224149pgg.75.2020.10.02.10.38.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:36 -0700 (PDT) From: Kees Cook To: Greg Kroah-Hartman Cc: Kees Cook , Mimi Zohar , Scott Branden , 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 v5 11/16] LSM: Add "contents" flag to kernel_read_file hook Date: Fri, 2 Oct 2020 10:38:23 -0700 Message-Id: <20201002173828.2099543-12-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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 Reviewed-by: James Morris --- 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 af9fb8c5f16a..8fa7bcfb2da2 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, char *description); -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); @@ -92,7 +93,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 83c6f1f5cc1e..d67cb3502310 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, char *description) 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 6bb4f1a0158c..8814e3d5952d 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -651,6 +651,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. @@ -659,6 +660,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 51c8e4e6b7cc..bc2725491560 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -391,7 +391,8 @@ 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, char *description); -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, @@ -1030,7 +1031,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 6f2b8352573a..939f53d02627 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 28782412febb..b12f7d986b1e 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -118,11 +118,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]) { @@ -179,7 +189,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 531b855826fc..a28045dc9e7f 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 558beee97d8d..dec654d52b68 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4003,13 +4003,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 Fri Oct 2 17:38:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814283 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 19C3492C for ; Fri, 2 Oct 2020 17:39:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F3F452085B for ; Fri, 2 Oct 2020 17:39:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="EDfqStII" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388465AbgJBRjR (ORCPT ); Fri, 2 Oct 2020 13:39:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55820 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388392AbgJBRil (ORCPT ); Fri, 2 Oct 2020 13:38:41 -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 09F1AC0613AC for ; Fri, 2 Oct 2020 10:38:41 -0700 (PDT) Received: by mail-pg1-x544.google.com with SMTP id g9so724293pgh.8 for ; Fri, 02 Oct 2020 10:38:41 -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=+iQNrYs3FwbgO/D5wBu/XH+65XZOVsrx8jBX4xhrznE=; b=EDfqStII1nyquW6vCDUJ0Tjh5LqLIxTDOCBsRG+Y5BOdp3rp+5tjRqeEdCtoyMHPmx MyVLigCKUXuy8gVZ4U6zpvuk9pmCPNlcQ2lULK3/4ExxQylIYS0LevTl1aWHi9IX8858 bhAQjK9Gpnc8WDPfEOCWZjhiE9R39MQAiqYfY= 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=+iQNrYs3FwbgO/D5wBu/XH+65XZOVsrx8jBX4xhrznE=; b=FpB0mKaiUzGeQndFTeM7G/uP7WAxxpjH5EdNewXsD79hGKgTmhUqhmXjBVPb+UGNAv VSH01CxKBZPWOXUNefejmIk9vC+wAcgEjoXq7w75XHR34lUY9hglD8KSDjp+rx+q/GBz OkmO14oAo7iu2kKFjmAeSvlJCz0RB8k5LygBtxH8TO8ONuDI1C2YyzmbyTUVYGEfw74f 0JhYar2DSbBP7PvBf65/aiRT2zpzVrsM5izaXaAXaD21Mb8p3aNymdJJihqN30UTWyPL IrcQcwWps6c3HbR360iL1ifHQ6ZvIQA76/Xw285Eq0WnXveCa93vII94yvLbsBcyY91p ZkRQ== X-Gm-Message-State: AOAM533xhwEEMHpOcaUidXzxBDEBQeWoJgX/8SfCyZIe/khAmK7O1DD1 FnTZK8RxNIjSoTf9pxq0ChDpfg== X-Google-Smtp-Source: ABdhPJyTPCXP4kCQY9q8tHg/I40D0cpppwMhWrbNdfV+VWl5wPSAP7pjwzJcV4nQvitE40P+5c9z6Q== X-Received: by 2002:a63:5b04:: with SMTP id p4mr3258880pgb.121.1601660320583; Fri, 02 Oct 2020 10:38:40 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id q18sm2653154pfg.158.2020.10.02.10.38.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:36 -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 v5 12/16] IMA: Add support for file reads without contents Date: Fri, 2 Oct 2020 10:38:24 -0700 Message-Id: <20201002173828.2099543-13-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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/ Signed-off-by: Kees Cook Reviewed-by: Mimi Zohar --- 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 939f53d02627..82c9d62bcb11 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 Fri Oct 2 17:38:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814263 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 B442C175A for ; Fri, 2 Oct 2020 17:39:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9A4B121481 for ; Fri, 2 Oct 2020 17:39:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="VDo5tX8n" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388372AbgJBRjI (ORCPT ); Fri, 2 Oct 2020 13:39:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55812 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388421AbgJBRio (ORCPT ); Fri, 2 Oct 2020 13:38:44 -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 97D0FC0613E2 for ; Fri, 2 Oct 2020 10:38:44 -0700 (PDT) Received: by mail-pj1-x1041.google.com with SMTP id q4so1291524pjh.5 for ; Fri, 02 Oct 2020 10:38:44 -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=A9Rq3b4KCQ4FxOzHf+bfvfTJvSHiqKnvNkPrejY2mCg=; b=VDo5tX8n4jsCduuRAefxgt/QAwRPuJu1/HLnvEVBoGLlaKXu0Y7dFzTgxRh9jddvUt Q3b/kNGbu1xU9x6q6wcllv6bvJmm5fTg/sFvUYGYI1zIAkBSybVEKb85WGjaMiu+PyZx dsolwth7kcoko7RGcZIh94Z4NEFkV6nHlN5eY= 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=A9Rq3b4KCQ4FxOzHf+bfvfTJvSHiqKnvNkPrejY2mCg=; b=BRPnd1rvQmxJsAipFDuS6MikH5LBQBTyLXZKbvhviPZdVwEMzgoZ26nDDgJxTaAvep g8zHWDqvpFB+mKUAe0XCOrgrQUqwOtIzEpx8cc3zetlWabskhu7kZ2cs7buo13YtxTNk zYQ30BJaq5zLcnnRJP2PFiQwFCkjoewGkQxUQFQDHZ5u1JmOZVl5bcwNdF7VQDQHZQDc hJsjfk8L+P5re1gAxBpobVHVpRVe7Jeuz1BIP6j4u9bAL4TufZAa0SKZ3wFGjmavZyCU R01xG6B2ZnqGs5ESwDNEo5eTqmUxQuKykF4sOT0sOLsiSrYYe5hmyjMuu9x1uBOaEKZC FN/w== X-Gm-Message-State: AOAM533nIsQwnohB2LUUZE+sQyWiGbu9XMrFV9nvEbqDDFqP9yEvR8k9 8m+M3zuinF0w2xQNfEVHM443wA== X-Google-Smtp-Source: ABdhPJzP9vRzKkF63PUjWCICE9WnxLmFLUnZ+dokL/JgGb+Ip1X/cPPBTnPGD9UkZWcuj3MNRxbwuw== X-Received: by 2002:a17:90a:1992:: with SMTP id 18mr3867983pji.143.1601660324116; Fri, 02 Oct 2020 10:38:44 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id g3sm2090472pjl.6.2020.10.02.10.38.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:42 -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 v5 13/16] fs/kernel_file_read: Add "offset" arg for partial reads Date: Fri, 2 Oct 2020 10:38:25 -0700 Message-Id: <20201002173828.2099543-14-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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 d9a180148c4b..79f86466d472 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -499,7 +499,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 ee51c1028658..84f7316792a7 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 adfa21dd3842..9c578e44abe7 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -4054,7 +4054,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 Fri Oct 2 17:38:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814233 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 6DA181746 for ; Fri, 2 Oct 2020 17:38:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 54BEB206CA for ; Fri, 2 Oct 2020 17:38:56 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="SDW1aCXs" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388409AbgJBRiz (ORCPT ); Fri, 2 Oct 2020 13:38:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55772 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388411AbgJBRip (ORCPT ); Fri, 2 Oct 2020 13:38:45 -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 21F1BC0613E2 for ; Fri, 2 Oct 2020 10:38:45 -0700 (PDT) Received: by mail-pg1-x543.google.com with SMTP id 5so1238245pgf.5 for ; Fri, 02 Oct 2020 10:38:45 -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=WHTJVbq+NEdOn0KG7xTVbIO+EPWzmJJD7edvoSx0fhQ=; b=SDW1aCXsi7GB1NUdEmgnrp+bHwHQoGoSWJOyLP0qTqqUQlVSknq7NxFIPEVQ9Y2j+P QIaJOySy3FRN2lvGV0GXbU/VyifBQ99x9nCJ2UBKC3L31TPgViV4h+DoOFY1gS5NfQyc 8+LKzKpNMC3OpSEL4GuhCkElvCK6DRm03gm9Y= 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=WHTJVbq+NEdOn0KG7xTVbIO+EPWzmJJD7edvoSx0fhQ=; b=PPQBqT8CZoyYYsA+xGgcG6SOEOSPKfwMdKHwO2aeH9HL49VCyZ5M2DRUcpTOZE3q1i JWxPksro+pFCbdCc10aE4WnfHRfvB80YnWDtBf1VCerC8lXJUodNIYrpSb9UmORWlqnS ub64YC6l9D3U2LYHTuSoMZum9TTxJEoVFjWAmptvynFlPS+RsJPjx3xK4gudrZcL1f8m YQdzGwBQWHSYxiV/0um+lbm0ijBhz2jDBGi5T4UrXrCV3HqcWrNC5uHJOjvctsnhMssG dasgtE4RvXN5VvSLFjtQulve798yx3MfR45HLVqEQYPULKd7gkhpn13pcIaT5g/NRw59 UU/w== X-Gm-Message-State: AOAM532f7BBwN+thv5wOiyywzYceWMOEmgdnVvfqzsltfPag2CECz9G/ 4TZiOCMLpuY2iA3fDf/L03lO5A== X-Google-Smtp-Source: ABdhPJxsFl7w0eHssgJAlItrXZUpI3j4cF+J9i83MBIGzUru+Nf9hzhT67KCdEEp/s/JO0pwtKcNbw== X-Received: by 2002:aa7:8f21:0:b029:142:2501:39e0 with SMTP id y1-20020aa78f210000b0290142250139e0mr3924207pfr.47.1601660324643; Fri, 02 Oct 2020 10:38:44 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id r19sm2104873pjz.23.2020.10.02.10.38.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:42 -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 v5 14/16] firmware: Store opt_flags in fw_priv Date: Fri, 2 Oct 2020 10:38:26 -0700 Message-Id: <20201002173828.2099543-15-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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 251d92fc8bae..c4765461a951 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 8bdf88043079..00af99f0aff2 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 d08efc77cf16..f86de5d7e0d7 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 79f86466d472..78c8e44c08cb 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)) @@ -640,7 +645,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; @@ -659,8 +664,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); @@ -672,7 +677,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); @@ -783,7 +788,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)) @@ -792,7 +797,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 Fri Oct 2 17:38:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814245 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 D97D7618 for ; Fri, 2 Oct 2020 17:39:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A863C20758 for ; Fri, 2 Oct 2020 17:39:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="e5jK07MV" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388303AbgJBRjE (ORCPT ); Fri, 2 Oct 2020 13:39:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55810 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388445AbgJBRir (ORCPT ); Fri, 2 Oct 2020 13:38:47 -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 B566AC0613E4 for ; Fri, 2 Oct 2020 10:38:45 -0700 (PDT) Received: by mail-pg1-x543.google.com with SMTP id o25so1250885pgm.0 for ; Fri, 02 Oct 2020 10:38:45 -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=crhb0wNCH/x3Qeeg8beqBz3Vy6smwdJwXb8eERMUYOA=; b=e5jK07MVrMCVnvOjZVV0ZTUzgzVXY8VVjIWZJFg5x1vBk4iXEFxJy/XEILnDBeXaiL N2nOoSgctGLRRHdQDxnS0FpKYpxFSynqQzkYJUoWjmjQAu00ACdZB9ClH6JS9/ULUKBh DJK+AYJ35HVUPbRGQIs62ZHLd2SPp8He79JrE= 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=crhb0wNCH/x3Qeeg8beqBz3Vy6smwdJwXb8eERMUYOA=; b=NdtnLrNO+B3EBTRiwx/widdf4IDTUASe7u+xEtSPKrdmbi2ZdIWZJsOz9QRSs3O4NV b8CnXOeDuqv1xDZXGqYKHF1hBqZfrNGsDE0UEXMtGGhPuULM5hlB1wa80RJBD3f9A4Yb /sjEnsctE4zG4IqrvdgZN+EzQxZf72Q6vZcezifERY2ialOveGBMOl51OKsasZ4DRRO1 o7AhG7IexfBGuxeP5CyfvAfHIAuHtXtr7d6KuvtPa/TFbcTNPqL2u0iXJrZhje4lvt88 LL1MlnTq6YI8V+OkcidBggrXyy6ULWLsOHIpNAconX0Mgq3hrI+QHhZzDrETX6o07OY1 E+TQ== X-Gm-Message-State: AOAM530RW2Vs7qXcqmThFp9898Ijxy/YpKCowmqs81dFK8GOvHNJVWn0 H3/5Vl57SmQQuZfvfKcDNUJoag== X-Google-Smtp-Source: ABdhPJxfK1NNqBcJBfEVA07BUmxJFLBpRd/TtaiXw8odbmFpMvNPd6zMXf18f1uLMCENzvyQUDRykA== X-Received: by 2002:a63:d841:: with SMTP id k1mr3235645pgj.59.1601660325171; Fri, 02 Oct 2020 10:38:45 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id k24sm2643539pfg.148.2020.10.02.10.38.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:38:42 -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 v5 15/16] firmware: Add request_partial_firmware_into_buf() Date: Fri, 2 Oct 2020 10:38:27 -0700 Message-Id: <20201002173828.2099543-16-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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 f86de5d7e0d7..63bd29fdcb9c 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 78c8e44c08cb..78355095e00d 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)) @@ -490,6 +505,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; @@ -503,9 +521,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) @@ -696,7 +723,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; @@ -715,7 +742,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 @@ -762,9 +789,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) @@ -776,18 +804,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) { @@ -795,7 +827,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); @@ -838,7 +872,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; @@ -865,7 +899,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; @@ -889,7 +923,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); @@ -914,7 +948,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; @@ -970,13 +1004,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 @@ -1009,7 +1074,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 Fri Oct 2 17:38:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11814351 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 72A52112E for ; Fri, 2 Oct 2020 17:46:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4376C208A9 for ; Fri, 2 Oct 2020 17:46:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="X+RtTZc0" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388198AbgJBRqo (ORCPT ); Fri, 2 Oct 2020 13:46:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57108 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387934AbgJBRqo (ORCPT ); Fri, 2 Oct 2020 13:46:44 -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 5F796C0613E6 for ; Fri, 2 Oct 2020 10:46:44 -0700 (PDT) Received: by mail-pg1-x543.google.com with SMTP id h6so571891pgk.4 for ; Fri, 02 Oct 2020 10:46:44 -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=RS1e+ajQGzgPWZqA6aLQAGY/Phtq1m+MrzqzoBscS2E=; b=X+RtTZc0ksin8udfAQHSEc3RaNSBoz52GvIleDBdA3c9hZDnAX7mRUJL6bhwx+Ezhm AJ3FufRS8b17tZ8NG9SusA+1mGVYL3uabH+JWjb706Dm7MkPBgSp1F9ZE5TsfdBa4x2O SN+QXpyvE/gpE0rH1eCTcT01qdx0DtG5HqAvU= 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=RS1e+ajQGzgPWZqA6aLQAGY/Phtq1m+MrzqzoBscS2E=; b=Ykfe+Jvs9i0jj4dniXY1qA1zJgoKmpVdZxbnneYweXK1wYhTtpENDKEc7Rj1PC3t7w GDWO4+YM38Bceond7QMIyv5xxWLcXZTCHxAaFaSM8BDrr6PRt9ufm3Lhn/48ikL6123M 5c7nUQxck0wl4xweKJ03ESTc52fNLdDsnHB7uh7Mo18fYcgw5oKl3Gimfd9ekID2hGPY UYLOPL1gKzUN1Qn8kZvYD7lHCclubkduKScg1j6H7riPScCWtqZtaYkk5YOl71fcX77B W8H/1/XpX5FhOd3tCwBkvSmzVcQ6IdwrquOXuWPqkrx6kQzEwHLbaJ5QYqJJrQ+oq/Ob AXnA== X-Gm-Message-State: AOAM531ec0ZukqW8lLFvffSNn3ocOv6cVPXPYeECijhrphZM0+KQ1yPp mtzX+VD9dPe9ooRzOhGNhTHIVw== X-Google-Smtp-Source: ABdhPJxAdwDKbvyQGKme0t5CtDP4a/u00W5eKQkBy2d4IaoSnwtXJSVWS8XhJW0L2rjigD1yHglhNg== X-Received: by 2002:a65:580c:: with SMTP id g12mr3323952pgr.257.1601660802346; Fri, 02 Oct 2020 10:46:42 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id g126sm1749542pfb.32.2020.10.02.10.46.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Oct 2020 10:46:41 -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 v5 16/16] test_firmware: Test partial read support Date: Fri, 2 Oct 2020 10:38:28 -0700 Message-Id: <20201002173828.2099543-17-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201002173828.2099543-1-keescook@chromium.org> References: <20201002173828.2099543-1-keescook@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@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 06c955057756..2baa275a6ddf 100644 --- a/lib/test_firmware.c +++ b/lib/test_firmware.c @@ -52,6 +52,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 @@ -91,6 +94,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; @@ -185,6 +191,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; @@ -238,28 +247,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); @@ -317,6 +333,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); @@ -402,6 +442,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) @@ -659,11 +776,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 { @@ -936,6 +1063,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