Kernel - Fix numerous procfs/ptrace issues
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 16 Aug 2012 00:18:31 +0000 (17:18 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 21 Aug 2012 03:58:25 +0000 (20:58 -0700)
* Fix interactions during exec and exit.  This should fix truss
  (bug 2313).

* Reset p_* fields related to tracing on last procfs close for the
  process.

sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c
sys/kern/kern_exec.c
sys/kern/kern_exit.c
sys/kern/kern_proc.c
sys/sys/proc.h
sys/vfs/procfs/procfs.h
sys/vfs/procfs/procfs_subr.c
sys/vfs/procfs/procfs_vnops.c

index 523a063..65c0c1d 100644 (file)
@@ -234,7 +234,7 @@ linprocfs_close(struct vop_close_args *ap)
                    && !(p->p_pfsflags & PF_LINGER)) {
                        p->p_stops = 0;
                        p->p_step = 0;
                    && !(p->p_pfsflags & PF_LINGER)) {
                        p->p_stops = 0;
                        p->p_step = 0;
-                       wakeup(&p->p_step);
+                       wakeup(&p->p_stype);
                }
                if (p)
                        PRELE(p);
                }
                if (p)
                        PRELE(p);
@@ -303,10 +303,28 @@ linprocfs_ioctl(struct vop_ioctl_args *ap)
          break;
        case PIOCWAIT:
          psp = (struct procfs_status *)ap->a_data;
          break;
        case PIOCWAIT:
          psp = (struct procfs_status *)ap->a_data;
+         spin_lock(&procp->p_spin);
          if (procp->p_step == 0) {
          if (procp->p_step == 0) {
-           error = tsleep(&procp->p_stype, PCATCH, "piocwait", 0);
+           spin_unlock(&procp->p_spin);
+           tsleep_interlock(&procp->p_stype, PCATCH);
+           if (procp->p_stops == 0) {
+               error = EINVAL;
+               goto done;
+           }
+           if (procp->p_flags & P_POSTEXIT) {
+               error = EINVAL;
+               goto done;
+           }
+           if (procp->p_flags & P_INEXEC) {
+               error = EAGAIN;
+               goto done;
+           }
+           error = tsleep(&procp->p_stype, PCATCH | PINTERLOCKED,
+                          "piocwait", 0);
            if (error)
              goto done;
            if (error)
              goto done;
+         } else {
+           spin_unlock(&procp->p_spin);
          }
          psp->state = 1;       /* It stopped */
          psp->flags = procp->p_pfsflags;
          }
          psp->state = 1;       /* It stopped */
          psp->flags = procp->p_pfsflags;
index dc7047e..74059f3 100644 (file)
@@ -502,6 +502,8 @@ interpret:
          */
        KNOTE(&p->p_klist, NOTE_EXEC);
        p->p_flags &= ~P_INEXEC;
          */
        KNOTE(&p->p_klist, NOTE_EXEC);
        p->p_flags &= ~P_INEXEC;
+       if (p->p_stops)
+               wakeup(&p->p_stype);
 
        /*
         * If tracing the process, trap to debugger so breakpoints
 
        /*
         * If tracing the process, trap to debugger so breakpoints
@@ -574,8 +576,11 @@ exec_fail:
         * raced another thread and that thread is responsible for
         * clearing it.
         */
         * raced another thread and that thread is responsible for
         * clearing it.
         */
