Hopefully improve control message passing over Unix domain sockets.
1) Allow the sending of more than one control message at a time over a unix domain socket. This should cover the PR 29499. 2) This requires that unp_{ex,in}ternalize and unp_scan understand mbufs with more than one control message at a time. 3) Internalize and externalize used to work on the mbuf in-place. This made life quite complicated and the code for sizeof(int) < sizeof(file *) could end up doing the wrong thing. The patch always create a new mbuf/cluster now. This resulted in the change of the prototype for the domain externalise function. 4) You can now send SCM_TIMESTAMP messages. 5) Always use CMSG_DATA(cm) to determine the start where the data in unp_{ex,in}ternalize. It was using ((struct cmsghdr *)cm + 1) in some places, which gives the wrong alignment on the alpha. (NetBSD made this fix some time ago). This results in an ABI change for discriptor passing and creds passing on the alpha. (Probably on the IA64 and Spare ports too). 6) Fix userland programs to use CMSG_* macros too. 7) Be more careful about freeing mbufs containing (file *)s. This is made possible by the prototype change of externalise. PR: 29499 MFC after: 6 weeks
This commit is contained in:
parent
15821eba77
commit
2bc21ed985
@ -793,7 +793,10 @@ __msgread(sock, buf, cnt)
|
|||||||
{
|
{
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct cmessage cm;
|
union {
|
||||||
|
struct cmsghdr cmsg;
|
||||||
|
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
|
||||||
|
} cm;
|
||||||
|
|
||||||
bzero((char *)&cm, sizeof(cm));
|
bzero((char *)&cm, sizeof(cm));
|
||||||
iov[0].iov_base = buf;
|
iov[0].iov_base = buf;
|
||||||
@ -804,7 +807,7 @@ __msgread(sock, buf, cnt)
|
|||||||
msg.msg_name = NULL;
|
msg.msg_name = NULL;
|
||||||
msg.msg_namelen = 0;
|
msg.msg_namelen = 0;
|
||||||
msg.msg_control = (caddr_t)&cm;
|
msg.msg_control = (caddr_t)&cm;
|
||||||
msg.msg_controllen = sizeof(struct cmessage);
|
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
return(_recvmsg(sock, &msg, 0));
|
return(_recvmsg(sock, &msg, 0));
|
||||||
@ -818,7 +821,10 @@ __msgwrite(sock, buf, cnt)
|
|||||||
{
|
{
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct cmessage cm;
|
union {
|
||||||
|
struct cmsghdr cmsg;
|
||||||
|
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
|
||||||
|
} cm;
|
||||||
|
|
||||||
bzero((char *)&cm, sizeof(cm));
|
bzero((char *)&cm, sizeof(cm));
|
||||||
iov[0].iov_base = buf;
|
iov[0].iov_base = buf;
|
||||||
@ -826,14 +832,14 @@ __msgwrite(sock, buf, cnt)
|
|||||||
|
|
||||||
cm.cmsg.cmsg_type = SCM_CREDS;
|
cm.cmsg.cmsg_type = SCM_CREDS;
|
||||||
cm.cmsg.cmsg_level = SOL_SOCKET;
|
cm.cmsg.cmsg_level = SOL_SOCKET;
|
||||||
cm.cmsg.cmsg_len = sizeof(struct cmessage);
|
cm.cmsg.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
|
||||||
|
|
||||||
msg.msg_iov = iov;
|
msg.msg_iov = iov;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
msg.msg_name = NULL;
|
msg.msg_name = NULL;
|
||||||
msg.msg_namelen = 0;
|
msg.msg_namelen = 0;
|
||||||
msg.msg_control = (caddr_t)&cm;
|
msg.msg_control = (caddr_t)&cm;
|
||||||
msg.msg_controllen = sizeof(struct cmessage);
|
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
return(_sendmsg(sock, &msg, 0));
|
return(_sendmsg(sock, &msg, 0));
|
||||||
|
@ -400,8 +400,6 @@ read_vc(xprtp, buf, len)
|
|||||||
struct pollfd pollfd;
|
struct pollfd pollfd;
|
||||||
struct sockaddr *sa;
|
struct sockaddr *sa;
|
||||||
struct cmessage *cm;
|
struct cmessage *cm;
|
||||||
struct cmsghdr *cmp;
|
|
||||||
struct sockcred *sc;
|
|
||||||
|
|
||||||
xprt = (SVCXPRT *)(void *)xprtp;
|
xprt = (SVCXPRT *)(void *)xprtp;
|
||||||
assert(xprt != NULL);
|
assert(xprt != NULL);
|
||||||
@ -429,9 +427,7 @@ read_vc(xprtp, buf, len)
|
|||||||
if (sa->sa_family == AF_LOCAL) {
|
if (sa->sa_family == AF_LOCAL) {
|
||||||
cm = (struct cmessage *)xprt->xp_verf.oa_base;
|
cm = (struct cmessage *)xprt->xp_verf.oa_base;
|
||||||
if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) {
|
if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) {
|
||||||
cmp = &cm->cmsg;
|
xprt->xp_p2 = &cm->cmcred;
|
||||||
sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
|
|
||||||
xprt->xp_p2 = sc;
|
|
||||||
return (len);
|
return (len);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -638,8 +634,14 @@ __msgread_withcred(sock, buf, cnt, cmp)
|
|||||||
{
|
{
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
|
union {
|
||||||
|
struct cmsghdr cmsg;
|
||||||
|
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
|
||||||
|
} cm;
|
||||||
|
int ret;
|
||||||
|
|
||||||
bzero(cmp, sizeof(*cmp));
|
|
||||||
|
bzero(&cm, sizeof(cm));
|
||||||
iov[0].iov_base = buf;
|
iov[0].iov_base = buf;
|
||||||
iov[0].iov_len = cnt;
|
iov[0].iov_len = cnt;
|
||||||
|
|
||||||
@ -647,11 +649,14 @@ __msgread_withcred(sock, buf, cnt, cmp)
|
|||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
msg.msg_name = NULL;
|
msg.msg_name = NULL;
|
||||||
msg.msg_namelen = 0;
|
msg.msg_namelen = 0;
|
||||||
msg.msg_control = cmp;
|
msg.msg_control = &cm;
|
||||||
msg.msg_controllen = sizeof(struct cmessage);
|
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
return(_recvmsg(sock, &msg, 0));
|
ret = _recvmsg(sock, &msg, 0);
|
||||||
|
bcopy(&cm.cmsg, &cmp->cmsg, sizeof(cmp->cmsg));
|
||||||
|
bcopy(CMSG_DATA(&cm), &cmp->cmcred, sizeof(cmp->cmcred));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -113,9 +113,9 @@ int error;
|
|||||||
int n;
|
int n;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct {
|
union {
|
||||||
struct cmsghdr cmsg;
|
struct cmsghdr cmsg;
|
||||||
int fd;
|
char control[CMSG_SPACE(sizeof(int))];
|
||||||
} ctl;
|
} ctl;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -137,10 +137,10 @@ int error;
|
|||||||
* construct a suitable rights control message.
|
* construct a suitable rights control message.
|
||||||
*/
|
*/
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
ctl.fd = fd;
|
ctl.cmsg.cmsg_len = CMSG_LEN(sizeof(int));
|
||||||
ctl.cmsg.cmsg_len = sizeof(ctl);
|
|
||||||
ctl.cmsg.cmsg_level = SOL_SOCKET;
|
ctl.cmsg.cmsg_level = SOL_SOCKET;
|
||||||
ctl.cmsg.cmsg_type = SCM_RIGHTS;
|
ctl.cmsg.cmsg_type = SCM_RIGHTS;
|
||||||
|
*((int *)CMSG_DATA(&ctl.cmsg)) = fd;
|
||||||
msg.msg_control = (caddr_t) &ctl;
|
msg.msg_control = (caddr_t) &ctl;
|
||||||
msg.msg_controllen = ctl.cmsg.cmsg_len;
|
msg.msg_controllen = ctl.cmsg.cmsg_len;
|
||||||
}
|
}
|
||||||
|
@ -672,7 +672,7 @@ soreceive(so, psa, uio, mp0, controlp, flagsp)
|
|||||||
struct mbuf **controlp;
|
struct mbuf **controlp;
|
||||||
int *flagsp;
|
int *flagsp;
|
||||||
{
|
{
|
||||||
register struct mbuf *m, **mp;
|
struct mbuf *m, **mp;
|
||||||
register int flags, len, error, s, offset;
|
register int flags, len, error, s, offset;
|
||||||
struct protosw *pr = so->so_proto;
|
struct protosw *pr = so->so_proto;
|
||||||
struct mbuf *nextrecord;
|
struct mbuf *nextrecord;
|
||||||
@ -798,23 +798,22 @@ dontblock:
|
|||||||
m = m->m_next;
|
m = m->m_next;
|
||||||
} else {
|
} else {
|
||||||
sbfree(&so->so_rcv, m);
|
sbfree(&so->so_rcv, m);
|
||||||
if (controlp) {
|
so->so_rcv.sb_mb = m->m_next;
|
||||||
if (pr->pr_domain->dom_externalize &&
|
m->m_next = NULL;
|
||||||
mtod(m, struct cmsghdr *)->cmsg_type ==
|
if (pr->pr_domain->dom_externalize)
|
||||||
SCM_RIGHTS)
|
error =
|
||||||
error = (*pr->pr_domain->dom_externalize)(m);
|
(*pr->pr_domain->dom_externalize)(m, controlp);
|
||||||
|
else if (controlp)
|
||||||
*controlp = m;
|
*controlp = m;
|
||||||
so->so_rcv.sb_mb = m->m_next;
|
else
|
||||||
m->m_next = 0;
|
m_freem(m);
|
||||||
m = so->so_rcv.sb_mb;
|
m = so->so_rcv.sb_mb;
|
||||||
} else {
|
|
||||||
MFREE(m, so->so_rcv.sb_mb);
|
|
||||||
m = so->so_rcv.sb_mb;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (controlp) {
|
if (controlp) {
|
||||||
orig_resid = 0;
|
orig_resid = 0;
|
||||||
controlp = &(*controlp)->m_next;
|
do
|
||||||
|
controlp = &(*controlp)->m_next;
|
||||||
|
while (*controlp != NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m) {
|
if (m) {
|
||||||
|
@ -90,7 +90,8 @@ static void unp_gc __P((void));
|
|||||||
static void unp_scan __P((struct mbuf *, void (*)(struct file *)));
|
static void unp_scan __P((struct mbuf *, void (*)(struct file *)));
|
||||||
static void unp_mark __P((struct file *));
|
static void unp_mark __P((struct file *));
|
||||||
static void unp_discard __P((struct file *));
|
static void unp_discard __P((struct file *));
|
||||||
static int unp_internalize __P((struct mbuf *, struct thread *));
|
static void unp_freerights __P((struct file **, int));
|
||||||
|
static int unp_internalize __P((struct mbuf **, struct thread *));
|
||||||
static int unp_listen __P((struct unpcb *, struct proc *));
|
static int unp_listen __P((struct unpcb *, struct proc *));
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -274,7 +275,7 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
|||||||
goto release;
|
goto release;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (control && (error = unp_internalize(control, td)))
|
if (control && (error = unp_internalize(&control, td)))
|
||||||
goto release;
|
goto release;
|
||||||
|
|
||||||
switch (so->so_type) {
|
switch (so->so_type) {
|
||||||
@ -952,80 +953,127 @@ unp_drain()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
unp_freerights(rp, fdcount)
|
||||||
|
struct file **rp;
|
||||||
|
int fdcount;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct file *fp;
|
||||||
|
|
||||||
|
for (i = 0; i < fdcount; i++) {
|
||||||
|
fp = *rp;
|
||||||
|
/*
|
||||||
|
* zero the pointer before calling
|
||||||
|
* unp_discard since it may end up
|
||||||
|
* in unp_gc()..
|
||||||
|
*/
|
||||||
|
*rp++ = 0;
|
||||||
|
unp_discard(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
unp_externalize(rights)
|
unp_externalize(control, controlp)
|
||||||
struct mbuf *rights;
|
struct mbuf *control, **controlp;
|
||||||
{
|
{
|
||||||
struct thread *td = curthread; /* XXX */
|
struct thread *td = curthread; /* XXX */
|
||||||
register int i;
|
struct cmsghdr *cm = mtod(control, struct cmsghdr *);
|
||||||
register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
|
int i;
|
||||||
register int *fdp;
|
int *fdp;
|
||||||
register struct file **rp;
|
struct file **rp;
|
||||||
register struct file *fp;
|
struct file *fp;
|
||||||
int newfds = (cm->cmsg_len - (CMSG_DATA(cm) - (u_char *)cm))
|
void *data;
|
||||||
/ sizeof (struct file *);
|
socklen_t clen = control->m_len, datalen;
|
||||||
|
int error, newfds;
|
||||||
int f;
|
int f;
|
||||||
|
u_int newlen;
|
||||||
|
|
||||||
/*
|
error = 0;
|
||||||
* if the new FD's will not fit, then we free them all
|
if (controlp != NULL) /* controlp == NULL => free control messages */
|
||||||
*/
|
*controlp = NULL;
|
||||||
if (!fdavail(td, newfds)) {
|
|
||||||
rp = (struct file **)CMSG_DATA(cm);
|
while (cm != NULL) {
|
||||||
for (i = 0; i < newfds; i++) {
|
if (sizeof(*cm) > clen || cm->cmsg_len > clen) {
|
||||||
fp = *rp;
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = CMSG_DATA(cm);
|
||||||
|
datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
|
||||||
|
|
||||||
|
if (cm->cmsg_level == SOL_SOCKET
|
||||||
|
&& cm->cmsg_type == SCM_RIGHTS) {
|
||||||
|
newfds = datalen / sizeof(struct file *);
|
||||||
|
rp = data;
|
||||||
|
|
||||||
|
/* If we're not outputting the discriptors free them. */
|
||||||
|
if (error || controlp == NULL) {
|
||||||
|
unp_freerights(rp, newfds);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
/* if the new FD's will not fit free them. */
|
||||||
|
if (!fdavail(td, newfds)) {
|
||||||
|
error = EMSGSIZE;
|
||||||
|
unp_freerights(rp, newfds);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* zero the pointer before calling unp_discard,
|
* now change each pointer to an fd in the global
|
||||||
* since it may end up in unp_gc()..
|
* table to an integer that is the index to the
|
||||||
|
* local fd table entry that we set up to point
|
||||||
|
* to the global one we are transferring.
|
||||||
*/
|
*/
|
||||||
*rp++ = 0;
|
newlen = newfds * sizeof(int);
|
||||||
unp_discard(fp);
|
*controlp = sbcreatecontrol(NULL, newlen,
|
||||||
|
SCM_RIGHTS, SOL_SOCKET);
|
||||||
|
if (*controlp == NULL) {
|
||||||
|
error = E2BIG;
|
||||||
|
unp_freerights(rp, newfds);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdp = (int *)
|
||||||
|
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
|
||||||
|
for (i = 0; i < newfds; i++) {
|
||||||
|
if (fdalloc(td, 0, &f))
|
||||||
|
panic("unp_externalize fdalloc failed");
|
||||||
|
fp = *rp++;
|
||||||
|
td->td_proc->p_fd->fd_ofiles[f] = fp;
|
||||||
|
fp->f_msgcount--;
|
||||||
|
unp_rights--;
|
||||||
|
*fdp++ = f;
|
||||||
|
}
|
||||||
|
} else { /* We can just copy anything else across */
|
||||||
|
if (error || controlp == NULL)
|
||||||
|
goto next;
|
||||||
|
*controlp = sbcreatecontrol(NULL, datalen,
|
||||||
|
cm->cmsg_type, cm->cmsg_level);
|
||||||
|
if (*controlp == NULL) {
|
||||||
|
error = ENOBUFS;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
bcopy(data,
|
||||||
|
CMSG_DATA(mtod(*controlp, struct cmsghdr *)),
|
||||||
|
datalen);
|
||||||
}
|
}
|
||||||
return (EMSGSIZE);
|
|
||||||
}
|
controlp = &(*controlp)->m_next;
|
||||||
/*
|
|
||||||
* now change each pointer to an fd in the global table to
|
next:
|
||||||
* an integer that is the index to the local fd table entry
|
if (CMSG_SPACE(datalen) < clen) {
|
||||||
* that we set up to point to the global one we are transferring.
|
clen -= CMSG_SPACE(datalen);
|
||||||
* If sizeof (struct file *) is bigger than or equal to sizeof int,
|
cm = (struct cmsghdr *)
|
||||||
* then do it in forward order. In that case, an integer will
|
((caddr_t)cm + CMSG_SPACE(datalen));
|
||||||
* always come in the same place or before its corresponding
|
} else {
|
||||||
* struct file pointer.
|
clen = 0;
|
||||||
* If sizeof (struct file *) is smaller than sizeof int, then
|
cm = NULL;
|
||||||
* do it in reverse order.
|
|
||||||
*/
|
|
||||||
if (sizeof (struct file *) >= sizeof (int)) {
|
|
||||||
fdp = (int *)(cm + 1);
|
|
||||||
rp = (struct file **)CMSG_DATA(cm);
|
|
||||||
for (i = 0; i < newfds; i++) {
|
|
||||||
if (fdalloc(td, 0, &f))
|
|
||||||
panic("unp_externalize");
|
|
||||||
fp = *rp++;
|
|
||||||
td->td_proc->p_fd->fd_ofiles[f] = fp;
|
|
||||||
fp->f_msgcount--;
|
|
||||||
unp_rights--;
|
|
||||||
*fdp++ = f;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fdp = (int *)(cm + 1) + newfds - 1;
|
|
||||||
rp = (struct file **)CMSG_DATA(cm) + newfds - 1;
|
|
||||||
for (i = 0; i < newfds; i++) {
|
|
||||||
if (fdalloc(td, 0, &f))
|
|
||||||
panic("unp_externalize");
|
|
||||||
fp = *rp--;
|
|
||||||
td->td_proc->p_fd->fd_ofiles[f] = fp;
|
|
||||||
fp->f_msgcount--;
|
|
||||||
unp_rights--;
|
|
||||||
*fdp-- = f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
m_freem(control);
|
||||||
* Adjust length, in case sizeof(struct file *) and sizeof(int)
|
|
||||||
* differs.
|
return (error);
|
||||||
*/
|
|
||||||
cm->cmsg_len = CMSG_LEN(newfds * sizeof(int));
|
|
||||||
rights->m_len = cm->cmsg_len;
|
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1043,109 +1091,134 @@ unp_init(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
unp_internalize(control, td)
|
unp_internalize(controlp, td)
|
||||||
struct mbuf *control;
|
struct mbuf **controlp;
|
||||||
struct thread *td;
|
struct thread *td;
|
||||||
{
|
{
|
||||||
|
struct mbuf *control = *controlp;
|
||||||
struct proc *p = td->td_proc;
|
struct proc *p = td->td_proc;
|
||||||
struct filedesc *fdescp = p->p_fd;
|
struct filedesc *fdescp = p->p_fd;
|
||||||
register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
|
struct cmsghdr *cm = mtod(control, struct cmsghdr *);
|
||||||
register struct file **rp;
|
struct cmsgcred *cmcred;
|
||||||
register struct file *fp;
|
struct file **rp;
|
||||||
register int i, fd, *fdp;
|
struct file *fp;
|
||||||
register struct cmsgcred *cmcred;
|
struct timeval *tv;
|
||||||
int oldfds;
|
int i, fd, *fdp;
|
||||||
|
void *data;
|
||||||
|
socklen_t clen = control->m_len, datalen;
|
||||||
|
int error, oldfds;
|
||||||
u_int newlen;
|
u_int newlen;
|
||||||
|
|
||||||
if ((cm->cmsg_type != SCM_RIGHTS && cm->cmsg_type != SCM_CREDS) ||
|
error = 0;
|
||||||
cm->cmsg_level != SOL_SOCKET || cm->cmsg_len != control->m_len)
|
*controlp = NULL;
|
||||||
return (EINVAL);
|
|
||||||
|
|
||||||
/*
|
while (cm != NULL) {
|
||||||
* Fill in credential information.
|
if (sizeof(*cm) > clen || cm->cmsg_level != SOL_SOCKET
|
||||||
*/
|
|| cm->cmsg_len > clen) {
|
||||||
if (cm->cmsg_type == SCM_CREDS) {
|
error = EINVAL;
|
||||||
cmcred = (struct cmsgcred *)(cm + 1);
|
goto out;
|
||||||
cmcred->cmcred_pid = p->p_pid;
|
}
|
||||||
cmcred->cmcred_uid = p->p_ucred->cr_ruid;
|
|
||||||
cmcred->cmcred_gid = p->p_ucred->cr_rgid;
|
data = CMSG_DATA(cm);
|
||||||
cmcred->cmcred_euid = p->p_ucred->cr_uid;
|
datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
|
||||||
cmcred->cmcred_ngroups = MIN(p->p_ucred->cr_ngroups,
|
|
||||||
|
switch (cm->cmsg_type) {
|
||||||
|
/*
|
||||||
|
* Fill in credential information.
|
||||||
|
*/
|
||||||
|
case SCM_CREDS:
|
||||||
|
*controlp = sbcreatecontrol(NULL, sizeof(*cmcred),
|
||||||
|
SCM_CREDS, SOL_SOCKET);
|
||||||
|
if (*controlp == NULL) {
|
||||||
|
error = ENOBUFS;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmcred = (struct cmsgcred *)
|
||||||
|
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
|
||||||
|
cmcred->cmcred_pid = p->p_pid;
|
||||||
|
cmcred->cmcred_uid = p->p_ucred->cr_ruid;
|
||||||
|
cmcred->cmcred_gid = p->p_ucred->cr_rgid;
|
||||||
|
cmcred->cmcred_euid = p->p_ucred->cr_uid;
|
||||||
|
cmcred->cmcred_ngroups = MIN(p->p_ucred->cr_ngroups,
|
||||||
CMGROUP_MAX);
|
CMGROUP_MAX);
|
||||||
for (i = 0; i < cmcred->cmcred_ngroups; i++)
|
for (i = 0; i < cmcred->cmcred_ngroups; i++)
|
||||||
cmcred->cmcred_groups[i] = p->p_ucred->cr_groups[i];
|
cmcred->cmcred_groups[i] =
|
||||||
return(0);
|
p->p_ucred->cr_groups[i];
|
||||||
}
|
break;
|
||||||
|
|
||||||
oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
|
case SCM_RIGHTS:
|
||||||
/*
|
oldfds = datalen / sizeof (int);
|
||||||
* check that all the FDs passed in refer to legal OPEN files
|
/*
|
||||||
* If not, reject the entire operation.
|
* check that all the FDs passed in refer to legal files
|
||||||
*/
|
* If not, reject the entire operation.
|
||||||
fdp = (int *)(cm + 1);
|
*/
|
||||||
for (i = 0; i < oldfds; i++) {
|
fdp = data;
|
||||||
fd = *fdp++;
|
for (i = 0; i < oldfds; i++) {
|
||||||
if ((unsigned)fd >= fdescp->fd_nfiles ||
|
fd = *fdp++;
|
||||||
fdescp->fd_ofiles[fd] == NULL)
|
if ((unsigned)fd >= fdescp->fd_nfiles ||
|
||||||
return (EBADF);
|
fdescp->fd_ofiles[fd] == NULL) {
|
||||||
}
|
error = EBADF;
|
||||||
/*
|
goto out;
|
||||||
* Now replace the integer FDs with pointers to
|
}
|
||||||
* the associated global file table entry..
|
}
|
||||||
* Allocate a bigger buffer as necessary. But if an cluster is not
|
/*
|
||||||
* enough, return E2BIG.
|
* Now replace the integer FDs with pointers to
|
||||||
*/
|
* the associated global file table entry..
|
||||||
newlen = CMSG_LEN(oldfds * sizeof(struct file *));
|
*/
|
||||||
if (newlen > MCLBYTES)
|
newlen = oldfds * sizeof(struct file *);
|
||||||
return (E2BIG);
|
*controlp = sbcreatecontrol(NULL, newlen,
|
||||||
if (newlen - control->m_len > M_TRAILINGSPACE(control)) {
|
SCM_RIGHTS, SOL_SOCKET);
|
||||||
if (control->m_flags & M_EXT)
|
if (*controlp == NULL) {
|
||||||
return (E2BIG);
|
error = E2BIG;
|
||||||
MCLGET(control, M_TRYWAIT);
|
goto out;
|
||||||
if ((control->m_flags & M_EXT) == 0)
|
}
|
||||||
return (ENOBUFS);
|
|
||||||
|
|
||||||
/* copy the data to the cluster */
|
fdp = data;
|
||||||
memcpy(mtod(control, char *), cm, cm->cmsg_len);
|
rp = (struct file **)
|
||||||
cm = mtod(control, struct cmsghdr *);
|
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
|
||||||
}
|
for (i = 0; i < oldfds; i++) {
|
||||||
|
fp = fdescp->fd_ofiles[*fdp++];
|
||||||
|
*rp++ = fp;
|
||||||
|
fp->f_count++;
|
||||||
|
fp->f_msgcount++;
|
||||||
|
unp_rights++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
case SCM_TIMESTAMP:
|
||||||
* Adjust length, in case sizeof(struct file *) and sizeof(int)
|
*controlp = sbcreatecontrol(NULL, sizeof(*tv),
|
||||||
* differs.
|
SCM_TIMESTAMP, SOL_SOCKET);
|
||||||
*/
|
if (*controlp == NULL) {
|
||||||
control->m_len = cm->cmsg_len = newlen;
|
error = ENOBUFS;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
tv = (struct timeval *)
|
||||||
|
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
|
||||||
|
microtime(tv);
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
default:
|
||||||
* Transform the file descriptors into struct file pointers.
|
error = EINVAL;
|
||||||
* If sizeof (struct file *) is bigger than or equal to sizeof int,
|
goto out;
|
||||||
* then do it in reverse order so that the int won't get until
|
|
||||||
* we're done.
|
|
||||||
* If sizeof (struct file *) is smaller than sizeof int, then
|
|
||||||
* do it in forward order.
|
|
||||||
*/
|
|
||||||
if (sizeof (struct file *) >= sizeof (int)) {
|
|
||||||
fdp = (int *)(cm + 1) + oldfds - 1;
|
|
||||||
rp = (struct file **)CMSG_DATA(cm) + oldfds - 1;
|
|
||||||
for (i = 0; i < oldfds; i++) {
|
|
||||||
fp = fdescp->fd_ofiles[*fdp--];
|
|
||||||
*rp-- = fp;
|
|
||||||
fp->f_count++;
|
|
||||||
fp->f_msgcount++;
|
|
||||||
unp_rights++;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
fdp = (int *)(cm + 1);
|
controlp = &(*controlp)->m_next;
|
||||||
rp = (struct file **)CMSG_DATA(cm);
|
|
||||||
for (i = 0; i < oldfds; i++) {
|
if (CMSG_SPACE(datalen) < clen) {
|
||||||
fp = fdescp->fd_ofiles[*fdp++];
|
clen -= CMSG_SPACE(datalen);
|
||||||
*rp++ = fp;
|
cm = (struct cmsghdr *)
|
||||||
fp->f_count++;
|
((caddr_t)cm + CMSG_SPACE(datalen));
|
||||||
fp->f_msgcount++;
|
} else {
|
||||||
unp_rights++;
|
clen = 0;
|
||||||
|
cm = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (0);
|
|
||||||
|
out:
|
||||||
|
m_freem(control);
|
||||||
|
|
||||||
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unp_defer, unp_gcing;
|
static int unp_defer, unp_gcing;
|
||||||
@ -1343,28 +1416,48 @@ unp_scan(m0, op)
|
|||||||
register struct mbuf *m0;
|
register struct mbuf *m0;
|
||||||
void (*op) __P((struct file *));
|
void (*op) __P((struct file *));
|
||||||
{
|
{
|
||||||
register struct mbuf *m;
|
struct mbuf *m;
|
||||||
register struct file **rp;
|
struct file **rp;
|
||||||
register struct cmsghdr *cm;
|
struct cmsghdr *cm;
|
||||||
register int i;
|
void *data;
|
||||||
|
int i;
|
||||||
|
socklen_t clen, datalen;
|
||||||
int qfds;
|
int qfds;
|
||||||
|
|
||||||
while (m0) {
|
while (m0) {
|
||||||
for (m = m0; m; m = m->m_next)
|
for (m = m0; m; m = m->m_next) {
|
||||||
if (m->m_type == MT_CONTROL &&
|
if (m->m_type == MT_CONTROL)
|
||||||
m->m_len >= sizeof(*cm)) {
|
continue;
|
||||||
cm = mtod(m, struct cmsghdr *);
|
|
||||||
if (cm->cmsg_level != SOL_SOCKET ||
|
cm = mtod(m, struct cmsghdr *);
|
||||||
cm->cmsg_type != SCM_RIGHTS)
|
clen = m->m_len;
|
||||||
continue;
|
|
||||||
qfds = (cm->cmsg_len -
|
while (cm != NULL) {
|
||||||
(CMSG_DATA(cm) - (u_char *)cm))
|
if (sizeof(*cm) > clen || cm->cmsg_len > clen)
|
||||||
/ sizeof (struct file *);
|
break;
|
||||||
rp = (struct file **)CMSG_DATA(cm);
|
|
||||||
for (i = 0; i < qfds; i++)
|
data = CMSG_DATA(cm);
|
||||||
(*op)(*rp++);
|
datalen = (caddr_t)cm + cm->cmsg_len
|
||||||
break; /* XXX, but saves time */
|
- (caddr_t)data;
|
||||||
|
|
||||||
|
if (cm->cmsg_level == SOL_SOCKET &&
|
||||||
|
cm->cmsg_type == SCM_RIGHTS) {
|
||||||
|
qfds = datalen / sizeof (struct file *);
|
||||||
|
rp = data;
|
||||||
|
for (i = 0; i < qfds; i++)
|
||||||
|
(*op)(*rp++);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CMSG_SPACE(datalen) < clen) {
|
||||||
|
clen -= CMSG_SPACE(datalen);
|
||||||
|
cm = (struct cmsghdr *)
|
||||||
|
((caddr_t)cm + CMSG_SPACE(datalen));
|
||||||
|
} else {
|
||||||
|
clen = 0;
|
||||||
|
cm = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
m0 = m0->m_act;
|
m0 = m0->m_act;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -583,7 +583,7 @@ ng_internalize(struct mbuf *control, struct thread *td)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check there is only one FD. XXX what would more than one signify? */
|
/* Check there is only one FD. XXX what would more than one signify? */
|
||||||
oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int);
|
oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int);
|
||||||
if (oldfds != 1) {
|
if (oldfds != 1) {
|
||||||
TRAP_ERROR;
|
TRAP_ERROR;
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
@ -591,7 +591,7 @@ ng_internalize(struct mbuf *control, struct thread *td)
|
|||||||
|
|
||||||
/* Check that the FD given is legit. and change it to a pointer to a
|
/* Check that the FD given is legit. and change it to a pointer to a
|
||||||
* struct file. */
|
* struct file. */
|
||||||
fd = *(int *) (cm + 1);
|
fd = CMSG_DATA(cm);
|
||||||
if ((unsigned) fd >= fdp->fd_nfiles
|
if ((unsigned) fd >= fdp->fd_nfiles
|
||||||
|| (fp = fdp->fd_ofiles[fd]) == NULL) {
|
|| (fp = fdp->fd_ofiles[fd]) == NULL) {
|
||||||
return (EBADF);
|
return (EBADF);
|
||||||
|
@ -52,7 +52,7 @@ struct domain {
|
|||||||
void (*dom_init) /* initialize domain data structures */
|
void (*dom_init) /* initialize domain data structures */
|
||||||
__P((void));
|
__P((void));
|
||||||
int (*dom_externalize) /* externalize access rights */
|
int (*dom_externalize) /* externalize access rights */
|
||||||
__P((struct mbuf *));
|
__P((struct mbuf *, struct mbuf **));
|
||||||
void (*dom_dispose) /* dispose of internalized rights */
|
void (*dom_dispose) /* dispose of internalized rights */
|
||||||
__P((struct mbuf *));
|
__P((struct mbuf *));
|
||||||
struct protosw *dom_protosw, *dom_protoswNPROTOSW;
|
struct protosw *dom_protosw, *dom_protoswNPROTOSW;
|
||||||
|
@ -59,7 +59,7 @@ int uipc_usrreq __P((struct socket *so, int req, struct mbuf *m,
|
|||||||
struct mbuf *nam, struct mbuf *control));
|
struct mbuf *nam, struct mbuf *control));
|
||||||
int unp_connect2 __P((struct socket *so, struct socket *so2));
|
int unp_connect2 __P((struct socket *so, struct socket *so2));
|
||||||
void unp_dispose __P((struct mbuf *m));
|
void unp_dispose __P((struct mbuf *m));
|
||||||
int unp_externalize __P((struct mbuf *rights));
|
int unp_externalize __P((struct mbuf *mbuf, struct mbuf **controlp));
|
||||||
void unp_init __P((void));
|
void unp_init __P((void));
|
||||||
extern struct pr_usrreqs uipc_usrreqs;
|
extern struct pr_usrreqs uipc_usrreqs;
|
||||||
#else /* !_KERNEL */
|
#else /* !_KERNEL */
|
||||||
|
@ -113,9 +113,9 @@ int error;
|
|||||||
int n;
|
int n;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct {
|
union {
|
||||||
struct cmsghdr cmsg;
|
struct cmsghdr cmsg;
|
||||||
int fd;
|
char control[CMSG_SPACE(sizeof(int))];
|
||||||
} ctl;
|
} ctl;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -137,10 +137,10 @@ int error;
|
|||||||
* construct a suitable rights control message.
|
* construct a suitable rights control message.
|
||||||
*/
|
*/
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
ctl.fd = fd;
|
ctl.cmsg.cmsg_len = CMSG_LEN(sizeof(int));
|
||||||
ctl.cmsg.cmsg_len = sizeof(ctl);
|
|
||||||
ctl.cmsg.cmsg_level = SOL_SOCKET;
|
ctl.cmsg.cmsg_level = SOL_SOCKET;
|
||||||
ctl.cmsg.cmsg_type = SCM_RIGHTS;
|
ctl.cmsg.cmsg_type = SCM_RIGHTS;
|
||||||
|
*((int *)CMSG_DATA(&ctl.cmsg)) = fd;
|
||||||
msg.msg_control = (caddr_t) &ctl;
|
msg.msg_control = (caddr_t) &ctl;
|
||||||
msg.msg_controllen = ctl.cmsg.cmsg_len;
|
msg.msg_controllen = ctl.cmsg.cmsg_len;
|
||||||
}
|
}
|
||||||
|
@ -1364,8 +1364,8 @@ bundle_ReceiveDatalink(struct bundle *bundle, int s)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = (int *)(cmsg + 1);
|
fd = (int *)CMSG_DATA(cmsg);
|
||||||
nfd = (cmsg->cmsg_len - sizeof *cmsg) / sizeof(int);
|
nfd = ((caddr_t)cmsg + cmsg->cmsg_len - (caddr_t)fd) / sizeof(int);
|
||||||
|
|
||||||
if (nfd < 2) {
|
if (nfd < 2) {
|
||||||
log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n",
|
log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n",
|
||||||
@ -1457,7 +1457,7 @@ bundle_ReceiveDatalink(struct bundle *bundle, int s)
|
|||||||
void
|
void
|
||||||
bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
|
bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
|
||||||
{
|
{
|
||||||
char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD];
|
char cmsgbuf[CMSG_SPACE(sizeof(int) * SEND_MAXFD)];
|
||||||
const char *constlock;
|
const char *constlock;
|
||||||
char *lock;
|
char *lock;
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
@ -1507,7 +1507,7 @@ bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
|
|||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
msg.msg_iov = iov;
|
msg.msg_iov = iov;
|
||||||
msg.msg_control = cmsgbuf;
|
msg.msg_control = cmsgbuf;
|
||||||
msg.msg_controllen = sizeof *cmsg + sizeof(int) * nfd;
|
msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfd);
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
cmsg = (struct cmsghdr *)cmsgbuf;
|
cmsg = (struct cmsghdr *)cmsgbuf;
|
||||||
@ -1516,7 +1516,7 @@ bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
|
|||||||
cmsg->cmsg_type = SCM_RIGHTS;
|
cmsg->cmsg_type = SCM_RIGHTS;
|
||||||
|
|
||||||
for (f = 0; f < nfd; f++)
|
for (f = 0; f < nfd; f++)
|
||||||
*((int *)(cmsg + 1) + f) = fd[f];
|
*((int *)CMSG_DATA(cmsg) + f) = fd[f];
|
||||||
|
|
||||||
for (f = 1, expect = 0; f < niov; f++)
|
for (f = 1, expect = 0; f < niov; f++)
|
||||||
expect += iov[f].iov_len;
|
expect += iov[f].iov_len;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user