Skip to content

Commit 32f5f73

Browse files
xinli-intelbp3tk0v
authored andcommitted
x86/fred: Fix INT80 emulation for FRED
Add a FRED-specific INT80 handler and document why it differs from the current one. Eventually, the common bits will be unified once FRED hw is available and it turns out that no further changes are needed but for now, keep the handlers separate for everyone's sanity's sake. [ bp: Zap duplicated commit message, massage. ] Fixes: 55617fb ("x86/entry: Do not allow external 0x80 interrupts") Suggested-by: H. Peter Anvin (Intel) <[email protected]> Signed-off-by: Xin Li (Intel) <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 6376306 commit 32f5f73

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

arch/x86/entry/common.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,71 @@ __visible noinstr void do_int80_emulation(struct pt_regs *regs)
255255
instrumentation_end();
256256
syscall_exit_to_user_mode(regs);
257257
}
258+
259+
#ifdef CONFIG_X86_FRED
260+
/*
261+
* A FRED-specific INT80 handler is warranted for the follwing reasons:
262+
*
263+
* 1) As INT instructions and hardware interrupts are separate event
264+
* types, FRED does not preclude the use of vector 0x80 for external
265+
* interrupts. As a result, the FRED setup code does not reserve
266+
* vector 0x80 and calling int80_is_external() is not merely
267+
* suboptimal but actively incorrect: it could cause a system call
268+
* to be incorrectly ignored.
269+
*
270+
* 2) It is called only for handling vector 0x80 of event type
271+
* EVENT_TYPE_SWINT and will never be called to handle any external
272+
* interrupt (event type EVENT_TYPE_EXTINT).
273+
*
274+
* 3) FRED has separate entry flows depending on if the event came from
275+
* user space or kernel space, and because the kernel does not use
276+
* INT insns, the FRED kernel entry handler fred_entry_from_kernel()
277+
* falls through to fred_bad_type() if the event type is
278+
* EVENT_TYPE_SWINT, i.e., INT insns. So if the kernel is handling
279+
* an INT insn, it can only be from a user level.
280+
*
281+
* 4) int80_emulation() does a CLEAR_BRANCH_HISTORY. While FRED will
282+
* likely take a different approach if it is ever needed: it
283+
* probably belongs in either fred_intx()/ fred_other() or
284+
* asm_fred_entrypoint_user(), depending on if this ought to be done
285+
* for all entries from userspace or only system
286+
* calls.
287+
*
288+
* 5) INT $0x80 is the fast path for 32-bit system calls under FRED.
289+
*/
290+
DEFINE_FREDENTRY_RAW(int80_emulation)
291+
{
292+
int nr;
293+
294+
enter_from_user_mode(regs);
295+
296+
instrumentation_begin();
297+
add_random_kstack_offset();
298+
299+
/*
300+
* FRED pushed 0 into regs::orig_ax and regs::ax contains the
301+
* syscall number.
302+
*
303+
* User tracing code (ptrace or signal handlers) might assume
304+
* that the regs::orig_ax contains a 32-bit number on invoking
305+
* a 32-bit syscall.
306+
*
307+
* Establish the syscall convention by saving the 32bit truncated
308+
* syscall number in regs::orig_ax and by invalidating regs::ax.
309+
*/
310+
regs->orig_ax = regs->ax & GENMASK(31, 0);
311+
regs->ax = -ENOSYS;
312+
313+
nr = syscall_32_enter(regs);
314+
315+
local_irq_enable();
316+
nr = syscall_enter_from_user_mode_work(regs, nr);
317+
do_syscall_32_irqs_on(regs, nr);
318+
319+
instrumentation_end();
320+
syscall_exit_to_user_mode(regs);
321+
}
322+
#endif
258323
#else /* CONFIG_IA32_EMULATION */
259324

260325
/* Handles int $0x80 on a 32bit kernel */

arch/x86/entry/entry_fred.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ static noinstr void fred_intx(struct pt_regs *regs)
6666
/* INT80 */
6767
case IA32_SYSCALL_VECTOR:
6868
if (ia32_enabled())
69-
return int80_emulation(regs);
69+
return fred_int80_emulation(regs);
7070
fallthrough;
7171
#endif
7272

0 commit comments

Comments
 (0)