diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2013-03-30 06:32:26 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2013-03-30 06:32:26 +0000 |
commit | e81aee4ff1f613b05626bc1aed55232335030d62 (patch) | |
tree | 942f150344e657e20c283d341796570678104b71 | |
parent | 4f7a98323dff19295cc69dbe376897b27932d7cc (diff) |
vrele() is a tricky beast. it can sleep if the refcount hits zero,
leaving us with a free type function that isn't atomic. deal with this
by erasing any reachable pointers to the vnode first, then free it.
ok deraadt guenther
-rw-r--r-- | sys/kern/kern_exec.c | 8 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 15 | ||||
-rw-r--r-- | sys/kern/uipc_usrreq.c | 6 | ||||
-rw-r--r-- | sys/kern/vfs_vnops.c | 7 |
4 files changed, 23 insertions, 13 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 83062ff016a..5046191d86b 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_exec.c,v 1.133 2013/03/28 16:55:25 deraadt Exp $ */ +/* $OpenBSD: kern_exec.c,v 1.134 2013/03/30 06:32:25 tedu Exp $ */ /* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */ /*- @@ -265,6 +265,7 @@ sys_execve(struct proc *p, void *v, register_t *retval) size_t pathbuflen; #endif char *pathbuf = NULL; + struct vnode *otvp; /* get other threads to stop */ if ((error = single_thread_set(p, SINGLE_UNWIND, 1))) @@ -477,10 +478,11 @@ sys_execve(struct proc *p, void *v, register_t *retval) pr->ps_acflag &= ~AFORK; /* record proc's vnode, for use by procfs and others */ - if (p->p_textvp) - vrele(p->p_textvp); + otvp = p->p_textvp; vref(pack.ep_vp); p->p_textvp = pack.ep_vp; + if (otvp) + vrele(otvp); atomic_setbits_int(&pr->ps_flags, PS_EXEC); if (pr->ps_flags & PS_PPWAIT) { diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 2681876b848..c63330165ac 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_exit.c,v 1.120 2013/03/28 16:55:25 deraadt Exp $ */ +/* $OpenBSD: kern_exit.c,v 1.121 2013/03/30 06:32:25 tedu Exp $ */ /* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */ /* @@ -120,6 +120,7 @@ exit1(struct proc *p, int rv, int flags) { struct process *pr, *qr, *nqr; struct rusage *rup; + struct vnode *ovp; if (p->p_pid == 1) panic("init died (signal %d, exit %d)", @@ -216,9 +217,10 @@ exit1(struct proc *p, int rv, int flags) VOP_REVOKE(sp->s_ttyvp, REVOKEALL); } - if (sp->s_ttyvp) - vrele(sp->s_ttyvp); + ovp = sp->s_ttyvp; sp->s_ttyvp = NULL; + if (ovp) + vrele(ovp); /* * s_ttyp is not zero'd; we use this to * indicate that the session once had a @@ -604,6 +606,7 @@ void proc_zap(struct proc *p) { struct process *pr = p->p_p; + struct vnode *otvp; /* * Finally finished with old proc entry. @@ -624,8 +627,10 @@ proc_zap(struct proc *p) /* * Release reference to text vnode */ - if (p->p_textvp) - vrele(p->p_textvp); + otvp = p->p_textvp; + p->p_textvp = NULL; + if (otvp) + vrele(otvp); /* * Remove us from our process list, possibly killing the process diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 849b40c6576..47a2f7da091 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_usrreq.c,v 1.69 2012/10/12 20:45:49 guenther Exp $ */ +/* $OpenBSD: uipc_usrreq.c,v 1.70 2013/03/30 06:32:25 tedu Exp $ */ /* $NetBSD: uipc_usrreq.c,v 1.18 1996/02/09 19:00:50 christos Exp $ */ /* @@ -365,11 +365,13 @@ unp_attach(struct socket *so) void unp_detach(struct unpcb *unp) { + struct vnode *vp; if (unp->unp_vnode) { unp->unp_vnode->v_socket = NULL; - vrele(unp->unp_vnode); + vp = unp->unp_vnode; unp->unp_vnode = NULL; + vrele(vp); } if (unp->unp_conn) unp_disconnect(unp); diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index b7927924bff..9d8ead6f30c 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_vnops.c,v 1.71 2012/07/11 12:39:20 guenther Exp $ */ +/* $OpenBSD: vfs_vnops.c,v 1.72 2013/03/30 06:32:25 tedu Exp $ */ /* $NetBSD: vfs_vnops.c,v 1.20 1996/02/04 02:18:41 christos Exp $ */ /* @@ -482,10 +482,11 @@ vn_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p) error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); if (error == 0 && com == TIOCSCTTY) { struct session *s = p->p_p->ps_session; - if (s->s_ttyvp) - vrele(s->s_ttyvp); + struct vnode *ovp = s->s_ttyvp; s->s_ttyvp = vp; vref(vp); + if (ovp) + vrele(ovp); } return (error); } |