-       if (imgp->vmspace_destroyed & 2)
+       if (imgp->vmspace_destroyed & 2) {
                p->p_flags &= ~P_INEXEC;
                p->p_flags &= ~P_INEXEC;
+               if (p->p_stops)
+                       wakeup(&p->p_stype);
+       }
        lwkt_reltoken(&p->p_token);
        if (imgp->vmspace_destroyed) {
                /*
        lwkt_reltoken(&p->p_token);
        if (imgp->vmspace_destroyed) {
                /*
@@ -766,6 +771,13 @@ exec_new_vmspace(struct image_params *imgp, struct vmspace *vmcopy)
        p->p_flags |= P_INEXEC;
 
        /*
        p->p_flags |= P_INEXEC;
 
        /*
+        * Tell procfs to release its hold on the process.  It
+        * will return EAGAIN.
+        */
+       if (p->p_stops)
+               wakeup(&p->p_stype);
+
+       /*
         * After setting P_INEXEC wait for any remaining references to
         * the process (p) to go away.
         *
         * After setting P_INEXEC wait for any remaining references to
         * the process (p) to go away.
         *
index 407b9dd..7d2216a 100644 (file)
@@ -328,7 +328,7 @@ exit1(int rv)
        vmsizmon();
 #endif
        STOPEVENT(p, S_EXIT, rv);
        vmsizmon();
 #endif
        STOPEVENT(p, S_EXIT, rv);
-       wakeup(&p->p_stype);    /* Wakeup anyone in procfs' PIOCWAIT */
+       p->p_flags |= P_POSTEXIT;       /* stop procfs stepping */
 
        /* 
         * Check if any loadable modules need anything done at process exit.
 
        /* 
         * Check if any loadable modules need anything done at process exit.
index 7808a9c..bda5911 100644 (file)
@@ -175,6 +175,19 @@ pstall(struct proc *p, const char *wmesg, int count)
                        break;
                n = o | PLOCK_WAITING;
                tsleep_interlock(&p->p_lock, 0);
                        break;
                n = o | PLOCK_WAITING;
                tsleep_interlock(&p->p_lock, 0);
+
+               /*
+                * If someone is trying to single-step the process they can
+                * prevent us from going into zombie-land.
+                */
+               if (p->p_step) {
+                       spin_lock(&p->p_spin);
+                       p->p_stops = 0;
+                       p->p_step = 0;
+                       spin_unlock(&p->p_spin);
+                       wakeup(&p->p_step);
+               }
+
                if (atomic_cmpset_int(&p->p_lock, o, n)) {
                        tsleep(&p->p_lock, PINTERLOCKED, wmesg, 0);
                }
                if (atomic_cmpset_int(&p->p_lock, o, n)) {
                        tsleep(&p->p_lock, PINTERLOCKED, wmesg, 0);
                }
index 2fdaef2..918d0ed 100644 (file)
@@ -345,7 +345,7 @@ struct      proc {
 #define P_SYSVSEM      0x00008 /* Might have SysV semaphores */
 #define        P_PPWAIT        0x00010 /* Parent is waiting for child to exec/exit */
 #define        P_PROFIL        0x00020 /* Has started profiling */
 #define P_SYSVSEM      0x00008 /* Might have SysV semaphores */
 #define        P_PPWAIT        0x00010 /* Parent is waiting for child to exec/exit */
 #define        P_PROFIL        0x00020 /* Has started profiling */
-#define P_UNUSED5      0x00040 /* was: Selecting; wakeup/waiting danger */
+#define P_POSTEXIT     0x00040 /* Prevent procfs from stepping after this pt */
 #define        P_UNUSED4       0x00080 /* was: Sleep is interruptible */
 #define        P_SUGID         0x00100 /* Had set id privileges since last exec */
 #define        P_SYSTEM        0x00200 /* System proc: no sigs, stats or swapping */
 #define        P_UNUSED4       0x00080 /* was: Sleep is interruptible */
 #define        P_SUGID         0x00100 /* Had set id privileges since last exec */
 #define        P_SYSTEM        0x00200 /* System proc: no sigs, stats or swapping */
index 61b3870..4ee03a8 100644 (file)
@@ -154,6 +154,7 @@ int procfs_validmap (struct lwp *);
 int procfs_validtype (struct lwp *);
 
 struct proc *pfs_pfind(pid_t);
 int procfs_validtype (struct lwp *);
 
 struct proc *pfs_pfind(pid_t);
+struct proc *pfs_zpfind(pid_t);
 void pfs_pdone(struct proc *);
 
 #define PROCFS_LOCKED  0x01
 void pfs_pdone(struct proc *);
 
 #define PROCFS_LOCKED  0x01
index 6ff2ae9..c71f809 100644 (file)
@@ -285,7 +285,35 @@ pfs_pfind(pid_t pfs_pid)
         */
        if (p) {
                lwkt_gettoken(&p->p_token);
         */
        if (p) {
                lwkt_gettoken(&p->p_token);
-               if (p->p_flags & P_WEXIT) {
+               if (p->p_flags & P_POSTEXIT) {
+                       lwkt_reltoken(&p->p_token);
+                       PRELE(p);
+                       p = NULL;
+               }
+       }
+       return p;
+}
+
+struct proc *
+pfs_zpfind(pid_t pfs_pid)
+{
+       struct proc *p = NULL;
+
+       if (pfs_pid == 0) {
+               p = &proc0;
+               PHOLD(p);
+       } else {
+               p = zpfind(pfs_pid);
+       }
+
+       /*
+        * Make sure the process is not in the middle of exiting (where
+        * a lot of its structural members may wind up being NULL).  If it
+        * is we give up on it.
+        */
+       if (p) {
+               lwkt_gettoken(&p->p_token);
+               if (p->p_flags & P_POSTEXIT) {
                        lwkt_reltoken(&p->p_token);
                        PRELE(p);
                        p = NULL;
                        lwkt_reltoken(&p->p_token);
                        PRELE(p);
                        p = NULL;
index d10bd5a..f3b79bd 100644 (file)
@@ -248,13 +248,14 @@ procfs_close(struct vop_close_args *ap)
                 */
                p = NULL;
                if ((ap->a_vp->v_opencount < 2)
                 */
                p = NULL;
                if ((ap->a_vp->v_opencount < 2)
-                   && (p = pfs_pfind(pfs->pfs_pid))
+                   && ((p = pfs_pfind(pfs->pfs_pid)) != NULL ||
+                       (p = pfs_zpfind(pfs->pfs_pid)) != NULL)
                    && !(p->p_pfsflags & PF_LINGER)) {
                        spin_lock(&p->p_spin);
                        p->p_stops = 0;
                        p->p_step = 0;
                        spin_unlock(&p->p_spin);
                    && !(p->p_pfsflags & PF_LINGER)) {
                        spin_lock(&p->p_spin);
                        p->p_stops = 0;
                        p->p_step = 0;
                        spin_unlock(&p->p_spin);
-                       wakeup(&p->p_step);
+                       wakeup(&p->p_stype);
                }
                pfs_pdone(p);
                break;
                }
                pfs_pdone(p);
                break;
@@ -351,7 +352,20 @@ procfs_ioctl(struct vop_ioctl_args *ap)
          while (procp->p_step == 0) {
            tsleep_interlock(&procp->p_stype, PCATCH);
            spin_unlock(&procp->p_spin);
          while (procp->p_step == 0) {
            tsleep_interlock(&procp->p_stype, PCATCH);
            spin_unlock(&procp->p_spin);
-           error = tsleep(&procp->p_stype, PCATCH | PINTERLOCKED, "piocwait", 0);
+           if (procp->p_stops == 0) {
+               error = EINVAL;
+               goto done;
+           }
+           if (procp->p_flags & P_POSTEXIT) {
+               error = EINVAL;
+               goto done;
+           }
+           if (procp->p_flags & P_INEXEC) {
+               error = EAGAIN;
+               goto done;
+           }
+           error = tsleep(&procp->p_stype, PCATCH | PINTERLOCKED,
+                          "piocwait", 0);
            if (error)
              goto done;
            spin_lock(&procp->p_spin);
            if (error)
              goto done;
            spin_lock(&procp->p_spin);