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
This commit is contained in:
parent
8a3cfbff92
commit
1af9474b26
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user