Skip to content

Commit 0dc1754

Browse files
committed
efi/libstub: Avoid legacy decompressor zlib/zstd wrappers
Remove EFI zboot's dependency on the decompression wrappers used by the legacy decompressor boot code, which can only process the input in one go, and this will not work for upcoming support for embedded ELF images. They also do some odd things like providing a barebones malloc() implementation, which is not needed in a hosted environment such as the EFI boot services. So instead, implement GZIP deflate and ZSTD decompression in terms of the underlying libraries. Support for other compression algoritms has already been dropped. Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
1 parent 74d613e commit 0dc1754

File tree

6 files changed

+136
-57
lines changed

6 files changed

+136
-57
lines changed

drivers/firmware/efi/libstub/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,12 @@ lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o
9292

9393
CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
9494

95-
zboot-obj-$(CONFIG_RISCV) := lib-clz_ctz.o lib-ashldi3.o
95+
zboot-obj-y := zboot-decompress-gzip.o
96+
CFLAGS_zboot-decompress-gzip.o += -I$(srctree)/lib/zlib_inflate
97+
zboot-obj-$(CONFIG_KERNEL_ZSTD) := zboot-decompress-zstd.o lib-xxhash.o
98+
CFLAGS_zboot-decompress-zstd.o += -I$(srctree)/lib/zstd
99+
100+
zboot-obj-$(CONFIG_RISCV) += lib-clz_ctz.o lib-ashldi3.o
96101
lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y)
97102

98103
lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o

drivers/firmware/efi/libstub/efistub.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,4 +1234,7 @@ void process_unaccepted_memory(u64 start, u64 end);
12341234
void accept_memory(phys_addr_t start, unsigned long size);
12351235
void arch_accept_memory(phys_addr_t start, phys_addr_t end);
12361236

1237+
efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size);
1238+
efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen);
1239+
12371240
#endif
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/efi.h>
4+
#include <linux/zlib.h>
5+
6+
#include <asm/efi.h>
7+
8+
#include "efistub.h"
9+
10+
#include "inftrees.c"
11+
#include "inffast.c"
12+
#include "inflate.c"
13+
14+
extern unsigned char _gzdata_start[], _gzdata_end[];
15+
extern u32 __aligned(1) payload_size;
16+
17+
static struct z_stream_s stream;
18+
19+
efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size)
20+
{
21+
efi_status_t status;
22+
int rc;
23+
24+
/* skip the 10 byte header, assume no recorded filename */
25+
stream.next_in = _gzdata_start + 10;
26+
stream.avail_in = _gzdata_end - stream.next_in;
27+
28+
status = efi_allocate_pages(zlib_inflate_workspacesize(),
29+
(unsigned long *)&stream.workspace,
30+
ULONG_MAX);
31+
if (status != EFI_SUCCESS)
32+
return status;
33+
34+
rc = zlib_inflateInit2(&stream, -MAX_WBITS);
35+
if (rc != Z_OK) {
36+
efi_err("failed to initialize GZIP decompressor: %d\n", rc);
37+
status = EFI_LOAD_ERROR;
38+
goto out;
39+
}
40+
41+
*alloc_size = payload_size;
42+
return EFI_SUCCESS;
43+
out:
44+
efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace);
45+
return status;
46+
}
47+
48+
efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen)
49+
{
50+
int rc;
51+
52+
stream.next_out = out;
53+
stream.avail_out = outlen;
54+
55+
rc = zlib_inflate(&stream, 0);
56+
zlib_inflateEnd(&stream);
57+
58+
efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace);
59+
60+
if (rc != Z_STREAM_END) {
61+
efi_err("GZIP decompression failed with status %d\n", rc);
62+
return EFI_LOAD_ERROR;
63+
}
64+
65+
efi_cache_sync_image((unsigned long)out, outlen);
66+
67+
return EFI_SUCCESS;
68+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/efi.h>
4+
#include <linux/zstd.h>
5+
6+
#include <asm/efi.h>
7+
8+
#include "decompress_sources.h"
9+
#include "efistub.h"
10+
11+
extern unsigned char _gzdata_start[], _gzdata_end[];
12+
extern u32 __aligned(1) payload_size;
13+
14+
static size_t wksp_size;
15+
static void *wksp;
16+
17+
efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size)
18+
{
19+
efi_status_t status;
20+
21+
wksp_size = zstd_dctx_workspace_bound();
22+
status = efi_allocate_pages(wksp_size, (unsigned long *)&wksp, ULONG_MAX);
23+
if (status != EFI_SUCCESS)
24+
return status;
25+
26+
*alloc_size = payload_size;
27+
return EFI_SUCCESS;
28+
}
29+
30+
efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen)
31+
{
32+
zstd_dctx *dctx = zstd_init_dctx(wksp, wksp_size);
33+
size_t ret;
34+
int retval;
35+
36+
ret = zstd_decompress_dctx(dctx, out, outlen, _gzdata_start,
37+
_gzdata_end - _gzdata_start - 4);
38+
efi_free(wksp_size, (unsigned long)wksp);
39+
40+
retval = zstd_get_error_code(ret);
41+
if (retval) {
42+
efi_err("ZSTD-decompression failed with status %d\n", retval);
43+
return EFI_LOAD_ERROR;
44+
}
45+
46+
efi_cache_sync_image((unsigned long)out, outlen);
47+
48+
return EFI_SUCCESS;
49+
}

