On Tue, Nov 30, 2021 at 06:55:57PM -0800, akpm@xxxxxxxxxxxxxxxxxxxx wrote: > > The patch titled > Subject: fs/binfmt_elf: Fix AT_PHDR for unusual ELF files > has been added to the -mm tree. Its filename is > fs-binfmt_elf-fix-at_phdr-for-unusual-elf-files.patch > > This patch should soon appear at > https://ozlabs.org/~akpm/mmots/broken-out/fs-binfmt_elf-fix-at_phdr-for-unusual-elf-files.patch > and later at > https://ozlabs.org/~akpm/mmotm/broken-out/fs-binfmt_elf-fix-at_phdr-for-unusual-elf-files.patch > > Before you just go and hit "reply", please: > a) Consider who else should be cc'ed > b) Prefer to cc a suitable mailing list as well > c) Ideally: find the original patch on the mailing list and do a > reply-to-all to that, adding suitable additional cc's > > *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** > > The -mm tree is included into linux-next and is updated > there every 3-4 working days > > ------------------------------------------------------ > From: Akira Kawata <akirakawata1@xxxxxxxxx> > Subject: fs/binfmt_elf: Fix AT_PHDR for unusual ELF files > > BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=197921 > > As pointed out in the discussion of buglink, we cannot calculate AT_PHDR > as the sum of load_addr and exec->e_phoff. > > : The AT_PHDR of ELF auxiliary vectors should point to the memory address of > : program header. But binfmt_elf.c calculates this address as follows: > : > : NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); > : > : which is wrong since e_phoff is the file offset of program header and > : load_addr is the memory base address from PT_LOAD entry. > : > : The ld.so uses AT_PHDR as the memory address of program header. In normal > : case, since the e_phoff is usually 64 and in the first PT_LOAD region, it > : is the correct program header address. > : > : But if the address of program header isn't equal to the first PT_LOAD > : address + e_phoff (e.g. Put the program header in other non-consecutive > : PT_LOAD region), ld.so will try to read program header from wrong address > : then crash or use incorrect program header. > > This is because exec->e_phoff > is the offset of PHDRs in the file and the address of PHDRs in the > memory may differ from it. This patch fixes the bug by calculating the > address of program headers from PT_LOADs directly. > > Link: https://lkml.kernel.org/r/20211130115906.414176-1-akirakawata1@xxxxxxxxx > Signed-off-by: Akira Kawata <akirakawata1@xxxxxxxxx> > Reported-by: kernel test robot <lkp@xxxxxxxxx> > Cc: Alexey Dobriyan <adobriyan@xxxxxxxxx> > Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> > Cc: Kees Cook <keescook@xxxxxxxxxxxx> > Cc: Eric Biederman <ebiederm@xxxxxxxxxxxx> > Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> > --- > > fs/binfmt_elf.c | 20 ++++++++++++++------ > 1 file changed, 14 insertions(+), 6 deletions(-) > > --- a/fs/binfmt_elf.c~fs-binfmt_elf-fix-at_phdr-for-unusual-elf-files > +++ a/fs/binfmt_elf.c > @@ -170,8 +170,8 @@ static int padzero(unsigned long elf_bss > > static int > create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, > - unsigned long load_addr, unsigned long interp_load_addr, > - unsigned long e_entry) > + unsigned long interp_load_addr, > + unsigned long e_entry, unsigned long phdr_addr) > { > struct mm_struct *mm = current->mm; > unsigned long p = bprm->p; > @@ -257,7 +257,7 @@ create_elf_tables(struct linux_binprm *b > NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); > NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); > NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); > - NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); > + NEW_AUX_ENT(AT_PHDR, phdr_addr); > NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); > NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); > NEW_AUX_ENT(AT_BASE, interp_load_addr); > @@ -823,7 +823,7 @@ static int parse_elf_properties(struct f > static int load_elf_binary(struct linux_binprm *bprm) > { > struct file *interpreter = NULL; /* to shut gcc up */ > - unsigned long load_addr = 0, load_bias = 0; > + unsigned long load_addr, load_bias = 0, phdr_addr = 0; > int load_addr_set = 0; > unsigned long error; > struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; > @@ -1169,6 +1169,13 @@ out_free_interp: > reloc_func_desc = load_bias; > } > } > + > + if (elf_ppnt->p_offset <= elf_ex->e_phoff && > + elf_ex->e_phoff < elf_ppnt->p_offset + elf_ppnt->p_filesz) { > + phdr_addr = elf_ex->e_phoff - elf_ppnt->p_offset + > + elf_ppnt->p_vaddr; > + } > + > k = elf_ppnt->p_vaddr; > if ((elf_ppnt->p_flags & PF_X) && k < start_code) > start_code = k; > @@ -1204,6 +1211,7 @@ out_free_interp: > } > > e_entry = elf_ex->e_entry + load_bias; > + phdr_addr += load_bias; > elf_bss += load_bias; > elf_brk += load_bias; > start_code += load_bias; > @@ -1267,8 +1275,8 @@ out_free_interp: > goto out; > #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ > > - retval = create_elf_tables(bprm, elf_ex, > - load_addr, interp_load_addr, e_entry); > + retval = create_elf_tables(bprm, elf_ex, interp_load_addr, > + e_entry, phdr_addr); > if (retval < 0) > goto out; > > _ > > Patches currently in -mm which might be from akirakawata1@xxxxxxxxx are > > fs-binfmt_elf-fix-at_phdr-for-unusual-elf-files.patch > Thank you. Akira