Re: [tip:x86/asm] x86/umip: Add emulation code for UMIP instructions

From: Denys Vlasenko
Date: Wed Nov 08 2017 - 11:14:46 EST


On 11/08/2017 12:00 PM, tip-bot for Ricardo Neri wrote:
Commit-ID: 1e5db223696afa55e6a038fac638f759e1fdcc01
Gitweb: https://git.kernel.org/tip/1e5db223696afa55e6a038fac638f759e1fdcc01
Author: Ricardo Neri <ricardo.neri-calderon@xxxxxxxxxxxxxxx>
AuthorDate: Sun, 5 Nov 2017 18:27:52 -0800
Committer: Ingo Molnar <mingo@xxxxxxxxxx>
CommitDate: Wed, 8 Nov 2017 11:16:22 +0100

x86/umip: Add emulation code for UMIP instructions

The feature User-Mode Instruction Prevention present in recent Intel
processor prevents a group of instructions (sgdt, sidt, sldt, smsw, and
str) from being executed with CPL > 0. Otherwise, a general protection
fault is issued.

This was arguably an oversight on Intel's part - these insns should have been
protected from the start, as they leak a tiny bit of kernel data.

Rather than relaying to the user space the general protection fault caused
by the UMIP-protected instructions (in the form of a SIGSEGV signal), it
can be trapped and the instruction emulated to provide a dummy result.
This allows to both conserve the current kernel behavior and not reveal the
system resources that UMIP intends to protect (i.e., the locations of the
global descriptor and interrupt descriptor tables, the segment selectors of
the local descriptor table, the value of the task state register and the
contents of the CR0 register).

This emulation is needed because certain applications (e.g., WineHQ and
DOSEMU2) rely on this subset of instructions to function.

I'm surprised. What in the world they need those insns for?

Wine uses sidt like this, to emulate "mov from r/m to reg" insns:

static LDT_ENTRY idt[256];
...
case 0x8a: /* mov Eb, Gb */
case 0x8b: /* mov Ev, Gv */
{
BYTE *data = INSTR_GetOperandAddr(context, instr + 1, long_addr,
segprefix, &len);
unsigned int data_size = (*instr == 0x8b) ? (long_op ? 4 : 2) : 1;
struct idtr idtr = get_idtr(); <=============================== HERE
unsigned int offset = data - idtr.base;

if (offset <= idtr.limit + 1 - data_size)
{
idt[1].LimitLow = 0x100; /* FIXME */
idt[2].LimitLow = 0x11E; /* FIXME */
idt[3].LimitLow = 0x500; /* FIXME */

switch (*instr)
{
case 0x8a: store_reg_byte( context, instr[1], (BYTE *)idt + offset ); break;
case 0x8b: store_reg_word( context, instr[1], (BYTE *)idt + offset, long_op ); break;
}
context->Eip += prefixlen + len + 1;
return ExceptionContinueExecution;
}
break; /* Unable to emulate it */
}

Looks baffling, to say the least... this supports someone who reads
IDT bytes via those insns, and they need to ensure that the values read
from idt[1/2/3].LimitLow are as expected. That's it? Pity git history
doesn't go far enough in the past, and comments are not informative as well...

I did not find smsw or sgdt in Wine git tree.

I did not find smsw, sidt or sgdt in dosemu2-devel git tree.

Can we avoid maintain emulation of these isns, by asking Wine to remove their use instead?