fs/binfmt_elf: Fix memory leak in load_elf_binary()
authorLi Zetao <lizetao1@huawei.com>
Mon, 24 Oct 2022 15:44:21 +0000 (23:44 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 Nov 2022 14:59:12 +0000 (23:59 +0900)
commit 594d2a14f2168c09b13b114c3d457aa939403e52 upstream.

There is a memory leak reported by kmemleak:

  unreferenced object 0xffff88817104ef80 (size 224):
    comm "xfs_admin", pid 47165, jiffies 4298708825 (age 1333.476s)
    hex dump (first 32 bytes):
      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      60 a8 b3 00 81 88 ff ff a8 10 5a 00 81 88 ff ff  `.........Z.....
    backtrace:
      [<ffffffff819171e1>] __alloc_file+0x21/0x250
      [<ffffffff81918061>] alloc_empty_file+0x41/0xf0
      [<ffffffff81948cda>] path_openat+0xea/0x3d30
      [<ffffffff8194ec89>] do_filp_open+0x1b9/0x290
      [<ffffffff8192660e>] do_open_execat+0xce/0x5b0
      [<ffffffff81926b17>] open_exec+0x27/0x50
      [<ffffffff81a69250>] load_elf_binary+0x510/0x3ed0
      [<ffffffff81927759>] bprm_execve+0x599/0x1240
      [<ffffffff8192a997>] do_execveat_common.isra.0+0x4c7/0x680
      [<ffffffff8192b078>] __x64_sys_execve+0x88/0xb0
      [<ffffffff83bbf0a5>] do_syscall_64+0x35/0x80

If "interp_elf_ex" fails to allocate memory in load_elf_binary(),
the program will take the "out_free_ph" error handing path,
resulting in "interpreter" file resource is not released.

Fix it by adding an error handing path "out_free_file", which will
release the file resource when "interp_elf_ex" failed to allocate
memory.

Fixes: 0693ffebcfe5 ("fs/binfmt_elf.c: allocate less for static executable")
Signed-off-by: Li Zetao <lizetao1@huawei.com>
Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20221024154421.982230-1-lizetao1@huawei.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/binfmt_elf.c

index c93150f..30379c3 100644 (file)
@@ -910,7 +910,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                interp_elf_ex = kmalloc(sizeof(*interp_elf_ex), GFP_KERNEL);
                if (!interp_elf_ex) {
                        retval = -ENOMEM;
-                       goto out_free_ph;
+                       goto out_free_file;
                }
 
                /* Get the exec headers */
@@ -1331,6 +1331,7 @@ out:
 out_free_dentry:
        kfree(interp_elf_ex);
        kfree(interp_elf_phdata);
+out_free_file:
        allow_write_access(interpreter);
        if (interpreter)
                fput(interpreter);