arch/x86/kernel/uprobes.c

Source file repositories/reference/linux-study-clean/arch/x86/kernel/uprobes.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kernel/uprobes.c
Extension
.c
Size
52944 bytes
Lines
1850
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: syscall or user/kernel boundary
Status
core implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

SYSCALL_DEFINE0(uretprobe)
{
	struct pt_regs *regs = task_pt_regs(current);
	struct uretprobe_syscall_args args;
	unsigned long err, ip, sp, tramp;

	/* If there's no trampoline, we are called from wrong place. */
	tramp = uprobe_get_trampoline_vaddr();
	if (unlikely(tramp == UPROBE_NO_TRAMPOLINE_VADDR))
		goto sigill;

	/* Make sure the ip matches the only allowed sys_uretprobe caller. */
	if (unlikely(regs->ip != trampoline_check_ip(tramp)))
		goto sigill;

	err = copy_from_user(&args, (void __user *)regs->sp, sizeof(args));
	if (err)
		goto sigill;

	/* expose the "right" values of r11/cx/ax/sp to uprobe_consumer/s */
	regs->r11 = args.r11;
	regs->cx  = args.cx;
	regs->ax  = args.ax;
	regs->sp += sizeof(args);
	regs->orig_ax = -1;

	ip = regs->ip;
	sp = regs->sp;

	uprobe_handle_trampoline(regs);

	/*
	 * Some of the uprobe consumers has changed sp, we can do nothing,
	 * just return via iret.
	 * .. or shadow stack is enabled, in which case we need to skip
	 * return through the user space stack address.
	 */
	if (regs->sp != sp || shstk_is_enabled())
		return regs->ax;
	regs->sp -= sizeof(args);

	/* for the case uprobe_consumer has changed r11/cx */
	args.r11 = regs->r11;
	args.cx  = regs->cx;

	/*
	 * ax register is passed through as return value, so we can use
	 * its space on stack for ip value and jump to it through the
	 * trampoline's ret instruction
	 */
	args.ax  = regs->ip;
	regs->ip = ip;

	err = copy_to_user((void __user *)regs->sp, &args, sizeof(args));
	if (err)
		goto sigill;

	/* ensure sysret, see do_syscall_64() */
	regs->r11 = regs->flags;
	regs->cx  = regs->ip;

	return regs->ax;

sigill:
	force_sig(SIGILL);
	return -1;
}

/*
 * If arch_uprobe->insn doesn't use rip-relative addressing, return
 * immediately.  Otherwise, rewrite the instruction so that it accesses
 * its memory operand indirectly through a scratch register.  Set
 * defparam->fixups accordingly. (The contents of the scratch register
 * will be saved before we single-step the modified instruction,
 * and restored afterward).
 *
 * We do this because a rip-relative instruction can access only a
 * relatively small area (+/- 2 GB from the instruction), and the XOL
 * area typically lies beyond that area.  At least for instructions
 * that store to memory, we can't execute the original instruction
 * and "fix things up" later, because the misdirected store could be
 * disastrous.
 *
 * Some useful facts about rip-relative instructions:
 *
 *  - There's always a modrm byte with bit layout "00 reg 101".
 *  - There's never a SIB byte.
 *  - The displacement is always 4 bytes.
 *  - REX.B=1 bit in REX prefix, which normally extends r/m field,
 *    has no effect on rip-relative mode. It doesn't make modrm byte

Annotation

Implementation Notes