/* * The sys_call_table[] is no longer used for system calls, but * kernel/trace/trace_syscalls.c still wants to know the system * call address.
*/ #ifdef CONFIG_X86_32 #define __SYSCALL(nr, sym) __ia32_##sym, const sys_call_ptr_t sys_call_table[] = { #include <asm/syscalls_32.h>
}; #undef __SYSCALL #endif
/* * Invoke a 32-bit syscall. Called with IRQs on in CT_STATE_KERNEL.
*/ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr)
{ /* * Convert negative numbers to very high and thus out of range * numbers for comparisons.
*/ unsignedint unr = nr;
/* The local APIC on XENPV guests is fake */ if (cpu_feature_enabled(X86_FEATURE_XENPV)) returnfalse;
/* * If vector 0x80 is set in the APIC ISR then this is an external * interrupt. Either from broken hardware or injected by a VMM. * * Note: In guest mode this is only valid for secure guests where * the secure module fully controls the vAPIC exposed to the guest.
*/ return apic_read(APIC_ISR + offs) & bit;
}
/** * do_int80_emulation - 32-bit legacy syscall C entry from asm * @regs: syscall arguments in struct pt_args on the stack. * * This entry point can be used by 32-bit and 64-bit programs to perform * 32-bit system calls. Instances of INT $0x80 can be found inline in * various programs and libraries. It is also used by the vDSO's * __kernel_vsyscall fallback for hardware that doesn't support a faster * entry method. Restarted 32-bit system calls also fall back to INT * $0x80 regardless of what instruction was originally used to do the * system call. * * This is considered a slow path. It is not used by most libc * implementations on modern hardware except during process startup. * * The arguments for the INT $0x80 based syscall are on stack in the * pt_regs structure: * eax: system call number * ebx, ecx, edx, esi, edi, ebp: arg1 - arg 6
*/
__visible noinstr void do_int80_emulation(struct pt_regs *regs)
{ int nr;
/* Kernel does not use INT $0x80! */ if (unlikely(!user_mode(regs))) {
irqentry_enter(regs);
instrumentation_begin();
panic("Unexpected external interrupt 0x80\n");
}
/* * Establish kernel context for instrumentation, including for * int80_is_external() below which calls into the APIC driver. * Identical for soft and external interrupts.
*/
enter_from_user_mode(regs);
/* Validate that this is a soft interrupt to the extent possible */ if (unlikely(int80_is_external()))
panic("Unexpected external interrupt 0x80\n");
/* * The low level idtentry code pushed -1 into regs::orig_ax * and regs::ax contains the syscall number. * * User tracing code (ptrace or signal handlers) might assume * that the regs::orig_ax contains a 32-bit number on invoking * a 32-bit syscall. * * Establish the syscall convention by saving the 32bit truncated * syscall number in regs::orig_ax and by invalidating regs::ax.
*/
regs->orig_ax = regs->ax & GENMASK(31, 0);
regs->ax = -ENOSYS;
nr = syscall_32_enter(regs);
local_irq_enable();
nr = syscall_enter_from_user_mode_work(regs, nr);
do_syscall_32_irqs_on(regs, nr);
#ifdef CONFIG_X86_FRED /* * A FRED-specific INT80 handler is warranted for the follwing reasons: * * 1) As INT instructions and hardware interrupts are separate event * types, FRED does not preclude the use of vector 0x80 for external * interrupts. As a result, the FRED setup code does not reserve * vector 0x80 and calling int80_is_external() is not merely * suboptimal but actively incorrect: it could cause a system call * to be incorrectly ignored. * * 2) It is called only for handling vector 0x80 of event type * EVENT_TYPE_SWINT and will never be called to handle any external * interrupt (event type EVENT_TYPE_EXTINT). * * 3) FRED has separate entry flows depending on if the event came from * user space or kernel space, and because the kernel does not use * INT insns, the FRED kernel entry handler fred_entry_from_kernel() * falls through to fred_bad_type() if the event type is * EVENT_TYPE_SWINT, i.e., INT insns. So if the kernel is handling * an INT insn, it can only be from a user level. * * 4) int80_emulation() does a CLEAR_BRANCH_HISTORY. While FRED will * likely take a different approach if it is ever needed: it * probably belongs in either fred_intx()/ fred_other() or * asm_fred_entrypoint_user(), depending on if this ought to be done * for all entries from userspace or only system * calls. * * 5) INT $0x80 is the fast path for 32-bit system calls under FRED.
*/
DEFINE_FREDENTRY_RAW(int80_emulation)
{ int nr;
/* * FRED pushed 0 into regs::orig_ax and regs::ax contains the * syscall number. * * User tracing code (ptrace or signal handlers) might assume * that the regs::orig_ax contains a 32-bit number on invoking * a 32-bit syscall. * * Establish the syscall convention by saving the 32bit truncated * syscall number in regs::orig_ax and by invalidating regs::ax.
*/
regs->orig_ax = regs->ax & GENMASK(31, 0);
regs->ax = -ENOSYS;
nr = syscall_32_enter(regs);
local_irq_enable();
nr = syscall_enter_from_user_mode_work(regs, nr);
do_syscall_32_irqs_on(regs, nr);
/* Handles int $0x80 on a 32bit kernel */
__visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
{ int nr = syscall_32_enter(regs);
add_random_kstack_offset(); /* * Subtlety here: if ptrace pokes something larger than 2^31-1 into * orig_ax, the int return value truncates it. This matches * the semantics of syscall_get_nr().
*/
nr = syscall_enter_from_user_mode(regs, nr);
instrumentation_begin();
static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
{ int nr = syscall_32_enter(regs); int res;
add_random_kstack_offset(); /* * This cannot use syscall_enter_from_user_mode() as it has to * fetch EBP before invoking any of the syscall entry work * functions.
*/
syscall_enter_from_user_mode_prepare(regs);
instrumentation_begin(); /* Fetch EBP from where the vDSO stashed it. */ if (IS_ENABLED(CONFIG_X86_64)) { /* * Micro-optimization: the pointer we're following is * explicitly 32 bits, so it can't be out of range.
*/
res = __get_user(*(u32 *)®s->bp,
(u32 __user __force *)(unsignedlong)(u32)regs->sp);
} else {
res = get_user(*(u32 *)®s->bp,
(u32 __user __force *)(unsignedlong)(u32)regs->sp);
}
if (res) { /* User code screwed up. */
regs->ax = -EFAULT;
/* Returns true to return using SYSEXIT/SYSRETL, or false to use IRET */
__visible noinstr bool do_fast_syscall_32(struct pt_regs *regs)
{ /* * Called using the internal vDSO SYSENTER/SYSCALL32 calling * convention. Adjust regs so it looks like we entered using int80.
*/ unsignedlong landing_pad = (unsignedlong)current->mm->context.vdso +
vdso_image_32.sym_int80_landing_pad;
/* * SYSENTER loses EIP, and even SYSCALL32 needs us to skip forward * so that 'regs->ip -= 2' lands back on an int $0x80 instruction. * Fix it up.
*/
regs->ip = landing_pad;
/* Invoke the syscall. If it failed, keep it simple: use IRET. */ if (!__do_fast_syscall_32(regs)) returnfalse;
/* * Check that the register state is valid for using SYSRETL/SYSEXIT * to exit to userspace. Otherwise use the slower but fully capable * IRET exit path.
*/
/* XEN PV guests always use the IRET path */ if (cpu_feature_enabled(X86_FEATURE_XENPV)) returnfalse;
/* EIP must point to the VDSO landing pad */ if (unlikely(regs->ip != landing_pad)) returnfalse;
/* CS and SS must match the values set in MSR_STAR */ if (unlikely(regs->cs != __USER32_CS || regs->ss != __USER_DS)) returnfalse;
/* If the TF, RF, or VM flags are set, use IRET */ if (unlikely(regs->flags & (X86_EFLAGS_RF | X86_EFLAGS_TF | X86_EFLAGS_VM))) returnfalse;
/* Use SYSRETL/SYSEXIT to exit to userspace */ returntrue;
}
/* Returns true to return using SYSEXIT/SYSRETL, or false to use IRET */
__visible noinstr bool do_SYSENTER_32(struct pt_regs *regs)
{ /* SYSENTER loses RSP, but the vDSO saved it in RBP. */
regs->sp = regs->bp;
/* SYSENTER clobbers EFLAGS.IF. Assume it was set in usermode. */
regs->flags |= X86_EFLAGS_IF;
return do_fast_syscall_32(regs);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.