Messages in this thread | | | From | Ricardo Neri <> | Subject | [PATCH v10 00/13] x86: Enable User-Mode Instruction Prevention | Date | Fri, 27 Oct 2017 16:51:37 -0700 |
| |
This the 10th revision of a patchset to enable User-Mode Instruction Prevention (UMIP) in Linux. This is the second part of two series. Instead of submitting a single huge series. It would be better to split the series for easier review and handling. The first part of the series can be found here [1]. In this series, support is added to handle 32-bit and 16-bit addresses in protected and virtual-8086 modes plus effectively enabling UMIP. See below for a description on why this support is needed.
=== What is UMIP?
User-Mode Instruction Prevention (UMIP) is a security feature present in new Intel Processors. If enabled, it prevents the execution of certain instructions if the Current Privilege Level (CPL) is greater than 0. If these instructions were executed while in CPL > 0, user space applications could have access to system-wide settings such as the global and local descriptor tables, the segment selectors to the current task state and the local descriptor table. Hiding these system resources reduces the tools available to craft privilege escalation attacks such as [2].
These are the instructions covered by UMIP: * SGDT - Store Global Descriptor Table * SIDT - Store Interrupt Descriptor Table * SLDT - Store Local Descriptor Table * SMSW - Store Machine Status Word * STR - Store Task Register
If any of these instructions is executed with CPL > 0, a general protection exception is issued when UMIP is enabled. This means that any process that attempts to use the aforementioned instructions would see a SIGSEGV signal.
=== How does it impact applications?
When enabled, however, UMIP will change the behavior that certain applications expect from the operating system. For instance, programs running on WineHQ and DOSEMU2 rely on some of these instructions to function. Stas Sergeev found that Microsoft Windows 3.1 and dos4gw use the instruction SMSW when running in virtual-8086 mode [3]. SGDT and SIDT can also be used on virtual-8086 mode.
In order to not change the behavior of the system (i.e., a SIGSEGV signal should not be generated when using these instructions), this implementation traps the #GP fault generated by the CPU and emulates SGDT, SIDT and SMSW. with dummy returned values. This should be sufficient to not break the applications mentioned above. Regarding the two remaining instructions, STR and SLDT, the WineHQ team has shown interest catching the general protection fault and use it as a vehicle to fix broken applications[4].
Thus, emulation is only provided for protected and virtual-8086 modes. No emulation is implemented for processes running in long mode. Also the instructions SLDT and STR are not emulated in any case.
DOSEMU2 emulates virtual-8086 mode via KVM. No applications will be broken unless DOSEMU2 decides to enable the CR4.UMIP bit in platforms that support it. Also, this should not pose a security risk as no system resources would be revealed. Instead, code running inside the KVM would only see the KVM's GDT, IDT and MSW.
=== How is this series laid out?
++ Extend the insn-eval library This library is extended to also support 32-bit and 16 bit addresses. This also implies to add functionality to enforce segment limits in protected mode and linear address sizes in virtual-8086 mode as described in the section 20.1.1 of the Intel 64 and IA-32 Architectures Software Development Manual Vol. 3.
++ Emulate UMIP instructions A new fixup_umip_exception() functions inspect the instruction at the instruction pointer. If it is an UMIP-protected instruction, it executes the emulation code.
++ Add self-tests Lastly, self-tests are added to entry_from_v86.c to exercise the most typical use cases of UMIP-protected instructions in a virtual-8086 mode.
++ Extensive tests Extensive tests were performed to test all the combinations of ModRM, SiB and displacements for 16-bit and 32-bit encodings for the SS, DS, ES, FS and GS segments. Tests also include a 64-bit program that uses segmentation via FS and GS. For this purpose, I temporarily enabled UMIP support for 64-bit process. This change is not part of this patchset. The intention is to test the computations of linear addresses in 64-bit mode, including the extra R8-R15 registers. Extensive test is also implemented for virtual-8086 tasks. Code of these tests can be found here [5] and here [6].
Thanks and BR, Ricardo
[1]. https://www.spinics.net/lists/kernel/msg2635138.html [2]. http://timetobleed.com/a-closer-look-at-a-recent-privilege-escalation-bug-in-linux-cve-2013-2094/ [3]. https://www.winehq.org/pipermail/wine-devel/2017-April/117159.html [4]. https://marc.info/?l=linux-kernel&m=147876798717927&w=2 [5]. https://github.com/01org/luv-yocto/tree/rneri/umip/meta-luv/recipes-core/umip/files [6]. https://github.com/01org/luv-yocto/commit/a72a7fe7d68693c0f4100ad86de6ecabde57334f#diff-3860c136a63add269bce4ea50222c248R1
Changes since V9: *All the changes described in [1], plus: *Created new utility functions utility functions to handle each x86 memory addressing mode separately. Also, such functions are extended to support 32-bit addresses. A separate set of function is used for 16-bit addresses. *Extended and rename the function get_seg_base_addr() as get_seg_base_addr() to also return the limit of the segment associated with the instruction operand. Ricardo Neri (13): x86/insn-eval: Extend get_seg_base_addr() to also obtain segment limit x86/insn-eval: Compute linear address in several utility functions x86/insn-eval: Add support to resolve 32-bit address encodings x86/insn-eval: Add wrapper function for 32 and 64-bit addresses x86/insn-eval: Handle 32-bit address encodings in virtual-8086 mode x86/insn-eval: Add support to resolve 16-bit address encodings x86/cpufeature: Add User-Mode Instruction Prevention definitions x86: Add emulation code for UMIP instructions x86/umip: Force a page fault when unable to copy emulated result to user x86: Enable User-Mode Instruction Prevention x86/traps: Fixup general protection faults caused by UMIP selftests/x86: Add tests for User-Mode Instruction Prevention selftests/x86: Add tests for instruction str and sldt
arch/x86/Kconfig | 10 + arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/disabled-features.h | 8 +- arch/x86/include/asm/umip.h | 12 + arch/x86/include/uapi/asm/processor-flags.h | 2 + arch/x86/kernel/Makefile | 1 + arch/x86/kernel/cpu/common.c | 25 +- arch/x86/kernel/traps.c | 5 + arch/x86/kernel/umip.c | 353 ++++++++++++++ arch/x86/lib/insn-eval.c | 637 +++++++++++++++++++++++--- tools/testing/selftests/x86/entry_from_vm86.c | 89 +++- 11 files changed, 1078 insertions(+), 65 deletions(-) create mode 100644 arch/x86/include/asm/umip.h create mode 100644 arch/x86/kernel/umip.c
-- 2.7.4
| |