Bug 161925
Summary: | CVE-2005-2708 user code panics kernel in exec.c | ||||||||
---|---|---|---|---|---|---|---|---|---|
Product: | Red Hat Enterprise Linux 3 | Reporter: | blossom <blossom> | ||||||
Component: | kernel | Assignee: | Dave Anderson <anderson> | ||||||
Status: | CLOSED ERRATA | QA Contact: | Brian Brock <bbrock> | ||||||
Severity: | high | Docs Contact: | |||||||
Priority: | medium | ||||||||
Version: | 3.0 | CC: | dannf, petrides, security-response-team | ||||||
Target Milestone: | --- | Keywords: | Security | ||||||
Target Release: | --- | ||||||||
Hardware: | x86_64 | ||||||||
OS: | Linux | ||||||||
Whiteboard: | source=bz,reported=20050628,public=20050628,impact=important | ||||||||
Fixed In Version: | RHSA-2006-0140 | Doc Type: | Bug Fix | ||||||
Doc Text: | Story Points: | --- | |||||||
Clone Of: | Environment: | ||||||||
Last Closed: | 2006-01-19 15:59:49 UTC | Type: | --- | ||||||
Regression: | --- | Mount Type: | --- | ||||||
Documentation: | --- | CRM: | |||||||
Verified Versions: | Category: | --- | |||||||
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||||
Cloudforms Team: | --- | Target Upstream Version: | |||||||
Embargoed: | |||||||||
Bug Depends On: | |||||||||
Bug Blocks: | 168424 | ||||||||
Attachments: |
|
Description
blossom
2005-06-28 14:56:07 UTC
Created attachment 116064 [details]
fixes bug in exec.c which now checks for return code during error condition
Hello. Firstly, the test program is irrelevant. On RHEL3 U4, the following command takes the code path in question (altered by the patch above): bash -c 'ulimit -v 100 ; /bin/date' However, my x86 box simply prints an error on the console about failing to load the interpreter for binfmt-464c. Thus, the steps listed to reproduce the problem are inadequate. Please try to reproduce this problem on the latest released kernel (which is version 2.4.21-32.0.1.EL, a post-U5 security erratum) that is untainted. Also, please correct the hardware architecture of this bug report if you're not using an x86-based system. Thanks in advance. -ernie Well, the problem is reproducible under RHEL 3 post update 5, 2.4.21- 32.0.1.EL kernel. We are using x86_64 system. Check whether the fix(attached) is fine Regards Girish Well, the problem is reproducible under RHEL 3 post update 5, 2.4.21- 32.0.1.EL kernel. We are using x86_64 system. Check whether the fix(attached) is fine Regards Girish Fixing hardware field of BZ. The patch in comment #1 is inappropriate because since "retval" is always -ENOEXEC in that code path, it effectively disables the call to request_module() every time. DaveA will try to reproduce this locally on an x86_64 system. Here is a better fix for the problem: Regards Girish diff -uprN linux-2.4.21/fs/binfmt_elf.c linux-2.4.21n/fs/binfmt_elf.c --- linux-2.4.21/fs/binfmt_elf.c 2005-08-26 02:34:17.000000000 +0530 +++ linux-2.4.21n/fs/binfmt_elf.c 2005-08-26 05:06:07.000000000 +0530 @@ -872,6 +872,7 @@ static int load_elf_binary(struct linux_ printk(KERN_ERR "Unable to load interpreter\n"); send_sig(SIGSEGV, current, 0); retval = -ENOEXEC; /* Nobody gets to see this, but.. */ + memset(bprm->buf, 0, strlen(bprm->buf)); goto out_free_dentry; } reloc_func_desc = interp_load_addr; diff -uprN linux-2.4.21/fs/exec.c linux-2.4.21n/fs/exec.c --- linux-2.4.21/fs/exec.c 2005-08-26 02:34:19.000000000 +0530 +++ linux-2.4.21n/fs/exec.c 2005-08-26 06:04:03.000000000 +0530 @@ -1061,7 +1061,7 @@ int search_binary_handler(struct linux_b if (printable(bprm->buf[0]) && printable(bprm->buf[1]) && printable(bprm->buf[2]) && - printable(bprm->buf[3])) + printable(bprm->buf[3]) || !(bprm->buf[2])) break; /* -ENOEXEC */ sprintf(modname, "binfmt-%04x", *(unsigned short *)(&bpr m->buf[2])); request_module(modname); Running on a RHEL3-U5'ish kernel (2.4.21-31+), a user process running this: $ bash -c 'ulimit -v 100 ; /bin/date' does cause a double fault in the same manner shown above, i.e., with the RIP and RSP registers getting NULL'd out: Unable to load interpreter request_module[binfmt-464c]: waitpid(2304,...) failed, errno 512 double fault: 0000 CPU 1 Pid: 2304, comm: modprobe Not tainted RIP: 0010:[<0000000000000000>] RSP: 0000:0000000000000000 EFLAGS: 00010202 RAX: 0000000000000000 RBX: 0000000000000040 RCX: 0000000000000000 RDX: ffffffff80436c60 RSI: 000001011a849f08 RDI: ffffffff80436b60 RBP: 000001001658fc40 R08: 0000000000000004 R09: 000001011b975a80 R10: 0000000000000000 R11: 0000000000000010 R12: 000001001658fc40 R13: 000001001658fc40 R14: 00000100161d7cc4 R15: 000001011a848000 FS: 0000002a95ada0a0(0000) GS:ffffffff805e6600(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000000 CR3: 000000001657f000 CR4: 00000000000006e0 Call Trace: <EOE> Process modprobe (pid: 2304, stackpage=1011a849000) Same with latest RHEL3-U6 (2.4.21-35): Unable to load interpreter request_module[binfmt-464c]: waitpid(2296,...) failed, errno 512 double fault: 0000 CPU 1 Pid: 2296, comm: modprobe Not tainted RIP: 0010:[<0000000000000000>] RSP: 0000:0000000000000000 EFLAGS: 00010202 RAX: 0000000000000000 RBX: 0000000000000040 RCX: 0000000000000000 RDX: ffffffff80437e60 RSI: 000001011887ff08 RDI: ffffffff80437d60 RBP: 000001001658fc40 R08: 000000000000002c R09: 000001011b8ae440 R10: 0000000000000000 R11: 0000000000000010 R12: 000001001658fc40 R13: 000001001658fc40 R14: 00000100161d6f04 R15: 000001011887e000 FS: 0000002a95ada0a0(0000) GS:ffffffff805e8080(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000000 CR3: 000000001657f000 CR4: 00000000000006e0 Call Trace: <EOE> Process modprobe (pid: 2296, stackpage=1011887f000) It doesn't happen on i386 or ia64 systems. 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. Working on a patch that addresses both problems, i.e., having load_elf_binary() return the proper errno value (ENOMEM), and preventing the request_module() from double-faulting -- presumably because the modprobe exec is reacting to the limited address space inherited from the process calling request_module(). The ENOMEM return will fix this problem, but for ELF objects only. If a legitimate "odd" binfmt request did in fact come in, and the user had done ulimit beforehand, then the oops would still occur. Thanks for the report -- and sorry for the delay. For future bug reports which have can have a security consequence please follow our procedure for reporting security issues, or at the least use the "Security Sensitive Bug" checkbox. http://www.redhat.com/security/team/contact/. This is CAN-2005-2708 A fix for this problem has just been committed to the RHEL3 U7 patch pool this evening (in kernel version 2.4.21-37.3.EL). (In reply to comment #15) > A fix for this problem has just been committed to the RHEL3 U7 > patch pool this evening (in kernel version 2.4.21-37.3.EL). > Is this fix available publicly? Created attachment 121437 [details]
Final patch
Note this issue only affects linux-2.4 and not linux-2.6 kernels.
In answer to comment #16, not yet. The RHEL3 U7 beta candidate kernel will probably be built later this week. A fix for this problem has also been committed to the RHEL3 E7 patch pool this evening (in kernel version 2.4.21-37.0.1.EL). An advisory has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on the solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHSA-2006-0140.html |