126ccf4f1SKonstantin Belousov /*- 226ccf4f1SKonstantin Belousov * Copyright (C) 1994, David Greenman 326ccf4f1SKonstantin Belousov * Copyright (c) 1990, 1993 426ccf4f1SKonstantin Belousov * The Regents of the University of California. All rights reserved. 526ccf4f1SKonstantin Belousov * Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org> 626ccf4f1SKonstantin Belousov * 726ccf4f1SKonstantin Belousov * This code is derived from software contributed to Berkeley by 826ccf4f1SKonstantin Belousov * the University of Utah, and William Jolitz. 926ccf4f1SKonstantin Belousov * 1026ccf4f1SKonstantin Belousov * Redistribution and use in source and binary forms, with or without 1126ccf4f1SKonstantin Belousov * modification, are permitted provided that the following conditions 1226ccf4f1SKonstantin Belousov * are met: 1326ccf4f1SKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 1426ccf4f1SKonstantin Belousov * notice, this list of conditions and the following disclaimer. 1526ccf4f1SKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 1626ccf4f1SKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 1726ccf4f1SKonstantin Belousov * documentation and/or other materials provided with the distribution. 1826ccf4f1SKonstantin Belousov * 3. All advertising materials mentioning features or use of this software 1926ccf4f1SKonstantin Belousov * must display the following acknowledgement: 2026ccf4f1SKonstantin Belousov * This product includes software developed by the University of 2126ccf4f1SKonstantin Belousov * California, Berkeley and its contributors. 2226ccf4f1SKonstantin Belousov * 4. Neither the name of the University nor the names of its contributors 2326ccf4f1SKonstantin Belousov * may be used to endorse or promote products derived from this software 2426ccf4f1SKonstantin Belousov * without specific prior written permission. 2526ccf4f1SKonstantin Belousov * 2626ccf4f1SKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2726ccf4f1SKonstantin Belousov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2826ccf4f1SKonstantin Belousov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2926ccf4f1SKonstantin Belousov * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3026ccf4f1SKonstantin Belousov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3126ccf4f1SKonstantin Belousov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3226ccf4f1SKonstantin Belousov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3326ccf4f1SKonstantin Belousov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3426ccf4f1SKonstantin Belousov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3526ccf4f1SKonstantin Belousov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3626ccf4f1SKonstantin Belousov * SUCH DAMAGE. 3726ccf4f1SKonstantin Belousov * 3826ccf4f1SKonstantin Belousov * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 3926ccf4f1SKonstantin Belousov */ 4026ccf4f1SKonstantin Belousov 4126ccf4f1SKonstantin Belousov #include "opt_capsicum.h" 4226ccf4f1SKonstantin Belousov #include "opt_ktrace.h" 4326ccf4f1SKonstantin Belousov 4426ccf4f1SKonstantin Belousov __FBSDID("$FreeBSD$"); 4526ccf4f1SKonstantin Belousov 464a144410SRobert Watson #include <sys/capsicum.h> 4726ccf4f1SKonstantin Belousov #include <sys/ktr.h> 48fef09913SGleb Smirnoff #include <sys/vmmeter.h> 4926ccf4f1SKonstantin Belousov #ifdef KTRACE 5026ccf4f1SKonstantin Belousov #include <sys/uio.h> 5126ccf4f1SKonstantin Belousov #include <sys/ktrace.h> 5226ccf4f1SKonstantin Belousov #endif 5326ccf4f1SKonstantin Belousov #include <security/audit/audit.h> 5426ccf4f1SKonstantin Belousov 5526ccf4f1SKonstantin Belousov static inline int 56*2d88da2fSKonstantin Belousov syscallenter(struct thread *td) 5726ccf4f1SKonstantin Belousov { 5826ccf4f1SKonstantin Belousov struct proc *p; 59*2d88da2fSKonstantin Belousov struct syscall_args *sa; 6026ccf4f1SKonstantin Belousov int error, traced; 6126ccf4f1SKonstantin Belousov 6283c9dea1SGleb Smirnoff VM_CNT_INC(v_syscall); 6326ccf4f1SKonstantin Belousov p = td->td_proc; 64*2d88da2fSKonstantin Belousov sa = &td->td_sa; 6526ccf4f1SKonstantin Belousov 6626ccf4f1SKonstantin Belousov td->td_pticks = 0; 674ea6a9a2SMateusz Guzik if (td->td_cowgen != p->p_cowgen) 684ea6a9a2SMateusz Guzik thread_cow_update(td); 69bdd64116SJohn Baldwin traced = (p->p_flag & P_TRACED) != 0; 70bdd64116SJohn Baldwin if (traced || td->td_dbgflags & TDB_USERWR) { 7126ccf4f1SKonstantin Belousov PROC_LOCK(p); 7226ccf4f1SKonstantin Belousov td->td_dbgflags &= ~TDB_USERWR; 73bdd64116SJohn Baldwin if (traced) 7426ccf4f1SKonstantin Belousov td->td_dbgflags |= TDB_SCE; 7526ccf4f1SKonstantin Belousov PROC_UNLOCK(p); 76bdd64116SJohn Baldwin } 77*2d88da2fSKonstantin Belousov error = (p->p_sysent->sv_fetch_syscall_args)(td); 7826ccf4f1SKonstantin Belousov #ifdef KTRACE 7926ccf4f1SKonstantin Belousov if (KTRPOINT(td, KTR_SYSCALL)) 8026ccf4f1SKonstantin Belousov ktrsyscall(sa->code, sa->narg, sa->args); 8126ccf4f1SKonstantin Belousov #endif 824c44811cSJeff Roberson KTR_START4(KTR_SYSC, "syscall", syscallname(p, sa->code), 837fc3ae51SOleksandr Tymoshenko (uintptr_t)td, "pid:%d", td->td_proc->p_pid, "arg0:%p", sa->args[0], 844c44811cSJeff Roberson "arg1:%p", sa->args[1], "arg2:%p", sa->args[2]); 8526ccf4f1SKonstantin Belousov 8626ccf4f1SKonstantin Belousov if (error == 0) { 874c44811cSJeff Roberson 8826ccf4f1SKonstantin Belousov STOPEVENT(p, S_SCE, sa->narg); 89189ac973SJohn Baldwin if (p->p_flag & P_TRACED) { 90343b391fSKonstantin Belousov PROC_LOCK(p); 918d570f64SJohn Baldwin if (p->p_ptevents & PTRACE_SCE) 9282a4538fSEric Badger ptracestop((td), SIGTRAP, NULL); 93343b391fSKonstantin Belousov PROC_UNLOCK(p); 94343b391fSKonstantin Belousov } 9526ccf4f1SKonstantin Belousov if (td->td_dbgflags & TDB_USERWR) { 9626ccf4f1SKonstantin Belousov /* 9726ccf4f1SKonstantin Belousov * Reread syscall number and arguments if 9826ccf4f1SKonstantin Belousov * debugger modified registers or memory. 9926ccf4f1SKonstantin Belousov */ 100*2d88da2fSKonstantin Belousov error = (p->p_sysent->sv_fetch_syscall_args)(td); 10126ccf4f1SKonstantin Belousov #ifdef KTRACE 10226ccf4f1SKonstantin Belousov if (KTRPOINT(td, KTR_SYSCALL)) 10326ccf4f1SKonstantin Belousov ktrsyscall(sa->code, sa->narg, sa->args); 10426ccf4f1SKonstantin Belousov #endif 10526ccf4f1SKonstantin Belousov if (error != 0) 10626ccf4f1SKonstantin Belousov goto retval; 10726ccf4f1SKonstantin Belousov } 10826ccf4f1SKonstantin Belousov 10926ccf4f1SKonstantin Belousov #ifdef CAPABILITY_MODE 11026ccf4f1SKonstantin Belousov /* 11126ccf4f1SKonstantin Belousov * In capability mode, we only allow access to system calls 11226ccf4f1SKonstantin Belousov * flagged with SYF_CAPENABLED. 11326ccf4f1SKonstantin Belousov */ 11426ccf4f1SKonstantin Belousov if (IN_CAPABILITY_MODE(td) && 11526ccf4f1SKonstantin Belousov !(sa->callp->sy_flags & SYF_CAPENABLED)) { 11626ccf4f1SKonstantin Belousov error = ECAPMODE; 11726ccf4f1SKonstantin Belousov goto retval; 11826ccf4f1SKonstantin Belousov } 11926ccf4f1SKonstantin Belousov #endif 12026ccf4f1SKonstantin Belousov 12126ccf4f1SKonstantin Belousov error = syscall_thread_enter(td, sa->callp); 12226ccf4f1SKonstantin Belousov if (error != 0) 12326ccf4f1SKonstantin Belousov goto retval; 12426ccf4f1SKonstantin Belousov 12526ccf4f1SKonstantin Belousov #ifdef KDTRACE_HOOKS 1268ff6d9ddSMark Johnston /* Give the syscall:::entry DTrace probe a chance to fire. */ 12726ccf4f1SKonstantin Belousov if (systrace_probe_func != NULL && sa->callp->sy_entry != 0) 1288ff6d9ddSMark Johnston (*systrace_probe_func)(sa, SYSTRACE_ENTRY, 0); 12926ccf4f1SKonstantin Belousov #endif 13026ccf4f1SKonstantin Belousov 13126ccf4f1SKonstantin Belousov AUDIT_SYSCALL_ENTER(sa->code, td); 13226ccf4f1SKonstantin Belousov error = (sa->callp->sy_call)(td, sa->args); 13326ccf4f1SKonstantin Belousov AUDIT_SYSCALL_EXIT(error, td); 13426ccf4f1SKonstantin Belousov 13526ccf4f1SKonstantin Belousov /* Save the latest error return value. */ 1362dd9ea6fSKonstantin Belousov if ((td->td_pflags & TDP_NERRNO) == 0) 13726ccf4f1SKonstantin Belousov td->td_errno = error; 13826ccf4f1SKonstantin Belousov 13926ccf4f1SKonstantin Belousov #ifdef KDTRACE_HOOKS 1408ff6d9ddSMark Johnston /* Give the syscall:::return DTrace probe a chance to fire. */ 14126ccf4f1SKonstantin Belousov if (systrace_probe_func != NULL && sa->callp->sy_return != 0) 1428ff6d9ddSMark Johnston (*systrace_probe_func)(sa, SYSTRACE_RETURN, 1438ff6d9ddSMark Johnston error ? -1 : td->td_retval[0]); 14426ccf4f1SKonstantin Belousov #endif 14526ccf4f1SKonstantin Belousov syscall_thread_exit(td, sa->callp); 14626ccf4f1SKonstantin Belousov } 14726ccf4f1SKonstantin Belousov retval: 1484c44811cSJeff Roberson KTR_STOP4(KTR_SYSC, "syscall", syscallname(p, sa->code), 1497fc3ae51SOleksandr Tymoshenko (uintptr_t)td, "pid:%d", td->td_proc->p_pid, "error:%d", error, 1504c44811cSJeff Roberson "retval0:%#lx", td->td_retval[0], "retval1:%#lx", 1514c44811cSJeff Roberson td->td_retval[1]); 15226ccf4f1SKonstantin Belousov if (traced) { 15326ccf4f1SKonstantin Belousov PROC_LOCK(p); 15426ccf4f1SKonstantin Belousov td->td_dbgflags &= ~TDB_SCE; 15526ccf4f1SKonstantin Belousov PROC_UNLOCK(p); 15626ccf4f1SKonstantin Belousov } 15726ccf4f1SKonstantin Belousov (p->p_sysent->sv_set_syscall_retval)(td, error); 15826ccf4f1SKonstantin Belousov return (error); 15926ccf4f1SKonstantin Belousov } 16026ccf4f1SKonstantin Belousov 16126ccf4f1SKonstantin Belousov static inline void 162*2d88da2fSKonstantin Belousov syscallret(struct thread *td, int error) 16326ccf4f1SKonstantin Belousov { 1641d7ca9bbSKonstantin Belousov struct proc *p, *p2; 165*2d88da2fSKonstantin Belousov struct syscall_args *sa; 166643f6f47SKonstantin Belousov ksiginfo_t ksi; 167643f6f47SKonstantin Belousov int traced, error1; 16826ccf4f1SKonstantin Belousov 169aff57357SEd Schouten KASSERT((td->td_pflags & TDP_FORKING) == 0, 170aff57357SEd Schouten ("fork() did not clear TDP_FORKING upon completion")); 171aff57357SEd Schouten 17226ccf4f1SKonstantin Belousov p = td->td_proc; 173*2d88da2fSKonstantin Belousov sa = &td->td_sa; 174643f6f47SKonstantin Belousov if ((trap_enotcap || (p->p_flag2 & P2_TRAPCAP) != 0) && 175643f6f47SKonstantin Belousov IN_CAPABILITY_MODE(td)) { 176643f6f47SKonstantin Belousov error1 = (td->td_pflags & TDP_NERRNO) == 0 ? error : 177643f6f47SKonstantin Belousov td->td_errno; 178643f6f47SKonstantin Belousov if (error1 == ENOTCAPABLE || error1 == ECAPMODE) { 179643f6f47SKonstantin Belousov ksiginfo_init_trap(&ksi); 180643f6f47SKonstantin Belousov ksi.ksi_signo = SIGTRAP; 181643f6f47SKonstantin Belousov ksi.ksi_errno = error1; 182643f6f47SKonstantin Belousov ksi.ksi_code = TRAP_CAP; 183643f6f47SKonstantin Belousov trapsignal(td, &ksi); 184643f6f47SKonstantin Belousov } 185643f6f47SKonstantin Belousov } 18626ccf4f1SKonstantin Belousov 18726ccf4f1SKonstantin Belousov /* 18826ccf4f1SKonstantin Belousov * Handle reschedule and other end-of-syscall issues 18926ccf4f1SKonstantin Belousov */ 19026ccf4f1SKonstantin Belousov userret(td, td->td_frame); 19126ccf4f1SKonstantin Belousov 19226ccf4f1SKonstantin Belousov #ifdef KTRACE 1932dd9ea6fSKonstantin Belousov if (KTRPOINT(td, KTR_SYSRET)) { 1942dd9ea6fSKonstantin Belousov ktrsysret(sa->code, (td->td_pflags & TDP_NERRNO) == 0 ? 1952dd9ea6fSKonstantin Belousov error : td->td_errno, td->td_retval[0]); 1962dd9ea6fSKonstantin Belousov } 19726ccf4f1SKonstantin Belousov #endif 1982dd9ea6fSKonstantin Belousov td->td_pflags &= ~TDP_NERRNO; 19926ccf4f1SKonstantin Belousov 20026ccf4f1SKonstantin Belousov if (p->p_flag & P_TRACED) { 20126ccf4f1SKonstantin Belousov traced = 1; 20226ccf4f1SKonstantin Belousov PROC_LOCK(p); 20326ccf4f1SKonstantin Belousov td->td_dbgflags |= TDB_SCX; 20426ccf4f1SKonstantin Belousov PROC_UNLOCK(p); 20526ccf4f1SKonstantin Belousov } else 20626ccf4f1SKonstantin Belousov traced = 0; 20726ccf4f1SKonstantin Belousov /* 20826ccf4f1SKonstantin Belousov * This works because errno is findable through the 20926ccf4f1SKonstantin Belousov * register set. If we ever support an emulation where this 21026ccf4f1SKonstantin Belousov * is not the case, this code will need to be revisited. 21126ccf4f1SKonstantin Belousov */ 21226ccf4f1SKonstantin Belousov STOPEVENT(p, S_SCX, sa->code); 21326ccf4f1SKonstantin Belousov if (traced || (td->td_dbgflags & (TDB_EXEC | TDB_FORK)) != 0) { 21426ccf4f1SKonstantin Belousov PROC_LOCK(p); 215ce8bd78bSKonstantin Belousov /* 216ce8bd78bSKonstantin Belousov * If tracing the execed process, trap to the debugger 217ce8bd78bSKonstantin Belousov * so that breakpoints can be set before the program 218ce8bd78bSKonstantin Belousov * executes. If debugger requested tracing of syscall 219ce8bd78bSKonstantin Belousov * returns, do it now too. 220ce8bd78bSKonstantin Belousov */ 2216ad1ff09SKonstantin Belousov if (traced && 2226ad1ff09SKonstantin Belousov ((td->td_dbgflags & (TDB_FORK | TDB_EXEC)) != 0 || 2238d570f64SJohn Baldwin (p->p_ptevents & PTRACE_SCX) != 0)) 22482a4538fSEric Badger ptracestop(td, SIGTRAP, NULL); 22526ccf4f1SKonstantin Belousov td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC | TDB_FORK); 22626ccf4f1SKonstantin Belousov PROC_UNLOCK(p); 22726ccf4f1SKonstantin Belousov } 2281d7ca9bbSKonstantin Belousov 2291d7ca9bbSKonstantin Belousov if (td->td_pflags & TDP_RFPPWAIT) { 2301d7ca9bbSKonstantin Belousov /* 2311d7ca9bbSKonstantin Belousov * Preserve synchronization semantics of vfork. If 2321d7ca9bbSKonstantin Belousov * waiting for child to exec or exit, fork set 2331d7ca9bbSKonstantin Belousov * P_PPWAIT on child, and there we sleep on our proc 2341d7ca9bbSKonstantin Belousov * (in case of exit). 2351d7ca9bbSKonstantin Belousov * 2361d7ca9bbSKonstantin Belousov * Do it after the ptracestop() above is finished, to 2371d7ca9bbSKonstantin Belousov * not block our debugger until child execs or exits 2381d7ca9bbSKonstantin Belousov * to finish vfork wait. 2391d7ca9bbSKonstantin Belousov */ 2401d7ca9bbSKonstantin Belousov td->td_pflags &= ~TDP_RFPPWAIT; 2411d7ca9bbSKonstantin Belousov p2 = td->td_rfppwait_p; 2428638fe7bSKonstantin Belousov again: 2431d7ca9bbSKonstantin Belousov PROC_LOCK(p2); 2448638fe7bSKonstantin Belousov while (p2->p_flag & P_PPWAIT) { 2458638fe7bSKonstantin Belousov PROC_LOCK(p); 2468638fe7bSKonstantin Belousov if (thread_suspend_check_needed()) { 2478638fe7bSKonstantin Belousov PROC_UNLOCK(p2); 2488638fe7bSKonstantin Belousov thread_suspend_check(0); 2498638fe7bSKonstantin Belousov PROC_UNLOCK(p); 2508638fe7bSKonstantin Belousov goto again; 2518638fe7bSKonstantin Belousov } else { 2528638fe7bSKonstantin Belousov PROC_UNLOCK(p); 2538638fe7bSKonstantin Belousov } 2548638fe7bSKonstantin Belousov cv_timedwait(&p2->p_pwait, &p2->p_mtx, hz); 2558638fe7bSKonstantin Belousov } 2561d7ca9bbSKonstantin Belousov PROC_UNLOCK(p2); 257fc4f075aSJohn Baldwin 258fc4f075aSJohn Baldwin if (td->td_dbgflags & TDB_VFORK) { 259fc4f075aSJohn Baldwin PROC_LOCK(p); 260fc4f075aSJohn Baldwin if (p->p_ptevents & PTRACE_VFORK) 26182a4538fSEric Badger ptracestop(td, SIGTRAP, NULL); 262fc4f075aSJohn Baldwin td->td_dbgflags &= ~TDB_VFORK; 263fc4f075aSJohn Baldwin PROC_UNLOCK(p); 264fc4f075aSJohn Baldwin } 2651d7ca9bbSKonstantin Belousov } 26626ccf4f1SKonstantin Belousov } 267