/*
- * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/fcntl.h>
#include <sys/malloc.h> /* XXX must be before <sys/file.h> */
#include <sys/file_internal.h>
+#include <sys/guarded.h>
#include <sys/filedesc.h>
#include <sys/lock.h>
#include <sys/mbuf.h>
#include <security/mac_framework.h>
#endif /* CONFIG_MACF */
+#include <mach/vm_param.h>
+
#define f_msgcount f_fglob->fg_msgcount
#define f_cred f_fglob->fg_cred
#define f_ops f_fglob->fg_ops
}
struct pr_usrreqs uipc_usrreqs = {
- uipc_abort, uipc_accept, uipc_attach, uipc_bind, uipc_connect,
- uipc_connect2, pru_control_notsupp, uipc_detach, uipc_disconnect,
- uipc_listen, uipc_peeraddr, uipc_rcvd, pru_rcvoob_notsupp,
- uipc_send, uipc_sense, uipc_shutdown, uipc_sockaddr,
- sosend, soreceive, pru_sopoll_notsupp
+ .pru_abort = uipc_abort,
+ .pru_accept = uipc_accept,
+ .pru_attach = uipc_attach,
+ .pru_bind = uipc_bind,
+ .pru_connect = uipc_connect,
+ .pru_connect2 = uipc_connect2,
+ .pru_detach = uipc_detach,
+ .pru_disconnect = uipc_disconnect,
+ .pru_listen = uipc_listen,
+ .pru_peeraddr = uipc_peeraddr,
+ .pru_rcvd = uipc_rcvd,
+ .pru_send = uipc_send,
+ .pru_sense = uipc_sense,
+ .pru_shutdown = uipc_shutdown,
+ .pru_sockaddr = uipc_sockaddr,
+ .pru_sosend = sosend,
+ .pru_soreceive = soreceive,
};
int
uipc_ctloutput(struct socket *so, struct sockopt *sopt)
{
struct unpcb *unp = sotounpcb(so);
- int error;
+ int error = 0;
+ pid_t peerpid;
+ struct socket *peerso;
switch (sopt->sopt_dir) {
case SOPT_GET:
error = EINVAL;
}
break;
+ case LOCAL_PEERPID:
+ case LOCAL_PEEREPID:
+ if (unp->unp_conn == NULL) {
+ error = ENOTCONN;
+ break;
+ }
+ peerso = unp->unp_conn->unp_socket;
+ if (peerso == NULL)
+ panic("peer is connected but has no socket?");
+ unp_get_locks_in_order(so, peerso);
+ if (sopt->sopt_name == LOCAL_PEEREPID &&
+ peerso->so_flags & SOF_DELEGATED)
+ peerpid = peerso->e_pid;
+ else
+ peerpid = peerso->last_pid;
+ socket_unlock(peerso, 1);
+ error = sooptcopyout(sopt, &peerpid, sizeof (peerpid));
+ break;
+ case LOCAL_PEERUUID:
+ case LOCAL_PEEREUUID:
+ if (unp->unp_conn == NULL) {
+ error = ENOTCONN;
+ break;
+ }
+ peerso = unp->unp_conn->unp_socket;
+ if (peerso == NULL)
+ panic("peer is connected but has no socket?");
+ unp_get_locks_in_order(so, peerso);
+ if (sopt->sopt_name == LOCAL_PEEREUUID &&
+ peerso->so_flags & SOF_DELEGATED)
+ error = sooptcopyout(sopt, &peerso->e_uuid,
+ sizeof (peerso->e_uuid));
+ else
+ error = sooptcopyout(sopt, &peerso->last_uuid,
+ sizeof (peerso->last_uuid));
+ socket_unlock(peerso, 1);
+ break;
default:
error = EOPNOTSUPP;
break;
error = EOPNOTSUPP;
break;
}
+
return (error);
}
lck_rw_lock_exclusive(unp_list_mtx);
LIST_REMOVE(unp, unp_link);
+ --unp_count;
+ ++unp_gencnt;
lck_rw_done(unp_list_mtx);
if (unp->unp_vnode) {
struct vnode *tvp = NULL;
if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
(so3 = sonewconn(so2, 0, nam)) == 0) {
error = ECONNREFUSED;
- socket_unlock(so2, 1);
- socket_lock(so, 0);
+ if (so != so2) {
+ socket_unlock(so2, 1);
+ socket_lock(so, 0);
+ } else {
+ socket_lock(so, 0);
+ /* Release the reference held for
+ * listen socket.
+ */
+ so2->so_usecount--;
+ }
goto out;
}
unp2 = sotounpcb(so2);
unpcb_to_compat(struct unpcb *up, struct unpcb_compat *cp)
{
#if defined(__LP64__)
- cp->unp_link.le_next = (u_int32_t)(uintptr_t)up->unp_link.le_next;
- cp->unp_link.le_prev = (u_int32_t)(uintptr_t)up->unp_link.le_prev;
+ cp->unp_link.le_next = (u_int32_t)
+ VM_KERNEL_ADDRPERM(up->unp_link.le_next);
+ cp->unp_link.le_prev = (u_int32_t)
+ VM_KERNEL_ADDRPERM(up->unp_link.le_prev);
#else
- cp->unp_link.le_next = (struct unpcb_compat *)up->unp_link.le_next;
- cp->unp_link.le_prev = (struct unpcb_compat **)up->unp_link.le_prev;
+ cp->unp_link.le_next = (struct unpcb_compat *)
+ VM_KERNEL_ADDRPERM(up->unp_link.le_next);
+ cp->unp_link.le_prev = (struct unpcb_compat **)
+ VM_KERNEL_ADDRPERM(up->unp_link.le_prev);
#endif
- cp->unp_socket = (_UNPCB_PTR(struct socket *))(uintptr_t)up->unp_socket;
- cp->unp_vnode = (_UNPCB_PTR(struct vnode *))(uintptr_t)up->unp_vnode;
+ cp->unp_socket = (_UNPCB_PTR(struct socket *))
+ VM_KERNEL_ADDRPERM(up->unp_socket);
+ cp->unp_vnode = (_UNPCB_PTR(struct vnode *))
+ VM_KERNEL_ADDRPERM(up->unp_vnode);
cp->unp_ino = up->unp_ino;
cp->unp_conn = (_UNPCB_PTR(struct unpcb_compat *))
- (uintptr_t)up->unp_conn;
- cp->unp_refs = (u_int32_t)(uintptr_t)up->unp_refs.lh_first;
+ VM_KERNEL_ADDRPERM(up->unp_conn);
+ cp->unp_refs = (u_int32_t)VM_KERNEL_ADDRPERM(up->unp_refs.lh_first);
#if defined(__LP64__)
cp->unp_reflink.le_next =
- (u_int32_t)(uintptr_t)up->unp_reflink.le_next;
+ (u_int32_t)VM_KERNEL_ADDRPERM(up->unp_reflink.le_next);
cp->unp_reflink.le_prev =
- (u_int32_t)(uintptr_t)up->unp_reflink.le_prev;
+ (u_int32_t)VM_KERNEL_ADDRPERM(up->unp_reflink.le_prev);
#else
cp->unp_reflink.le_next =
- (struct unpcb_compat *)up->unp_reflink.le_next;
+ (struct unpcb_compat *)VM_KERNEL_ADDRPERM(up->unp_reflink.le_next);
cp->unp_reflink.le_prev =
- (struct unpcb_compat **)up->unp_reflink.le_prev;
+ (struct unpcb_compat **)VM_KERNEL_ADDRPERM(up->unp_reflink.le_prev);
#endif
cp->unp_addr = (_UNPCB_PTR(struct sockaddr_un *))
- (uintptr_t)up->unp_addr;
+ VM_KERNEL_ADDRPERM(up->unp_addr);
cp->unp_cc = up->unp_cc;
cp->unp_mbcnt = up->unp_mbcnt;
cp->unp_gencnt = up->unp_gencnt;
bzero(&xu, sizeof (xu));
xu.xu_len = sizeof (xu);
xu.xu_unpp = (_UNPCB_PTR(struct unpcb_compat *))
- (uintptr_t)unp;
+ VM_KERNEL_ADDRPERM(unp);
/*
* XXX - need more locking here to protect against
* connect/disconnect races for SMP.
(caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb",
"List of active local stream sockets");
-#if !CONFIG_EMBEDDED
static int
unp_pcblist64 SYSCTL_HANDLER_ARGS
bzero(&xu, xu_len);
xu.xu_len = xu_len;
- xu.xu_unpp = (u_int64_t)(uintptr_t)unp;
- xu.xunp_link.le_next =
- (u_int64_t)(uintptr_t)unp->unp_link.le_next;
- xu.xunp_link.le_prev =
- (u_int64_t)(uintptr_t)unp->unp_link.le_prev;
- xu.xunp_socket = (u_int64_t)(uintptr_t)unp->unp_socket;
- xu.xunp_vnode = (u_int64_t)(uintptr_t)unp->unp_vnode;
+ xu.xu_unpp = (u_int64_t)VM_KERNEL_ADDRPERM(unp);
+ xu.xunp_link.le_next = (u_int64_t)
+ VM_KERNEL_ADDRPERM(unp->unp_link.le_next);
+ xu.xunp_link.le_prev = (u_int64_t)
+ VM_KERNEL_ADDRPERM(unp->unp_link.le_prev);
+ xu.xunp_socket = (u_int64_t)
+ VM_KERNEL_ADDRPERM(unp->unp_socket);
+ xu.xunp_vnode = (u_int64_t)
+ VM_KERNEL_ADDRPERM(unp->unp_vnode);
xu.xunp_ino = unp->unp_ino;
- xu.xunp_conn = (u_int64_t)(uintptr_t)unp->unp_conn;
- xu.xunp_refs = (u_int64_t)(uintptr_t)unp->unp_refs.lh_first;
- xu.xunp_reflink.le_next =
- (u_int64_t)(uintptr_t)unp->unp_reflink.le_next;
- xu.xunp_reflink.le_prev =
- (u_int64_t)(uintptr_t)unp->unp_reflink.le_prev;
+ xu.xunp_conn = (u_int64_t)
+ VM_KERNEL_ADDRPERM(unp->unp_conn);
+ xu.xunp_refs = (u_int64_t)
+ VM_KERNEL_ADDRPERM(unp->unp_refs.lh_first);
+ xu.xunp_reflink.le_next = (u_int64_t)
+ VM_KERNEL_ADDRPERM(unp->unp_reflink.le_next);
+ xu.xunp_reflink.le_prev = (u_int64_t)
+ VM_KERNEL_ADDRPERM(unp->unp_reflink.le_prev);
xu.xunp_cc = unp->unp_cc;
xu.xunp_mbcnt = unp->unp_mbcnt;
xu.xunp_gencnt = unp->unp_gencnt;
(caddr_t)(long)SOCK_STREAM, 0, unp_pcblist64, "S,xunpcb64",
"List of active local stream sockets 64 bit");
-#endif /* !CONFIG_EMBEDDED */
static void
unp_shutdown(struct unpcb *unp)
if (fdalloc(p, 0, &f))
panic("unp_externalize:fdalloc");
fg = rp[i];
- MALLOC_ZONE(fp, struct fileproc *, sizeof (struct fileproc),
- M_FILEPROC, M_WAITOK);
+ fp = fileproc_alloc_init(NULL);
if (fp == NULL)
panic("unp_externalize: MALLOC_ZONE");
- bzero(fp, sizeof (struct fileproc));
fp->f_iocount = 0;
fp->f_fglob = fg;
fg_removeuipc(fg);
if (((error = fdgetf_noref(p, fds[i], &tmpfp)) != 0)) {
proc_fdunlock(p);
return (error);
- } else if (!filetype_issendable(tmpfp->f_fglob->fg_type)) {
+ } else if (!filetype_issendable(FILEGLOB_DTYPE(tmpfp->f_fglob))) {
proc_fdunlock(p);
return (EINVAL);
+ } else if (FP_ISGUARDED(tmpfp, GUARD_SOCKET_IPC)) {
+ error = fp_guard_exception(p,
+ fds[i], tmpfp, kGUARD_EXC_SOCKET_IPC);
+ proc_fdunlock(p);
+ return (error);
}
}
rp = (struct fileglob **)(cm + 1);
* accessible and not already marked so.
* Now check if it is possibly one of OUR sockets.
*/
- if (fg->fg_type != DTYPE_SOCKET ||
+ if (FILEGLOB_DTYPE(fg) != DTYPE_SOCKET ||
(so = (struct socket *)fg->fg_data) == 0) {
lck_mtx_unlock(&fg->fg_lock);
continue;
}
- if (so->so_proto->pr_domain != &localdomain ||
+ if (so->so_proto->pr_domain != localdomain ||
(so->so_proto->pr_flags&PR_RIGHTS) == 0) {
lck_mtx_unlock(&fg->fg_lock);
continue;
tfg = *fpp;
- if (tfg->fg_type == DTYPE_SOCKET && tfg->fg_data != NULL) {
+ if (FILEGLOB_DTYPE(tfg) == DTYPE_SOCKET &&
+ tfg->fg_data != NULL) {
so = (struct socket *)(tfg->fg_data);
socket_lock(so, 0);
lck_mtx_unlock(mutex_held);
- unp->unp_gencnt = ++unp_gencnt;
+ lck_mtx_destroy(&unp->unp_mtx, unp_mtx_grp);
zfree(unp_zone, unp);
- --unp_count;
unp_gc();
} else {