COMMAND

    kernel

SYSTEMS AFFECTED

    FreeBSD 3.x, 4.x and 5.x prior to the correction date

PROBLEM

    Following  is  based  on  a  FreeBSD-SA-00:41 Security Advisory by
    FreeBSD  and  it  was  found  by  Adam  McDougall.  The ELF binary
    format is used for  binary executable programs on  modern versions
    of FreeBSD.

    The ELF image activator  did not perform sufficient  sanity checks
    on the ELF  image header, and  when confronted with  an invalid or
    truncated header it suffered a sign overflow bug which caused  the
    CPU to enter into a very long loop in the kernel.

    The result of this is that  the system will appear to lock  up for
    an extended period of time  before control returns.  This  bug can
    be exploited by unprivileged local users.

    This vulnerability is not present in FreeBSD 4.1-RELEASE, although
    3.5-RELEASE and 3.5.1-RELEASE are vulnerable.

    Local users can cause the system to lock up for an extended period
    of time (15 minutes or more, depending on CPU speed), during which
    time the  system is  completely unresponsive  to local  and remote
    users.

SOLUTION

    One of the following.

    1) Upgrade  your  vulnerable   FreeBSD  system  to    4.1-RELEASE,
       4.1-STABLE  or  5.0-CURRENT  after  the  respective  correction
       dates.   FreeBSD  3.5-STABLE  has  not  yet  been  fixed due to
       logistical difficulties  (and the  patch below  does not  apply
       cleanly).   Consider  upgrading  to  4.1-RELEASE  if  this is a
       concern -  this advisory  will be  reissued once  the patch has
       been applied to the 3.x branch.

    2) Apply the patch below and recompile your kernel.

       Either save this advisory to a file, or download the patch.

        ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-00:41/elf.patch

       # cd /usr/src/sys/kern
       # patch -p < /path/to/patch_or_advisory
       [ Recompile your kernel and reboot the system ]

    --- imgact_elf.c	2000/04/30 18:51:39	1.75
    +++ imgact_elf.c	2000/07/23 22:19:49	1.78
    @@ -190,6 +190,21 @@
 	    object = vp->v_object;
 	    error = 0;
    
    +	/*
    +	 * It's necessary to fail if the filsz + offset taken from the
    +	 * header is greater than the actual file pager object's size.
    +	 * If we were to allow this, then the vm_map_find() below would
    +	 * walk right off the end of the file object and into the ether.
    +	 *
    +	 * While I'm here, might as well check for something else that
    +	 * is invalid: filsz cannot be greater than memsz.
    +	 */
    +	if ((off_t)filsz + offset > object->un_pager.vnp.vnp_size ||
    +	    filsz > memsz) {
    +		uprintf("elf_load_section: truncated ELF file\n");
    +		return (ENOEXEC);
    +	}
    +
 	    map_addr = trunc_page((vm_offset_t)vmaddr);
 	    file_addr = trunc_page(offset);
    
    @@ -341,6 +356,12 @@
 	    }
    
 	    error = exec_map_first_page(imgp);
    +	/*
    +	 * Also make certain that the interpreter stays the same, so set
    +	 * its VTEXT flag, too.
    +	 */
    +	if (error == 0)
    +		nd.ni_vp->v_flag |= VTEXT;
 	    VOP_UNLOCK(nd.ni_vp, 0, p);
 	    if (error)
                     goto fail;
    @@ -449,6 +470,17 @@
 	    /*
 	     * From this point on, we may have resources that need to be freed.
 	     */
    +
    +	/*
    +	 * Yeah, I'm paranoid.  There is every reason in the world to get
    +	 * VTEXT now since from here on out, there are places we can have
    +	 * a context switch.  Better safe than sorry; I really don't want
    +	 * the file to change while it's being loaded.
    +	 */
    +	simple_lock(&imgp->vp->v_interlock);
    +	imgp->vp->v_flag |= VTEXT;
    +	simple_unlock(&imgp->vp->v_interlock);
    +
 	    if ((error = exec_extract_strings(imgp)) != 0)
 		    goto fail;
    
    @@ -610,9 +642,6 @@
 	    imgp->auxargs = elf_auxargs;
 	    imgp->interpreted = 0;
    
    -	/* don't allow modifying the file while we run it */
    -	imgp->vp->v_flag |= VTEXT;
    -
     fail:
 	    return error;
     }