Skip to content

Commit 198a6f4

Browse files
Peter Zijlstragregkh
authored andcommitted
x86/entry_32: Fix segment exceptions
commit 9cdbeec upstream. The LKP robot reported that commit in Fixes: caused a failure. Turns out the ldt_gdt_32 selftest turns into an infinite loop trying to clear the segment. As discovered by Sean, what happens is that PARANOID_EXIT_TO_KERNEL_MODE in the handle_exception_return path overwrites the entry stack data with the task stack data, restoring the "bad" segment value. Instead of having the exception retry the instruction, have it emulate the full instruction. Replace EX_TYPE_POP_ZERO with EX_TYPE_POP_REG which will do the equivalent of: POP %reg; MOV $imm, %reg. In order to encode the segment registers, add them as registers 8-11 for 32-bit. By setting regs->[defg]s the (nested) RESTORE_REGS will pop this value at the end of the exception handler and by increasing regs->sp, it will have skipped the stack slot. This was debugged by Sean Christopherson <[email protected]>. [ bp: Add EX_REG_GS too. ] Fixes: aa93e2a ("x86/entry_32: Remove .fixup usage") Reported-by: kernel test robot <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lore.kernel.org/r/Yd1l0gInc4zRcnt/@hirez.programming.kicks-ass.net Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent ec9ec3b commit 198a6f4

File tree

4 files changed

+27
-19
lines changed

4 files changed

+27
-19
lines changed

arch/x86/entry/entry_32.S

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,16 @@
268268
1: popl %ds
269269
2: popl %es
270270
3: popl %fs
271-
addl $(4 + \pop), %esp /* pop the unused "gs" slot */
271+
4: addl $(4 + \pop), %esp /* pop the unused "gs" slot */
272272
IRET_FRAME
273-
_ASM_EXTABLE_TYPE(1b, 1b, EX_TYPE_POP_ZERO)
274-
_ASM_EXTABLE_TYPE(2b, 2b, EX_TYPE_POP_ZERO)
275-
_ASM_EXTABLE_TYPE(3b, 3b, EX_TYPE_POP_ZERO)
273+
274+
/*
275+
* There is no _ASM_EXTABLE_TYPE_REG() for ASM, however since this is
276+
* ASM the registers are known and we can trivially hard-code them.
277+
*/
278+
_ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_POP_ZERO|EX_REG_DS)
279+
_ASM_EXTABLE_TYPE(2b, 3b, EX_TYPE_POP_ZERO|EX_REG_ES)
280+
_ASM_EXTABLE_TYPE(3b, 4b, EX_TYPE_POP_ZERO|EX_REG_FS)
276281
.endm
277282

278283
.macro RESTORE_ALL_NMI cr3_reg:req pop=0

arch/x86/include/asm/extable_fixup_types.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,16 @@
1616
#define EX_DATA_FLAG_SHIFT 12
1717
#define EX_DATA_IMM_SHIFT 16
1818

19+
#define EX_DATA_REG(reg) ((reg) << EX_DATA_REG_SHIFT)
1920
#define EX_DATA_FLAG(flag) ((flag) << EX_DATA_FLAG_SHIFT)
2021
#define EX_DATA_IMM(imm) ((imm) << EX_DATA_IMM_SHIFT)
2122

23+
/* segment regs */
24+
#define EX_REG_DS EX_DATA_REG(8)
25+
#define EX_REG_ES EX_DATA_REG(9)
26+
#define EX_REG_FS EX_DATA_REG(10)
27+
#define EX_REG_GS EX_DATA_REG(11)
28+
2229
/* flags */
2330
#define EX_FLAG_CLEAR_AX EX_DATA_FLAG(1)
2431
#define EX_FLAG_CLEAR_DX EX_DATA_FLAG(2)
@@ -41,7 +48,9 @@
4148
#define EX_TYPE_RDMSR_IN_MCE 13
4249
#define EX_TYPE_DEFAULT_MCE_SAFE 14
4350
#define EX_TYPE_FAULT_MCE_SAFE 15
44-
#define EX_TYPE_POP_ZERO 16
51+
52+
#define EX_TYPE_POP_REG 16 /* sp += sizeof(long) */
53+
#define EX_TYPE_POP_ZERO (EX_TYPE_POP_REG | EX_DATA_IMM(0))
4554

4655
#define EX_TYPE_IMM_REG 17 /* reg := (long)imm */
4756
#define EX_TYPE_EFAULT_REG (EX_TYPE_IMM_REG | EX_DATA_IMM(-EFAULT))

arch/x86/lib/insn-eval.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,11 @@ static const int pt_regoff[] = {
430430
offsetof(struct pt_regs, r13),
431431
offsetof(struct pt_regs, r14),
432432
offsetof(struct pt_regs, r15),
433+
#else
434+
offsetof(struct pt_regs, ds),
435+
offsetof(struct pt_regs, es),
436+
offsetof(struct pt_regs, fs),
437+
offsetof(struct pt_regs, gs),
433438
#endif
434439
};
435440

arch/x86/mm/extable.c

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,6 @@ static bool ex_handler_clear_fs(const struct exception_table_entry *fixup,
118118
return ex_handler_default(fixup, regs);
119119
}
120120

121-
static bool ex_handler_pop_zero(const struct exception_table_entry *fixup,
122-
struct pt_regs *regs)
123-
{
124-
/*
125-
* Typically used for when "pop %seg" traps, in which case we'll clear
126-
* the stack slot and re-try the instruction, which will then succeed
127-
* to pop zero.
128-
*/
129-
*((unsigned long *)regs->sp) = 0;
130-
return ex_handler_default(fixup, regs);
131-
}
132-
133121
static bool ex_handler_imm_reg(const struct exception_table_entry *fixup,
134122
struct pt_regs *regs, int reg, int imm)
135123
{
@@ -203,8 +191,9 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
203191
case EX_TYPE_RDMSR_IN_MCE:
204192
ex_handler_msr_mce(regs, false);
205193
break;
206-
case EX_TYPE_POP_ZERO:
207-
return ex_handler_pop_zero(e, regs);
194+
case EX_TYPE_POP_REG:
195+
regs->sp += sizeof(long);
196+
fallthrough;
208197
case EX_TYPE_IMM_REG:
209198
return ex_handler_imm_reg(e, regs, reg, imm);
210199
}

0 commit comments

Comments
 (0)