Example #1
0
void do_syscall_trace_exit(struct pt_regs *regs)
{
	long errno;

	/*
	 * We may come here right after calling schedule_user()
	 * in which case we can be in RCU user mode.
	 */
	user_exit();

	/*
	 * The standard tile calling convention returns the value (or negative
	 * errno) in r0, and zero (or positive errno) in r1.
	 * It saves a couple of cycles on the hot path to do this work in
	 * registers only as we return, rather than updating the in-memory
	 * struct ptregs.
	 */
	errno = (long) regs->regs[0];
	if (errno < 0 && errno > -4096)
		regs->regs[1] = -errno;
	else
		regs->regs[1] = 0;

	if (test_thread_flag(TIF_SYSCALL_TRACE))
		tracehook_report_syscall_exit(regs, 0);

	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
		trace_sys_exit(regs, regs->regs[0]);
}
Example #2
0
asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
{
	unsigned long saved_reg;

	if (!test_thread_flag(TIF_SYSCALL_TRACE))
		return regs->syscallno;

	if (is_compat_task()) {
		/* AArch32 uses ip (r12) for scratch */
		saved_reg = regs->regs[12];
		regs->regs[12] = dir;
	} else {
		/*
		 * Save X7. X7 is used to denote syscall entry/exit:
		 *   X7 = 0 -> entry, = 1 -> exit
		 */
		saved_reg = regs->regs[7];
		regs->regs[7] = dir;
	}

	if (dir)
		tracehook_report_syscall_exit(regs, 0);
	else if (tracehook_report_syscall_entry(regs))
		regs->syscallno = ~0UL;

	if (is_compat_task())
		regs->regs[12] = saved_reg;
	else
		regs->regs[7] = saved_reg;

	return regs->syscallno;
}
Example #3
0
void do_syscall_trace_exit(struct pt_regs *regs)
{
	int stepping = test_thread_flag(TIF_SINGLESTEP) ||
		test_thread_flag(TIF_BLOCKSTEP);

	if (stepping || test_thread_flag(TIF_SYSCALL_TRACE))
		tracehook_report_syscall_exit(regs, stepping);
}
Example #4
0
void syscall_trace_leave(struct pt_regs *regs)
{
	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
		trace_sys_exit(regs, regs->ctx.DX[0].U1);

	if (test_thread_flag(TIF_SYSCALL_TRACE))
		tracehook_report_syscall_exit(regs, 0);
}
asmlinkage void syscall_trace_leave(struct pt_regs *regs)
{
	int step;

	step = test_thread_flag(TIF_SINGLESTEP);
	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
		tracehook_report_syscall_exit(regs, step);
}
Example #6
0
asmlinkage void syscall_trace_exit(struct pt_regs *regs)
{
	audit_syscall_exit(regs);

	if (test_thread_flag(TIF_SYSCALL_TRACE))
		tracehook_report_syscall_exit(regs, 0);

	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
		trace_sys_exit(regs, syscall_get_return_value(current, regs));
}
asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
{
	int step;

	if (unlikely(current->audit_context))
		audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3);

	step = test_thread_flag(TIF_SINGLESTEP);
	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
		tracehook_report_syscall_exit(regs, step);
}
asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
{
	int ret = 0;

	if (test_thread_flag(TIF_SYSCALL_TRACE)) {
		if (syscall_exit_p)
			tracehook_report_syscall_exit(regs, 0);
		else
			ret = tracehook_report_syscall_entry(regs);
	}

	return ret;
}
Example #9
0
/*
 * Called with IRQs on and fully valid regs.  Returns with IRQs off in a
 * state such that we can immediately switch to user mode.
 */
