Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp1444503imm; Fri, 15 Jun 2018 18:10:33 -0700 (PDT) X-Google-Smtp-Source: ADUXVKLUBUh8stSy80es17wk1ZyRCGr309qTbyb0c9+4w4Fa5gRdLeipjqi9erxmxv2Gf4Z1PJ9y X-Received: by 2002:a17:902:8a4:: with SMTP id 33-v6mr4444886pll.343.1529111433369; Fri, 15 Jun 2018 18:10:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529111433; cv=none; d=google.com; s=arc-20160816; b=sbZNdar1Ue7RRG6VfbAtgi4iazBz5x9MyzaMfXW/Wkx5EUspY7w1ty5STTeRGtqbcY Y+X34clQhJ1ccgftUy9b8gOO1HE+2D5q/yykBfP5NkSPk/gjafyOgWG4kshz7Hqn/wXm p6JOTqohXVwiBPly69MLA0P6oEAx/3swP/mgjOGByvKENUV5+I66BdND23tILk8f76K7 zPx7ejhPgVKzP3FsKmcjAT2/0J9/BEkW1rY1mZQFe8vNYRj33DNK3MuFehd1I4QFEKck uAi4I1+ZLlGHgx26ogo3UcHXW931d35l9sqrVjHQAYxm98t/I1AjagsvD1LNGdyiFWHa IoTQ== 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 :arc-authentication-results; bh=UCt1bxgLWxY9+RgUvycOhpXtuM0fyKKhypPBYe7BpPY=; b=vnYdxS2oFBsQ8uyT9GfUcEmLHMASiijcikvp5RH5nWTt0SF8r/j47AytL99NDH32JU N8Vn3UNpIBmMcOyPEzAZ0yWdsChDAHr0sb6oxVBqWgO2ZGF1A6+UVAammC/wEyj4Dr0y zyE31F31ZMh/Xd+6kflmWEIo+nWB3IaHGBSMSWm77qJRwQIwlRG2w/M/p4YZzTZD+j3z 5kXesfUTyY42AC56kEWO7r7VwMqtKGnqYF6p5mAG5ofxmfhii34rW1vVXz3LvLy5xTWG LQ/0lHMH9jaykNvV5DPMMaS4aNmni/imZIKoX75VazdbOfjNCPYOPxiOygb+sL+He7at NIog== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p61-v6si9127328plb.472.2018.06.15.18.10.18; Fri, 15 Jun 2018 18:10:33 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756369AbeFPBJl (ORCPT + 99 others); Fri, 15 Jun 2018 21:09:41 -0400 Received: from mga02.intel.com ([134.134.136.20]:62578 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756240AbeFPBJj (ORCPT ); Fri, 15 Jun 2018 21:09:39 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 15 Jun 2018 18:09:39 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.51,228,1526367600"; d="scan'208";a="237893143" Received: from sai-dev-mach.sc.intel.com ([143.183.140.145]) by fmsmga006.fm.intel.com with ESMTP; 15 Jun 2018 18:09:38 -0700 From: Sai Praneeth Prakhya To: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Sai Praneeth , Lee Chun-Yi , Borislav Petkov , Tony Luck , Dave Hansen , Bhupesh Sharma , Ricardo Neri , Peter Zijlstra , Ravi Shankar , Matt Fleming , Ard Biesheuvel Subject: [PATCH] x86/efi: Free allocated memory if remap fails Date: Fri, 15 Jun 2018 18:09:24 -0700 Message-Id: <1529111365-32295-1-git-send-email-sai.praneeth.prakhya@intel.com> X-Mailer: git-send-email 2.7.4 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Sai Praneeth efi_memmap_alloc(), as the name suggests, allocates memory for a new efi memory map. It's referenced from couple of places, namely, efi_arch_mem_reserve() and efi_free_boot_services(). These callers, after allocating memory, remap it for further use. As usual, a routine check is performed to confirm successful remap. If the remap fails, ideally, the allocated memory should be freed but presently we just return without freeing it up. Hence, fix this bug by introducing efi_memmap_free() which frees memory allocated by efi_memmap_alloc(). As efi_memmap_alloc() allocates memory depending on whether mm_init() has already been invoked or not, similarly efi_memmap_free() frees memory accordingly. efi_fake_memmap() also references efi_memmap_alloc() but it frees memory correctly using memblock_free(), but replace it with efi_memmap_free() to maintain consistency, as in, allocate memory with efi_memmap_alloc() and free memory with efi_memmap_free(). It's a fact that memremap() and early_memremap() might never fail and this code might never get a chance to run but to maintain good kernel programming semantics, we might need this patch. Signed-off-by: Sai Praneeth Prakhya Reviewed-by: Ricardo Neri Cc: Lee Chun-Yi Cc: Borislav Petkov Cc: Tony Luck Cc: Dave Hansen Cc: Bhupesh Sharma Cc: Ricardo Neri Cc: Peter Zijlstra Cc: Ravi Shankar Cc: Matt Fleming Cc: Ard Biesheuvel --- I found this bug when working on a different patch set which uses efi_memmap_alloc() and then noticed that I never freed the allocated memory. I found it weird, in the sense that, memory is allocated but is not freed (upon returning from an error). So, wasn't sure if that should be treated as a bug or should I just leave it as is because everything works fine even without this patch. Since the effort for the patch is very minimal, I just went ahead and posted one, so that I could know your thoughts on it. Note: Patch based on Linus's mainline tree V4.17 arch/x86/platform/efi/quirks.c | 10 ++++++---- drivers/firmware/efi/fake_mem.c | 2 +- drivers/firmware/efi/memmap.c | 27 +++++++++++++++++++++++++++ include/linux/efi.h | 1 + 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 36c1f8b9f7e0..f223093f2df7 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -285,6 +285,7 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size) new = early_memremap(new_phys, new_size); if (!new) { pr_err("Failed to map new boot services memmap\n"); + efi_memmap_free(new_phys, num_entries); return; } @@ -429,7 +430,7 @@ void __init efi_free_boot_services(void) new = memremap(new_phys, new_size, MEMREMAP_WB); if (!new) { pr_err("Failed to map new EFI memmap\n"); - return; + goto free_mem; } /* @@ -450,10 +451,11 @@ void __init efi_free_boot_services(void) memunmap(new); - if (efi_memmap_install(new_phys, num_entries)) { + if (efi_memmap_install(new_phys, num_entries)) pr_err("Could not install new EFI memmap\n"); - return; - } + +free_mem: + efi_memmap_free(new_phys, num_entries); } /* diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c index 6c7d60c239b5..63edcedee25b 100644 --- a/drivers/firmware/efi/fake_mem.c +++ b/drivers/firmware/efi/fake_mem.c @@ -79,7 +79,7 @@ void __init efi_fake_memmap(void) new_memmap = early_memremap(new_memmap_phy, efi.memmap.desc_size * new_nr_map); if (!new_memmap) { - memblock_free(new_memmap_phy, efi.memmap.desc_size * new_nr_map); + efi_memmap_free(new_memmap_phy, new_nr_map); return; } diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c index 5fc70520e04c..27d28cb4652d 100644 --- a/drivers/firmware/efi/memmap.c +++ b/drivers/firmware/efi/memmap.c @@ -50,6 +50,33 @@ phys_addr_t __init efi_memmap_alloc(unsigned int num_entries) } /** + * efi_memmap_free - Free memory allocated by efi_memmap_alloc() + * @mem: Physical address allocated by efi_memmap_alloc() + * @num_entries: Number of entries in the allocated map. + * + * efi_memmap_alloc() allocates memory depending on whether mm_init() + * has already been invoked or not. It uses either memblock or "normal" + * page allocation. Use this function to free the memory allocated by + * efi_memmap_alloc(). Since the allocation is done in two different + * ways, similarly, we free it in two different ways. + * + */ +void __init efi_memmap_free(phys_addr_t mem, unsigned int num_entries) +{ + unsigned long size = num_entries * efi.memmap.desc_size; + unsigned int order = get_order(size); + phys_addr_t end = mem + size - 1; + + if (slab_is_available()) { + __free_pages(pfn_to_page(PHYS_PFN(mem)), order); + return; + } + + if (memblock_free(mem, size)) + pr_err("Failed to free mem from %pa to %pa\n", &mem, &end); +} + +/** * __efi_memmap_init - Common code for mapping the EFI memory map * @data: EFI memory map data * @late: Use early or late mapping function? diff --git a/include/linux/efi.h b/include/linux/efi.h index 3016d8c456bc..f5d1cf44b320 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1016,6 +1016,7 @@ extern int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range); extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf, struct efi_mem_range *mem); +void __init efi_memmap_free(phys_addr_t mem, unsigned int num_entries); extern int efi_config_init(efi_config_table_type_t *arch_tables); #ifdef CONFIG_EFI_ESRT -- 2.7.4