Skip to content

Commit 0008633

Browse files
committed
Merge tag 'efi-urgent-2020-04-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull EFI fixes from Ingo Molnar: "Misc EFI fixes, including the boot failure regression caused by the BSS section not being cleared by the loaders" * tag 'efi-urgent-2020-04-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: efi/x86: Revert struct layout change to fix kexec boot regression efi/x86: Don't remap text<->rodata gap read-only for mixed mode efi/x86: Fix the deletion of variables in mixed mode efi/libstub/file: Merge file name buffers to reduce stack usage Documentation/x86, efi/x86: Clarify EFI handover protocol and its requirements efi/arm: Deal with ADR going out of range in efi_enter_kernel() efi/x86: Always relocate the kernel for EFI handover entry efi/x86: Move efi stub globals from .bss to .data efi/libstub/x86: Remove redundant assignment to pointer hdr efi/cper: Use scnprintf() for avoiding potential buffer overflow
2 parents 8632e9b + a088b85 commit 0008633

File tree

8 files changed

+61
-30
lines changed

8 files changed

+61
-30
lines changed

Documentation/x86/boot.rst

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,15 +1399,21 @@ must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
13991399
must be __BOOT_DS; interrupt must be disabled; %rsi must hold the base
14001400
address of the struct boot_params.
14011401

1402-
EFI Handover Protocol
1403-
=====================
1402+
EFI Handover Protocol (deprecated)
1403+
==================================
14041404

14051405
This protocol allows boot loaders to defer initialisation to the EFI
14061406
boot stub. The boot loader is required to load the kernel/initrd(s)
14071407
from the boot media and jump to the EFI handover protocol entry point
14081408
which is hdr->handover_offset bytes from the beginning of
14091409
startup_{32,64}.
14101410

1411+
The boot loader MUST respect the kernel's PE/COFF metadata when it comes
1412+
to section alignment, the memory footprint of the executable image beyond
1413+
the size of the file itself, and any other aspect of the PE/COFF header
1414+
that may affect correct operation of the image as a PE/COFF binary in the
1415+
execution context provided by the EFI firmware.
1416+
14111417
The function prototype for the handover entry point looks like this::
14121418

14131419
efi_main(void *handle, efi_system_table_t *table, struct boot_params *bp)
@@ -1419,9 +1425,18 @@ UEFI specification. 'bp' is the boot loader-allocated boot params.
14191425

14201426
The boot loader *must* fill out the following fields in bp::
14211427

1422-
- hdr.code32_start
14231428
- hdr.cmd_line_ptr
14241429
- hdr.ramdisk_image (if applicable)
14251430
- hdr.ramdisk_size (if applicable)
14261431

14271432
All other fields should be zero.
1433+
1434+
NOTE: The EFI Handover Protocol is deprecated in favour of the ordinary PE/COFF
1435+
entry point, combined with the LINUX_EFI_INITRD_MEDIA_GUID based initrd
1436+
loading protocol (refer to [0] for an example of the bootloader side of
1437+
this), which removes the need for any knowledge on the part of the EFI
1438+
bootloader regarding the internal representation of boot_params or any
1439+
requirements/limitations regarding the placement of the command line
1440+
and ramdisk in memory, or the placement of the kernel image itself.
1441+
1442+
[0] https://github.com/u-boot/u-boot/commit/ec80b4735a593961fe701cc3a5d717d4739b0fd0

arch/arm/boot/compressed/head.S

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1450,7 +1450,8 @@ ENTRY(efi_enter_kernel)
14501450
@ running beyond the PoU, and so calling cache_off below from
14511451
@ inside the PE/COFF loader allocated region is unsafe unless
14521452
@ we explicitly clean it to the PoC.
1453-
adr r0, call_cache_fn @ region of code we will
1453+
ARM( adrl r0, call_cache_fn )
1454+
THUMB( adr r0, call_cache_fn ) @ region of code we will
14541455
adr r1, 0f @ run with MMU off
14551456
bl cache_clean_flush
14561457
bl cache_off

arch/x86/include/asm/efi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,10 @@ extern void efi_free_boot_services(void);
178178
extern pgd_t * __init efi_uv1_memmap_phys_prolog(void);
179179
extern void __init efi_uv1_memmap_phys_epilog(pgd_t *save_pgd);
180180

