File descriptor passing internalizes process fd's to an array of
struct file *. This results in tricky pointer management.
How about passing it as an array of structs instead. Only one field
inside for now, struct file *. However soon I'll need to pass additional
fields along with the file, and I didn't want to use the low bits of the
pointer :)
Index: kern/uipc_usrreq.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.109
diff -u -p -u -r1.109 uipc_usrreq.c
--- kern/uipc_usrreq.c 29 Dec 2016 12:12:43 -0000 1.109
+++ kern/uipc_usrreq.c 23 Jan 2017 23:02:15 -0000
@@ -63,8 +63,8 @@ LIST_HEAD(unp_head, unpcb) unp_head = LI
struct unp_deferral {
SLIST_ENTRY(unp_deferral) ud_link;
int ud_n;
- /* followed by ud_n struct file * pointers */
- struct file *ud_fp[];
+ /* followed by ud_n struct fdpass */
+ struct fdpass ud_fp[];
};
/* list of sets of files that were sent over sockets that are now closed */
@@ -664,12 +664,12 @@ unp_externalize(struct mbuf *rights, soc
struct proc *p = curproc; /* XXX */
struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
int i, *fdp = NULL;
- struct file **rp;
+ struct fdpass *rp;
struct file *fp;
int nfds, error = 0;
nfds = (cm->cmsg_len - CMSG_ALIGN(sizeof(*cm))) /
- sizeof(struct file *);
+ sizeof(struct fdpass);
if (controllen < CMSG_ALIGN(sizeof(struct cmsghdr)))
controllen = 0;
else
@@ -680,9 +680,10 @@ unp_externalize(struct mbuf *rights, soc
}
/* Make sure the recipient should be able to see the descriptors.. */
- rp = (struct file **)CMSG_DATA(cm);
+ rp = (struct fdpass *)CMSG_DATA(cm);
for (i = 0; i < nfds; i++) {
- fp = *rp++;
+ fp = rp->fp;
+ rp++;
error = pledge_recvfd(p, fp);
if (error)
break;
@@ -709,7 +710,7 @@ restart:
fdplock(p->p_fd);
if (error != 0) {
if (nfds > 0) {
- rp = ((struct file **)CMSG_DATA(cm));
+ rp = ((struct fdpass *)CMSG_DATA(cm));
unp_discard(rp, nfds);
}
goto out;
@@ -719,7 +720,7 @@ restart:
* First loop -- allocate file descriptor table slots for the
* new descriptors.
*/
- rp = ((struct file **)CMSG_DATA(cm));
+ rp = ((struct fdpass *)CMSG_DATA(cm));
for (i = 0; i < nfds; i++) {
if ((error = fdalloc(p, 0, &fdp[i])) != 0) {
/*
@@ -748,7 +749,8 @@ restart:
* fdalloc() works properly.. We finalize it all
* in the loop below.
*/
- p->p_fd->fd_ofiles[fdp[i]] = *rp++;
+ p->p_fd->fd_ofiles[fdp[i]] = rp->fp;
+ rp++;
if (flags & MSG_CMSG_CLOEXEC)
p->p_fd->fd_ofileflags[fdp[i]] |= UF_EXCLOSE;
@@ -758,11 +760,12 @@ restart:
* Now that adding them has succeeded, update all of the
* descriptor passing state.
*/
- rp = (struct file **)CMSG_DATA(cm);
+ rp = (struct fdpass *)CMSG_DATA(cm);
for (i = 0; i < nfds; i++) {
struct unpcb *unp;
- fp = *rp++;
+ fp = rp->fp;
+ rp++;
if ((unp = fptounp(fp)) != NULL)
unp->unp_msgcount--;
unp_rights--;
@@ -787,7 +790,8 @@ unp_internalize(struct mbuf *control, st
{
struct filedesc *fdp = p->p_fd;
struct cmsghdr *cm = mtod(control, struct cmsghdr *);
- struct file **rp, *fp;
+ struct fdpass *rp;
+ struct file *fp;
struct unpcb *unp;
int i, error;
int nfds, *ip, fd, neededspace;
@@ -807,7 +811,7 @@ unp_internalize(struct mbuf *control, st
/* Make sure we have room for the struct file pointers */
morespace:
- neededspace = CMSG_SPACE(nfds * sizeof(struct file *)) -
+ neededspace = CMSG_SPACE(nfds * sizeof(struct fdpass)) -
control->m_len;
if (neededspace > M_TRAILINGSPACE(control)) {
char *tmp;
@@ -834,11 +838,11 @@ morespace:
}
/* adjust message & mbuf to note amount of space actually used. */
- cm->cmsg_len = CMSG_LEN(nfds * sizeof(struct file *));
- control->m_len = CMSG_SPACE(nfds * sizeof(struct file *));
+ cm->cmsg_len = CMSG_LEN(nfds * sizeof(struct fdpass));
+ control->m_len = CMSG_SPACE(nfds * sizeof(struct fdpass));
ip = ((int *)CMSG_DATA(cm)) + nfds - 1;
- rp = ((struct file **)CMSG_DATA(cm)) + nfds - 1;
+ rp = ((struct fdpass *)CMSG_DATA(cm)) + nfds - 1;
for (i = 0; i < nfds; i++) {
memcpy(&fd, ip, sizeof fd);
ip--;
@@ -859,7 +863,7 @@ morespace:
error = EINVAL;
goto fail;
}
- memcpy(rp, &fp, sizeof fp);
+ rp->fp = fp;
rp--;
fp->f_count++;
if ((unp = fptounp(fp)) != NULL) {
@@ -873,7 +877,7 @@ fail:
/* Back out what we just did. */
for ( ; i > 0; i--) {
rp++;
- memcpy(&fp, rp, sizeof(fp));
+ fp = rp->fp;
fp->f_count--;
if ((unp = fptounp(fp)) != NULL)
unp->unp_msgcount--;
@@ -902,7 +906,7 @@ unp_gc(void *arg __unused)
while ((defer = SLIST_FIRST(&unp_deferred)) != NULL) {
SLIST_REMOVE_HEAD(&unp_deferred, ud_link);
for (i = 0; i < defer->ud_n; i++) {
- fp = defer->ud_fp[i];
+ fp = defer->ud_fp[i].fp;
if (fp == NULL)
continue;
FREF(fp);
@@ -911,7 +915,7 @@ unp_gc(void *arg __unused)
unp_rights--;
(void) closef(fp, NULL);
}
- free(defer, M_TEMP, sizeof(*defer) + sizeof(fp) * defer->ud_n);
+ free(defer, M_TEMP, sizeof(*defer) + sizeof(struct fdpass) *
defer->ud_n);
}
unp_defer = 0;
@@ -1005,10 +1009,10 @@ unp_dispose(struct mbuf *m)
}
void
-unp_scan(struct mbuf *m0, void (*op)(struct file **, int))
+unp_scan(struct mbuf *m0, void (*op)(struct fdpass *, int))
{
struct mbuf *m;
- struct file **rp;
+ struct fdpass *rp;
struct cmsghdr *cm;
int qfds;
@@ -1021,9 +1025,9 @@ unp_scan(struct mbuf *m0, void (*op)(str
cm->cmsg_type != SCM_RIGHTS)
continue;
qfds = (cm->cmsg_len - CMSG_ALIGN(sizeof *cm))
- / sizeof(struct file *);
+ / sizeof(struct fdpass);
if (qfds > 0) {
- rp = (struct file **)CMSG_DATA(cm);
+ rp = (struct fdpass *)CMSG_DATA(cm);
op(rp, qfds);
}
break; /* XXX, but saves time */
@@ -1034,16 +1038,16 @@ unp_scan(struct mbuf *m0, void (*op)(str
}
void
-unp_mark(struct file **rp, int nfds)
+unp_mark(struct fdpass *rp, int nfds)
{
struct unpcb *unp;
int i;
for (i = 0; i < nfds; i++) {
- if (rp[i] == NULL)
+ if (rp[i].fp == NULL)
continue;
- unp = fptounp(rp[i]);
+ unp = fptounp(rp[i].fp);
if (unp == NULL)
continue;
@@ -1057,7 +1061,7 @@ unp_mark(struct file **rp, int nfds)
}
void
-unp_discard(struct file **rp, int nfds)
+unp_discard(struct fdpass *rp, int nfds)
{
struct unp_deferral *defer;
Index: sys/unpcb.h
===================================================================
RCS file: /cvs/src/sys/sys/unpcb.h,v
retrieving revision 1.12
diff -u -p -u -r1.12 unpcb.h
--- sys/unpcb.h 28 Aug 2015 04:38:47 -0000 1.12
+++ sys/unpcb.h 23 Jan 2017 23:01:51 -0000
@@ -86,17 +86,21 @@ struct unpcb {
#define sotounpcb(so) ((struct unpcb *)((so)->so_pcb))
#ifdef _KERNEL
+struct fdpass {
+ struct file *fp;
+};
+
int unp_attach(struct socket *);
int unp_bind(struct unpcb *, struct mbuf *, struct proc *);
int unp_connect(struct socket *, struct mbuf *, struct proc *);
int unp_connect2(struct socket *, struct socket *);
void unp_detach(struct unpcb *);
-void unp_discard(struct file **, int);
+void unp_discard(struct fdpass *, int);
void unp_disconnect(struct unpcb *);
void unp_drop(struct unpcb *, int);
void unp_gc(void *);
-void unp_mark(struct file **, int);
-void unp_scan(struct mbuf *, void (*)(struct file **, int));
+void unp_mark(struct fdpass *, int);
+void unp_scan(struct mbuf *, void (*)(struct fdpass *, int));
void unp_shutdown(struct unpcb *);
int unp_externalize(struct mbuf *, socklen_t, int);
int unp_internalize(struct mbuf *, struct proc *);