Author: jhb
Date: Mon Jul 15 21:16:01 2019
New Revision: 350012
URL: https://svnweb.freebsd.org/changeset/base/350012

Log:
  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

Modified:
  head/sys/kern/kern_thread.c
  head/sys/kern/subr_syscall.c
  head/sys/sys/proc.h

Modified: head/sys/kern/kern_thread.c
==============================================================================
--- head/sys/kern/kern_thread.c Mon Jul 15 20:45:01 2019        (r350011)
+++ head/sys/kern/kern_thread.c Mon Jul 15 21:16:01 2019        (r350012)
@@ -84,7 +84,7 @@ _Static_assert(offsetof(struct thread, td_pflags) == 0
     "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) == 0x
     "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");

Modified: head/sys/kern/subr_syscall.c
==============================================================================
--- head/sys/kern/subr_syscall.c        Mon Jul 15 20:45:01 2019        
(r350011)
+++ head/sys/kern/subr_syscall.c        Mon Jul 15 21:16:01 2019        
(r350012)
@@ -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;

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h Mon Jul 15 20:45:01 2019        (r350011)
+++ head/sys/sys/proc.h Mon Jul 15 21:16:01 2019        (r350012)
@@ -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 */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to