Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
From: security-officernetbsd.org
Date: Fri Feb 16 2001 - 00:33:55 CST

  • Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

    Subject: NetBSD Security Advisory 2001-002
    Organisation: The NetBSD Foundation, Inc.
    Reply-to: security-officernetbsd.org


                     NetBSD Security Advisory 2001-002

    Topic: Vulnerability in x86 USER_LDT validation.
    Version: All versions of NetBSD, on the i386 platform ONLY.
    Severity: Local users may execute code with system priveleges
    Fixed: NetBSD-current: January 16, 2001
                    NetBSD-1.5 branch: January 17, 2001
                    NetBSD-1.4 branch: January 17, 2001


    A subtle bug in validation of user-supplied arguments to a syscall
    can allow allow user applications on the i386 platform to transfer
    control to arbitrary addresses in kernel memory, bypassing normal
    system protections.

    This problem is only present on the i386 platform, and only when the
    USER_LDT kernel configuration option is enabled at compile
    time. Unfortunately, this option is present in the GENERIC and
    GENERIC_LAPTOP kernel configurations shipped with NetBSD releases, as
    well as several examples, so many users will be affected.

    The problem stems from the complexity of the x86 processor
    architecture memory protection system, and other systems are known to
    be affected. This includes systems with code derived from NetBSD as
    well as other independently-written systems, indicating that the same
    mistake may have been repeated elsewhere as well.

    Technical Details

    The Intel i386 architecture supports a complex and confusing
    protection and segmentation model relying on rings, segment selectors,
    segment descriptors, gates, descriptor tables and the like.

    The Local Descriptor Table (LDT) is usually a per-process segment;
    most unix OS's provide system calls allowing application processes to
    add new segments to the LDT. In NetBSD, this option is enabled with
    "options USER_LDT" in the kernel configuration file, and is generally
    enabled for the WINE Windows emulator.

    One segment type is a "call gate", which allows code in outer rings to
    make calls to code in inner, more priviledged rings. Call gates are
    one of the three (or more?) different ways to implement system calls
    on the x86. The segment descriptor in the LDT for a call gate
    contains a segment selector and offset; when a program running in an
    outer ring executes a "ljmp" or "lcall" instruction which specifies
    the segment selector of a call gate, control is transferred to the
    specified offset of the specified code segment. If the gate target is
    an inner-ring code segment, a ring transition occurs; therefore it is
    vital for code which creates call gate descriptors to validate that
    the target segment and offset of the gate is appropriate.

    While reviewing code in NetBSD, it was discovered that the NetBSD
    "i386_set_ldt" syscall did not do appropriate validation of call gate
    targets; in short, it's possible to create a call gate in the LDT
    which transfers control to an arbitrary address in the kernel.

    The problem affects other Operating Systems also:

     * OpenBSD has the same bug, in code inherited directly from NetBSD.
     * FreeBSD also once had the bug, but it was eliminated a couple of
       years ago as part of a change to disable setting call gates.
     * Sun Solaris/x86 has the same bug, in a different implementation of
       a similar mechanism.
     * The problem is not necessarily limited to unix; any OS for the x86
       which allows an unprivileged program to create gate descriptors in its
       LDT could have this bug.

    A common misunderstanding of how gate descriptors work may result in
    the programmer believing they've defended against this attack (by
    checking the gate's DPL) without having done so (you need to check the
    DPL of the code segment that the gate targets).

    Note that this behaviour is not restricted to Intel processors; the bug
    applies to implementations of the x86 architecture by other
    manufacturers as well.

    Solutions and Workarounds

    Systems running NetBSD/i386 with the USER_LDT kernel option enabled
    are vulnerable. This includes users running the GENERIC kernel
    configurations distributed with releases, or users who have built
    their own kernel configurations based on GENERIC and not removed the
    USER_LDT option.

    The most effective and simplest workaround, for users not requiring
    this option for Wine or similar emulators, is to build a kernel
    without "options USER_LDT".

    For users who need this option enabled, kernel sources must be updated
    and a new kernel built and installed.

    Systems running releases older than NetBSD 1.4 should be upgraded to
    NetBSD 1.4.3 before applying the fixes described here.

    Systems running NetBSD-current dated from before 2001-01-17 should be
    upgraded to NetBSD-current dated 2001-01-17 or later.

    Systems running NetBSD-release-1-4 or NetBSD-release-1-5 dated from
    before 2001-01-18 should be upgraded to 2001-01-18 later.

    The following patch to /sys/arch/i386/i386/sys_machdep.c should be
    applied before rebuilding a new kernel with USER_LDT enabled. This
    patch can be applied (with offset differences) to NetBSD-1.4.x,
    NetBSD-1.5 or NetBSD-current kernel sources.

    Index: sys_machdep.c
    RCS file: /cvsroot/syssrc/sys/arch/i386/i386/sys_machdep.c,v
    retrieving revision 1.54
    retrieving revision 1.55
    diff -c -r1.54 -r1.55
    *** sys_machdep.c 2001/01/16 01:50:36 1.54
    - --- sys_machdep.c 2001/01/16 23:32:21 1.55
    *** 222,227 ****
    - --- 222,238 ----
                      case SDT_SYS286CGT:
                      case SDT_SYS386CGT:
    + /*
    + * Only allow call gates targeting a segment
    + * in the LDT or a user segment in the fixed
    + * part of the gdt. Segments in the LDT are
    + * constrained (below) to be user segments.
    + */
    + if (desc.gd.gd_p != 0 && !ISLDT(desc.gd.gd_selector) &&
    + ((IDXSEL(desc.gd.gd_selector) >= NGDT) ||
    + (gdt[IDXSEL(desc.gd.gd_selector)].sd.sd_dpl !=
    + SEL_UPL)))
    + return (EACCES);
                              /* Can't replace in use descriptor with gate. */
                              if (n == fsslot || n == gsslot)
                                      return (EBUSY);

    For all NetBSD versions:

      * either apply the above patch to your kernel source tree using the
        patch(1) command, or

      * edit your kernel configuration file to remove or comment out
        "options USER_LDT", save, and rerun config(8)

    Then rebuild, install the new kernel, and reboot. For more information
    on how to do this, see:


    Thanks To

    Thanks to Bill Sommerfeld for discovery, analysis and fixing the
    problem, and to Charles Hannum for additional discussion.

    Revision History

            2000-02-16 Initial Release

    More Information

    Information about NetBSD and NetBSD security can be found at
    http://www.NetBSD.ORG/ and http://www.NetBSD.ORG/Security/.

    Copyright 2001, The NetBSD Foundation, Inc. All Rights Reserved.

    $NetBSD: NetBSD-SA2001-002.txt,v 1.4 2001/02/16 04:43:40 dan Exp $

    Version: 2.6.3ia
    Charset: noconv

    -----END PGP SIGNATURE-----