|
45 | 45 | * value that, lies close to the top of the kernel memory. The limit for the GDT |
46 | 46 | * and the IDT are set to zero. |
47 | 47 | * |
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 |
52 | 49 | * 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). |
53 | 54 | * |
54 | 55 | * Emulation is provided for both 32-bit and 64-bit processes. |
55 | 56 | * |
@@ -244,24 +245,41 @@ static int emulate_umip_insn(struct insn *insn, int umip_inst, |
244 | 245 | *data_size += UMIP_GDT_IDT_LIMIT_SIZE; |
245 | 246 | memcpy(data, &dummy_limit, UMIP_GDT_IDT_LIMIT_SIZE); |
246 | 247 |
|
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(¤t->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(¤t->mm->context.ldt_usr_sem); |
| 264 | +#else |
| 265 | + dummy_value = 0; |
| 266 | +#endif |
| 267 | + } |
249 | 268 |
|
250 | 269 | /* |
251 | | - * Even though the CR0 register has 4 bytes, the number |
| 270 | + * For these 3 instructions, the number |
252 | 271 | * of bytes to be copied in the result buffer is determined |
253 | 272 | * by whether the operand is a register or a memory location. |
254 | 273 | * If operand is a register, return as many bytes as the operand |
255 | 274 | * size. If operand is memory, return only the two least |
256 | | - * siginificant bytes of CR0. |
| 275 | + * siginificant bytes. |
257 | 276 | */ |
258 | 277 | if (X86_MODRM_MOD(insn->modrm.value) == 3) |
259 | 278 | *data_size = insn->opnd_bytes; |
260 | 279 | else |
261 | 280 | *data_size = 2; |
262 | 281 |
|
263 | 282 | memcpy(data, &dummy_value, *data_size); |
264 | | - /* STR and SLDT are not emulated */ |
265 | 283 | } else { |
266 | 284 | return -EINVAL; |
267 | 285 | } |
@@ -383,10 +401,6 @@ bool fixup_umip_exception(struct pt_regs *regs) |
383 | 401 | umip_pr_warn(regs, "%s instruction cannot be used by applications.\n", |
384 | 402 | umip_insns[umip_inst]); |
385 | 403 |
|
386 | | - /* Do not emulate (spoof) SLDT or STR. */ |
387 | | - if (umip_inst == UMIP_INST_STR || umip_inst == UMIP_INST_SLDT) |
388 | | - return false; |
389 | | - |
390 | 404 | umip_pr_warn(regs, "For now, expensive software emulation returns the result.\n"); |
391 | 405 |
|
392 | 406 | if (emulate_umip_insn(&insn, umip_inst, dummy_data, &dummy_data_size, |
|
0 commit comments