From 1af9474b2608696269c52a7dd77c54c9fae615d9 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 15 Jul 2019 21:16:01 +0000 Subject: [PATCH] Always set td_errno to the error value of a system call. Early errors prior to a system call did not set td_errno. This commit sets td_errno for all errors during syscallenter(). As a result, syscallret() can now always use td_errno without checking TDP_NERRNO. Reviewed by: kib MFC after: 1 month Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D20898 --- sys/kern/kern_thread.c | 4 ++-- sys/kern/subr_syscall.c | 31 ++++++++++++++++++------------- sys/sys/proc.h | 3 +-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index c1966bf88de2..378bdb88d3a6 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -84,7 +84,7 @@ _Static_assert(offsetof(struct thread, td_pflags) == 0x104, "struct thread KBI td_pflags"); _Static_assert(offsetof(struct thread, td_frame) == 0x478, "struct thread KBI td_frame"); -_Static_assert(offsetof(struct thread, td_emuldata) == 0x548, +_Static_assert(offsetof(struct thread, td_emuldata) == 0x540, "struct thread KBI td_emuldata"); _Static_assert(offsetof(struct proc, p_flag) == 0xb0, "struct proc KBI p_flag"); @@ -102,7 +102,7 @@ _Static_assert(offsetof(struct thread, td_flags) == 0x98, "struct thread KBI td_flags"); _Static_assert(offsetof(struct thread, td_pflags) == 0xa0, "struct thread KBI td_pflags"); -_Static_assert(offsetof(struct thread, td_frame) == 0x2ec, +_Static_assert(offsetof(struct thread, td_frame) == 0x2f0, "struct thread KBI td_frame"); _Static_assert(offsetof(struct thread, td_emuldata) == 0x338, "struct thread KBI td_emuldata"); diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c index 74df5b2589aa..b15cc6dea330 100644 --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -85,8 +85,10 @@ syscallenter(struct thread *td) (uintptr_t)td, "pid:%d", td->td_proc->p_pid, "arg0:%p", sa->args[0], "arg1:%p", sa->args[1], "arg2:%p", sa->args[2]); - if (error != 0) + if (error != 0) { + td->td_errno = error; goto retval; + } STOPEVENT(p, S_SCE, sa->narg); if ((p->p_flag & P_TRACED) != 0) { @@ -105,8 +107,10 @@ syscallenter(struct thread *td) if (KTRPOINT(td, KTR_SYSCALL)) ktrsyscall(sa->code, sa->narg, sa->args); #endif - if (error != 0) + if (error != 0) { + td->td_errno = error; goto retval; + } } #ifdef CAPABILITY_MODE @@ -116,14 +120,16 @@ syscallenter(struct thread *td) */ if (IN_CAPABILITY_MODE(td) && !(sa->callp->sy_flags & SYF_CAPENABLED)) { - error = ECAPMODE; + td->td_errno = error = ECAPMODE; goto retval; } #endif error = syscall_thread_enter(td, sa->callp); - if (error != 0) + if (error != 0) { + td->td_errno = error; goto retval; + } #ifdef KDTRACE_HOOKS /* Give the syscall:::entry DTrace probe a chance to fire. */ @@ -131,6 +137,9 @@ syscallenter(struct thread *td) (*systrace_probe_func)(sa, SYSTRACE_ENTRY, 0); #endif + /* Let system calls set td_errno directly. */ + td->td_pflags &= ~TDP_NERRNO; + AUDIT_SYSCALL_ENTER(sa->code, td); error = (sa->callp->sy_call)(td, sa->args); AUDIT_SYSCALL_EXIT(error, td); @@ -162,12 +171,12 @@ syscallenter(struct thread *td) } static inline void -syscallret(struct thread *td, int error) +syscallret(struct thread *td, int error __unused) { struct proc *p; struct syscall_args *sa; ksiginfo_t ksi; - int traced, error1; + int traced; KASSERT((td->td_pflags & TDP_FORKING) == 0, ("fork() did not clear TDP_FORKING upon completion")); @@ -176,12 +185,10 @@ syscallret(struct thread *td, int error) sa = &td->td_sa; if ((trap_enotcap || (p->p_flag2 & P2_TRAPCAP) != 0) && IN_CAPABILITY_MODE(td)) { - error1 = (td->td_pflags & TDP_NERRNO) == 0 ? error : - td->td_errno; - if (error1 == ENOTCAPABLE || error1 == ECAPMODE) { + if (td->td_errno == ENOTCAPABLE || td->td_errno == ECAPMODE) { ksiginfo_init_trap(&ksi); ksi.ksi_signo = SIGTRAP; - ksi.ksi_errno = error1; + ksi.ksi_errno = td->td_errno; ksi.ksi_code = TRAP_CAP; trapsignal(td, &ksi); } @@ -194,11 +201,9 @@ syscallret(struct thread *td, int error) #ifdef KTRACE if (KTRPOINT(td, KTR_SYSRET)) { - ktrsysret(sa->code, (td->td_pflags & TDP_NERRNO) == 0 ? - error : td->td_errno, td->td_retval[0]); + ktrsysret(sa->code, td->td_errno, td->td_retval[0]); } #endif - td->td_pflags &= ~TDP_NERRNO; if (p->p_flag & P_TRACED) { traced = 1; diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 857bb5234d12..54728697b945 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -303,6 +303,7 @@ struct thread { void *td_su; /* (k) FFS SU private */ sbintime_t td_sleeptimo; /* (t) Sleep timeout. */ int td_rtcgen; /* (s) rtc_generation of abs. sleep */ + int td_errno; /* (k) Error from last syscall. */ size_t td_vslock_sz; /* (k) amount of vslock-ed space */ struct kcov_info *td_kcov_info; /* (*) Kernel code coverage data */ #define td_endzero td_sigmask @@ -353,8 +354,6 @@ struct thread { struct kaudit_record *td_ar; /* (k) Active audit record, if any. */ struct lpohead td_lprof[2]; /* (a) lock profiling objects. */ struct kdtrace_thread *td_dtrace; /* (*) DTrace-specific data. */ - int td_errno; /* Error returned by last syscall. */ - /* LP64 hole */ struct vnet *td_vnet; /* (k) Effective vnet. */ const char *td_vnet_lpush; /* (k) Debugging vnet push / pop. */ struct trapframe *td_intr_frame;/* (k) Frame of the current irq */