From patchwork Tue Dec 26 13:21:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 122748 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp955000qgn; Tue, 26 Dec 2017 05:22:07 -0800 (PST) X-Google-Smtp-Source: ACJfBos5rG6WS3buYfkiyeIdeHgO4We5h+jb77WjNItedU2pD/0GX+RZ0oopSBAPaGGUnBf1CKa7 X-Received: by 10.101.86.133 with SMTP id v5mr22054811pgs.266.1514294526987; Tue, 26 Dec 2017 05:22:06 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1514294526; cv=none; d=google.com; s=arc-20160816; b=Ilo8zK0agRvAAIYqt3bKrynYns1QLuWmP4Tk6pFO81yOw7wQiitaYlKYc6829UpUdn ZtOUbk9GFUdpKumCXkdtoDgn8i6o32Cdanr1uapKscOgq/mlQeD+F5nDmwdRl6sQy+GL j8QAiCNV7e2s4ULrXrrakykZDiEUKHqth1JEegeAys8TN9Q6RNvMR32CZAXMvGuofP6p xUTBzw2c6j8p2cek5xZqe+hBISUXRsFFEoPY5ZkpvnRMtqWrc2yOPqDmaY6MLmiBEqfI zi+q4kCsbSbieDd3PiywqklnPtkeqU+pcJoOrQSR0+rmNlPmPIODhTXjyT0wnqDB2Fgc k+Vw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=zm3R07S4sn3zMv2lbrIw4nzcNIJxJ7U0lHVXHSjLbAA=; b=pxn3Wyl1BwTGKojZY5Sk9DrrdpbhsWxjX4n0cJWPTP6kyHq9DKVNYPrLx6vhMnLpN5 nqAVBo1wyuG3OqIjRf33Abxko+8ykyoIslF9bx6ArcWYrmILa1P89Lm2GSvpfy+NUIB4 liahCs+yYB+O2IFX8//mVEDTTrKovqB/HFOGSvgy+yYPWnVTgNZNIh+FnUmoCISqCogh 6kF/qjmmYSmmyPxSwFds6urr0R9geZJij79HjRrI2WyYXjMEwtBFF7v4Jo3zfa8qufiY vWUwuxyXlkPpZeNUJfUXuI1+NmWVFlenTh0dDx39sQh54iUxuTOJ3JheUEeN4+30hfGv IrLw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=SHesf/1Z; spf=pass (google.com: best guess record for domain of linux-efi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-efi-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 78si22979359pfq.361.2017.12.26.05.22.06; Tue, 26 Dec 2017 05:22:06 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-efi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=SHesf/1Z; spf=pass (google.com: best guess record for domain of linux-efi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-efi-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750757AbdLZNWF (ORCPT + 2 others); Tue, 26 Dec 2017 08:22:05 -0500 Received: from mail-wm0-f68.google.com ([74.125.82.68]:44951 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750737AbdLZNWE (ORCPT ); Tue, 26 Dec 2017 08:22:04 -0500 Received: by mail-wm0-f68.google.com with SMTP id t8so35025311wmc.3 for ; Tue, 26 Dec 2017 05:22:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=O9fyzelKM//FC9nas0pzpgUpSybbViCuW6WWD6bQ5cI=; b=SHesf/1ZNtQVAdx0+/ah4p8t6I5UTkEx/4mMgCG553vYXQFEWXtLHuAuq1+8xMMjBI rR0QnXAwaB7FgZQIp5ro5azq5U9gFbGA1asNMmhWepUOjykL22kyTysWuzqu8ySeQav2 SssGlrHs6Ayy6gi7LSdQLcaRjAZDheZMGwUEk= 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; bh=O9fyzelKM//FC9nas0pzpgUpSybbViCuW6WWD6bQ5cI=; b=cWEsx0jGAE2P198BDkC87VTvZxNBgdIs+vAyqfgWHLKAF+jXGzwG5YIKbhw8jgKI+K 8cEs8e1AOxuhjwwTYzGVNq8Ygny6EIoZJy3osFnerH+hkE45JuoDKWlrKpmW9tToRh9J Iz1j1EWU1MBCa539e9dP5HEP7rkhoCvhmSIT1UAPP4es27iZYOhRxsAmQ72ruVVSX9id sAIqINvlLVtElV45qJAfPPc+7Co48WNlkMHSGlSjt4vwMXq5IdVFky30DMupBiBtP5yn idoVycKh7ttCfFGYZXHeiNvU4//+xSNBJR3aryPr7o1NMNxaroEMhp4GqQsCQG6XulLT hL1Q== X-Gm-Message-State: AKGB3mLgFtsL4Afxuwy8xFaypJxSu5SxrBTRclF3kRTprpT0sEOJKPo3 UX7zZMQxwuFf+n6ULZC33OGic05Z2Ag= X-Received: by 10.28.8.212 with SMTP id 203mr19842655wmi.8.1514294522937; Tue, 26 Dec 2017 05:22:02 -0800 (PST) Received: from localhost.localdomain ([160.171.216.245]) by smtp.gmail.com with ESMTPSA id a8sm9228730wmh.41.2017.12.26.05.22.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 26 Dec 2017 05:22:02 -0800 (PST) From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Matt Fleming , Jan Kiszka , Bryan O'Donoghue , Richard Ruigrok , Ge Song Subject: [RFT PATCH] efi: capsule-loader: reinstate virtual capsule mapping Date: Tue, 26 Dec 2017 13:21:42 +0000 Message-Id: <20171226132142.3254-1-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.11.0 Sender: linux-efi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-efi@vger.kernel.org Commit 82c3768b8d68 ("efi/capsule-loader: Use a cached copy of the capsule header") refactored the capsule loading code that maps the capsule header, to avoid having to map it several times. However, as it turns out, the vmap() call we ended up removing did not just map the header, but the entire capsule image, and dropping this virtual mapping breaks capsules that are processed by the firmware immediately (i.e., without a reboot). Unfortunately, that change was part of a larger refactor that allowed a quirk to be implemented for Quark, which has a non-standard memory layout for capsules, and we have slightly painted ourselves into a corner by allowing quirk code to mangle the capsule header and memory layout. So we need to fix this without breaking Quark. Fortunately, Quark does not appear to care about the virtual mapping, and so we can simply do a partial revert of commit 2a457fb31df6 ("efi/capsule-loader: Use page addresses rather than struct page pointers"), and create a vmap() mapping of the entire capsule (including header) based on the reinstated struct page array, unless running on Quark, in which case we pass the capsule header copy as before. Cc: Matt Fleming Cc: Jan Kiszka Cc: Bryan O'Donoghue Cc: Richard Ruigrok Cc: Ge Song Signed-off-by: Ard Biesheuvel --- arch/x86/platform/efi/quirks.c | 13 +++++- drivers/firmware/efi/capsule-loader.c | 45 ++++++++++++++++---- include/linux/efi.h | 4 +- 3 files changed, 52 insertions(+), 10 deletions(-) -- 2.11.0 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Tested-by: Bryan O'Donoghue Tested-by: Ge Song diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 8a99a2e96537..5b513ccffde4 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -592,7 +592,18 @@ static int qrk_capsule_setup_info(struct capsule_info *cap_info, void **pkbuff, /* * Update the first page pointer to skip over the CSH header. */ - cap_info->pages[0] += csh->headersize; + cap_info->phys[0] += csh->headersize; + + /* + * cap_info->capsule should point at a virtual mapping of the entire + * capsule, starting at the capsule header. Our image has the Quark + * security header prepended, so we cannot rely on the default vmap() + * mapping created by the generic capsule code. + * Given that the Quark firmware does not appear to care about the + * virtual mapping, let's just point cap_info->capsule at our copy + * of the capsule header. + */ + cap_info->capsule = &cap_info->header; return 1; } diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index 51d2874942a2..e456f4602df1 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -20,10 +20,6 @@ #define NO_FURTHER_WRITE_ACTION -1 -#ifndef phys_to_page -#define phys_to_page(x) pfn_to_page((x) >> PAGE_SHIFT) -#endif - /** * efi_free_all_buff_pages - free all previous allocated buffer pages * @cap_info: pointer to current instance of capsule_info structure @@ -35,7 +31,7 @@ static void efi_free_all_buff_pages(struct capsule_info *cap_info) { while (cap_info->index > 0) - __free_page(phys_to_page(cap_info->pages[--cap_info->index])); + __free_page(cap_info->pages[--cap_info->index]); cap_info->index = NO_FURTHER_WRITE_ACTION; } @@ -71,6 +67,14 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) cap_info->pages = temp_page; + temp_page = krealloc(cap_info->phys, + pages_needed * sizeof(phys_addr_t *), + GFP_KERNEL | __GFP_ZERO); + if (!temp_page) + return -ENOMEM; + + cap_info->phys = temp_page; + return 0; } @@ -105,9 +109,24 @@ int __weak efi_capsule_setup_info(struct capsule_info *cap_info, void *kbuff, **/ static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info) { + bool do_vunmap = false; int ret; - ret = efi_capsule_update(&cap_info->header, cap_info->pages); + /* + * cap_info->capsule may have been assigned already by a quirk + * handler, so only overwrite it if it is NULL + */ + if (!cap_info->capsule) { + cap_info->capsule = vmap(cap_info->pages, cap_info->index, + VM_MAP, PAGE_KERNEL); + if (!cap_info->capsule) + return -ENOMEM; + do_vunmap = true; + } + + ret = efi_capsule_update(cap_info->capsule, cap_info->phys); + if (do_vunmap) + vunmap(cap_info->capsule); if (ret) { pr_err("capsule update failed\n"); return ret; @@ -165,10 +184,12 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff, goto failed; } - cap_info->pages[cap_info->index++] = page_to_phys(page); + cap_info->pages[cap_info->index] = page; + cap_info->phys[cap_info->index] = page_to_phys(page); cap_info->page_bytes_remain = PAGE_SIZE; + cap_info->index++; } else { - page = phys_to_page(cap_info->pages[cap_info->index - 1]); + page = cap_info->pages[cap_info->index - 1]; } kbuff = kmap(page); @@ -252,6 +273,7 @@ static int efi_capsule_release(struct inode *inode, struct file *file) struct capsule_info *cap_info = file->private_data; kfree(cap_info->pages); + kfree(cap_info->phys); kfree(file->private_data); file->private_data = NULL; return 0; @@ -281,6 +303,13 @@ static int efi_capsule_open(struct inode *inode, struct file *file) return -ENOMEM; } + cap_info->phys = kzalloc(sizeof(void *), GFP_KERNEL); + if (!cap_info->phys) { + kfree(cap_info->pages); + kfree(cap_info); + return -ENOMEM; + } + file->private_data = cap_info; return 0; diff --git a/include/linux/efi.h b/include/linux/efi.h index d813f7b04da7..29fdf8029cf6 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -140,11 +140,13 @@ struct efi_boot_memmap { struct capsule_info { efi_capsule_header_t header; + efi_capsule_header_t *capsule; int reset_type; long index; size_t count; size_t total_size; - phys_addr_t *pages; + struct page **pages; + phys_addr_t *phys; size_t page_bytes_remain; };