summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2013-03-30 06:32:26 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2013-03-30 06:32:26 +0000
commite81aee4ff1f613b05626bc1aed55232335030d62 (patch)
tree942f150344e657e20c283d341796570678104b71
parent4f7a98323dff19295cc69dbe376897b27932d7cc (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.c8
-rw-r--r--sys/kern/kern_exit.c15
-rw-r--r--sys/kern/uipc_usrreq.c6
-rw-r--r--sys/kern/vfs_vnops.c7
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);
}