The current ELF loading mechancism provides page-aligned mappings. This can lead to the program being loaded in a way unsuitable for file-backed, transparent huge pages when handling PIE executables.
Tested: verified program with -Wl,-z,max-page-size=0x200000 loading Signed-off-by: Chris Kennelly <ckenne...@google.com> --- fs/binfmt_elf.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index f4713ea76e827..83fadf66d25ef 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -418,6 +418,25 @@ static int elf_read(struct file *file, void *buf, size_t len, loff_t pos) return 0; } +static unsigned long maximum_alignment(struct elf_phdr *cmds, int nr) +{ + unsigned long alignment = 0; + int i; + + for (i = 0; i < nr; i++) { + if (cmds[i].p_type == PT_LOAD) { + /* skip non-power of two alignments */ + if (cmds[i].p_align & (cmds[i].p_align - 1)) + continue; + if (cmds[i].p_align > alignment) + alignment = cmds[i].p_align; + } + } + + /* ensure we align to at least one page */ + return ELF_PAGEALIGN(alignment); +} + /** * load_elf_phdrs() - load ELF program headers * @elf_ex: ELF header of the binary whose program headers should be loaded @@ -883,6 +902,7 @@ static int load_elf_binary(struct linux_binprm *bprm) int elf_prot, elf_flags; unsigned long k, vaddr; unsigned long total_size = 0; + unsigned long alignment; if (elf_ppnt->p_type != PT_LOAD) continue; @@ -960,6 +980,10 @@ static int load_elf_binary(struct linux_binprm *bprm) 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); + if (alignment) + load_bias &= ~(alignment - 1); elf_flags |= MAP_FIXED; } else load_bias = 0; -- 2.28.0.rc0.105.gf9edc3c819-goog