On 09. 04. 20, 14:34, Ard Biesheuvel wrote: > Commit > > d9e3d2c4f10320 ("efi/x86: Don't map the entire kernel text RW for mixed mode") > > updated the code that creates the 1:1 memory mapping to use read-only > attributes for the 1:1 alias of the kernel's text and rodata sections, to > protect it from inadvertent modification. However, it failed to take into > account that the unused gap between text and rodata is given to the page > allocator for general use. > > If the vmap'ed stack happens to be allocated from this region, any by-ref > output arguments passed to EFI runtime services that are allocated on the > stack (such as the 'datasize' argument taken by GetVariable() when invoked > from efivar_entry_size()) will be referenced via a read-only mapping, > resulting in a page fault if the EFI code tries to write to it: > > BUG: unable to handle page fault for address: 00000000386aae88 ... > > Let's fix this by remapping text and rodata individually, and leave the > gaps mapped read-write. > > Reported-by: Jiri Slaby <jslaby@xxxxxxx> LGTM, thanks. Tested-by: Jiri Slaby <jslaby@xxxxxxx> > Cc: Gary Lin <glin@xxxxxxxx> > Signed-off-by: Ard Biesheuvel <ardb@xxxxxxxxxx> > --- > arch/x86/platform/efi/efi_64.c | 12 ++++++++++-- > 1 file changed, 10 insertions(+), 2 deletions(-) > > diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c > index e0e2e8136cf5..c5e393f8bb3f 100644 > --- a/arch/x86/platform/efi/efi_64.c > +++ b/arch/x86/platform/efi/efi_64.c > @@ -202,7 +202,7 @@ virt_to_phys_or_null_size(void *va, unsigned long size) > > int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) > { > - unsigned long pfn, text, pf; > + unsigned long pfn, text, pf, rodata; > struct page *page; > unsigned npages; > pgd_t *pgd = efi_mm.pgd; > @@ -256,7 +256,7 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) > > efi_scratch.phys_stack = page_to_phys(page + 1); /* stack grows down */ > > - npages = (__end_rodata_aligned - _text) >> PAGE_SHIFT; > + npages = (_etext - _text) >> PAGE_SHIFT; > text = __pa(_text); > pfn = text >> PAGE_SHIFT; > > @@ -266,6 +266,14 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) > return 1; > } > > + npages = (__end_rodata - __start_rodata) >> PAGE_SHIFT; > + rodata = __pa(__start_rodata); > + pfn = rodata >> PAGE_SHIFT; > + if (kernel_map_pages_in_pgd(pgd, pfn, rodata, npages, pf)) { > + pr_err("Failed to map kernel rodata 1:1\n"); > + return 1; > + } > + > return 0; > } > > -- js suse labs