Skip to content

Commit b91e708

Browse files
mrpippysuryasaimadhu
authored andcommitted
x86/umip: Add emulation/spoofing for SLDT and STR instructions
Add emulation/spoofing of SLDT and STR for both 32- and 64-bit processes. Wine users have found a small number of Windows apps using SLDT that were crashing when run on UMIP-enabled systems. Originally-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com> Reported-by: Andreas Rammhold <andi@notmuch.email> Signed-off-by: Brendan Shanks <bshanks@codeweavers.com> Signed-off-by: Borislav Petkov <bp@suse.de> Acked-by: Andy Lutomirski <luto@kernel.org> Reviewed-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com> Tested-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com> Link: https://lkml.kernel.org/r/20200710224525.21966-1-bshanks@codeweavers.com
1 parent 40eb0cb commit b91e708

1 file changed

Lines changed: 27 additions & 13 deletions

File tree

arch/x86/kernel/umip.c

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@
4545
* value that, lies close to the top of the kernel memory. The limit for the GDT
4646
* and the IDT are set to zero.
4747
*
48-
* Given that SLDT and STR are not commonly used in programs that run on WineHQ
49-
* or DOSEMU2, they are not emulated.
50-
*
51-
* The instruction smsw is emulated to return the value that the register CR0
48+
* The instruction SMSW is emulated to return the value that the register CR0
5249
* has at boot time as set in the head_32.
50+
* SLDT and STR are emulated to return the values that the kernel programmatically
51+
* assigns:
52+
* - SLDT returns (GDT_ENTRY_LDT * 8) if an LDT has been set, 0 if not.
53+
* - STR returns (GDT_ENTRY_TSS * 8).
5354
*
5455
* Emulation is provided for both 32-bit and 64-bit processes.
5556
*
@@ -244,24 +245,41 @@ static int emulate_umip_insn(struct insn *insn, int umip_inst,
244245
*data_size += UMIP_GDT_IDT_LIMIT_SIZE;
245246
memcpy(data, &dummy_limit, UMIP_GDT_IDT_LIMIT_SIZE);
246247

247-
} else if (umip_inst == UMIP_INST_SMSW) {
248-
unsigned long dummy_value = CR0_STATE;
248+
} else if (umip_inst == UMIP_INST_SMSW || umip_inst == UMIP_INST_SLDT ||
249+
umip_inst == UMIP_INST_STR) {
250+
unsigned long dummy_value;
251+
252+
if (umip_inst == UMIP_INST_SMSW) {
253+
dummy_value = CR0_STATE;
254+
} else if (umip_inst == UMIP_INST_STR) {
255+
dummy_value = GDT_ENTRY_TSS * 8;
256+
} else if (umip_inst == UMIP_INST_SLDT) {
257+
#ifdef CONFIG_MODIFY_LDT_SYSCALL
258+
down_read(&current->mm->context.ldt_usr_sem);
259+
if (current->mm->context.ldt)
260+
dummy_value = GDT_ENTRY_LDT * 8;
261+
else
262+
dummy_value = 0;
263+
up_read(&current->mm->context.ldt_usr_sem);
264+
#else
265+
dummy_value = 0;
266+
#endif
267+
}
249268

250269
/*
251-
* Even though the CR0 register has 4 bytes, the number
270+
* For these 3 instructions, the number
252271
* of bytes to be copied in the result buffer is determined
253272
* by whether the operand is a register or a memory location.
254273
* If operand is a register, return as many bytes as the operand
255274
* size. If operand is memory, return only the two least
256-
* siginificant bytes of CR0.
275+
* siginificant bytes.
257276
*/
258277
if (X86_MODRM_MOD(insn->modrm.value) == 3)
259278
*data_size = insn->opnd_bytes;
260279
else
261280
*data_size = 2;
262281

263282
memcpy(data, &dummy_value, *data_size);
264-
/* STR and SLDT are not emulated */
265283
} else {
266284
return -EINVAL;
267285
}
@@ -383,10 +401,6 @@ bool fixup_umip_exception(struct pt_regs *regs)
383401
umip_pr_warn(regs, "%s instruction cannot be used by applications.\n",
384402
umip_insns[umip_inst]);
385403

386-
/* Do not emulate (spoof) SLDT or STR. */
387-
if (umip_inst == UMIP_INST_STR || umip_inst == UMIP_INST_SLDT)
388-
return false;
389-
390404
umip_pr_warn(regs, "For now, expensive software emulation returns the result.\n");
391405

392406
if (emulate_umip_insn(&insn, umip_inst, dummy_data, &dummy_data_size,

0 commit comments

Comments
 (0)