goto release;
}
- if (control && (error = unp_internalize(control, p)))
- goto release;
+ if (control) {
+ socket_unlock(so, 0); /* release global lock to avoid deadlock (4436174) */
+ error = unp_internalize(control, p);
+ socket_lock(so, 0);
+ if (error)
+ goto release;
+ }
switch (so->so_type) {
case SOCK_DGRAM:
char buf[SOCK_MAXADDRLEN];
context.vc_proc = p;
- context.vc_ucred = p->p_ucred; /* XXX kauth_cred_get() ??? proxy */
+ context.vc_ucred = kauth_cred_proc_ref(p); /* XXX kauth_cred_get() ??? proxy */
- if (unp->unp_vnode != NULL)
+ if (unp->unp_vnode != NULL) {
+ kauth_cred_unref(&context.vc_ucred);
return (EINVAL);
+ }
namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path);
- if (namelen <= 0)
+ if (namelen <= 0) {
+ kauth_cred_unref(&context.vc_ucred);
return EINVAL;
+ }
strncpy(buf, soun->sun_path, namelen);
buf[namelen] = 0; /* null-terminate the string */
NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE32,
/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
error = namei(&nd);
if (error) {
+ kauth_cred_unref(&context.vc_ucred);
return (error);
}
dvp = nd.ni_dvp;
vnode_put(dvp);
vnode_put(vp);
+ kauth_cred_unref(&context.vc_ucred);
return (EADDRINUSE);
}
vnode_put(dvp);
if (error) {
+ kauth_cred_unref(&context.vc_ucred);
return (error);
}
vnode_ref(vp); /* gain a longterm reference */
unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam, 1);
vnode_put(vp); /* drop the iocount */
+ kauth_cred_unref(&context.vc_ucred);
return (0);
}
char buf[SOCK_MAXADDRLEN];
context.vc_proc = p;
- context.vc_ucred = p->p_ucred; /* XXX kauth_cred_get() ??? proxy */
+ context.vc_ucred = kauth_cred_proc_ref(p); /* XXX kauth_cred_get() ??? proxy */
so2 = so3 = NULL;
len = nam->sa_len - offsetof(struct sockaddr_un, sun_path);
- if (len <= 0)
+ if (len <= 0) {
+ kauth_cred_unref(&context.vc_ucred);
return EINVAL;
+ }
strncpy(buf, soun->sun_path, len);
buf[len] = 0;
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE32, CAST_USER_ADDR_T(buf), &context);
error = namei(&nd);
if (error) {
+ kauth_cred_unref(&context.vc_ucred);
return (error);
}
nameidone(&nd);
* from its process structure at the time of connect()
* (which is now).
*/
- cru2x(p->p_ucred, &unp3->unp_peercred);
+ cru2x(context.vc_ucred, &unp3->unp_peercred);
unp3->unp_flags |= UNP_HAVEPC;
/*
* The receiver's (server's) credentials are copied
so2->so_usecount--; /* release count on socket */
vnode_put(vp);
+ kauth_cred_unref(&context.vc_ucred);
return (error);
}
bzero(fp, sizeof(struct fileproc));
fp->f_iocount = 0;
fp->f_fglob = fg;
- p->p_fd->fd_ofiles[f] = fp;
fg_removeuipc(fg);
- *fdflags(p, f) &= ~UF_RESERVED;
+ procfdtbl_releasefd(p, f, fp);
unp_rights--;
*(int *)rp++ = f;
}
return (0);
}
-static int unp_defer, unp_gcing;
+static int unp_defer, unp_gcing, unp_gcwait;
+/* always called under uipc_lock */
+void
+unp_gc_wait(void)
+{
+ while (unp_gcing != 0) {
+ unp_gcwait = 1;
+ msleep(&unp_gcing, uipc_lock, 0 , "unp_gc_wait", NULL);
+ }
+}
static void
unp_gc()
register struct socket *so;
struct fileglob **extra_ref, **fpp;
int nunref, i;
-
+ int need_gcwakeup = 0;
+
lck_mtx_lock(uipc_lock);
if (unp_gcing) {
lck_mtx_unlock(uipc_lock);
}
for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
closef_locked((struct fileproc *)0, *fpp, (struct proc *) NULL);
+ lck_mtx_lock(uipc_lock);
unp_gcing = 0;
+
+ if (unp_gcwait != 0) {
+ unp_gcwait = 0;
+ need_gcwakeup = 1;
+ }
+ lck_mtx_unlock(uipc_lock);
+
+ if (need_gcwakeup != 0)
+ wakeup(&unp_gcing);
FREE((caddr_t)extra_ref, M_FILEGLOB);
}
struct unpcb *unp,
struct proc *p)
{
-
- cru2x(p->p_ucred, &unp->unp_peercred);
+ kauth_cred_t safecred = kauth_cred_proc_ref(p);
+ cru2x(safecred, &unp->unp_peercred);
+ kauth_cred_unref(&safecred);
unp->unp_flags |= UNP_HAVEPCCACHED;
return (0);
}