drivers/firmware/efi/libstub/zboot.c

Lines changed: 9 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,6 @@
77

88
#include "efistub.h"
99

10-
static unsigned char zboot_heap[SZ_256K] __aligned(64);
11-
static unsigned long free_mem_ptr, free_mem_end_ptr;
12-
13-
#define STATIC static
14-
#if defined(CONFIG_KERNEL_GZIP)
15-
#include "../../../../lib/decompress_inflate.c"
16-
#elif defined(CONFIG_KERNEL_LZ4)
17-
#include "../../../../lib/decompress_unlz4.c"
18-
#elif defined(CONFIG_KERNEL_LZMA)
19-
#include "../../../../lib/decompress_unlzma.c"
20-
#elif defined(CONFIG_KERNEL_LZO)
21-
#include "../../../../lib/decompress_unlzo.c"
22-
#elif defined(CONFIG_KERNEL_XZ)
23-
#undef memcpy
24-
#define memcpy memcpy
25-
#undef memmove
26-
#define memmove memmove
27-
#include "../../../../lib/decompress_unxz.c"
28-
#elif defined(CONFIG_KERNEL_ZSTD)
29-
#include "../../../../lib/decompress_unzstd.c"
30-
#endif
31-
32-
extern char efi_zboot_header[];
33-
extern char _gzdata_start[], _gzdata_end[];
34-
35-
static void error(char *x)
36-
{
37-
efi_err("EFI decompressor: %s\n", x);
38-
}
39-
4010
static unsigned long alloc_preferred_address(unsigned long alloc_size)
4111
{
4212
#ifdef EFI_KIMG_PREFERRED_ADDRESS
@@ -64,22 +34,17 @@ struct screen_info *alloc_screen_info(void)
6434
asmlinkage efi_status_t __efiapi
6535
efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
6636
{
67-
unsigned long compressed_size = _gzdata_end - _gzdata_start;
37+
char *cmdline_ptr __free(efi_pool) = NULL;
6838
unsigned long image_base, alloc_size;
6939
efi_loaded_image_t *image;
7040
efi_status_t status;
71-
char *cmdline_ptr;
72-
int ret;
7341

7442
WRITE_ONCE(efi_system_table, systab);
7543

76-
free_mem_ptr = (unsigned long)&zboot_heap;
77-
free_mem_end_ptr = free_mem_ptr + sizeof(zboot_heap);
78-
7944
status = efi_bs_call(handle_protocol, handle,
8045
&LOADED_IMAGE_PROTOCOL_GUID, (void **)&image);
8146
if (status != EFI_SUCCESS) {
82-
error("Failed to locate parent's loaded image protocol");
47+
efi_err("Failed to locate parent's loaded image protocol\n");
8348
return status;
8449
}
8550

@@ -89,9 +54,9 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
8954

9055
efi_info("Decompressing Linux Kernel...\n");
9156

92-
// SizeOfImage from the compressee's PE/COFF header
93-
alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4),
94-
EFI_ALLOC_ALIGN);
57+
status = efi_zboot_decompress_init(&alloc_size);
58+
if (status != EFI_SUCCESS)
59+
return status;
9560

9661
// If the architecture has a preferred address for the image,
9762
// try that first.
@@ -122,26 +87,14 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
12287
seed, EFI_LOADER_CODE, 0, EFI_ALLOC_LIMIT);
12388
if (status != EFI_SUCCESS) {
12489
efi_err("Failed to allocate memory\n");
125-
goto free_cmdline;
90+
return status;
12691
}
12792
}
12893

129-
// Decompress the payload into the newly allocated buffer.
130-
ret = __decompress(_gzdata_start, compressed_size, NULL, NULL,
131-
(void *)image_base, alloc_size, NULL, error);
132-
if (ret < 0) {
133-
error("Decompression failed");
134-
status = EFI_DEVICE_ERROR;
135-
goto free_image;
136-
}
137-
138-
efi_cache_sync_image(image_base, alloc_size);
139-
140-
status = efi_stub_common(handle, image, image_base, cmdline_ptr);
94+
// Decompress the payload into the newly allocated buffer
95+
status = efi_zboot_decompress((void *)image_base, alloc_size) ?:
96+
efi_stub_common(handle, image, image_base, cmdline_ptr);
14197

142-
free_image:
14398
efi_free(alloc_size, image_base);
144-
free_cmdline:
145-
efi_bs_call(free_pool, cmdline_ptr);
14699
return status;
147100
}

drivers/firmware/efi/libstub/zboot.lds

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ SECTIONS
1717
.rodata : ALIGN(8) {
1818
__efistub__gzdata_start = .;
1919
*(.gzdata)
20+
__efistub_payload_size = . - 4;
2021
__efistub__gzdata_end = .;
2122
*(.rodata* .init.rodata* .srodata*)
2223

0 commit comments

Comments
 (0)