mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
binfmt_elf: Honor PT_LOAD alignment for static PIE
The p_align values in PT_LOAD were ignored for static PIE executables (i.e. ET_DYN without PT_INTERP). This is because there is no way to request a non-fixed mmap region with a specific alignment. ET_DYN with PT_INTERP uses a separate base address (ELF_ET_DYN_BASE) and binfmt_elf performs the ASLR itself, which means it can also apply alignment. For the mmap region, the address selection happens deep within the vm_mmap() implementation (when the requested address is 0). The earlier attempt to implement this: commit9630f0d60f
("fs/binfmt_elf: use PT_LOAD p_align values for static PIE") commit925346c129
("fs/binfmt_elf: fix PT_LOAD p_align values for loaders") did not take into account the different base address origins, and were eventually reverted:aeb7923733
("revert "fs/binfmt_elf: use PT_LOAD p_align values for static PIE"") In order to get the correct alignment from an mmap base, binfmt_elf must perform a 0-address load first, then tear down the mapping and perform alignment on the resulting address. Since this is slightly more overhead, only do this when it is needed (i.e. the alignment is not the default ELF alignment). This does, however, have the benefit of being able to use MAP_FIXED_NOREPLACE, to avoid potential collisions. With this fixed, enable the static PIE self tests again. Reported-by: H.J. Lu <hjl.tools@gmail.com> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=215275 Link: https://lore.kernel.org/r/20240508173149.677910-3-keescook@chromium.org Signed-off-by: Kees Cook <kees@kernel.org>
This commit is contained in:
parent
2d4cf7b190
commit
3545deff0e
@ -1088,10 +1088,13 @@ out_free_interp:
|
||||
goto out_free_dentry;
|
||||
}
|
||||
|
||||
/* Calculate any requested alignment. */
|
||||
alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum);
|
||||
|
||||
/*
|
||||
* There are effectively two types of ET_DYN
|
||||
* binaries: programs (i.e. PIE: ET_DYN with INTERP)
|
||||
* and loaders (ET_DYN without INTERP, since they
|
||||
* binaries: programs (i.e. PIE: ET_DYN with PT_INTERP)
|
||||
* and loaders (ET_DYN without PT_INTERP, since they
|
||||
* _are_ the ELF interpreter). The loaders must
|
||||
* be loaded away from programs since the program
|
||||
* may otherwise collide with the loader (especially
|
||||
@ -1111,15 +1114,44 @@ out_free_interp:
|
||||
* without MAP_FIXED nor MAP_FIXED_NOREPLACE).
|
||||
*/
|
||||
if (interpreter) {
|
||||
/* On ET_DYN with PT_INTERP, we do the ASLR. */
|
||||
load_bias = ELF_ET_DYN_BASE;
|
||||
if (current->flags & PF_RANDOMIZE)
|
||||
load_bias += arch_mmap_rnd();
|
||||
alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum);
|
||||
/* Adjust alignment as requested. */
|
||||
if (alignment)
|
||||
load_bias &= ~(alignment - 1);
|
||||
elf_flags |= MAP_FIXED_NOREPLACE;
|
||||
} else
|
||||
load_bias = 0;
|
||||
} else {
|
||||
/*
|
||||
* For ET_DYN without PT_INTERP, we rely on
|
||||
* the architectures's (potentially ASLR) mmap
|
||||
* base address (via a load_bias of 0).
|
||||
*
|
||||
* When a large alignment is requested, we
|
||||
* must do the allocation at address "0" right
|
||||
* now to discover where things will load so
|
||||
* that we can adjust the resulting alignment.
|
||||
* In this case (load_bias != 0), we can use
|
||||
* MAP_FIXED_NOREPLACE to make sure the mapping
|
||||
* doesn't collide with anything.
|
||||
*/
|
||||
if (alignment > ELF_MIN_ALIGN) {
|
||||
load_bias = elf_load(bprm->file, 0, elf_ppnt,
|
||||
elf_prot, elf_flags, total_size);
|
||||
if (BAD_ADDR(load_bias)) {
|
||||
retval = IS_ERR_VALUE(load_bias) ?
|
||||
PTR_ERR((void*)load_bias) : -EINVAL;
|
||||
goto out_free_dentry;
|
||||
}
|
||||
vm_munmap(load_bias, total_size);
|
||||
/* Adjust alignment as requested. */
|
||||
if (alignment)
|
||||
load_bias &= ~(alignment - 1);
|
||||
elf_flags |= MAP_FIXED_NOREPLACE;
|
||||
} else
|
||||
load_bias = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since load_bias is used for all subsequent loading
|
||||
|
@ -6,7 +6,7 @@ CFLAGS += -D_GNU_SOURCE
|
||||
ALIGNS := 0x1000 0x200000 0x1000000
|
||||
ALIGN_PIES := $(patsubst %,load_address.%,$(ALIGNS))
|
||||
ALIGN_STATIC_PIES := $(patsubst %,load_address.static.%,$(ALIGNS))
|
||||
ALIGNMENT_TESTS := $(ALIGN_PIES)
|
||||
ALIGNMENT_TESTS := $(ALIGN_PIES) $(ALIGN_STATIC_PIES)
|
||||
|
||||
TEST_PROGS := binfmt_script.py
|
||||
TEST_GEN_PROGS := execveat non-regular $(ALIGNMENT_TESTS)
|
||||
|
Loading…
Reference in New Issue
Block a user