fs/binfmt_elf.c: free PT_INTERP filename ASAP

There is no reason for PT_INTERP filename to linger till the end of the
whole loading process.

Link: http://lkml.kernel.org/r/20190314204953.GD18143@avx2
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Nikitas Angelinas <nikitas.angelinas@gmail.com>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Mukesh Ojha <mojha@codeaurora.org>
[nikitas.angelinas@gmail.com: fix GPF when dereferencing invalid interpreter]
  Link: http://lkml.kernel.org/r/20190330140032.GA1527@vostro
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Alexey Dobriyan 2019-05-14 15:43:39 -07:00 коммит произвёл Linus Torvalds
Родитель 5cf4a36382
Коммит cc338010a2
1 изменённых файлов: 11 добавлений и 9 удалений

Просмотреть файл

@ -687,7 +687,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
struct file *interpreter = NULL; /* to shut gcc up */ struct file *interpreter = NULL; /* to shut gcc up */
unsigned long load_addr = 0, load_bias = 0; unsigned long load_addr = 0, load_bias = 0;
int load_addr_set = 0; int load_addr_set = 0;
char * elf_interpreter = NULL;
unsigned long error; unsigned long error;
struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL;
unsigned long elf_bss, elf_brk; unsigned long elf_bss, elf_brk;
@ -743,6 +742,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
for (i = 0; i < loc->elf_ex.e_phnum; i++) { for (i = 0; i < loc->elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) { if (elf_ppnt->p_type == PT_INTERP) {
char *elf_interpreter;
loff_t pos; loff_t pos;
/* This is the program interpreter used for /* This is the program interpreter used for
@ -774,9 +774,10 @@ static int load_elf_binary(struct linux_binprm *bprm)
goto out_free_interp; goto out_free_interp;
interpreter = open_exec(elf_interpreter); interpreter = open_exec(elf_interpreter);
kfree(elf_interpreter);
retval = PTR_ERR(interpreter); retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter)) if (IS_ERR(interpreter))
goto out_free_interp; goto out_free_ph;
/* /*
* If the binary is not readable then enforce * If the binary is not readable then enforce
@ -796,6 +797,10 @@ static int load_elf_binary(struct linux_binprm *bprm)
} }
break; break;
out_free_interp:
kfree(elf_interpreter);
goto out_free_ph;
} }
elf_ppnt++; elf_ppnt++;
} }
@ -820,7 +825,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
} }
/* Some simple consistency checks for the interpreter */ /* Some simple consistency checks for the interpreter */
if (elf_interpreter) { if (interpreter) {
retval = -ELIBBAD; retval = -ELIBBAD;
/* Not an ELF interpreter */ /* Not an ELF interpreter */
if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
@ -977,7 +982,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
* independently randomized mmap region (0 load_bias * independently randomized mmap region (0 load_bias
* without MAP_FIXED). * without MAP_FIXED).
*/ */
if (elf_interpreter) { if (interpreter) {
load_bias = ELF_ET_DYN_BASE; load_bias = ELF_ET_DYN_BASE;
if (current->flags & PF_RANDOMIZE) if (current->flags & PF_RANDOMIZE)
load_bias += arch_mmap_rnd(); load_bias += arch_mmap_rnd();
@ -1075,7 +1080,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
goto out_free_dentry; goto out_free_dentry;
} }
if (elf_interpreter) { if (interpreter) {
unsigned long interp_map_addr = 0; unsigned long interp_map_addr = 0;
elf_entry = load_elf_interp(&loc->interp_elf_ex, elf_entry = load_elf_interp(&loc->interp_elf_ex,
@ -1099,7 +1104,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
allow_write_access(interpreter); allow_write_access(interpreter);
fput(interpreter); fput(interpreter);
kfree(elf_interpreter);
} else { } else {
elf_entry = loc->elf_ex.e_entry; elf_entry = loc->elf_ex.e_entry;
if (BAD_ADDR(elf_entry)) { if (BAD_ADDR(elf_entry)) {
@ -1114,7 +1118,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
set_binfmt(&elf_format); set_binfmt(&elf_format);
#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
retval = arch_setup_additional_pages(bprm, !!elf_interpreter); retval = arch_setup_additional_pages(bprm, !!interpreter);
if (retval < 0) if (retval < 0)
goto out; goto out;
#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
@ -1175,8 +1179,6 @@ out_free_dentry:
allow_write_access(interpreter); allow_write_access(interpreter);
if (interpreter) if (interpreter)
fput(interpreter); fput(interpreter);
out_free_interp:
kfree(elf_interpreter);
out_free_ph: out_free_ph:
kfree(elf_phdata); kfree(elf_phdata);
goto out; goto out;