| From b582ef5c53040c5feef4c96a8f9585b6831e2441 Mon Sep 17 00:00:00 2001 |
| From: "Maciej W. Rozycki" <macro@imgtec.com> |
| Date: Mon, 26 Oct 2015 15:48:19 +0000 |
| Subject: binfmt_elf: Don't clobber passed executable's file header |
| |
| commit b582ef5c53040c5feef4c96a8f9585b6831e2441 upstream. |
| |
| Do not clobber the buffer space passed from `search_binary_handler' and |
| originally preloaded by `prepare_binprm' with the executable's file |
| header by overwriting it with its interpreter's file header. Instead |
| keep the buffer space intact and directly use the data structure locally |
| allocated for the interpreter's file header, fixing a bug introduced in |
| 2.1.14 with loadable module support (linux-mips.org commit beb11695 |
| [Import of Linux/MIPS 2.1.14], predating kernel.org repo's history). |
| Adjust the amount of data read from the interpreter's file accordingly. |
| |
| This was not an issue before loadable module support, because back then |
| `load_elf_binary' was executed only once for a given ELF executable, |
| whether the function succeeded or failed. |
| |
| With loadable module support supported and enabled, upon a failure of |
| `load_elf_binary' -- which may for example be caused by architecture |
| code rejecting an executable due to a missing hardware feature requested |
| in the file header -- a module load is attempted and then the function |
| reexecuted by `search_binary_handler'. With the executable's file |
| header replaced with its interpreter's file header the executable can |
| then be erroneously accepted in this subsequent attempt. |
| |
| Signed-off-by: Maciej W. Rozycki <macro@imgtec.com> |
| Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> |
| Signed-off-by: Zefan Li <lizefan@huawei.com> |
| --- |
| fs/binfmt_elf.c | 10 +++++----- |
| 1 file changed, 5 insertions(+), 5 deletions(-) |
| |
| --- a/fs/binfmt_elf.c |
| +++ b/fs/binfmt_elf.c |
| @@ -668,16 +668,16 @@ static int load_elf_binary(struct linux_ |
| */ |
| would_dump(bprm, interpreter); |
| |
| - retval = kernel_read(interpreter, 0, bprm->buf, |
| - BINPRM_BUF_SIZE); |
| - if (retval != BINPRM_BUF_SIZE) { |
| + /* Get the exec headers */ |
| + retval = kernel_read(interpreter, 0, |
| + (void *)&loc->interp_elf_ex, |
| + sizeof(loc->interp_elf_ex)); |
| + if (retval != sizeof(loc->interp_elf_ex)) { |
| if (retval >= 0) |
| retval = -EIO; |
| goto out_free_dentry; |
| } |
| |
| - /* Get the exec headers */ |
| - loc->interp_elf_ex = *((struct elfhdr *)bprm->buf); |
| break; |
| } |
| elf_ppnt++; |