fs/binfmt_elf.c: free PT_INTERP filename ASAP
authorAlexey Dobriyan <adobriyan@gmail.com>
Tue, 14 May 2019 22:43:39 +0000 (15:43 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 15 May 2019 02:52:50 +0000 (19:52 -0700)
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>
fs/binfmt_elf.c

index ce276a46fa123a911166abb63f9b1881bda4fe4e..7402cbd92046e67ad664b5abe5e03b316ef9993b 100644 (file)
@@ -687,7 +687,6 @@ 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;
        int load_addr_set = 0;
-       char * elf_interpreter = NULL;
        unsigned long error;
        struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL;
        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++) {
                if (elf_ppnt->p_type == PT_INTERP) {
+                       char *elf_interpreter;
                        loff_t pos;
 
                        /* This is the program interpreter used for
@@ -774,9 +774,10 @@ static int load_elf_binary(struct linux_binprm *bprm)
                                goto out_free_interp;
 
                        interpreter = open_exec(elf_interpreter);
+                       kfree(elf_interpreter);
                        retval = PTR_ERR(interpreter);
                        if (IS_ERR(interpreter))
-                               goto out_free_interp;
+                               goto out_free_ph;
 
                        /*
                         * If the binary is not readable then enforce
@@ -796,6 +797,10 @@ static int load_elf_binary(struct linux_binprm *bprm)
                        }
 
                        break;
+
+out_free_interp:
+                       kfree(elf_interpreter);
+                       goto out_free_ph;
                }
                elf_ppnt++;
        }
@@ -820,7 +825,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                }
 
        /* Some simple consistency checks for the interpreter */
-       if (elf_interpreter) {
+       if (interpreter) {
                retval = -ELIBBAD;
                /* Not an ELF interpreter */
                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
                         * without MAP_FIXED).
                         */
-                       if (elf_interpreter) {
+                       if (interpreter) {
                                load_bias = ELF_ET_DYN_BASE;
                                if (current->flags & PF_RANDOMIZE)
                                        load_bias += arch_mmap_rnd();
@@ -1075,7 +1080,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                goto out_free_dentry;
        }
 
-       if (elf_interpreter) {
+       if (interpreter) {
                unsigned long interp_map_addr = 0;
 
                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);
                fput(interpreter);
-               kfree(elf_interpreter);
        } else {
                elf_entry = loc->elf_ex.e_entry;
                if (BAD_ADDR(elf_entry)) {
@@ -1114,7 +1118,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
        set_binfmt(&elf_format);
 
 #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
-       retval = arch_setup_additional_pages(bprm, !!elf_interpreter);
+       retval = arch_setup_additional_pages(bprm, !!interpreter);
        if (retval < 0)
                goto out;
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
@@ -1175,8 +1179,6 @@ out_free_dentry:
        allow_write_access(interpreter);
        if (interpreter)
                fput(interpreter);
-out_free_interp:
-       kfree(elf_interpreter);
 out_free_ph:
        kfree(elf_phdata);
        goto out;