From owner-freebsd-bugs Tue Apr 25 10:20: 8 2000 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (Postfix) with ESMTP id E01F237BDFC for ; Tue, 25 Apr 2000 10:20:02 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id KAA95203; Tue, 25 Apr 2000 10:20:02 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: from jsn.kmost.express.ru (jsn.kmost.express.ru [212.24.37.101]) by hub.freebsd.org (Postfix) with ESMTP id 9DCEB37BDB1 for ; Tue, 25 Apr 2000 10:15:08 -0700 (PDT) (envelope-from jason@jsn.kmost.express.ru) Received: (from jason@localhost) by jsn.kmost.express.ru (8.9.3/8.9.3) id VAA00672; Tue, 25 Apr 2000 21:17:43 +0400 (MSD) (envelope-from jason) Message-Id: <200004251717.VAA00672@jsn.kmost.express.ru> Date: Tue, 25 Apr 2000 21:17:43 +0400 (MSD) From: jason@express.ru Reply-To: jason@express.ru To: FreeBSD-gnats-submit@freebsd.org X-Send-Pr-Version: 3.2 Subject: kern/18209: rlimits are never checked in exec() if executable format is ELF Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 18209 >Category: kern >Synopsis: rlimits are never checked in exec() if executable format is ELF >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue Apr 25 10:20:01 PDT 2000 >Closed-Date: >Last-Modified: >Originator: Dmitry Kim >Release: FreeBSD 4.0-RELEASE i386 >Organization: TSB "Russian Express" >Environment: Any version of FreeBSD from 3.0 to CURRENT >Description: when handling exec*() system calls, FreeBSD checks if the new executable image memory requirements fit into active RLIMIT_* bounds. if they do not fit, exec*() fails returning ENOMEM. The problem is, this check is never done for ELF binaries, thus, ELF-format program can grab all available memory, no matter how low *rlimits are. >How-To-Repeat: /* * This program demonstrates a leak in freebsd exec(), which [erroneously] * allows ELF program to get as much memory as it wishes, ignoring *rlimit * settings, while [correctly] denying any non-ELF program to exceed *rlimit * settings on exec(). * How to use: * gcc -elf -o m_elf m.c # compat 3 probably required for fbsd4 * gcc -aout -o m_aout m.c * /usr/bin/limits -d 1 ./m_aout * /usr/bin/limits -d 1 ./m_elf * you'll see the difference. */ #include #include #include char a[ 10000000 ] ; int main( int ac, char **av ) { memset( a, 1, sizeof(a) ) ; puts( "sleeping" ) ; sleep( 100 ) ; return 0 ; } >Fix: Index: kern/imgact_elf.c =================================================================== RCS file: /home/cvsroot/jsn/sys/kern/imgact_elf.c,v retrieving revision 1.1.1.1 retrieving revision 1.4 diff -u -r1.1.1.1 -r1.4 --- kern/imgact_elf.c 2000/04/17 10:30:39 1.1.1.1 +++ kern/imgact_elf.c 2000/04/25 16:52:11 1.4 @@ -451,7 +451,39 @@ return ENOEXEC; } phdr = (const Elf_Phdr*)(imgp->image_header + hdr->e_phoff); + + /* we better check rlimits *before* new vmspace is exec()-ed */ + for (i = 0; i < hdr->e_phnum; i++) { + if (phdr[i].p_type == PT_LOAD) { /* Loadable segment */ + /* + * Is this .text or .data ?? + * + * We only handle one each of those yet XXX + */ + if (hdr->e_entry >= phdr[i].p_vaddr && + hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { + text_addr = trunc_page(phdr[i].p_vaddr); + text_size = round_page(phdr[i].p_memsz + + phdr[i].p_vaddr - + text_addr); + entry = (u_long)hdr->e_entry; + } else { + data_addr = trunc_page(phdr[i].p_vaddr); + data_size = round_page(phdr[i].p_memsz + + phdr[i].p_vaddr - + data_addr); + } + } + } + + if (text_size > MAXTSIZ || + text_size + data_size > + imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur) { + error = ENOMEM ; + goto fail ; + } + /* * From this point on, we may have resources that need to be freed. */ @@ -481,25 +513,6 @@ phdr[i].p_memsz, phdr[i].p_filesz, prot)) != 0) goto fail; - - /* - * Is this .text or .data ?? - * - * We only handle one each of those yet XXX - */ - if (hdr->e_entry >= phdr[i].p_vaddr && - hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { - text_addr = trunc_page(phdr[i].p_vaddr); - text_size = round_page(phdr[i].p_memsz + - phdr[i].p_vaddr - - text_addr); - entry = (u_long)hdr->e_entry; - } else { - data_addr = trunc_page(phdr[i].p_vaddr); - data_size = round_page(phdr[i].p_memsz + - phdr[i].p_vaddr - - data_addr); - } break; case PT_INTERP: /* Path to interpreter */ if (phdr[i].p_filesz > MAXPATHLEN || >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message