OSDN Git Service

[PATCH] x86-64: user code panics kernel in exec.c (CVE-2005-2708)
authorDave Anderson <anderson@redhat.com>
Fri, 25 Nov 2005 03:00:35 +0000 (12:00 +0900)
committerMarcelo Tosatti <marcelo@dmt.cnet>
Fri, 23 Dec 2005 18:15:11 +0000 (16:15 -0200)
commitaa6dde2aa87277f42afb91e55700481b20c000b7
treef229143f5256a54212b486d8b0b612b9dc42c38c
parentc86cde33de3fb4ef7e47f6bcca5618b2748d16bf
[PATCH] x86-64: user code panics kernel in exec.c (CVE-2005-2708)

There seems to be a local DoS in exec on AMD64 / linux 2.4
when the system is under memory pressure.

https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=161925

Comment #9 From Dave Anderson    on 2005-08-31 14:36 EST

I don't particularly care for either patch suggestion. The problem is
that load_elf_binary() -- which is trying to load a legitimate ELF
binary, is returning -ENOEXEC back to search_binary_handler() because
load_elf_interp() has returned a BAD_ADDR:

        if (elf_interpreter) {
                if (interpreter_type == INTERPRETER_AOUT)
                        elf_entry = load_aout_interp(&interp_ex,
                                                     interpreter);
                else
                        elf_entry = load_elf_interp(&interp_elf_ex,
                                                    interpreter,
                                                    &interp_load_addr);

                if (BAD_ADDR(elf_entry)) {
                        printk(KERN_ERR "Unable to load interpreter\n");
                        send_sig(SIGSEGV, current, 0);
                        retval = -ENOEXEC; /* Nobody gets to see this, but.. */
                        goto out_free_dentry;
                }
                reloc_func_desc = interp_load_addr;

                allow_write_access(interpreter);
                fput(interpreter);
                kfree(elf_interpreter);
        }

and *because* search_binary_handler() sees the -ENOEXEC, it kicks off
the attempt to load the bogus module. And therein lies the problem, for
whatever reason, the modprobe process results in the double-fault, and
the original exec operation continues, and fails as it should. But that
all may be a red herring, since ENOEXEC with respect to execve means:

      ENOEXEC An  executable  is  not in a recognised format, is for the wrong
              architecture, or has some other format error that means it  can-
              not be executed.

However in this case, that's not at all true. It's legitimate, but the
attempt to load the /lib64/ld-linux-x86-64.so.2 interpreter into the
limited address space fails, and load_elf_interp() returns -ENOMEM. But
the ENOMEM is "lost" in the elf_entry variable. However, if -ENOMEM is
in fact returned back to search_binary_handler(), it all works just
fine. ENOMEM with respect to execve means:

       ENOMEM Insufficient kernel memory was available.

which isn't *exactly* what's going on here, but pretty close...

There's also the question of why the modprobe is failing, given that the
bogus module name doesn't exist. You would think that shouldn't cause
the kernel to double-fault. I mean do *all* of the request_module()
calls in the kernel require that the target module pre-exist? Since the
kernel seems to handle it differently/successfully on at least i386
and ia64, I haven't determined whether the request_module() is even
attempted on those architectures, or whether the operation fails in a
different code path.
fs/binfmt_elf.c
kernel/kmod.c