diff options
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/imgact_aout.c | 4 | ||||
-rw-r--r-- | sys/kern/init_main.c | 21 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 2 | ||||
-rw-r--r-- | sys/kern/subr_trap.c | 162 | ||||
-rw-r--r-- | sys/kern/sys_process.c | 8 |
6 files changed, 197 insertions, 4 deletions
diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c index 6c2f627..6710135 100644 --- a/sys/kern/imgact_aout.c +++ b/sys/kern/imgact_aout.c @@ -89,6 +89,10 @@ struct sysentvec aout_sysvec = { #else #error Choose SV_XXX flags for the platform #endif + , + .sv_set_syscall_retval = cpu_set_syscall_retval, + .sv_fetch_syscall_args = cpu_fetch_syscall_args, + .sv_syscallnames = syscallnames, }; static int diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index e9090fb..d608e25 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -334,6 +334,21 @@ set_boot_verbose(void *data __unused) } SYSINIT(boot_verbose, SI_SUB_TUNABLES, SI_ORDER_ANY, set_boot_verbose, NULL); +static int +null_fetch_syscall_args(struct thread *td __unused, + struct syscall_args *sa __unused) +{ + + panic("null_fetch_syscall_args"); +} + +static void +null_set_syscall_retval(struct thread *td __unused, int error __unused) +{ + + panic("null_set_syscall_retval"); +} + struct sysentvec null_sysvec = { .sv_size = 0, .sv_table = NULL, @@ -361,7 +376,11 @@ struct sysentvec null_sysvec = { .sv_copyout_strings = NULL, .sv_setregs = NULL, .sv_fixlimit = NULL, - .sv_maxssiz = NULL + .sv_maxssiz = NULL, + .sv_flags = 0, + .sv_set_syscall_retval = null_set_syscall_retval, + .sv_fetch_syscall_args = null_fetch_syscall_args, + .sv_syscallnames = NULL, }; /* diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index fc87d63..149e6df 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -871,6 +871,10 @@ exec_fail_dealloc: free(imgp->freepath, M_TEMP); if (error == 0) { + PROC_LOCK(p); + td->td_dbgflags |= TDB_EXEC; + PROC_UNLOCK(p); + /* * Stop the process here if its stop event mask has * the S_EXEC bit set. diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 789bb61..d52cedb 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1483,7 +1483,7 @@ kern_sigsuspend(struct thread *td, sigset_t mask) * thread. But sigsuspend should return only on signal * delivery. */ - cpu_set_syscall_retval(td, EINTR); + (p->p_sysent->sv_set_syscall_retval)(td, EINTR); for (has_sig = 0; !has_sig;) { while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "pause", 0) == 0) diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 4d20ebd..4cc56cc 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -58,15 +58,20 @@ __FBSDID("$FreeBSD$"); #include <sys/pmckern.h> #include <sys/proc.h> #include <sys/ktr.h> +#include <sys/pioctl.h> +#include <sys/ptrace.h> #include <sys/resourcevar.h> #include <sys/sched.h> #include <sys/signalvar.h> +#include <sys/syscall.h> +#include <sys/sysent.h> #include <sys/systm.h> #include <sys/vmmeter.h> #ifdef KTRACE #include <sys/uio.h> #include <sys/ktrace.h> #endif +#include <security/audit/audit.h> #include <machine/cpu.h> #include <machine/pcb.h> @@ -253,3 +258,160 @@ ast(struct trapframe *framep) userret(td, framep); mtx_assert(&Giant, MA_NOTOWNED); } + +#ifdef HAVE_SYSCALL_ARGS_DEF +static const char *syscallname(struct proc *p, u_int code) __unused; +static const char * +syscallname(struct proc *p, u_int code) +{ + static const char unknown[] = "unknown"; + + if (p->p_sysent->sv_syscallnames == NULL) + return (unknown); + return (p->p_sysent->sv_syscallnames[code]); +} + +int +syscallenter(struct thread *td, struct syscall_args *sa) +{ + struct proc *p; + int error, traced; + + PCPU_INC(cnt.v_syscall); + p = td->td_proc; + td->td_syscalls++; + + td->td_pticks = 0; + if (td->td_ucred != p->p_ucred) + cred_update_thread(td); + if (p->p_flag & P_TRACED) { + traced = 1; + PROC_LOCK(p); + td->td_dbgflags &= ~TDB_USERWR; + td->td_dbgflags |= TDB_SCE; + PROC_UNLOCK(p); + } else + traced = 0; + error = (p->p_sysent->sv_fetch_syscall_args)(td, sa); +#ifdef KTRACE + if (KTRPOINT(td, KTR_SYSCALL)) + ktrsyscall(sa->code, sa->narg, sa->args); +#endif + + CTR6(KTR_SYSC, +"syscall: td=%p pid %d %s (%#lx, %#lx, %#lx)", + td, td->td_proc->p_pid, syscallname(p, sa->code), + sa->args[0], sa->args[1], sa->args[2]); + + if (error == 0) { + STOPEVENT(p, S_SCE, sa->narg); + PTRACESTOP_SC(p, td, S_PT_SCE); + if (td->td_dbgflags & TDB_USERWR) { + /* + * Reread syscall number and arguments if + * debugger modified registers or memory. + */ + error = (p->p_sysent->sv_fetch_syscall_args)(td, sa); +#ifdef KTRACE + if (KTRPOINT(td, KTR_SYSCALL)) + ktrsyscall(sa->code, sa->narg, sa->args); +#endif + if (error != 0) + goto retval; + } + +#ifdef KDTRACE_HOOKS + /* + * If the systrace module has registered it's probe + * callback and if there is a probe active for the + * syscall 'entry', process the probe. + */ + if (systrace_probe_func != NULL && sa->callp->sy_entry != 0) + (*systrace_probe_func)(sa->callp->sy_entry, sa->code, + sa->callp, sa->args); +#endif + + AUDIT_SYSCALL_ENTER(sa->code, td); + error = (sa->callp->sy_call)(td, sa->args); + AUDIT_SYSCALL_EXIT(error, td); + + /* Save the latest error return value. */ + td->td_errno = error; + +#ifdef KDTRACE_HOOKS + /* + * If the systrace module has registered it's probe + * callback and if there is a probe active for the + * syscall 'return', process the probe. + */ + if (systrace_probe_func != NULL && sa->callp->sy_return != 0) + (*systrace_probe_func)(sa->callp->sy_return, sa->code, + sa->callp, sa->args); +#endif + CTR4(KTR_SYSC, "syscall: p=%p error=%d return %#lx %#lx", + p, error, td->td_retval[0], td->td_retval[1]); + } + retval: + if (traced) { + PROC_LOCK(p); + td->td_dbgflags &= ~TDB_SCE; + PROC_UNLOCK(p); + } + (p->p_sysent->sv_set_syscall_retval)(td, error); + return (error); +} + +void +syscallret(struct thread *td, int error, struct syscall_args *sa __unused) +{ + struct proc *p; + int traced; + + p = td->td_proc; + + /* + * Check for misbehavior. + */ + WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning", + syscallname(p, sa->code)); + KASSERT(td->td_critnest == 0, + ("System call %s returning in a critical section", + syscallname(p, sa->code))); + KASSERT(td->td_locks == 0, + ("System call %s returning with %d locks held", + syscallname(p, sa->code), td->td_locks)); + + /* + * Handle reschedule and other end-of-syscall issues + */ + userret(td, td->td_frame); + + CTR4(KTR_SYSC, "syscall %s exit thread %p pid %d proc %s", + syscallname(p, sa->code), td, td->td_proc->p_pid, td->td_name); + +#ifdef KTRACE + if (KTRPOINT(td, KTR_SYSRET)) + ktrsysret(sa->code, error, td->td_retval[0]); +#endif + + if (p->p_flag & P_TRACED) { + traced = 1; + PROC_LOCK(p); + td->td_dbgflags |= TDB_SCX; + PROC_UNLOCK(p); + } else + traced = 0; + /* + * This works because errno is findable through the + * register set. If we ever support an emulation where this + * is not the case, this code will need to be revisited. + */ + STOPEVENT(p, S_SCX, sa->code); + PTRACESTOP_SC(p, td, S_PT_SCX); + if (traced || (td->td_dbgflags & TDB_EXEC) != 0) { + PROC_LOCK(p); + td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC); + PROC_UNLOCK(p); + } +} +#endif /* HAVE_SYSCALL_ARGS_DEF */ diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index d8cc4f0..6decc02 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -1105,9 +1105,13 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) pl->pl_lwpid = td2->td_tid; if (td2->td_dbgflags & TDB_XSIG) pl->pl_event = PL_EVENT_SIGNAL; - else - pl->pl_event = 0; pl->pl_flags = 0; + if (td2->td_dbgflags & TDB_SCE) + pl->pl_flags |= PL_FLAG_SCE; + else if (td2->td_dbgflags & TDB_SCX) + pl->pl_flags |= PL_FLAG_SCX; + if (td2->td_dbgflags & TDB_EXEC) + pl->pl_flags |= PL_FLAG_EXEC; pl->pl_sigmask = td2->td_sigmask; pl->pl_siglist = td2->td_siglist; break; |