181+
/* kexec external ABI */
181182
struct efi_setup_data {
182183
u64 fw_vendor;
184+
u64 __unused;
183185
u64 tables;
184186
u64 smbios;
185187
u64 reserved[8];

arch/x86/platform/efi/efi_64.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ virt_to_phys_or_null_size(void *va, unsigned long size)
202202

203203
int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
204204
{
205-
unsigned long pfn, text, pf;
205+
unsigned long pfn, text, pf, rodata;
206206
struct page *page;
207207
unsigned npages;
208208
pgd_t *pgd = efi_mm.pgd;
@@ -256,7 +256,7 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
256256

257257
efi_scratch.phys_stack = page_to_phys(page + 1); /* stack grows down */
258258

259-
npages = (__end_rodata_aligned - _text) >> PAGE_SHIFT;
259+
npages = (_etext - _text) >> PAGE_SHIFT;
260260
text = __pa(_text);
261261
pfn = text >> PAGE_SHIFT;
262262

@@ -266,6 +266,14 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
266266
return 1;
267267
}
268268

269+
npages = (__end_rodata - __start_rodata) >> PAGE_SHIFT;
270+
rodata = __pa(__start_rodata);
271+
pfn = rodata >> PAGE_SHIFT;
272+
if (kernel_map_pages_in_pgd(pgd, pfn, rodata, npages, pf)) {
273+
pr_err("Failed to map kernel rodata 1:1\n");
274+
return 1;
275+
}
276+
269277
return 0;
270278
}
271279

@@ -638,7 +646,7 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
638646
phys_vendor = virt_to_phys_or_null(vnd);
639647
phys_data = virt_to_phys_or_null_size(data, data_size);
640648

641-
if (!phys_name || !phys_data)
649+
if (!phys_name || (data && !phys_data))
642650
status = EFI_INVALID_PARAMETER;
643651
else
644652
status = efi_thunk(set_variable, phys_name, phys_vendor,
@@ -669,7 +677,7 @@ efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
669677
phys_vendor = virt_to_phys_or_null(vnd);
670678
phys_data = virt_to_phys_or_null_size(data, data_size);
671679

672-
if (!phys_name || !phys_data)
680+
if (!phys_name || (data && !phys_data))
673681
status = EFI_INVALID_PARAMETER;
674682
else
675683
status = efi_thunk(set_variable, phys_name, phys_vendor,

drivers/firmware/efi/cper.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ void cper_print_bits(const char *pfx, unsigned int bits,
101101
if (!len)
102102
len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
103103
else
104-
len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
104+
len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str);
105105
}
106106
if (len)
107107
printk("%s\n", buf);

drivers/firmware/efi/libstub/efistub.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
2626
#endif
2727

28-
#ifdef CONFIG_ARM
28+
#if defined(CONFIG_ARM) || defined(CONFIG_X86)
2929
#define __efistub_global __section(.data)
3030
#else
3131
#define __efistub_global

drivers/firmware/efi/libstub/file.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,38 +29,39 @@
2929
*/
3030
#define EFI_READ_CHUNK_SIZE SZ_1M
3131

32+
struct finfo {
33+
efi_file_info_t info;
34+
efi_char16_t filename[MAX_FILENAME_SIZE];
35+
};
36+
3237
static efi_status_t efi_open_file(efi_file_protocol_t *volume,
33-
efi_char16_t *filename_16,
38+
struct finfo *fi,
3439
efi_file_protocol_t **handle,
3540
unsigned long *file_size)
3641
{
37-
struct {
38-
efi_file_info_t info;
39-
efi_char16_t filename[MAX_FILENAME_SIZE];
40-
} finfo;
4142
efi_guid_t info_guid = EFI_FILE_INFO_ID;
4243
efi_file_protocol_t *fh;
4344
unsigned long info_sz;
4445
efi_status_t status;
4546

46-
status = volume->open(volume, &fh, filename_16, EFI_FILE_MODE_READ, 0);
47+
status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0);
4748
if (status != EFI_SUCCESS) {
4849
pr_efi_err("Failed to open file: ");
49-
efi_char16_printk(filename_16);
50+
efi_char16_printk(fi->filename);
5051
efi_printk("\n");
5152
return status;
5253
}
5354

54-
info_sz = sizeof(finfo);
55-
status = fh->get_info(fh, &info_guid, &info_sz, &finfo);
55+
info_sz = sizeof(struct finfo);
56+
status = fh->get_info(fh, &info_guid, &info_sz, fi);
5657
if (status != EFI_SUCCESS) {
5758
pr_efi_err("Failed to get file info\n");
5859
fh->close(fh);
5960
return status;
6061
}
6162

6263
*handle = fh;
63-
*file_size = finfo.info.file_size;
64+
*file_size = fi->info.file_size;
6465
return EFI_SUCCESS;
6566
}
6667

