-----BEGIN PGP SIGNED MESSAGE----- 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 Abstract ======== 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 ---- break; 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: http://www.netbsd.org/Documentation/kernel/#building_a_kernel 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 $ -----BEGIN PGP SIGNATURE----- Version: 2.6.3ia Charset: noconv iQCVAwUBOoy2Yj5Ru2/4N2IFAQF9fgQAoWYyT1U+BoduaNM24a0Z258erw2unXfs vclZqO+pBjwoz4nciAr+oisB6Wh7r67l+pLWdba1tQBVMe8kWT+ui7cutUjeycI8 6hEEiENDRgC1KUM6F7cuQ/4TL7ML03Y8TR3CPjfpRuOYzQJM+vXx8IQfzOTDg2B5 G1WQC3ZDdWg= =clr4 -----END PGP SIGNATURE-----