__visible void syscall_return_slowpath(struct pt_regs *regs)
{
    struct thread_info *ti = pt_regs_to_thread_info(regs);
    u32 cached_flags = READ_ONCE(ti->flags);
    bool step;

    CT_WARN_ON(ct_state() != CONTEXT_KERNEL);

    if (WARN(irqs_disabled(), "syscall %ld left IRQs disabled",
             regs->orig_ax))
        local_irq_enable();

    /*
     * First do one-time work.  If these work items are enabled, we
     * want to run them exactly once per syscall exit with IRQs on.
     */
    if (cached_flags & (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT |
                        _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT)) {
        audit_syscall_exit(regs);

        if (cached_flags & _TIF_SYSCALL_TRACEPOINT)
            trace_sys_exit(regs, regs->ax);

        /*
         * If TIF_SYSCALL_EMU is set, we only get here because of
         * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP).
         * We already reported this syscall instruction in
         * syscall_trace_enter().
         */
        step = unlikely(
                   (cached_flags & (_TIF_SINGLESTEP | _TIF_SYSCALL_EMU))
                   == _TIF_SINGLESTEP);
        if (step || cached_flags & _TIF_SYSCALL_TRACE)
            tracehook_report_syscall_exit(regs, step);
    }

#ifdef CONFIG_COMPAT
    /*
     * Compat syscalls set TS_COMPAT.  Make sure we clear it before
     * returning to user mode.
     */
    ti->status &= ~TS_COMPAT;
#endif

    local_irq_disable();
    prepare_exit_to_usermode(regs);
}
Example #10
0
void syscall_trace_leave(struct pt_regs *regs)
{
	int ptraced = current->ptrace;

	audit_syscall_exit(regs);

	/* Fake a debug trap */
	if (ptraced & PT_DTRACE)
		send_sigtrap(current, &regs->regs, 0);

	if (!test_thread_flag(TIF_SYSCALL_TRACE))
		return;

	tracehook_report_syscall_exit(regs, 0);
	/* force do_signal() --> is_syscall() */
	if (ptraced & PT_PTRACED)
		set_thread_flag(TIF_SIGPENDING);
}
Example #11
0
/*
 * Notification of system call entry/exit
 * - triggered by current->work.syscall_trace
 */
asmlinkage void syscall_trace_leave(struct pt_regs *regs)
{
        /*
	 * We may come here right after calling schedule_user()
	 * or do_notify_resume(), in which case we can be in RCU
	 * user mode.
	 */
	user_exit();

	audit_syscall_exit(regs);

	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
		trace_sys_exit(regs, regs_return_value(regs));

	if (test_thread_flag(TIF_SYSCALL_TRACE))
		tracehook_report_syscall_exit(regs, 0);

	user_enter();
}
static void tracehook_report_syscall(struct pt_regs *regs,
				     enum ptrace_syscall_dir dir)
{
	int regno;
	unsigned long saved_reg;

	/*
	 * A scratch register (ip(r12) on AArch32, x7 on AArch64) is
	 * used to denote syscall entry/exit:
	 */
	regno = (is_compat_task() ? 12 : 7);
	saved_reg = regs->regs[regno];
	regs->regs[regno] = dir;

	if (dir == PTRACE_SYSCALL_EXIT)
		tracehook_report_syscall_exit(regs, 0);
	else if (tracehook_report_syscall_entry(regs))
		regs->syscallno = ~0UL;

	regs->regs[regno] = saved_reg;
}
Example #13
0
static void syscall_slow_exit_work(struct pt_regs *regs, u32 cached_flags)
{
	bool step;

	audit_syscall_exit(regs);

	if (cached_flags & _TIF_SYSCALL_TRACEPOINT)
		trace_sys_exit(regs, regs->ax);

	/*
	 * If TIF_SYSCALL_EMU is set, we only get here because of
	 * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP).
	 * We already reported this syscall instruction in
	 * syscall_trace_enter().
	 */
	step = unlikely(
		(cached_flags & (_TIF_SINGLESTEP | _TIF_SYSCALL_EMU))
		== _TIF_SINGLESTEP);
	if (step || cached_flags & _TIF_SYSCALL_TRACE)
		tracehook_report_syscall_exit(regs, step);
}
Example #14
0
asmlinkage void syscall_trace_exit(struct pt_regs *regs)
{
	tracehook_report_syscall_exit(regs, 0);
}