static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
{
	int i, copied;
	unsigned char opcode[15];
	unsigned long addr = convert_ip_to_linear(child, regs);

	copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);
	for (i = 0; i < copied; i++) {
		switch (opcode[i]) {
		/* popf and iret */
		case 0x9d: case 0xcf:
			return 1;

			/* CHECKME: 64 65 */

		/* opcode and address size prefixes */
		case 0x66: case 0x67:
			continue;
		/* irrelevant prefixes (segment overrides and repeats) */
		case 0x26: case 0x2e:
		case 0x36: case 0x3e:
		case 0x64: case 0x65:
		case 0xf0: case 0xf2: case 0xf3:
			continue;

#ifdef CONFIG_X86_64
		case 0x40 ... 0x4f:
			if (!user_64bit_mode(regs))
				/* 32-bit mode: register increment */
				return 0;
			/* 64-bit mode: REX prefix */
			continue;
#endif

			/* CHECKME: f2, f3 */

		/*
		 * pushf: NOTE! We should probably not let
		 * the user see the TF bit being set. But
		 * it's more pain than it's worth to avoid
		 * it, and a debugger could emulate this
		 * all in user space if it _really_ cares.
		 */
		case 0x9c:
		default:
			return 0;
		}
	}
	return 0;
}
예제 #2
0
void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
{
	/* Don't leak in-kernel non-uapi flags to user-space */
	if (oact)
		oact->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);

	if (!act)
		return;

	/* Don't let flags to be set from userspace */
	act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);

	if (user_64bit_mode(current_pt_regs()))
		return;

	if (in_ia32_syscall())
		act->sa.sa_flags |= SA_IA32_ABI;
	if (in_x32_syscall())
		act->sa.sa_flags |= SA_X32_ABI;
}
예제 #3
0
void perf_get_regs_user(struct perf_regs *regs_user,
                        struct pt_regs *regs,
                        struct pt_regs *regs_user_copy)
{
    struct pt_regs *user_regs = task_pt_regs(current);

    /*
     * If we're in an NMI that interrupted task_pt_regs setup, then
     * we can't sample user regs at all.  This check isn't really
     * sufficient, though, as we could be in an NMI inside an interrupt
     * that happened during task_pt_regs setup.
     */
    if (regs->sp > (unsigned long)&user_regs->r11 &&
            regs->sp <= (unsigned long)(user_regs + 1)) {
        regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
        regs_user->regs = NULL;
        return;
    }

    /*
     * RIP, flags, and the argument registers are usually saved.
     * orig_ax is probably okay, too.
     */
    regs_user_copy->ip = user_regs->ip;
    regs_user_copy->cx = user_regs->cx;
    regs_user_copy->dx = user_regs->dx;
    regs_user_copy->si = user_regs->si;
    regs_user_copy->di = user_regs->di;
    regs_user_copy->r8 = user_regs->r8;
    regs_user_copy->r9 = user_regs->r9;
    regs_user_copy->r10 = user_regs->r10;
    regs_user_copy->r11 = user_regs->r11;
    regs_user_copy->orig_ax = user_regs->orig_ax;
    regs_user_copy->flags = user_regs->flags;

    /*
     * Don't even try to report the "rest" regs.
     */
    regs_user_copy->bx = -1;
    regs_user_copy->bp = -1;
    regs_user_copy->r12 = -1;
    regs_user_copy->r13 = -1;
    regs_user_copy->r14 = -1;
    regs_user_copy->r15 = -1;

    /*
     * For this to be at all useful, we need a reasonable guess for
     * sp and the ABI.  Be careful: we're in NMI context, and we're
     * considering current to be the current task, so we should
     * be careful not to look at any other percpu variables that might
     * change during context switches.
     */
    if (IS_ENABLED(CONFIG_IA32_EMULATION) &&
            task_thread_info(current)->status & TS_COMPAT) {
        /* Easy case: we're in a compat syscall. */
        regs_user->abi = PERF_SAMPLE_REGS_ABI_32;
        regs_user_copy->sp = user_regs->sp;
        regs_user_copy->cs = user_regs->cs;
        regs_user_copy->ss = user_regs->ss;
    } else if (user_regs->orig_ax != -1) {
        /*
         * We're probably in a 64-bit syscall.
         * Warning: this code is severely racy.  At least it's better
         * than just blindly copying user_regs.
         */
        regs_user->abi = PERF_SAMPLE_REGS_ABI_64;
        regs_user_copy->sp = this_cpu_read(old_rsp);
        regs_user_copy->cs = __USER_CS;
        regs_user_copy->ss = __USER_DS;
        regs_user_copy->cx = -1;  /* usually contains garbage */
    } else {
        /* We're probably in an interrupt or exception. */
        regs_user->abi = user_64bit_mode(user_regs) ?
                         PERF_SAMPLE_REGS_ABI_64 : PERF_SAMPLE_REGS_ABI_32;
        regs_user_copy->sp = user_regs->sp;
        regs_user_copy->cs = user_regs->cs;
        regs_user_copy->ss = user_regs->ss;
    }

    regs_user->regs = regs_user_copy;
}