From patchwork Wed Dec 18 15:03:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 853019 Received: from mail-wr1-f73.google.com (mail-wr1-f73.google.com [209.85.221.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C5AC71C5CCF for ; Wed, 18 Dec 2024 15:03:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734534215; cv=none; b=YSa1Nt9bglUql6nI0XAw555Zj4jec8zbwztricgg+fvSUy3SuBiBs7rCKUzHBwUD0rXmMVM3p0dc0dG8nW2eoNGkjURP8a29fAf31RWJjdp7e2JM0+5f3CQn24JpVJNIFqx2/onBFVk6B5aEg11M7ZJJoCfuqYaCfRhSu2hppCE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734534215; c=relaxed/simple; bh=3GFm17Gc+6T4haDEAV6CbnWMIZrtp2CBH2AwPVaT/wk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=cpBcm76eAS9gz5O14mN6cpqhJ48yTErzwsRxzC4z/vsyjETSaFahBDXIzRbSCiWHBgTtPzmFg/7N5BeUfduUO5e6Cj+3kflHyWK+vGhqtkzrciMCX3xYtJrraOSiLrrag3SUtehgvFJFI7fgMfnZ8+AZRgrXn8ek0y5DqsbiZK4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--ardb.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=NJRAS29A; arc=none smtp.client-ip=209.85.221.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--ardb.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="NJRAS29A" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-385dcae001fso2950186f8f.1 for ; Wed, 18 Dec 2024 07:03:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734534212; x=1735139012; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=eEvz3WkqoxlF0K6VcJwCgl3tz0ai2j43+8VZsmCvsTg=; b=NJRAS29A3H3JdwtfEaQXC+4LUAb8T6c8+hR2S81UnzyPZMxnRIQ8iK41bRVnaBcT3f kBaWS7wc/fFH5F2XhrFtFtZ3RmKgx+GQczGyjITRyTK1f4buOu4EK0QjuT5ZrZkL74+A mustYUajcKMfv7XfG7cALEjWg1FdvRkJcFI6/0/2NmfA7gx02NDq6cM9xYWZsabLjbtb 5gGJiNWyg8Ip3h4E79nuHZL96TD1gShMOXi0/jdRyCCx0G9hoRkpLeiqLUi/vvmNJ+Fo dpWmOosKn3ik0FksU4Cj8hz63qQ6u76bLo07isnXX5pIdMXGHcuJ9/dGkXT6LajqOf85 FLkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734534212; x=1735139012; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=eEvz3WkqoxlF0K6VcJwCgl3tz0ai2j43+8VZsmCvsTg=; b=kHQUNoDSUYmJ/l9kXtZHlM3QpsImFuyJsUo0HFeTqz55seULm5PxBNfcivY1Yk8BV1 mbTPMM1hCynifQ/YE2/EprOy0reIoPh7bU8VEOZCBS+MljjHcRYtxI0DjrvS38LJykYf g/r7KN+2tlDSGCVIDKjXpP80H5Whv9Qc3AxqYz60nrC1RWfKGFl76PzkirficYd/0spl gB+UCNReKHOwhd25/6Zi97nmIITAe8sbwkeILwmwY7/Q1GDcBbfbDuKpwVN1x6qQQwDf Z+6rKph9Vkg3m7eh4AfhuBBR/9KZpcIuFAM2rOEYITxx+YaPKgtnO1fOzNjhcYDOXD69 BPlg== X-Gm-Message-State: AOJu0YydmF+gg2eUPIkllNPKVVQDVV8ykMwBviWr7b7VXShJhV2Nu4YL vxcAS0k2cEQ+tj8+aACbYKXU+VVVt79paoqY8LuHC3M3La/Va1rSZwOSrrRP9Ek40CDut1Kofl6 Tqmq0UvA1svcqjK0tvuyTz0f77+DjzdYnrgrtIvuDbuULk7HO99iXJcc8YwlZ9mdTn/fJNAz9b0 ACb5bA+h6DbwXdZ9/nsRtKn2Q80g== X-Google-Smtp-Source: AGHT+IEWZolnCKG7iU5fUYcCHbKJHKCWd9k51M4vGXEMA4pR0Qo2YM1Mg4EpBBuqvk1yrSiAOQbK5KRA X-Received: from wmrn13.prod.google.com ([2002:a05:600c:500d:b0:434:9e7b:42c1]) (user=ardb job=prod-delivery.src-stubby-dispatcher) by 2002:a5d:5846:0:b0:386:378c:b7ec with SMTP id ffacd0b85a97d-388e4da21f3mr2529657f8f.58.1734534212211; Wed, 18 Dec 2024 07:03:32 -0800 (PST) Date: Wed, 18 Dec 2024 16:03:17 +0100 In-Reply-To: <20241218150316.1583806-6-ardb+git@google.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241218150316.1583806-6-ardb+git@google.com> X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 X-Developer-Signature: v=1; a=openpgp-sha256; l=9968; i=ardb@kernel.org; h=from:subject; bh=MBzjTZ4rXvoYTGPsHDhEdVg7zo7i35qAoS9awftgito=; b=owGbwMvMwCFmkMcZplerG8N4Wi2JIT3piVlpTZvnnltHV777IdkfEHvANyf7uaXxu/q2kvXaP WpT1/t3lLIwiHEwyIopsgjM/vtu5+mJUrXOs2Rh5rAygQxh4OIUgIlwfWH4H/htod+EjeatnFy6 WvnLNLIl7ixjLLOPCJsgMj1UKvXabYb/9T+ZD5/YfpV/HsumvTF35eNXrrHm+s2xe3nnqal9Ny4 f5QUA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241218150316.1583806-7-ardb+git@google.com> Subject: [RFC PATCH 1/4] efi/libstub: Avoid legacy decompressor zlib/zstd wrappers From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Linton , Gerd Hoffmann , Pingfan Liu , Dave Young , Catalin Marinas , Will Deacon , Mark Rutland , Kees Cook From: Ard Biesheuvel Remove the dependency on the decompression wrappers used by the legacy decompressor, which do some odd things like providing a barebones malloc() implementation. Instead, implement GZIP deflate and ZSTD decompression in terms of the underlying libraries. Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/Makefile | 7 +- drivers/firmware/efi/libstub/efistub.h | 3 + drivers/firmware/efi/libstub/zboot-decompress-gzip.c | 66 ++++++++++++++++ drivers/firmware/efi/libstub/zboot-decompress-zstd.c | 81 ++++++++++++++++++++ drivers/firmware/efi/libstub/zboot.c | 51 ++---------- drivers/firmware/efi/libstub/zboot.lds | 1 + 6 files changed, 163 insertions(+), 46 deletions(-) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index ed4e8ddbe76a..e04285a7a6b9 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -89,7 +89,12 @@ lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) -zboot-obj-$(CONFIG_RISCV) := lib-clz_ctz.o lib-ashldi3.o +zboot-obj-y := zboot-decompress-gzip.o +CFLAGS_zboot-decompress-gzip.o += -I$(srctree)/lib/zlib_inflate +zboot-obj-$(CONFIG_KERNEL_ZSTD) := zboot-decompress-zstd.o lib-xxhash.o +CFLAGS_zboot-decompress-zstd.o += -I$(srctree)/lib/zstd + +zboot-obj-$(CONFIG_RISCV) += lib-clz_ctz.o lib-ashldi3.o lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y) lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 76e44c185f29..172f4edab30b 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -1232,4 +1232,7 @@ void process_unaccepted_memory(u64 start, u64 end); void accept_memory(phys_addr_t start, unsigned long size); void arch_accept_memory(phys_addr_t start, phys_addr_t end); +efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size); +efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen); + #endif diff --git a/drivers/firmware/efi/libstub/zboot-decompress-gzip.c b/drivers/firmware/efi/libstub/zboot-decompress-gzip.c new file mode 100644 index 000000000000..79cf8c48b033 --- /dev/null +++ b/drivers/firmware/efi/libstub/zboot-decompress-gzip.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include + +#include "efistub.h" + +#include "inftrees.c" +#include "inffast.c" +#include "inflate.c" + +extern unsigned char _gzdata_start[], _gzdata_end[]; +extern u32 __aligned(1) payload_size; + +static struct z_stream_s stream; + +efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size) +{ + efi_status_t status; + int rc; + + /* skip the 10 byte header, assume no recorded filename */ + stream.next_in = _gzdata_start + 10; + stream.avail_in = _gzdata_end - stream.next_in; + + status = efi_allocate_pages(zlib_inflate_workspacesize(), + (unsigned long *)&stream.workspace, + ULONG_MAX); + if (status != EFI_SUCCESS) + return status; + + rc = zlib_inflateInit2(&stream, -MAX_WBITS); + if (rc != Z_OK) { + efi_err("failed to initialize GZIP decompressor: %d\n", rc); + status = EFI_LOAD_ERROR; + goto out; + } + + *alloc_size = payload_size; + return EFI_SUCCESS; +out: + efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace); + return status; +} + +efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen) +{ + int rc; + + stream.next_out = out; + stream.avail_out = outlen; + + rc = zlib_inflate(&stream, 0); + zlib_inflateEnd(&stream); + + efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace); + + if (rc != Z_STREAM_END) { + efi_err("GZIP decompression failed with status %d\n", rc); + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/drivers/firmware/efi/libstub/zboot-decompress-zstd.c b/drivers/firmware/efi/libstub/zboot-decompress-zstd.c new file mode 100644 index 000000000000..268ae53c6fda --- /dev/null +++ b/drivers/firmware/efi/libstub/zboot-decompress-zstd.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include + +#include "decompress_sources.h" +#include "efistub.h" + +extern unsigned char _gzdata_start[], _gzdata_end[]; +extern u32 __aligned(1) payload_size; + +static ZSTD_inBuffer zstd_buf; +static ZSTD_DStream *dstream; +static size_t wksp_size; +static void *wksp; + +efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size) +{ + zstd_frame_header header; + efi_status_t status; + size_t ret; + + zstd_buf.src = _gzdata_start; + zstd_buf.pos = 0; + zstd_buf.size = _gzdata_end - _gzdata_start; + + ret = zstd_get_frame_header(&header, zstd_buf.src, zstd_buf.size); + if (ret != 0) { + efi_err("ZSTD-compressed data has an incomplete frame header\n"); + status = EFI_LOAD_ERROR; + goto out; + } + + if (header.windowSize > (1 << ZSTD_WINDOWLOG_MAX)) { + efi_err("ZSTD-compressed data has too large a window size\n"); + status = EFI_LOAD_ERROR; + goto out; + } + + wksp_size = zstd_dstream_workspace_bound(header.windowSize); + status = efi_allocate_pages(wksp_size, (unsigned long *)&wksp, ULONG_MAX); + if (status != EFI_SUCCESS) + goto out; + + dstream = zstd_init_dstream(header.windowSize, wksp, wksp_size); + if (!dstream) { + efi_err("Can't initialize ZSTD stream\n"); + status = EFI_OUT_OF_RESOURCES; + goto out; + } + + *alloc_size = payload_size; + return EFI_SUCCESS; +out: + efi_free(wksp_size, (unsigned long)wksp); + return status; +} + +efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen) +{ + ZSTD_outBuffer zstd_dec; + size_t ret; + int retval; + + zstd_dec.dst = out; + zstd_dec.pos = 0; + zstd_dec.size = outlen; + + ret = zstd_decompress_stream(dstream, &zstd_dec, &zstd_buf); + efi_free(wksp_size, (unsigned long)wksp); + + retval = zstd_get_error_code(ret); + if (retval) { + efi_err("ZSTD-decompression failed with status %d\n", retval); + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c index af23b3c50228..4a885fbe1ccc 100644 --- a/drivers/firmware/efi/libstub/zboot.c +++ b/drivers/firmware/efi/libstub/zboot.c @@ -7,36 +7,6 @@ #include "efistub.h" -static unsigned char zboot_heap[SZ_256K] __aligned(64); -static unsigned long free_mem_ptr, free_mem_end_ptr; - -#define STATIC static -#if defined(CONFIG_KERNEL_GZIP) -#include "../../../../lib/decompress_inflate.c" -#elif defined(CONFIG_KERNEL_LZ4) -#include "../../../../lib/decompress_unlz4.c" -#elif defined(CONFIG_KERNEL_LZMA) -#include "../../../../lib/decompress_unlzma.c" -#elif defined(CONFIG_KERNEL_LZO) -#include "../../../../lib/decompress_unlzo.c" -#elif defined(CONFIG_KERNEL_XZ) -#undef memcpy -#define memcpy memcpy -#undef memmove -#define memmove memmove -#include "../../../../lib/decompress_unxz.c" -#elif defined(CONFIG_KERNEL_ZSTD) -#include "../../../../lib/decompress_unzstd.c" -#endif - -extern char efi_zboot_header[]; -extern char _gzdata_start[], _gzdata_end[]; - -static void error(char *x) -{ - efi_err("EFI decompressor: %s\n", x); -} - static unsigned long alloc_preferred_address(unsigned long alloc_size) { #ifdef EFI_KIMG_PREFERRED_ADDRESS @@ -64,22 +34,17 @@ struct screen_info *alloc_screen_info(void) asmlinkage efi_status_t __efiapi efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) { - unsigned long compressed_size = _gzdata_end - _gzdata_start; unsigned long image_base, alloc_size; efi_loaded_image_t *image; efi_status_t status; char *cmdline_ptr; - int ret; WRITE_ONCE(efi_system_table, systab); - free_mem_ptr = (unsigned long)&zboot_heap; - free_mem_end_ptr = free_mem_ptr + sizeof(zboot_heap); - status = efi_bs_call(handle_protocol, handle, &LOADED_IMAGE_PROTOCOL_GUID, (void **)&image); if (status != EFI_SUCCESS) { - error("Failed to locate parent's loaded image protocol"); + efi_err("Failed to locate parent's loaded image protocol\n"); return status; } @@ -89,9 +54,9 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) efi_info("Decompressing Linux Kernel...\n"); - // SizeOfImage from the compressee's PE/COFF header - alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4), - EFI_ALLOC_ALIGN); + status = efi_zboot_decompress_init(&alloc_size); + if (status != EFI_SUCCESS) + return status; // If the architecture has a preferred address for the image, // try that first. @@ -127,13 +92,9 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) } // Decompress the payload into the newly allocated buffer. - ret = __decompress(_gzdata_start, compressed_size, NULL, NULL, - (void *)image_base, alloc_size, NULL, error); - if (ret < 0) { - error("Decompression failed"); - status = EFI_DEVICE_ERROR; + status = efi_zboot_decompress((void *)image_base, alloc_size); + if (status != EFI_SUCCESS) goto free_image; - } efi_cache_sync_image(image_base, alloc_size); diff --git a/drivers/firmware/efi/libstub/zboot.lds b/drivers/firmware/efi/libstub/zboot.lds index af2c82f7bd90..9ecc57ff5b45 100644 --- a/drivers/firmware/efi/libstub/zboot.lds +++ b/drivers/firmware/efi/libstub/zboot.lds @@ -17,6 +17,7 @@ SECTIONS .rodata : ALIGN(8) { __efistub__gzdata_start = .; *(.gzdata) + __efistub_payload_size = . - 4; __efistub__gzdata_end = .; *(.rodata* .init.rodata* .srodata*) From patchwork Wed Dec 18 15:03:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 851857 Received: from mail-wm1-f73.google.com (mail-wm1-f73.google.com [209.85.128.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 399131C5CCF for ; Wed, 18 Dec 2024 15:03:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734534218; cv=none; b=OYI1A+fX3DAxEoLz1VsPwYVnzs0Deq7O8ho+8ePfSnwrGi53UnREStxL98T4750p9MIgJT6dx8JAC6zsUZISiZUcj8xm37BeKX7QMe12+AADNcUYIsfAr9IObschmfOW5PmrTKwFDF5D0y7DrGHDVrUZXQ9SKLxCjXzsGWAi4wc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734534218; c=relaxed/simple; bh=U4cHDMcfPRusQq8PMbCuBEMWc9zrewwQ0Kku3ElObxU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ayNjD28dUg0iEu9ZVwje1YDxdP5I5z5YUgdJn40fb8agH86lju0yR5AnDKtbswfcvbb2mBbNarjY9yYtYm66lnH8pYtzlelDrHnXy7FDF6QexF99ACRncAMYXu23+7j4KN8SU/75HTW7ZcUDb7Ty0AE39BMkeV6Vc05vZAjEOdc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--ardb.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=s/fSG0Dv; arc=none smtp.client-ip=209.85.128.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--ardb.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="s/fSG0Dv" Received: by mail-wm1-f73.google.com with SMTP id 5b1f17b1804b1-43651b1ba8aso10129345e9.1 for ; Wed, 18 Dec 2024 07:03:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734534214; x=1735139014; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=zNQbG6H5H6XADyINQgA2DDX+81fSWOZqhKxaQqigsX4=; b=s/fSG0DvoR1SxzYtgEgs6p6NejgkG6uryPndHfUck1pvX3URnBsTHfGBYXgcO1PTmr qhncOAL9PUVpOAT8pPMoRCO5JhH6QG1mVNyl+AjvI5pt0B0zqX4KP1AOaS2/gvUh9cUI X/go8cz6SKg8ABTFJ23pfJ3GbL9UdV4aONphm5dBT4bkJKeL7H2bs07PHx2a6GZJpxe8 1X3l/zqk+M8pPq/asmPRHuZmvU5/3IfYIUo4uPMLvToGcpZhTXF9MD0N4McKhVc+E/D4 jgS6dL1qAdiENTg56U0b/3oqrC1MAph/iQE4fjcirg53rCJFIrx+96U+zwqIuMjoEwi+ xc8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734534214; x=1735139014; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=zNQbG6H5H6XADyINQgA2DDX+81fSWOZqhKxaQqigsX4=; b=pQJlX3y+ULYRvwnJLvGGWDDovNCvF4gd/R9UmCZ3Zs6nJpxamMm92fhJPldxnOSIjW frZ53JbzbTVyjHiRiO9QDdLwjdIdexXreLubMclmEhFgxZUhrWUo4WC19wSO9JOH20BX ixxPTB79tPi1guVKL1pU0d3b4NsImDaW3QS941oPULIbsKeLQH9fOId5bX8FEeSnSdlt WW2XYjem2MGVcwTQiM6aP8X91nwWG9YyUECKgsitzapmXrZZnpK6/0iwFBzTKpZrwadm /4Ep/BIoiTPXiYJpmaKHRgjkokbQOKIDtoTNvv3YQXD2ugjO+d7PTt4oj814vMPyLi3s tC8A== X-Gm-Message-State: AOJu0YzeUhYeFfQvlp3KS/F06XlmrJnh/9GuTyAehtwTX7DAUg7PkEH7 vMcA7nk1KBhhpkBrwPrGPjvaURMWO7XloQPCYSrX5hmqzMY7reAxEEjnzpvWfsSQ7MbaKvzjWMk BSXQFC72IxL1tPvMSubsu4l4gmou+Ds63uBsPCPqTw0rkU+EHNEQ3nX7GWMgMpmSZkH7xrUkAfL JclfdhbU2HD+UnrLCBZbExJch6hw== X-Google-Smtp-Source: AGHT+IG6ccznB3EClUSdci9uiwo+dV47rrW4SBEb0jzk8Wgv315gjnYs4IYfT/rGE3/6sgwPlLIQ1aP+ X-Received: from wmbbi21.prod.google.com ([2002:a05:600c:3d95:b0:434:f21d:7e31]) (user=ardb job=prod-delivery.src-stubby-dispatcher) by 2002:a5d:584b:0:b0:388:e178:ddb7 with SMTP id ffacd0b85a97d-388e4d9d498mr2996698f8f.56.1734534214313; Wed, 18 Dec 2024 07:03:34 -0800 (PST) Date: Wed, 18 Dec 2024 16:03:18 +0100 In-Reply-To: <20241218150316.1583806-6-ardb+git@google.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241218150316.1583806-6-ardb+git@google.com> X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 X-Developer-Signature: v=1; a=openpgp-sha256; l=15536; i=ardb@kernel.org; h=from:subject; bh=1XUDRpFF0wEqMKBIW6qxREWBIHWww70FQxyUSFWIEag=; b=owGbwMvMwCFmkMcZplerG8N4Wi2JIT3pibnZVA+F6iWyIowruALvCBY4ah+apcTOcHEGT4fyE mXLfMmOUhYGMQ4GWTFFFoHZf9/tPD1RqtZ5lizMHFYmkCEMXJwCMJH4+4wMm+trpVZrVtyeWiC5 v9um/X3L/fjuO1Pm1QZqFrz5ZdTKwshweYmz6hols4Mzd+kFv2iaPNtAV/rLclexy1mKj75tWvS NCQA= X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241218150316.1583806-8-ardb+git@google.com> Subject: [RFC PATCH 2/4] efi/zboot: Add support for ELF payloads From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Linton , Gerd Hoffmann , Pingfan Liu , Dave Young , Catalin Marinas , Will Deacon , Mark Rutland , Kees Cook From: Ard Biesheuvel Some architectures (such as x86) embed the ELF build of vmlinux in the decompressor, and this is relied upon by, e.g., the Xen loader, which uses the ELF notes to find the various entrypoints into the executable. Implement support for this in EFI zboot, but avoid the need to decompress the entire ELF image, and instead, use the PT_LOAD headers to selectively decompress those slices of the the payload that are actually part of the memory image. Signed-off-by: Ard Biesheuvel --- arch/arm64/include/asm/efi.h | 2 +- drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/Makefile.zboot | 6 + drivers/firmware/efi/libstub/arm64-stub.c | 2 +- drivers/firmware/efi/libstub/arm64.c | 16 +- drivers/firmware/efi/libstub/efistub.h | 8 +- drivers/firmware/efi/libstub/zboot-decompress-gzip.c | 25 ++- drivers/firmware/efi/libstub/zboot-decompress-zstd.c | 26 +++- drivers/firmware/efi/libstub/zboot-decompress.c | 161 ++++++++++++++++++++ drivers/firmware/efi/libstub/zboot.c | 9 +- 10 files changed, 223 insertions(+), 34 deletions(-) diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index bcd5622aa096..da502c34a5ea 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -103,7 +103,7 @@ static inline unsigned long efi_get_kimg_min_align(void) #define EFI_ALLOC_ALIGN SZ_64K #define EFI_ALLOC_LIMIT ((1UL << 48) - 1) -extern unsigned long primary_entry_offset(void); +extern unsigned long entry_offset(void); /* * On ARM systems, virtually remapped UEFI runtime services are set up in two diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index e04285a7a6b9..8e2fe499f1f6 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -95,7 +95,7 @@ zboot-obj-$(CONFIG_KERNEL_ZSTD) := zboot-decompress-zstd.o lib-xxhash.o CFLAGS_zboot-decompress-zstd.o += -I$(srctree)/lib/zstd zboot-obj-$(CONFIG_RISCV) += lib-clz_ctz.o lib-ashldi3.o -lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y) +lib-$(CONFIG_EFI_ZBOOT) += zboot.o zboot-decompress.o $(zboot-obj-y) lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot index 48842b5c106b..bb598544b6ba 100644 --- a/drivers/firmware/efi/libstub/Makefile.zboot +++ b/drivers/firmware/efi/libstub/Makefile.zboot @@ -8,9 +8,15 @@ quiet_cmd_copy_and_pad = PAD $@ cmd_copy_and_pad = cp $< $@; \ truncate -s $$(hexdump -s16 -n4 -e '"%u"' $<) $@ +ifneq ($(EFI_ZBOOT_PAYLOAD),) # Pad the file to the size of the uncompressed image in memory, including BSS $(obj)/vmlinux.bin: $(obj)/$(EFI_ZBOOT_PAYLOAD) FORCE $(call if_changed,copy_and_pad) +else +$(obj)/vmlinux.bin: OBJCOPYFLAGS := -R .note -R .note.gnu.build-id -R .comment -S +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) +endif # in GZIP, the appended le32 carrying the uncompressed size is part of the # format, but in other cases, we just append it at the end for convenience, diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index 2c3869356147..56509a1f8406 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -45,7 +45,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, asmlinkage void primary_entry(void); -unsigned long primary_entry_offset(void) +unsigned long entry_offset(void) { /* * When built as part of the kernel, the EFI stub cannot branch to the diff --git a/drivers/firmware/efi/libstub/arm64.c b/drivers/firmware/efi/libstub/arm64.c index e57cd3de0a00..f6c8e1992e54 100644 --- a/drivers/firmware/efi/libstub/arm64.c +++ b/drivers/firmware/efi/libstub/arm64.c @@ -100,7 +100,7 @@ void efi_cache_sync_image(unsigned long image_base, /* only perform the cache maintenance if needed for I/D coherency */ if (!(ctr & BIT(CTR_EL0_IDC_SHIFT))) { unsigned long base = image_base; - unsigned long size = code_size; + unsigned long size = alloc_size; do { asm("dc " DCTYPE ", %0" :: "r"(base)); @@ -116,24 +116,12 @@ void efi_cache_sync_image(unsigned long image_base, efi_remap_image(image_base, alloc_size, code_size); } -unsigned long __weak primary_entry_offset(void) -{ - /* - * By default, we can invoke the kernel via the branch instruction in - * the image header, so offset #0. This will be overridden by the EFI - * stub build that is linked into the core kernel, as in that case, the - * image header may not have been loaded into memory, or may be mapped - * with non-executable permissions. - */ - return 0; -} - void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt_addr, unsigned long fdt_size) { void (* __noreturn enter_kernel)(u64, u64, u64, u64); - enter_kernel = (void *)entrypoint + primary_entry_offset(); + enter_kernel = (void *)entrypoint + entry_offset(); enter_kernel(fdt_addr, 0, 0, 0); } diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 172f4edab30b..76bfc9f9017e 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -1232,7 +1232,13 @@ void process_unaccepted_memory(u64 start, u64 end); void accept_memory(phys_addr_t start, unsigned long size); void arch_accept_memory(phys_addr_t start, phys_addr_t end); -efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size); +efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size, + unsigned long *entry); efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen); +bool efi_zboot_check_header(unsigned long *alloc_size, + unsigned long *entry); +bool efi_zboot_decompress_segments(u8 *out, unsigned long outlen); +bool efi_zboot_decompress_slice(u8 *out, unsigned long outlen); + #endif diff --git a/drivers/firmware/efi/libstub/zboot-decompress-gzip.c b/drivers/firmware/efi/libstub/zboot-decompress-gzip.c index 79cf8c48b033..6a7b5d5b5a18 100644 --- a/drivers/firmware/efi/libstub/zboot-decompress-gzip.c +++ b/drivers/firmware/efi/libstub/zboot-decompress-gzip.c @@ -12,11 +12,11 @@ #include "inflate.c" extern unsigned char _gzdata_start[], _gzdata_end[]; -extern u32 __aligned(1) payload_size; static struct z_stream_s stream; -efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size) +efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size, + unsigned long *entry) { efi_status_t status; int rc; @@ -38,14 +38,18 @@ efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size) goto out; } - *alloc_size = payload_size; + if (!efi_zboot_check_header(alloc_size, entry)) { + status = EFI_LOAD_ERROR; + goto out; + } + return EFI_SUCCESS; out: efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace); return status; } -efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen) +bool efi_zboot_decompress_slice(u8 *out, unsigned long outlen) { int rc; @@ -53,12 +57,19 @@ efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen) stream.avail_out = outlen; rc = zlib_inflate(&stream, 0); - zlib_inflateEnd(&stream); + return rc == Z_OK || rc == Z_STREAM_END; +} + +efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen) +{ + bool ret = efi_zboot_decompress_segments(out, outlen); + + zlib_inflateEnd(&stream); efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace); - if (rc != Z_STREAM_END) { - efi_err("GZIP decompression failed with status %d\n", rc); + if (!ret) { + efi_err("GZIP decompression failed\n"); return EFI_LOAD_ERROR; } diff --git a/drivers/firmware/efi/libstub/zboot-decompress-zstd.c b/drivers/firmware/efi/libstub/zboot-decompress-zstd.c index 268ae53c6fda..61a25c75788f 100644 --- a/drivers/firmware/efi/libstub/zboot-decompress-zstd.c +++ b/drivers/firmware/efi/libstub/zboot-decompress-zstd.c @@ -9,14 +9,14 @@ #include "efistub.h" extern unsigned char _gzdata_start[], _gzdata_end[]; -extern u32 __aligned(1) payload_size; static ZSTD_inBuffer zstd_buf; static ZSTD_DStream *dstream; static size_t wksp_size; static void *wksp; -efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size) +efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size, + unsigned long *entry) { zstd_frame_header header; efi_status_t status; @@ -51,29 +51,39 @@ efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size) goto out; } - *alloc_size = payload_size; + if (!efi_zboot_check_header(alloc_size, entry)) { + status = EFI_LOAD_ERROR; + goto out; + } + return EFI_SUCCESS; out: efi_free(wksp_size, (unsigned long)wksp); return status; } -efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen) +bool efi_zboot_decompress_slice(u8 *out, unsigned long outlen) { ZSTD_outBuffer zstd_dec; size_t ret; - int retval; zstd_dec.dst = out; zstd_dec.pos = 0; zstd_dec.size = outlen; ret = zstd_decompress_stream(dstream, &zstd_dec, &zstd_buf); + + return zstd_get_error_code(ret) == 0; +} + +efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen) +{ + bool ret = efi_zboot_decompress_segments(out, outlen); + efi_free(wksp_size, (unsigned long)wksp); - retval = zstd_get_error_code(ret); - if (retval) { - efi_err("ZSTD-decompression failed with status %d\n", retval); + if (!ret) { + efi_err("ZSTD-decompression failed\n"); return EFI_LOAD_ERROR; } diff --git a/drivers/firmware/efi/libstub/zboot-decompress.c b/drivers/firmware/efi/libstub/zboot-decompress.c new file mode 100644 index 000000000000..964fe445713c --- /dev/null +++ b/drivers/firmware/efi/libstub/zboot-decompress.c @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include + +#include + +#include "efistub.h" + +extern u32 __aligned(1) payload_size; + +static struct { +#ifdef CONFIG_64BIT + Elf64_Ehdr ehdr; + Elf64_Phdr phdr[5]; +#else + Elf32_Ehdr ehdr; + Elf32_Phdr phdr[5]; +#endif +} elf_header; + +static bool is_elf; + +bool efi_zboot_check_header(unsigned long *alloc_size, + unsigned long *entry) +{ + unsigned long min = ULONG_MAX, max = 0; + bool ret; + + ret = efi_zboot_decompress_slice((u8 *)&elf_header, sizeof(elf_header)); + if (!ret) { + efi_err("failed to extract header\n"); + return false; + } + + /* Check the ELF magic */ + if (elf_header.ehdr.e_ident[EI_MAG0] != ELFMAG0 || + elf_header.ehdr.e_ident[EI_MAG1] != ELFMAG1 || + elf_header.ehdr.e_ident[EI_MAG2] != ELFMAG2 || + elf_header.ehdr.e_ident[EI_MAG3] != ELFMAG3) { + /* + * Raw images are padded to the memory size before compression, + * so the payload size equals the allocation size. + */ + *alloc_size = payload_size; + *entry = 0; + return true; + } + + /* + * Check whether the executable header and program headers are laid out + * as expected. + */ + if (elf_header.ehdr.e_phoff != offsetof(typeof(elf_header), phdr) || + elf_header.ehdr.e_phnum > ARRAY_SIZE(elf_header.phdr)) { + efi_err("Unexpected ELF header layout\n"); + return false; + } + + /* + * Iterate over the PT_LOAD headers to find the size of the executable + * image in memory. + */ + for (int i = 0; i < elf_header.ehdr.e_phnum; i++) { + __auto_type ph = &elf_header.phdr[i]; + + if (ph->p_type != PT_LOAD) + continue; + + min = min(min, ph->p_paddr); + max = max(max, ph->p_paddr + ph->p_memsz); + } + + if (min >= max) { + efi_err("Failed to determine ELF memory size\n"); + return false; + } + + efi_info("ELF zboot payload detected\n"); + + *alloc_size = max - min; + *entry = elf_header.ehdr.e_entry - elf_header.phdr[0].p_paddr; + is_elf = true; + + return true; +} + +bool efi_zboot_decompress_segments(u8 *out, unsigned long outlen) +{ + efi_memory_attribute_protocol_t *memattr = NULL; + unsigned long pos = sizeof(elf_header); + + if (!is_elf) { + /* + * If this is a raw image, first copy the data we already + * extracted from the compressed blob into the output. + */ + memcpy(out, &elf_header, pos); + + return efi_zboot_decompress_slice(out + pos, outlen - pos); + } + + /* grab a reference to the memory attributes protocol, if available */ + efi_bs_call(locate_protocol, &EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID, NULL, + (void **)&memattr); + + /* + * Iterate over the program headers, and decompress the payload of each + * PT_LOAD entry. This involves skipping the padding by decompressing + * it into the output buffer before overwriting it with the actual + * data. + */ + for (int i = 0; i < elf_header.ehdr.e_phnum; i++) { + __auto_type ph = &elf_header.phdr[i]; + void *dst = out + ph->p_paddr - elf_header.phdr[0].p_paddr; + unsigned long pa = (unsigned long)dst; + + if (ph->p_type != PT_LOAD) + continue; + + if (ph->p_offset < pos) { + efi_err("ELF PT_LOAD headers out of order\n"); + return false; + } + + /* extract and discard the padding */ + while (ph->p_offset > pos) { + unsigned long l = min(ph->p_offset - pos, ph->p_memsz); + + efi_zboot_decompress_slice(dst, l); + pos += l; + } + + /* decompress payload */ + efi_zboot_decompress_slice(dst, ph->p_filesz); + + /* clear area that was not covered by file data */ + if (ph->p_memsz > ph->p_filesz) + memset(dst + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz); + + if (memattr && ph->p_flags == (PF_R | PF_X)) { + unsigned long l = ALIGN(ph->p_memsz, EFI_PAGE_SIZE); + efi_status_t status; + + status = memattr->set_memory_attributes(memattr, pa, l, EFI_MEMORY_RO); + if (status != EFI_SUCCESS) + efi_warn("Failed to set EFI_MEMORY_RO on R-X region\n"); + + status = memattr->clear_memory_attributes(memattr, pa, l, EFI_MEMORY_XP); + if (status != EFI_SUCCESS) + efi_warn("Failed to clear EFI_MEMORY_XP from R-X region\n"); + } + + if (ph->p_flags & PF_X) + efi_cache_sync_image(pa, ph->p_filesz); + + pos = ph->p_offset + ph->p_filesz; + } + + return true; +} diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c index 4a885fbe1ccc..96546b6da59f 100644 --- a/drivers/firmware/efi/libstub/zboot.c +++ b/drivers/firmware/efi/libstub/zboot.c @@ -31,6 +31,13 @@ struct screen_info *alloc_screen_info(void) return __alloc_screen_info(); } +static unsigned long entrypoint; + +unsigned long entry_offset(void) +{ + return entrypoint; +} + asmlinkage efi_status_t __efiapi efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) { @@ -54,7 +61,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) efi_info("Decompressing Linux Kernel...\n"); - status = efi_zboot_decompress_init(&alloc_size); + status = efi_zboot_decompress_init(&alloc_size, &entrypoint); if (status != EFI_SUCCESS) return status; From patchwork Wed Dec 18 15:03:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 853018 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 46D081B042F for ; Wed, 18 Dec 2024 15:03:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734534220; cv=none; b=k1gbM2NK5hbtxJyiumtfnzCCsgbzLA89DbVQTAV9S/l90JU7KJwIM7gtDvnY9j27I80qFMhs2yrH5T8/Hrl9r2JwXJuP57Q6tMmBBQhnlqoR2MaH+t/a2KxF6DOGLKDIWVaGrmN+LyyQCJeBWB90CLl804ujSrViqOFPJTh9t/4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734534220; c=relaxed/simple; bh=UkEQAPU0BOE7Cvbr49Sj5hH1WmXbgLg2wGhFh652QNc=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Krq2g54t3rrJvok5HVR3oZcoNMAWN6cTAKbIjkQ0gZ94JskVadxp5U7Iq4PMaO3PO6J6D6TpNsHYxkgnb020fi5LwzxGfPP/B3rrfsNoL26pSPaAglwBE9lAB6QW6w/EX7oJG0RIRFnv0e1WqKCgpd5Z2GDHHCwGhrXXnVFPlZ8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--ardb.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=pwmuQfAh; arc=none smtp.client-ip=209.85.128.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--ardb.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="pwmuQfAh" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-43627bb20b5so52095685e9.1 for ; Wed, 18 Dec 2024 07:03:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734534216; x=1735139016; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=KuIlLWp32KxrnX+b+TFBJxsTzZwQ84RmgJbgBG8fYVY=; b=pwmuQfAhMTc1HCZFd1trx1HZhcMVKpdOJ1SWtywb61hh544bY/SLQ+hwc5TrgRjn7L n+V3E2Fwt5X+b2+YzxN3c0ws4NZiP5yuxau5FybHkt05+tdyUPgCkQbT+tLpWPvwFKK5 KbxzpL6xT/CNEwJqJJyILfEEb5Lkuc9WXiuc05ZaxtQ7F40FPSm63bJNCtoLCltjAiiU T+6aHBYXSDEhY4IxIyeC40hsxnZhBBZnfRIbczxwgY7x8U2r5DNKEHEDxMaVIZk6qm4a E6RdgZhevRb75OvbFWiy310htZk4I+lX61cRAziWBDN9c7MGspXnfLNDFTiBCJgFtYF1 DD9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734534217; x=1735139017; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=KuIlLWp32KxrnX+b+TFBJxsTzZwQ84RmgJbgBG8fYVY=; b=Xjr7Um+hbXddPMBZitLQ+k9Xk03CHoCZ/80mtKvsZrhrpMg1pNhhwzfQi7CWkrPoYd W7VAyqdstFG0Me3MARoPuSKxgZ06nm3CJoeqccvoFAzL0KvwURr5d7/J2lmv1TksUesT SOH+PcgweDint7yCadpHA4A5KWH/rOEWV0X30DcN9eAitT8v6UCM2XBm6HsvyboC8+8z a4tamHoXTaJOLFuGbTlMzAyLLVD/eXPQ3X4v186Qnh2DWebuXx8R204391DZjEvyiXzP U9z47fc5J1ApoqFp1aki0obLreFsjaTpt+YS+vF+YCoYWVJ7Er6kLUUMZnXJVBg+px9L pOzw== X-Gm-Message-State: AOJu0Yw7BN+Hn74N+tQnuKN2m2hPlEYjQD5HOatEerLBtlIJnQQcsPh3 BQFSVECjiOUjlmFmEXlReDF/6F2uPGhDxlB2B06MhLZjXz+/kDHwpz61fMnhHqTLbK6AJ8VJpxw u4kL0fiEXVl+ikK1ymGisKpYknRtFEtGdk/FyWSqhw5U1L0rzoI1qDaEQE2iWV3KkYpDyEcMLgn EtvUK/OQpXEciq31ihtkGQDhwMzA== X-Google-Smtp-Source: AGHT+IHUywDhYzEQoh8qG89QtR2fYeZOhh/y11YZQtpRYKYnPH/DXnov2cw8yVX+5sfOgjyqqIWOAgGk X-Received: from wmbew11.prod.google.com ([2002:a05:600c:808b:b0:434:9da4:2fa5]) (user=ardb job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:154c:b0:42c:c28c:e477 with SMTP id 5b1f17b1804b1-436553e9de5mr22498345e9.23.1734534216426; Wed, 18 Dec 2024 07:03:36 -0800 (PST) Date: Wed, 18 Dec 2024 16:03:19 +0100 In-Reply-To: <20241218150316.1583806-6-ardb+git@google.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241218150316.1583806-6-ardb+git@google.com> X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 X-Developer-Signature: v=1; a=openpgp-sha256; l=2496; i=ardb@kernel.org; h=from:subject; bh=9vtzUeuZVMHbyIAsApU0U8bu7QdcmCaocZ+3CwCVfC4=; b=owGbwMvMwCFmkMcZplerG8N4Wi2JIT3piaUno547e6+JR9A/T93Xr8ODTxv9nO16fum1uPkOI WeSUnZ3lLIwiHEwyIopsgjM/vtu5+mJUrXOs2Rh5rAygQxh4OIUgImYz2FkaJn6tCnlud+MmkNC 9Xtndx32tApetqxm41l9eS7PNaxnRRkZtkpuiE3dvOWI5odN+7+9+jOdgWXP6XcfO65srvu0lOf VRxYA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241218150316.1583806-9-ardb+git@google.com> Subject: [RFC PATCH 3/4] arm64/boot: Populate vmlinux ELF program headers From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Linton , Gerd Hoffmann , Pingfan Liu , Dave Young , Catalin Marinas , Will Deacon , Mark Rutland , Kees Cook From: Ard Biesheuvel In order to be able to use the ELF vmlinux image as the [zboot compressed] boot image, populate the program headers explicitly to describe text+rodata+inittext as R-X and initdata+data+bss as RW-. Signed-off-by: Ard Biesheuvel --- arch/arm64/kernel/vmlinux.lds.S | 33 +++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index f84c71f04d9e..33d9c683e434 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -59,6 +59,7 @@ #define RO_EXCEPTION_TABLE_ALIGN 4 #define RUNTIME_DISCARD_EXIT +#define LOAD_OFFSET KIMAGE_VADDR #include #include @@ -70,7 +71,9 @@ #include "image.h" OUTPUT_ARCH(aarch64) -ENTRY(_text) +ENTRY(elf_entry) + +elf_entry = ABSOLUTE(primary_entry - KIMAGE_VADDR); jiffies = jiffies_64; @@ -150,6 +153,11 @@ PECOFF_FILE_ALIGNMENT = 0x200; #define PECOFF_EDATA_PADDING #endif +PHDRS { + text PT_LOAD FLAGS(5); /* R_X */ + data PT_LOAD FLAGS(6); /* RW_ */ +} + SECTIONS { /* @@ -166,10 +174,10 @@ SECTIONS . = KIMAGE_VADDR; - .head.text : { + .head.text : AT (0x0) { _text = .; HEAD_TEXT - } + } :text .text : ALIGN(SEGMENT_ALIGN) { /* Real text segment */ _stext = .; /* Text and read-only data */ IRQENTRY_TEXT @@ -248,10 +256,6 @@ SECTIONS __inittext_end = .; __initdata_begin = .; - init_idmap_pg_dir = .; - . += INIT_IDMAP_DIR_SIZE; - init_idmap_pg_end = .; - .init.data : { INIT_DATA INIT_SETUP(16) @@ -259,13 +263,18 @@ SECTIONS CON_INITCALL INIT_RAM_FS *(.init.altinstructions .init.bss) /* from the EFI stub */ - } + } :data .exit.data : { EXIT_DATA } RUNTIME_CONST_VARIABLES + . = ALIGN(PAGE_SIZE); + init_idmap_pg_dir = .; + . += INIT_IDMAP_DIR_SIZE; + init_idmap_pg_end = .; + PERCPU_SECTION(L1_CACHE_BYTES) HYPERVISOR_PERCPU_SECTION @@ -325,10 +334,12 @@ SECTIONS init_pg_end = .; /* end of zero-init region */ - . += SZ_4K; /* stack for the early C runtime */ - early_init_stack = .; + .early_init_stack : { + . += SZ_4K; /* stack for the early C runtime */ + early_init_stack = .; - . = ALIGN(SEGMENT_ALIGN); + . = ALIGN(SEGMENT_ALIGN); + } __pecoff_data_size = ABSOLUTE(. - __initdata_begin); _end = .; From patchwork Wed Dec 18 15:03:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 851856 Received: from mail-wm1-f73.google.com (mail-wm1-f73.google.com [209.85.128.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9DF561B425F for ; Wed, 18 Dec 2024 15:03:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734534222; cv=none; b=qAbaQDa6HGJlPb87KAQaYz9uI1+O23YQTdDBTPQJRLbxsnx+4WYzgytTKuk8PR9mzLFYmA+UJrtZqfnm6sQ8bCQrnwDvYkf2/tj6I0DpZAI4bouynb8mEp/h3zPbszlpF+gFl+5F6eqm9tTEE7BQ/6RZAFQX3eHkoXdJYweJBxE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734534222; c=relaxed/simple; bh=gbn/sr6lKWzSFEyjMNNuLZ20Ed7uHNh9ByYZj5qat/M=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=fVwhwhrbpJOrkPhnbota1+uyQKyjmsl2Mr/nnD/QS9cfoYqmeW45+eW9O2YXIx7viDYSxru/HVYN1+I/XAyqnRgmi0nJSk1cRhh5J48yfwLZ/IwD1ybZ9n2v6BRfxRUQWTB0Tt4WFJTLqEizgdXMloA2Zgr96Uzo2KuAjP6pMxo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--ardb.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=mVCEaD/i; arc=none smtp.client-ip=209.85.128.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--ardb.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="mVCEaD/i" Received: by mail-wm1-f73.google.com with SMTP id 5b1f17b1804b1-43625ceae52so37118005e9.0 for ; Wed, 18 Dec 2024 07:03:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734534219; x=1735139019; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=tlXVUt3o80MSmJGhEnnWhOtf5ByGllnGOXqBF1r6osY=; b=mVCEaD/irn0oekH8w+k1bzHqw4ucbyEQkbEBBXGkAPtG+zZe5Dt0+JY2qZx+AtjDRN UhLX5hgK7G6qap97SNSqbI4A9pY1GZu6hA1pZzrtwAjn/GJ5rwKWQr86NGuD2bAphmma ozx9nyDzzd/hDNq7XxilDvCzgvmPZ/syVdbKPANs+HUQmO7/WjIGGchtcQErMtN4Z0/E X/l1g4R0kDDoGeF0By797JRWz2An+SM/ag7cScdQWrhMpoQYToytlPnBuH6yRKTjYEeS w1fTnSbuNMZCvusPz5Qz4dr7FycyDwXjo++oaPqaJ8hqk89ernpTvGxNopyIYIewRQ2+ OjtA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734534219; x=1735139019; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=tlXVUt3o80MSmJGhEnnWhOtf5ByGllnGOXqBF1r6osY=; b=laB2bDQQai/8X0YMQhD6sXys7h6qRxHmgTl40zn4CdBJusl3UZRZYbQsHilb7BJZY1 YUThLpk5iwZy1IBoi8rqqYCq82FjPVdfFRfB+6EFPk9JDS8bcc6WTzQ6YaE74lbMM1Q9 XT8ntVKra8dhdQpMMbDDcjXjgE1Ql+VXmsyhpKBn6XkqTRdfzHIMebkVPi+70Kug2DxZ +FBOCjwtED7cmLwzUj7zvObIGFS8ehERX24jgo7H4QPKs/v5l08HToGlMawBgSV/bLdg AhAEPHqSGDB7532LMThizogbLGOwuz8kYvS78GeApzOjmC1cdKKdGWYxQtQbXBgD4wtt 29uw== X-Gm-Message-State: AOJu0Yx8/v3Pn9Rdx5RG8qKmr/S/qR0uyYdwNd4j0Ejht4nqQB/txfOA cnskubisvpTkbxivRmulgnQ8h5zMg8CvcSa9sjnK8O88qxRMCHuYvqb6ltVOd/Ax9O+hFcBMe9i mNT+6FcMTT0rQEkOCrQP9YlMQP6RaK2h0QzfgSlHRNrXYFK9ihKD0Pk1v0bzK/Ppg87sN4oBAFW 42ZZvsqBOUwT5NM1gkyn5cIpb+HA== X-Google-Smtp-Source: AGHT+IElZoDBtrV078cb504PgSiVgLf/jzQIBTrfLTI3yRr6HCB+vv7sFozB63FztHxOEuvBcRNPEYhQ X-Received: from wmbfl17.prod.google.com ([2002:a05:600c:b91:b0:434:fc6f:e8c3]) (user=ardb job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:468c:b0:433:c76d:d57e with SMTP id 5b1f17b1804b1-436553433ebmr27744215e9.5.1734534218766; Wed, 18 Dec 2024 07:03:38 -0800 (PST) Date: Wed, 18 Dec 2024 16:03:20 +0100 In-Reply-To: <20241218150316.1583806-6-ardb+git@google.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241218150316.1583806-6-ardb+git@google.com> X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 X-Developer-Signature: v=1; a=openpgp-sha256; l=3423; i=ardb@kernel.org; h=from:subject; bh=tH1lCvrU4ctbGRiyycueYH4HRv9gwLP/NbEyTuvF2dQ=; b=owGbwMvMwCFmkMcZplerG8N4Wi2JIT3piRU/Q+e6qE1WGt+dZ75t+5Uc/2cmz8J4i1mfMrVN3 4e5y3N2lLIwiHEwyIopsgjM/vtu5+mJUrXOs2Rh5rAygQxh4OIUgIksfsbwm6WiznfjvikBDDYM ysEfzi+d6Jqx6us6DZ6NYnw37jbKtDIy/DWQfH3R+33fxBkf2OpPni0s+rxg6ufZt9zV1zUFtgh xcwEA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241218150316.1583806-10-ardb+git@google.com> Subject: [RFC PATCH 4/4] efi/arm64: Use ELF payload for EFI zboot From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Linton , Gerd Hoffmann , Pingfan Liu , Dave Young , Catalin Marinas , Will Deacon , Mark Rutland , Kees Cook From: Ard Biesheuvel Instead of a raw binary executable, embed an ELF build of the core kernel into the EFI zboot image. Given that the memory layout of the kernel executable is described by ELF program headers, this removes the need to rely on symbols injected into the build to describe things like the size of the text area, which are not accessible to other consumers of the EFI zboot format, e.g., the kexec loader. Given that the EFI zboot loader only decompresses those parts of the payload covered by PT_LOAD program headers, stripping the encapsulated ELF image is not strictly necessary, making the EFI zboot format suitable for distributing the bootable image and the debug symbols in a single compressed image. Signed-off-by: Ard Biesheuvel --- arch/arm64/boot/Makefile | 4 ---- arch/arm64/kernel/image-vars.h | 4 ---- drivers/firmware/efi/libstub/arm64.c | 4 ---- drivers/firmware/efi/libstub/zboot.lds | 6 ------ 4 files changed, 18 deletions(-) diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile index b5a08333bc57..cfd76bcbb81f 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -46,12 +46,8 @@ $(obj)/Image.xz: $(obj)/Image FORCE $(obj)/image.fit: $(obj)/Image $(obj)/dts/dtbs-list FORCE $(call if_changed,fit) -EFI_ZBOOT_PAYLOAD := Image EFI_ZBOOT_BFD_TARGET := elf64-littleaarch64 EFI_ZBOOT_MACH_TYPE := ARM64 EFI_ZBOOT_FORWARD_CFI := $(CONFIG_ARM64_BTI_KERNEL) -EFI_ZBOOT_OBJCOPY_FLAGS = --add-symbol zboot_code_size=0x$$( \ - $(NM) vmlinux|grep _kernel_codesize|cut -d' ' -f1) - include $(srctree)/drivers/firmware/efi/libstub/Makefile.zboot diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index 8f5422ed1b75..7e1c3f1f1372 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h @@ -140,8 +140,4 @@ KVM_NVHE_ALIAS(kvm_protected_mode_initialized); #endif /* CONFIG_KVM */ -#ifdef CONFIG_EFI_ZBOOT -_kernel_codesize = ABSOLUTE(__inittext_end - _text); -#endif - #endif /* __ARM64_KERNEL_IMAGE_VARS_H */ diff --git a/drivers/firmware/efi/libstub/arm64.c b/drivers/firmware/efi/libstub/arm64.c index f6c8e1992e54..b339fa34d2f2 100644 --- a/drivers/firmware/efi/libstub/arm64.c +++ b/drivers/firmware/efi/libstub/arm64.c @@ -88,8 +88,6 @@ efi_status_t check_platform_features(void) #define DCTYPE "cvau" #endif -u32 __weak code_size; - void efi_cache_sync_image(unsigned long image_base, unsigned long alloc_size) { @@ -112,8 +110,6 @@ void efi_cache_sync_image(unsigned long image_base, asm("ic ialluis"); dsb(ish); isb(); - - efi_remap_image(image_base, alloc_size, code_size); } void __noreturn efi_enter_kernel(unsigned long entrypoint, diff --git a/drivers/firmware/efi/libstub/zboot.lds b/drivers/firmware/efi/libstub/zboot.lds index 9ecc57ff5b45..143597d0e5dc 100644 --- a/drivers/firmware/efi/libstub/zboot.lds +++ b/drivers/firmware/efi/libstub/zboot.lds @@ -2,8 +2,6 @@ ENTRY(__efistub_efi_zboot_header); -PROVIDE(zboot_code_size = ABSOLUTE(0)); - SECTIONS { .head : ALIGN(4096) { @@ -21,10 +19,6 @@ SECTIONS __efistub__gzdata_end = .; *(.rodata* .init.rodata* .srodata*) - . = ALIGN(4); - __efistub_code_size = .; - LONG(zboot_code_size); - _etext = ALIGN(4096); . = _etext; }