From: Matthew Dillon Date: Thu, 16 Aug 2012 00:18:31 +0000 (-0700) Subject: Kernel - Fix numerous procfs/ptrace issues X-Git-Tag: v3.0.3~11 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/7c37ea07d05e9d655d81a67590bed953314af717?ds=sidebyside Kernel - Fix numerous procfs/ptrace issues * 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. --- diff --git a/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c b/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c index 523a06343c..65c0c1d24b 100644 --- a/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c +++ b/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c @@ -234,7 +234,7 @@ linprocfs_close(struct vop_close_args *ap) && !(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); @@ -303,10 +303,28 @@ linprocfs_ioctl(struct vop_ioctl_args *ap) break; case PIOCWAIT: psp = (struct procfs_status *)ap->a_data; + spin_lock(&procp->p_spin); 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; + } else { + spin_unlock(&procp->p_spin); } psp->state = 1; /* It stopped */ psp->flags = procp->p_pfsflags; diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index dc7047e1c7..74059f39b1 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -502,6 +502,8 @@ interpret: */ 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 @@ -574,8 +576,11 @@ exec_fail: * 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; + if (p->p_stops) + wakeup(&p->p_stype); + } lwkt_reltoken(&p->p_token); if (imgp->vmspace_destroyed) { /* @@ -765,6 +770,13 @@ exec_new_vmspace(struct image_params *imgp, struct vmspace *vmcopy) imgp->vmspace_destroyed |= 2; /* we are responsible for 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. diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 407b9ddb32..7d2216afe9 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -328,7 +328,7 @@ exit1(int 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. diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 7808a9c6d9..bda5911fb8 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -175,6 +175,19 @@ pstall(struct proc *p, const char *wmesg, int count) 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); } diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 2fdaef244e..918d0edb82 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -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_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 */ diff --git a/sys/vfs/procfs/procfs.h b/sys/vfs/procfs/procfs.h index 61b38703a4..4ee03a8bfa 100644 --- a/sys/vfs/procfs/procfs.h +++ b/sys/vfs/procfs/procfs.h @@ -154,6 +154,7 @@ int procfs_validmap (struct lwp *); 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 diff --git a/sys/vfs/procfs/procfs_subr.c b/sys/vfs/procfs/procfs_subr.c index 6ff2ae94cf..c71f80952c 100644 --- a/sys/vfs/procfs/procfs_subr.c +++ b/sys/vfs/procfs/procfs_subr.c @@ -285,7 +285,35 @@ pfs_pfind(pid_t pfs_pid) */ 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; diff --git a/sys/vfs/procfs/procfs_vnops.c b/sys/vfs/procfs/procfs_vnops.c index d10bd5a6c5..f3b79bd7dc 100644 --- a/sys/vfs/procfs/procfs_vnops.c +++ b/sys/vfs/procfs/procfs_vnops.c @@ -248,13 +248,14 @@ procfs_close(struct vop_close_args *ap) */ 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); - wakeup(&p->p_step); + wakeup(&p->p_stype); } 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); - 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);