126ccf4f1SKonstantin Belousov /*- 2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 3df57947fSPedro F. Giffuni * 426ccf4f1SKonstantin Belousov * Copyright (C) 1994, David Greenman 526ccf4f1SKonstantin Belousov * Copyright (c) 1990, 1993 626ccf4f1SKonstantin Belousov * The Regents of the University of California. All rights reserved. 726ccf4f1SKonstantin Belousov * Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org> 826ccf4f1SKonstantin Belousov * 926ccf4f1SKonstantin Belousov * This code is derived from software contributed to Berkeley by 1026ccf4f1SKonstantin Belousov * the University of Utah, and William Jolitz. 1126ccf4f1SKonstantin Belousov * 1226ccf4f1SKonstantin Belousov * Redistribution and use in source and binary forms, with or without 1326ccf4f1SKonstantin Belousov * modification, are permitted provided that the following conditions 1426ccf4f1SKonstantin Belousov * are met: 1526ccf4f1SKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 1626ccf4f1SKonstantin Belousov * notice, this list of conditions and the following disclaimer. 1726ccf4f1SKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 1826ccf4f1SKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 1926ccf4f1SKonstantin Belousov * documentation and/or other materials provided with the distribution. 2026ccf4f1SKonstantin Belousov * 3. All advertising materials mentioning features or use of this software 2126ccf4f1SKonstantin Belousov * must display the following acknowledgement: 2226ccf4f1SKonstantin Belousov * This product includes software developed by the University of 2326ccf4f1SKonstantin Belousov * California, Berkeley and its contributors. 2426ccf4f1SKonstantin Belousov * 4. Neither the name of the University nor the names of its contributors 2526ccf4f1SKonstantin Belousov * may be used to endorse or promote products derived from this software 2626ccf4f1SKonstantin Belousov * without specific prior written permission. 2726ccf4f1SKonstantin Belousov * 2826ccf4f1SKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2926ccf4f1SKonstantin Belousov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3026ccf4f1SKonstantin Belousov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3126ccf4f1SKonstantin Belousov * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3226ccf4f1SKonstantin Belousov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3326ccf4f1SKonstantin Belousov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3426ccf4f1SKonstantin Belousov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3526ccf4f1SKonstantin Belousov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3626ccf4f1SKonstantin Belousov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3726ccf4f1SKonstantin Belousov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3826ccf4f1SKonstantin Belousov * SUCH DAMAGE. 3926ccf4f1SKonstantin Belousov * 4026ccf4f1SKonstantin Belousov * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 4126ccf4f1SKonstantin Belousov */ 4226ccf4f1SKonstantin Belousov 4326ccf4f1SKonstantin Belousov #include "opt_capsicum.h" 4426ccf4f1SKonstantin Belousov #include "opt_ktrace.h" 4526ccf4f1SKonstantin Belousov 4626ccf4f1SKonstantin Belousov __FBSDID("$FreeBSD$"); 4726ccf4f1SKonstantin Belousov 484a144410SRobert Watson #include <sys/capsicum.h> 4926ccf4f1SKonstantin Belousov #include <sys/ktr.h> 50fef09913SGleb Smirnoff #include <sys/vmmeter.h> 5126ccf4f1SKonstantin Belousov #ifdef KTRACE 5226ccf4f1SKonstantin Belousov #include <sys/uio.h> 5326ccf4f1SKonstantin Belousov #include <sys/ktrace.h> 5426ccf4f1SKonstantin Belousov #endif 5526ccf4f1SKonstantin Belousov #include <security/audit/audit.h> 5626ccf4f1SKonstantin Belousov 57c18ca749SJohn Baldwin static inline void 582d88da2fSKonstantin Belousov syscallenter(struct thread *td) 5926ccf4f1SKonstantin Belousov { 6026ccf4f1SKonstantin Belousov struct proc *p; 612d88da2fSKonstantin Belousov struct syscall_args *sa; 6226ccf4f1SKonstantin Belousov int error, traced; 6326ccf4f1SKonstantin Belousov 6483c9dea1SGleb Smirnoff VM_CNT_INC(v_syscall); 6526ccf4f1SKonstantin Belousov p = td->td_proc; 662d88da2fSKonstantin Belousov sa = &td->td_sa; 6726ccf4f1SKonstantin Belousov 6826ccf4f1SKonstantin Belousov td->td_pticks = 0; 69e272bf47SMateusz Guzik if (__predict_false(td->td_cowgen != p->p_cowgen)) 704ea6a9a2SMateusz Guzik thread_cow_update(td); 71bdd64116SJohn Baldwin traced = (p->p_flag & P_TRACED) != 0; 720e84a878SMateusz Guzik if (__predict_false(traced || td->td_dbgflags & TDB_USERWR)) { 7326ccf4f1SKonstantin Belousov PROC_LOCK(p); 7426ccf4f1SKonstantin Belousov td->td_dbgflags &= ~TDB_USERWR; 75bdd64116SJohn Baldwin if (traced) 7626ccf4f1SKonstantin Belousov td->td_dbgflags |= TDB_SCE; 7726ccf4f1SKonstantin Belousov PROC_UNLOCK(p); 78bdd64116SJohn Baldwin } 792d88da2fSKonstantin Belousov error = (p->p_sysent->sv_fetch_syscall_args)(td); 8026ccf4f1SKonstantin Belousov #ifdef KTRACE 8126ccf4f1SKonstantin Belousov if (KTRPOINT(td, KTR_SYSCALL)) 821e2521ffSEdward Tomasz Napierala ktrsyscall(sa->code, sa->callp->sy_narg, sa->args); 8326ccf4f1SKonstantin Belousov #endif 844c44811cSJeff Roberson KTR_START4(KTR_SYSC, "syscall", syscallname(p, sa->code), 857fc3ae51SOleksandr Tymoshenko (uintptr_t)td, "pid:%d", td->td_proc->p_pid, "arg0:%p", sa->args[0], 864c44811cSJeff Roberson "arg1:%p", sa->args[1], "arg2:%p", sa->args[2]); 8726ccf4f1SKonstantin Belousov 880e84a878SMateusz Guzik if (__predict_false(error != 0)) { 891af9474bSJohn Baldwin td->td_errno = error; 90c26541e3SJohn Baldwin goto retval; 911af9474bSJohn Baldwin } 924c44811cSJeff Roberson 93*34098649SEdward Tomasz Napierala if (__predict_false(traced)) { 94343b391fSKonstantin Belousov PROC_LOCK(p); 958d570f64SJohn Baldwin if (p->p_ptevents & PTRACE_SCE) 9682a4538fSEric Badger ptracestop((td), SIGTRAP, NULL); 97343b391fSKonstantin Belousov PROC_UNLOCK(p); 98343b391fSKonstantin Belousov } 990e84a878SMateusz Guzik if (__predict_false((td->td_dbgflags & TDB_USERWR) != 0)) { 10026ccf4f1SKonstantin Belousov /* 101c26541e3SJohn Baldwin * Reread syscall number and arguments if debugger 102c26541e3SJohn Baldwin * modified registers or memory. 10326ccf4f1SKonstantin Belousov */ 1042d88da2fSKonstantin Belousov error = (p->p_sysent->sv_fetch_syscall_args)(td); 10526ccf4f1SKonstantin Belousov #ifdef KTRACE 10626ccf4f1SKonstantin Belousov if (KTRPOINT(td, KTR_SYSCALL)) 1071e2521ffSEdward Tomasz Napierala ktrsyscall(sa->code, sa->callp->sy_narg, sa->args); 10826ccf4f1SKonstantin Belousov #endif 1091af9474bSJohn Baldwin if (error != 0) { 1101af9474bSJohn Baldwin td->td_errno = error; 11126ccf4f1SKonstantin Belousov goto retval; 11226ccf4f1SKonstantin Belousov } 1131af9474bSJohn Baldwin } 11426ccf4f1SKonstantin Belousov 11526ccf4f1SKonstantin Belousov #ifdef CAPABILITY_MODE 11626ccf4f1SKonstantin Belousov /* 11726ccf4f1SKonstantin Belousov * In capability mode, we only allow access to system calls 11826ccf4f1SKonstantin Belousov * flagged with SYF_CAPENABLED. 11926ccf4f1SKonstantin Belousov */ 1200e84a878SMateusz Guzik if (__predict_false(IN_CAPABILITY_MODE(td) && 1210e84a878SMateusz Guzik !(sa->callp->sy_flags & SYF_CAPENABLED))) { 1221af9474bSJohn Baldwin td->td_errno = error = ECAPMODE; 12326ccf4f1SKonstantin Belousov goto retval; 12426ccf4f1SKonstantin Belousov } 12526ccf4f1SKonstantin Belousov #endif 12626ccf4f1SKonstantin Belousov 12726ccf4f1SKonstantin Belousov error = syscall_thread_enter(td, sa->callp); 1281af9474bSJohn Baldwin if (error != 0) { 1291af9474bSJohn Baldwin td->td_errno = error; 13026ccf4f1SKonstantin Belousov goto retval; 1311af9474bSJohn Baldwin } 13226ccf4f1SKonstantin Belousov 133146fc63fSKonstantin Belousov /* 134a113b17fSKonstantin Belousov * Fetch fast sigblock value at the time of syscall entry to 135a113b17fSKonstantin Belousov * handle sleepqueue primitives which might call cursig(). 136146fc63fSKonstantin Belousov */ 137a113b17fSKonstantin Belousov if (__predict_false(sigfastblock_fetch_always)) 138a113b17fSKonstantin Belousov (void)sigfastblock_fetch(td); 139146fc63fSKonstantin Belousov 1402f729243SMateusz Guzik /* Let system calls set td_errno directly. */ 1412f729243SMateusz Guzik td->td_pflags &= ~TDP_NERRNO; 14226ccf4f1SKonstantin Belousov 14346994ec2SMark Johnston if (__predict_false(SYSTRACE_ENABLED() || 14446994ec2SMark Johnston AUDIT_SYSCALL_ENTER(sa->code, td))) { 1452f729243SMateusz Guzik #ifdef KDTRACE_HOOKS 1462f729243SMateusz Guzik /* Give the syscall:::entry DTrace probe a chance to fire. */ 1472f729243SMateusz Guzik if (__predict_false(sa->callp->sy_entry != 0)) 1482f729243SMateusz Guzik (*systrace_probe_func)(sa, SYSTRACE_ENTRY, 0); 1492f729243SMateusz Guzik #endif 1502f729243SMateusz Guzik error = (sa->callp->sy_call)(td, sa->args); 15126ccf4f1SKonstantin Belousov /* Save the latest error return value. */ 1520e84a878SMateusz Guzik if (__predict_false((td->td_pflags & TDP_NERRNO) == 0)) 15326ccf4f1SKonstantin Belousov td->td_errno = error; 1542f729243SMateusz Guzik AUDIT_SYSCALL_EXIT(error, td); 15526ccf4f1SKonstantin Belousov #ifdef KDTRACE_HOOKS 1568ff6d9ddSMark Johnston /* Give the syscall:::return DTrace probe a chance to fire. */ 1572f729243SMateusz Guzik if (__predict_false(sa->callp->sy_return != 0)) 1588ff6d9ddSMark Johnston (*systrace_probe_func)(sa, SYSTRACE_RETURN, 1598ff6d9ddSMark Johnston error ? -1 : td->td_retval[0]); 16026ccf4f1SKonstantin Belousov #endif 1612f729243SMateusz Guzik } else { 1622f729243SMateusz Guzik error = (sa->callp->sy_call)(td, sa->args); 1632f729243SMateusz Guzik /* Save the latest error return value. */ 1642f729243SMateusz Guzik if (__predict_false((td->td_pflags & TDP_NERRNO) == 0)) 1652f729243SMateusz Guzik td->td_errno = error; 1662f729243SMateusz Guzik } 16726ccf4f1SKonstantin Belousov syscall_thread_exit(td, sa->callp); 168c26541e3SJohn Baldwin 16926ccf4f1SKonstantin Belousov retval: 1704c44811cSJeff Roberson KTR_STOP4(KTR_SYSC, "syscall", syscallname(p, sa->code), 1717fc3ae51SOleksandr Tymoshenko (uintptr_t)td, "pid:%d", td->td_proc->p_pid, "error:%d", error, 1724c44811cSJeff Roberson "retval0:%#lx", td->td_retval[0], "retval1:%#lx", 1734c44811cSJeff Roberson td->td_retval[1]); 1740e84a878SMateusz Guzik if (__predict_false(traced)) { 17526ccf4f1SKonstantin Belousov PROC_LOCK(p); 17626ccf4f1SKonstantin Belousov td->td_dbgflags &= ~TDB_SCE; 17726ccf4f1SKonstantin Belousov PROC_UNLOCK(p); 17826ccf4f1SKonstantin Belousov } 17926ccf4f1SKonstantin Belousov (p->p_sysent->sv_set_syscall_retval)(td, error); 18026ccf4f1SKonstantin Belousov } 18126ccf4f1SKonstantin Belousov 18226ccf4f1SKonstantin Belousov static inline void 183c18ca749SJohn Baldwin syscallret(struct thread *td) 18426ccf4f1SKonstantin Belousov { 1857d065d87SMateusz Guzik struct proc *p; 1862d88da2fSKonstantin Belousov struct syscall_args *sa; 187643f6f47SKonstantin Belousov ksiginfo_t ksi; 1881af9474bSJohn Baldwin int traced; 18926ccf4f1SKonstantin Belousov 190aff57357SEd Schouten KASSERT((td->td_pflags & TDP_FORKING) == 0, 191aff57357SEd Schouten ("fork() did not clear TDP_FORKING upon completion")); 192aff57357SEd Schouten 19326ccf4f1SKonstantin Belousov p = td->td_proc; 1942d88da2fSKonstantin Belousov sa = &td->td_sa; 1950e84a878SMateusz Guzik if (__predict_false(td->td_errno == ENOTCAPABLE || 1960e84a878SMateusz Guzik td->td_errno == ECAPMODE)) { 1970e84a878SMateusz Guzik if ((trap_enotcap || 1980e84a878SMateusz Guzik (p->p_flag2 & P2_TRAPCAP) != 0) && IN_CAPABILITY_MODE(td)) { 199643f6f47SKonstantin Belousov ksiginfo_init_trap(&ksi); 200643f6f47SKonstantin Belousov ksi.ksi_signo = SIGTRAP; 2011af9474bSJohn Baldwin ksi.ksi_errno = td->td_errno; 202643f6f47SKonstantin Belousov ksi.ksi_code = TRAP_CAP; 203643f6f47SKonstantin Belousov trapsignal(td, &ksi); 204643f6f47SKonstantin Belousov } 205643f6f47SKonstantin Belousov } 20626ccf4f1SKonstantin Belousov 20726ccf4f1SKonstantin Belousov /* 20826ccf4f1SKonstantin Belousov * Handle reschedule and other end-of-syscall issues 20926ccf4f1SKonstantin Belousov */ 21026ccf4f1SKonstantin Belousov userret(td, td->td_frame); 21126ccf4f1SKonstantin Belousov 21226ccf4f1SKonstantin Belousov #ifdef KTRACE 2132dd9ea6fSKonstantin Belousov if (KTRPOINT(td, KTR_SYSRET)) { 2141af9474bSJohn Baldwin ktrsysret(sa->code, td->td_errno, td->td_retval[0]); 2152dd9ea6fSKonstantin Belousov } 21626ccf4f1SKonstantin Belousov #endif 21726ccf4f1SKonstantin Belousov 2180e84a878SMateusz Guzik traced = 0; 2190e84a878SMateusz Guzik if (__predict_false(p->p_flag & P_TRACED)) { 22026ccf4f1SKonstantin Belousov traced = 1; 22126ccf4f1SKonstantin Belousov PROC_LOCK(p); 22226ccf4f1SKonstantin Belousov td->td_dbgflags |= TDB_SCX; 22326ccf4f1SKonstantin Belousov PROC_UNLOCK(p); 2240e84a878SMateusz Guzik } 2250e84a878SMateusz Guzik if (__predict_false(traced || 2260e84a878SMateusz Guzik (td->td_dbgflags & (TDB_EXEC | TDB_FORK)) != 0)) { 22726ccf4f1SKonstantin Belousov PROC_LOCK(p); 228ce8bd78bSKonstantin Belousov /* 229ce8bd78bSKonstantin Belousov * If tracing the execed process, trap to the debugger 230ce8bd78bSKonstantin Belousov * so that breakpoints can be set before the program 231ce8bd78bSKonstantin Belousov * executes. If debugger requested tracing of syscall 232ce8bd78bSKonstantin Belousov * returns, do it now too. 233ce8bd78bSKonstantin Belousov */ 2346ad1ff09SKonstantin Belousov if (traced && 2356ad1ff09SKonstantin Belousov ((td->td_dbgflags & (TDB_FORK | TDB_EXEC)) != 0 || 2368d570f64SJohn Baldwin (p->p_ptevents & PTRACE_SCX) != 0)) 23782a4538fSEric Badger ptracestop(td, SIGTRAP, NULL); 23826ccf4f1SKonstantin Belousov td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC | TDB_FORK); 23926ccf4f1SKonstantin Belousov PROC_UNLOCK(p); 24026ccf4f1SKonstantin Belousov } 2411d7ca9bbSKonstantin Belousov 2427d065d87SMateusz Guzik if (__predict_false(td->td_pflags & TDP_RFPPWAIT)) 2437d065d87SMateusz Guzik fork_rfppwait(td); 24426ccf4f1SKonstantin Belousov } 245