@@ -146,13 +147,13 @@ static efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
146147

147148
alloc_addr = alloc_size = 0;
148149
do {
149-
efi_char16_t filename[MAX_FILENAME_SIZE];
150+
struct finfo fi;
150151
unsigned long size;
151152
void *addr;
152153

153154
offset = find_file_option(cmdline, cmdline_len,
154155
optstr, optstr_size,
155-
filename, ARRAY_SIZE(filename));
156+
fi.filename, ARRAY_SIZE(fi.filename));
156157

157158
if (!offset)
158159
break;
@@ -166,7 +167,7 @@ static efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
166167
return status;
167168
}
168169

169-
status = efi_open_file(volume, filename, &file, &size);
170+
status = efi_open_file(volume, &fi, &file, &size);
170171
if (status != EFI_SUCCESS)
171172
goto err_close_volume;
172173

drivers/firmware/efi/libstub/x86-stub.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
/* Maximum physical address for 64-bit kernel with 4-level paging */
2121
#define MAXMEM_X86_64_4LEVEL (1ull << 46)
2222

23-
static efi_system_table_t *sys_table;
23+
static efi_system_table_t *sys_table __efistub_global;
2424
extern const bool efi_is64;
2525
extern u32 image_offset;
2626

@@ -392,8 +392,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
392392
image_base = efi_table_attr(image, image_base);
393393
image_offset = (void *)startup_32 - image_base;
394394

395-
hdr = &((struct boot_params *)image_base)->hdr;
396-
397395
status = efi_allocate_pages(0x4000, (unsigned long *)&boot_params, ULONG_MAX);
398396
if (status != EFI_SUCCESS) {
399397
efi_printk("Failed to allocate lowmem for boot params\n");
@@ -742,8 +740,15 @@ unsigned long efi_main(efi_handle_t handle,
742740
* now use KERNEL_IMAGE_SIZE, which will be 512MiB, the same as what
743741
* KASLR uses.
744742
*
745-
* Also relocate it if image_offset is zero, i.e. we weren't loaded by
746-
* LoadImage, but we are not aligned correctly.
743+
* Also relocate it if image_offset is zero, i.e. the kernel wasn't
744+
* loaded by LoadImage, but rather by a bootloader that called the
745+
* handover entry. The reason we must always relocate in this case is
746+
* to handle the case of systemd-boot booting a unified kernel image,
747+
* which is a PE executable that contains the bzImage and an initrd as
748+
* COFF sections. The initrd section is placed after the bzImage
749+
* without ensuring that there are at least init_size bytes available
750+
* for the bzImage, and thus the compressed kernel's startup code may
751+
* overwrite the initrd unless it is moved out of the way.
747752
*/
748753

749754
buffer_start = ALIGN(bzimage_addr - image_offset,
@@ -753,8 +758,7 @@ unsigned long efi_main(efi_handle_t handle,
753758
if ((buffer_start < LOAD_PHYSICAL_ADDR) ||
754759
(IS_ENABLED(CONFIG_X86_32) && buffer_end > KERNEL_IMAGE_SIZE) ||
755760
(IS_ENABLED(CONFIG_X86_64) && buffer_end > MAXMEM_X86_64_4LEVEL) ||
756-
(image_offset == 0 && !IS_ALIGNED(bzimage_addr,
757-
hdr->kernel_alignment))) {
761+
(image_offset == 0)) {
758762
status = efi_relocate_kernel(&bzimage_addr,
759763
hdr->init_size, hdr->init_size,
760764
hdr->pref_address,

0 commit comments

Comments
 (0)