Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/uipc_usrreq.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/kern/uipc_usrreq.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.95 retrieving revision 1.95.2.6 diff -u -p -r1.95 -r1.95.2.6 --- src/sys/kern/uipc_usrreq.c 2007/03/04 06:03:11 1.95 +++ src/sys/kern/uipc_usrreq.c 2007/11/05 17:20:34 1.95.2.6 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_usrreq.c,v 1.95 2007/03/04 06:03:11 christos Exp $ */ +/* $NetBSD: uipc_usrreq.c,v 1.95.2.6 2007/11/05 17:20:34 ad Exp $ */ /*- * Copyright (c) 1998, 2000, 2004 The NetBSD Foundation, Inc. @@ -103,7 +103,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.95 2007/03/04 06:03:11 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.95.2.6 2007/11/05 17:20:34 ad Exp $"); #include #include @@ -121,6 +121,7 @@ __KERNEL_RCSID(0, "$NetBSD: uipc_usrreq. #include #include #include +#include /* * Unix communications domain. @@ -154,6 +155,7 @@ unp_output(struct mbuf *m, struct mbuf * control = unp_addsockcred(l, control); if (sbappendaddr(&so2->so_rcv, (const struct sockaddr *)sun, m, control) == 0) { + unp_dispose(control); m_freem(control); m_freem(m); so2->so_rcv.sb_overflowed++; @@ -329,6 +331,7 @@ uipc_usrreq(struct socket *so, int req, error = unp_connect(so, nam, l); if (error) { die: + unp_dispose(control); m_freem(control); m_freem(m); break; @@ -368,8 +371,10 @@ uipc_usrreq(struct socket *so, int req, * Wake up readers. */ if (control) { - if (sbappendcontrol(rcv, m, control) == 0) + if (sbappendcontrol(rcv, m, control) == 0) { + unp_dispose(control); m_freem(control); + } } else sbappend(rcv, m); snd->sb_mbmax -= @@ -454,7 +459,7 @@ uipc_ctloutput(int op, struct socket *so int optval = 0, error = 0; if (level != 0) { - error = EINVAL; + error = ENOPROTOOPT; if (op == PRCO_SETOPT && m) (void) m_free(m); } else switch (op) { @@ -495,17 +500,22 @@ uipc_ctloutput(int op, struct socket *so case PRCO_GETOPT: switch (optname) { + case LOCAL_PEEREID: + if (unp->unp_flags & UNP_EIDSVALID) { + *mp = m = m_get(M_WAIT, MT_SOOPTS); + m->m_len = sizeof(struct unpcbid); + *mtod(m, struct unpcbid *) = unp->unp_connid; + } else { + error = EINVAL; + } + break; case LOCAL_CREDS: *mp = m = m_get(M_WAIT, MT_SOOPTS); m->m_len = sizeof(int); - switch (optname) { #define OPTBIT(bit) (unp->unp_flags & (bit) ? 1 : 0) - case LOCAL_CREDS: - optval = OPTBIT(UNP_WANTCRED); - break; - } + optval = OPTBIT(UNP_WANTCRED); *mtod(m, int *) = optval; break; #undef OPTBIT @@ -605,7 +615,6 @@ unp_bind(struct unpcb *unp, struct mbuf { struct sockaddr_un *sun; struct vnode *vp; - struct mount *mp; struct vattr vattr; size_t addrlen; struct proc *p; @@ -626,37 +635,28 @@ unp_bind(struct unpcb *unp, struct mbuf m_copydata(nam, 0, nam->m_len, (void *)sun); *(((char *)sun) + nam->m_len) = '\0'; -restart: - NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE, + NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT | TRYEMULROOT, UIO_SYSSPACE, sun->sun_path, l); /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ if ((error = namei(&nd)) != 0) goto bad; vp = nd.ni_vp; - if (vp != NULL || vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { + if (vp != NULL) { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == vp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); vrele(vp); - if (vp != NULL) { - error = EADDRINUSE; - goto bad; - } - error = vn_start_write(NULL, &mp, - V_WAIT | V_SLEEPONLY | V_PCATCH); - if (error) - goto bad; - goto restart; + error = EADDRINUSE; + goto bad; } VATTR_NULL(&vattr); vattr.va_type = VSOCK; vattr.va_mode = ACCESSPERMS & ~(p->p_cwdi->cwdi_cmask); VOP_LEASE(nd.ni_dvp, l, l->l_cred, LEASE_WRITE); error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); - vn_finished_write(mp, 0); if (error) goto bad; vp = nd.ni_vp; @@ -664,6 +664,10 @@ restart: unp->unp_vnode = vp; unp->unp_addrlen = addrlen; unp->unp_addr = sun; + unp->unp_connid.unp_pid = p->p_pid; + unp->unp_connid.unp_euid = kauth_cred_geteuid(p->p_cred); + unp->unp_connid.unp_egid = kauth_cred_getegid(p->p_cred); + unp->unp_flags |= UNP_EIDSBIND; VOP_UNLOCK(vp, 0); return (0); @@ -678,11 +682,13 @@ unp_connect(struct socket *so, struct mb struct sockaddr_un *sun; struct vnode *vp; struct socket *so2, *so3; - struct unpcb *unp2, *unp3; + struct unpcb *unp, *unp2, *unp3; size_t addrlen; + struct proc *p; int error; struct nameidata nd; + p = l->l_proc; /* * Allocate a temporary sockaddr. We have to allocate one extra * byte so that we can ensure that the pathname is nul-terminated. @@ -694,7 +700,7 @@ unp_connect(struct socket *so, struct mb m_copydata(nam, 0, nam->m_len, (void *)sun); *(((char *)sun) + nam->m_len) = '\0'; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, sun->sun_path, l); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_SYSSPACE, sun->sun_path, l); if ((error = namei(&nd)) != 0) goto bad2; @@ -720,6 +726,7 @@ unp_connect(struct socket *so, struct mb error = ECONNREFUSED; goto bad; } + unp = sotounpcb(so); unp2 = sotounpcb(so2); unp3 = sotounpcb(so3); if (unp2->unp_addr) { @@ -730,7 +737,15 @@ unp_connect(struct socket *so, struct mb unp3->unp_addrlen = unp2->unp_addrlen; } unp3->unp_flags = unp2->unp_flags; + unp3->unp_connid.unp_pid = p->p_pid; + unp3->unp_connid.unp_euid = kauth_cred_geteuid(p->p_cred); + unp3->unp_connid.unp_egid = kauth_cred_getegid(p->p_cred); + unp3->unp_flags |= UNP_EIDSVALID; so2 = so3; + if (unp2->unp_flags & UNP_EIDSBIND) { + unp->unp_connid = unp2->unp_connid; + unp->unp_flags |= UNP_EIDSVALID; + } } error = unp_connect2(so, so2, PRU_CONNECT); bad: @@ -865,6 +880,7 @@ unp_externalize(struct mbuf *rights, str rp = (struct file **)CMSG_DATA(cm); fdp = malloc(nfds * sizeof(int), M_TEMP, M_WAITOK); + rw_enter(&p->p_cwdi->cwdi_lock, RW_READER); /* Make sure the recipient should be able to see the descriptors.. */ if (p->p_cwdi->cwdi_rdir != NULL) { @@ -935,7 +951,9 @@ unp_externalize(struct mbuf *rights, str * fdalloc() works properly.. We finalize it all * in the loop below. */ + rw_enter(&p->p_fd->fd_lock, RW_WRITER); p->p_fd->fd_ofiles[fdp[i]] = fp; + rw_exit(&p->p_fd->fd_lock); } /* @@ -957,6 +975,7 @@ unp_externalize(struct mbuf *rights, str cm->cmsg_len = CMSG_LEN(nfds * sizeof(int)); rights->m_len = CMSG_SPACE(nfds * sizeof(int)); out: + rw_exit(&p->p_cwdi->cwdi_lock); free(fdp, M_TEMP); return (error); } @@ -985,7 +1004,8 @@ unp_internalize(struct mbuf *control, st fd = *fdp++; if ((fp = fd_getfile(fdescp, fd)) == NULL) return (EBADF); - simple_unlock(&fp->f_slock); + /* XXXSMP grab reference to file */ + mutex_exit(&fp->f_lock); } /* Make sure we have room for the struct file pointers */ @@ -997,8 +1017,10 @@ unp_internalize(struct mbuf *control, st newcm = malloc( CMSG_SPACE(nfds * sizeof(struct file *)), M_MBUF, M_WAITOK); - if (newcm == NULL) + if (newcm == NULL) { + /* XXXSMP drop references to files */ return (E2BIG); + } memcpy(newcm, cm, sizeof(struct cmsghdr)); files = (struct file **)CMSG_DATA(newcm); } else { @@ -1012,11 +1034,12 @@ unp_internalize(struct mbuf *control, st * reverse order so that if pointers are bigger than ints, the * int won't get until we're done. */ + rw_enter(&fdescp->fd_lock, RW_READER); fdp = (int *)CMSG_DATA(cm) + nfds; rp = files + nfds; for (i = 0; i < nfds; i++) { fp = fdescp->fd_ofiles[*--fdp]; - simple_lock(&fp->f_slock); + mutex_enter(&fp->f_lock); #ifdef DIAGNOSTIC if (fp->f_iflags & FIF_WANTCLOSE) panic("unp_internalize: file already closed"); @@ -1024,9 +1047,10 @@ unp_internalize(struct mbuf *control, st *--rp = fp; fp->f_count++; fp->f_msgcount++; - simple_unlock(&fp->f_slock); + mutex_exit(&fp->f_lock); unp_rights++; } + rw_exit(&fdescp->fd_lock); if (newcm) { if (control->m_flags & M_EXT) @@ -1137,6 +1161,8 @@ unp_gc(void) unp_gcing = 1; unp_defer = 0; + mutex_enter(&filelist_lock); + /* Clear mark bits */ LIST_FOREACH(fp, &filehead, f_list) fp->f_flag &= ~(FMARK|FDEFER); @@ -1148,7 +1174,8 @@ unp_gc(void) */ do { LIST_FOREACH(fp, &filehead, f_list) { - if (fp->f_flag & FDEFER) { + mutex_enter(&fp->f_lock); + if (fp->f_flag & FDEFER) { fp->f_flag &= ~FDEFER; unp_defer--; #ifdef DIAGNOSTIC @@ -1156,21 +1183,22 @@ unp_gc(void) panic("unp_gc: deferred unreferenced socket"); #endif } else { - if (fp->f_count == 0) - continue; - if (fp->f_flag & FMARK) - continue; - if (fp->f_count == fp->f_msgcount) + if (fp->f_count == 0 || + (fp->f_flag & FMARK) || + fp->f_count == fp->f_msgcount) { + mutex_exit(&fp->f_lock); continue; + } } fp->f_flag |= FMARK; if (fp->f_type != DTYPE_SOCKET || - (so = (struct socket *)fp->f_data) == 0) - continue; - if (so->so_proto->pr_domain != &unixdomain || - (so->so_proto->pr_flags&PR_RIGHTS) == 0) + (so = (struct socket *)fp->f_data) == 0 || + so->so_proto->pr_domain != &unixdomain || + (so->so_proto->pr_flags&PR_RIGHTS) == 0) { + mutex_exit(&fp->f_lock); continue; + } #ifdef notdef if (so->so_rcv.sb_flags & SB_LOCK) { /* @@ -1187,6 +1215,8 @@ unp_gc(void) goto restart; } #endif + mutex_exit(&fp->f_lock); + unp_scan(so->so_rcv.sb_mb, unp_mark, 0); /* * mark descriptors referenced from sockets queued on the accept queue as well. @@ -1199,9 +1229,11 @@ unp_gc(void) unp_scan(so1->so_rcv.sb_mb, unp_mark, 0); } } - } } while (unp_defer); + + mutex_exit(&filelist_lock); + /* * Sweep pass. Find unmarked descriptors, and free them. * @@ -1244,22 +1276,26 @@ unp_gc(void) * * 91/09/19, bsy@cs.cmu.edu */ - extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK); + extra_ref = kmem_alloc(nfiles * sizeof(struct file *), KM_SLEEP); + + mutex_enter(&filelist_lock); for (nunref = 0, fp = LIST_FIRST(&filehead), fpp = extra_ref; fp != 0; fp = nextfp) { nextfp = LIST_NEXT(fp, f_list); - simple_lock(&fp->f_slock); + mutex_enter(&fp->f_lock); if (fp->f_count != 0 && fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) { *fpp++ = fp; nunref++; fp->f_count++; } - simple_unlock(&fp->f_slock); + mutex_exit(&fp->f_lock); } + mutex_exit(&filelist_lock); + for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) { fp = *fpp; - simple_lock(&fp->f_slock); + mutex_enter(&fp->f_lock); FILE_USE(fp); if (fp->f_type == DTYPE_SOCKET) sorflush((struct socket *)fp->f_data); @@ -1267,11 +1303,11 @@ unp_gc(void) } for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) { fp = *fpp; - simple_lock(&fp->f_slock); + mutex_enter(&fp->f_lock); FILE_USE(fp); (void) closef(fp, (struct lwp *)0); } - free((void *)extra_ref, M_FILE); + kmem_free(extra_ref, nfiles * sizeof(struct file *)); unp_gcing = 0; } @@ -1320,15 +1356,16 @@ unp_scan(struct mbuf *m0, void (*op)(str void unp_mark(struct file *fp) { - if (fp == NULL) - return; - if (fp->f_flag & FMARK) + if (fp == NULL) return; /* If we're already deferred, don't screw up the defer count */ - if (fp->f_flag & FDEFER) + mutex_enter(&fp->f_lock); + if (fp->f_flag & (FMARK | FDEFER)) { + mutex_exit(&fp->f_lock); return; + } /* * Minimize the number of deferrals... Sockets are the only @@ -1344,6 +1381,7 @@ unp_mark(struct file *fp) } else { fp->f_flag |= FMARK; } + mutex_exit(&fp->f_lock); return; } @@ -1352,10 +1390,10 @@ unp_discard(struct file *fp) { if (fp == NULL) return; - simple_lock(&fp->f_slock); + mutex_enter(&fp->f_lock); fp->f_usecount++; /* i.e. FILE_USE(fp) sans locking */ fp->f_msgcount--; - simple_unlock(&fp->f_slock); + mutex_exit(&fp->f_lock); unp_rights--; (void) closef(fp, (struct lwp *)0); }