Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 07 Aug 2001 17:49:21 +0100
From:      David Malone <dwmalone@maths.tcd.ie>
To:        freebsd-audit@freebsd.org
Cc:        dwmalone@maths.tcd.ie
Subject:   Unix domain control messages.
Message-ID:   <200108071749.aa74603@salmon.maths.tcd.ie>

next in thread | raw e-mail | index | archive | help
I've produced a set of patches which aim to fix some of the problems
with the unix domain control message passing code. I'm looking for
someone who can review or comment on these changes. The patch aims
to:

        1) Allow the sending of more than one control message at
        a time over a unix domain socket. This should cover the
	recently submitted 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. Sbcreatecontrol has been extended to deal with this.

        4) You can now send SCM_TIMESTAMP messages 'cos it was
        trivial to add.

	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).

	6) Fix userland programs to use CMSG_* macros too.

        7) Be more careful about freeing mbufs containing (file *)s.

To allow (7) and (2) I had to change the prototype of the domain
externalize function. Since the unix domain is the only thing that
uses the externalize method this isn't too serious.

(5) results in an ABI change for the alpha. The old ABI isn't
consistent with other uses of control messages in the kernel, isn't
consistant with the ABI Stevens describes and isn't consistant with
NetBSD. I think this suggests we can consider it a bug fix rather
than something requiring new syscalls? (Passing of discriptors
and creds is fairly rare so the impact should be small.)

The code still has my debugging printfs in it, but I'd like to see
if anyone could provide any useful feedback.

	David.


Index: lib/libc/rpc/clnt_vc.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/lib/libc/rpc/clnt_vc.c,v
retrieving revision 1.7
diff -u -r1.7 clnt_vc.c
--- lib/libc/rpc/clnt_vc.c	2001/06/01 15:20:45	1.7
+++ lib/libc/rpc/clnt_vc.c	2001/07/15 15:18:58
@@ -793,7 +793,10 @@
 {
 	struct iovec iov[1];
 	struct msghdr msg;
-	struct cmessage cm;
+	union {
+		struct cmsghdr cmsg;
+		char control[CMSG_SPACE(sizeof(struct cmsgcred))];
+	} cm;
  
 	bzero((char *)&cm, sizeof(cm));
 	iov[0].iov_base = buf;
@@ -804,7 +807,7 @@
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
 	msg.msg_control = (caddr_t)&cm;
-	msg.msg_controllen = sizeof(struct cmessage);
+	msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
 	msg.msg_flags = 0;
  
 	return(_recvmsg(sock, &msg, 0));
@@ -818,7 +821,10 @@
 {
 	struct iovec iov[1];
 	struct msghdr msg;
-	struct cmessage cm;
+	union {
+		struct cmsghdr cmsg;
+		char control[CMSG_SPACE(sizeof(struct cmsgcred))];
+	} cm;
  
 	bzero((char *)&cm, sizeof(cm));
 	iov[0].iov_base = buf;
@@ -826,14 +832,14 @@
  
 	cm.cmsg.cmsg_type = SCM_CREDS;
 	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_iovlen = 1;
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
 	msg.msg_control = (caddr_t)&cm;
-	msg.msg_controllen = sizeof(struct cmessage);
+	msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
 	msg.msg_flags = 0;
 
 	return(_sendmsg(sock, &msg, 0));
Index: lib/libc/rpc/svc_vc.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/lib/libc/rpc/svc_vc.c,v
retrieving revision 1.5
diff -u -r1.5 svc_vc.c
--- lib/libc/rpc/svc_vc.c	2001/04/02 21:41:44	1.5
+++ lib/libc/rpc/svc_vc.c	2001/07/15 15:38:39
@@ -400,8 +400,6 @@
 	struct pollfd pollfd;
 	struct sockaddr *sa;
 	struct cmessage *cm;
-	struct cmsghdr *cmp;
-	struct sockcred *sc;
 
 	xprt = (SVCXPRT *)(void *)xprtp;
 	assert(xprt != NULL);
@@ -429,9 +427,7 @@
 	if (sa->sa_family == AF_LOCAL) {
 		cm = (struct cmessage *)xprt->xp_verf.oa_base;
 		if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) {
-			cmp = &cm->cmsg;
-			sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
-			xprt->xp_p2 = sc;
+			xprt->xp_p2 = &cm->cmcred;
 			return (len);
 		}
 	} else {
@@ -638,8 +634,14 @@
 {
 	struct iovec iov[1];
 	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_len = cnt;
  
@@ -647,11 +649,14 @@
 	msg.msg_iovlen = 1;
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
-	msg.msg_control = cmp;
-	msg.msg_controllen = sizeof(struct cmessage);
+	msg.msg_control = &cm;
+	msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
 	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
Index: sbin/mount_portalfs/activate.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/sbin/mount_portalfs/activate.c,v
retrieving revision 1.7
diff -u -r1.7 activate.c
--- sbin/mount_portalfs/activate.c	1999/08/28 00:13:35	1.7
+++ sbin/mount_portalfs/activate.c	2001/07/15 14:58:01
@@ -113,9 +113,9 @@
 	int n;
 	struct iovec iov;
 	struct msghdr msg;
-	struct {
+	union {
 		struct cmsghdr cmsg;
-		int fd;
+		char control[CMSG_SPACE(sizeof(int))];
 	} ctl;
 
 	/*
@@ -137,10 +137,10 @@
 	 * construct a suitable rights control message.
 	 */
 	if (fd >= 0) {
-		ctl.fd = fd;
-		ctl.cmsg.cmsg_len = sizeof(ctl);
+		ctl.cmsg.cmsg_len = CMSG_LEN(sizeof(int));
 		ctl.cmsg.cmsg_level = SOL_SOCKET;
 		ctl.cmsg.cmsg_type = SCM_RIGHTS;
+		*((int *)CMSG_DATA(&ctl.cmsg)) = fd;
 		msg.msg_control = (caddr_t) &ctl;
 		msg.msg_controllen = ctl.cmsg.cmsg_len;
 	}
Index: sys/kern/uipc_socket.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/sys/kern/uipc_socket.c,v
retrieving revision 1.97
diff -u -r1.97 uipc_socket.c
--- sys/kern/uipc_socket.c	2001/05/01 08:12:58	1.97
+++ sys/kern/uipc_socket.c	2001/07/10 20:35:09
@@ -672,7 +672,7 @@
 	struct mbuf **controlp;
 	int *flagsp;
 {
-	register struct mbuf *m, **mp;
+	struct mbuf *m, **mp;
 	register int flags, len, error, s, offset;
 	struct protosw *pr = so->so_proto;
 	struct mbuf *nextrecord;
@@ -798,23 +798,22 @@
 			m = m->m_next;
 		} else {
 			sbfree(&so->so_rcv, m);
-			if (controlp) {
-				if (pr->pr_domain->dom_externalize &&
-				    mtod(m, struct cmsghdr *)->cmsg_type ==
-				    SCM_RIGHTS)
-				   error = (*pr->pr_domain->dom_externalize)(m);
+			so->so_rcv.sb_mb = m->m_next;
+			m->m_next = NULL;
+			if (pr->pr_domain->dom_externalize)
+				error =
+				(*pr->pr_domain->dom_externalize)(m, controlp);
+			else if (controlp)
 				*controlp = m;
-				so->so_rcv.sb_mb = m->m_next;
-				m->m_next = 0;
-				m = so->so_rcv.sb_mb;
-			} else {
-				MFREE(m, so->so_rcv.sb_mb);
-				m = so->so_rcv.sb_mb;
-			}
+			else
+				m_freem(m);
+			m = so->so_rcv.sb_mb;
 		}
 		if (controlp) {
 			orig_resid = 0;
-			controlp = &(*controlp)->m_next;
+			do
+				controlp = &(*controlp)->m_next;
+			while (*controlp != NULL);
 		}
 	}
 	if (m) {
Index: sys/kern/uipc_socket2.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/sys/kern/uipc_socket2.c,v
retrieving revision 1.73
diff -u -r1.73 uipc_socket2.c
--- sys/kern/uipc_socket2.c	2001/06/29 04:01:38	1.73
+++ sys/kern/uipc_socket2.c	2001/07/08 19:45:05
@@ -851,13 +852,23 @@
 	register struct cmsghdr *cp;
 	struct mbuf *m;
 
-	if (CMSG_SPACE((u_int)size) > MLEN)
+	if (CMSG_SPACE((u_int)size) > MCLBYTES)
 		return ((struct mbuf *) NULL);
 	if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
 		return ((struct mbuf *) NULL);
+	if (CMSG_SPACE((u_int)size) > MLEN) {
+		MCLGET(m, M_DONTWAIT);
+		if ((m->m_flags & M_EXT) == 0) {
+			m_free(m);
+			return ((struct mbuf *) NULL);
+		}
+	}
 	cp = mtod(m, struct cmsghdr *);
-	/* XXX check size? */
-	(void)memcpy(CMSG_DATA(cp), p, size);
+	m->m_len = 0;
+	KASSERT(CMSG_SPACE((u_int)size) <= M_TRAILINGSPACE(m),
+	    ("sbcreatecontrol: short mbuf"));
+	if (p != NULL)
+		(void)memcpy(CMSG_DATA(cp), p, size);
 	m->m_len = CMSG_SPACE(size);
 	cp->cmsg_len = CMSG_LEN(size);
 	cp->cmsg_level = level;
Index: sys/kern/uipc_usrreq.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.66
diff -u -r1.66 uipc_usrreq.c
--- sys/kern/uipc_usrreq.c	2001/05/25 16:59:07	1.66
+++ sys/kern/uipc_usrreq.c	2001/07/15 13:42:17
@@ -90,7 +90,8 @@
 static void    unp_scan __P((struct mbuf *, void (*)(struct file *)));
 static void    unp_mark __P((struct file *));
 static void    unp_discard __P((struct file *));
-static int     unp_internalize __P((struct mbuf *, struct proc *));
+static void    unp_freerights __P((struct file **, int));
+static int     unp_internalize __P((struct mbuf **, struct proc *));
 
 static int
 uipc_abort(struct socket *so)
@@ -273,7 +274,7 @@
 		goto release;
 	}
 
-	if (control && (error = unp_internalize(control, p)))
+	if (control && (error = unp_internalize(&control, p)))
 		goto release;
 
 	switch (so->so_type) {
@@ -874,80 +875,129 @@
 }
 #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
-unp_externalize(rights)
-	struct mbuf *rights;
+unp_externalize(control, controlp)
+	struct mbuf *control, **controlp;
 {
 	struct proc *p = curproc;		/* XXX */
-	register int i;
-	register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
-	register int *fdp;
-	register struct file **rp;
-	register struct file *fp;
-	int newfds = (cm->cmsg_len - (CMSG_DATA(cm) - (u_char *)cm))
-		/ sizeof (struct file *);
+	struct cmsghdr *cm = mtod(control, struct cmsghdr *);
+	int i;
+	int *fdp;
+	struct file **rp;
+	struct file *fp;
+	void *data;
+	socklen_t clen = control->m_len, datalen;
+	int error, newfds;
 	int f;
+	u_int newlen;
 
-	/*
-	 * if the new FD's will not fit, then we free them all
-	 */
-	if (!fdavail(p, newfds)) {
-		rp = (struct file **)CMSG_DATA(cm);
-		for (i = 0; i < newfds; i++) {
-			fp = *rp;
+	error = 0;
+	if (controlp != NULL) /* controlp == NULL => free control messages */
+		*controlp = NULL;
+
+	while (cm != NULL) {
+		if (sizeof(*cm) > clen || cm->cmsg_len > clen) {
+			error = EINVAL;
+			break;
+		}
+
+		data = CMSG_DATA(cm);
+		datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
+
+		/* DMXXX */ printf("PID %d Externalising (%d:%d) size %d (%d) in %d\n", p->p_pid, cm->cmsg_level, cm->cmsg_type, datalen, CMSG_SPACE(datalen), clen);
+
+		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(p, newfds)) {
+				error = EMSGSIZE;
+				unp_freerights(rp, newfds);
+				goto next;
+			}
 			/*
-			 * zero the pointer before calling unp_discard,
-			 * since it may end up in unp_gc()..
+			 * now change each pointer to an fd in the global
+			 * 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;
-			unp_discard(fp);
-		}
-		return (EMSGSIZE);
-	}
-	/*
-	 * now change each pointer to an fd in the global 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.
-	 * If sizeof (struct file *) is bigger than or equal to sizeof int,
-	 * then do it in forward order. In that case, an integer will
-	 * always come in the same place or before its corresponding
-	 * struct file pointer.
-	 * If sizeof (struct file *) is smaller than sizeof int, then
-	 * 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(p, 0, &f))
-				panic("unp_externalize");
-			fp = *rp++;
-			p->p_fd->fd_ofiles[f] = fp;
-			fp->f_msgcount--;
-			unp_rights--;
-			*fdp++ = f;
+			newlen = newfds * sizeof(int);
+			*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(p, 0, &f))
+					panic("unp_externalize fdalloc failed");
+				fp = *rp++;
+				p->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);
 		}
-	} else {
-		fdp = (int *)(cm + 1) + newfds - 1;
-		rp = (struct file **)CMSG_DATA(cm) + newfds - 1;
-		for (i = 0; i < newfds; i++) {
-			if (fdalloc(p, 0, &f))
-				panic("unp_externalize");
-			fp = *rp--;
-			p->p_fd->fd_ofiles[f] = fp;
-			fp->f_msgcount--;
-			unp_rights--;
-			*fdp-- = f;
+
+		controlp = &(*controlp)->m_next;
+
+next:
+		if (CMSG_SPACE(datalen) < clen) {
+			clen -= CMSG_SPACE(datalen);
+			cm = (struct cmsghdr *)
+			    ((caddr_t)cm + CMSG_SPACE(datalen));
+		} else {
+			clen = 0;
+			cm = NULL;
 		}
 	}
 
-	/*
-	 * Adjust length, in case sizeof(struct file *) and sizeof(int)
-	 * differs.
-	 */
-	cm->cmsg_len = CMSG_LEN(newfds * sizeof(int));
-	rights->m_len = cm->cmsg_len;
-	return (0);
+	m_freem(control);
+
+	return (error);
 }
 
 void
@@ -965,108 +1015,136 @@
 #endif
 
 static int
-unp_internalize(control, p)
-	struct mbuf *control;
+unp_internalize(controlp, p)
+	struct mbuf **controlp;
 	struct proc *p;
 {
+	struct mbuf *control = *controlp;
 	struct filedesc *fdescp = p->p_fd;
-	register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
-	register struct file **rp;
-	register struct file *fp;
-	register int i, fd, *fdp;
-	register struct cmsgcred *cmcred;
-	int oldfds;
+	struct cmsghdr *cm = mtod(control, struct cmsghdr *);
+	struct cmsgcred *cmcred;
+	struct file **rp;
+	struct file *fp;
+	struct timeval *tv;
+	int i, fd, *fdp;
+	void *data;
+	socklen_t clen = control->m_len, datalen;
+	int error, oldfds;
 	u_int newlen;
 
-	if ((cm->cmsg_type != SCM_RIGHTS && cm->cmsg_type != SCM_CREDS) ||
-	    cm->cmsg_level != SOL_SOCKET || cm->cmsg_len != control->m_len)
-		return (EINVAL);
+	error = 0;
+	*controlp = NULL;
 
-	/*
-	 * Fill in credential information.
-	 */
-	if (cm->cmsg_type == SCM_CREDS) {
-		cmcred = (struct cmsgcred *)(cm + 1);
-		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,
+	while (cm != NULL) {
+		if (sizeof(*cm) > clen || cm->cmsg_level != SOL_SOCKET
+		    || cm->cmsg_len > clen) {
+			error = EINVAL;
+			goto out;
+		}
+
+		data = CMSG_DATA(cm);
+		datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
+
+		/* DMXXX */ printf("PID %d Internalising (%d:%d) size %d (%d) in %d\n", p->p_pid, cm->cmsg_level, cm->cmsg_type, datalen, CMSG_SPACE(datalen), clen);
+
+		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);
-		for (i = 0; i < cmcred->cmcred_ngroups; i++)
-			cmcred->cmcred_groups[i] = p->p_ucred->cr_groups[i];
-		return(0);
-	}
+			for (i = 0; i < cmcred->cmcred_ngroups; i++)
+				cmcred->cmcred_groups[i] =
+				    p->p_ucred->cr_groups[i];
+			break;
 
-	oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
-	/*
-	 * check that all the FDs passed in refer to legal OPEN files
-	 * If not, reject the entire operation.
-	 */
-	fdp = (int *)(cm + 1);
-	for (i = 0; i < oldfds; i++) {
-		fd = *fdp++;
-		if ((unsigned)fd >= fdescp->fd_nfiles ||
-		    fdescp->fd_ofiles[fd] == NULL)
-			return (EBADF);
-	}
-	/*
-	 * 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.
-	 */
-	newlen = CMSG_LEN(oldfds * sizeof(struct file *));
-	if (newlen > MCLBYTES)
-		return (E2BIG);
-	if (newlen - control->m_len > M_TRAILINGSPACE(control)) {
-		if (control->m_flags & M_EXT)
-			return (E2BIG);
-		MCLGET(control, M_TRYWAIT);
-		if ((control->m_flags & M_EXT) == 0)
-			return (ENOBUFS);
-
-		/* copy the data to the cluster */
-		memcpy(mtod(control, char *), cm, cm->cmsg_len);
-		cm = mtod(control, struct cmsghdr *);
-	}
+		case SCM_RIGHTS:
+			oldfds = datalen / sizeof (int);
+			/*
+			 * check that all the FDs passed in refer to legal files
+			 * If not, reject the entire operation.
+			 */
+			fdp = data;
+			for (i = 0; i < oldfds; i++) {
+				fd = *fdp++;
+				if ((unsigned)fd >= fdescp->fd_nfiles ||
+				    fdescp->fd_ofiles[fd] == NULL) {
+					error = EBADF;
+					goto out;
+				}
+			}
+			/*
+			 * Now replace the integer FDs with pointers to
+			 * the associated global file table entry..
+			 */
+			newlen = oldfds * sizeof(struct file *);
+			*controlp = sbcreatecontrol(NULL, newlen,
+			    SCM_RIGHTS, SOL_SOCKET);
+			if (*controlp == NULL) {
+				error = E2BIG;
+				goto out;
+			}
 
-	/*
-	 * Adjust length, in case sizeof(struct file *) and sizeof(int)
-	 * differs.
-	 */
-	control->m_len = cm->cmsg_len = newlen;
+			fdp = data;
+			rp = (struct file **)
+			    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;
 
-	/*
-	 * Transform the file descriptors into struct file pointers.
-	 * If sizeof (struct file *) is bigger than or equal to sizeof int,
-	 * 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++;
+		case SCM_TIMESTAMP:
+			*controlp = sbcreatecontrol(NULL, sizeof(*tv),
+			    SCM_TIMESTAMP, SOL_SOCKET);
+			if (*controlp == NULL) {
+				error = ENOBUFS;
+				goto out;
+			}
+			tv = (struct timeval *)
+			    CMSG_DATA(mtod(*controlp, struct cmsghdr *));
+			microtime(tv);
+			break;
+
+		default:
+			error = EINVAL;
+			goto out;
 		}
-	} else {
-		fdp = (int *)(cm + 1);
-		rp = (struct file **)CMSG_DATA(cm);
-		for (i = 0; i < oldfds; i++) {
-			fp = fdescp->fd_ofiles[*fdp++];
-			*rp++ = fp;
-			fp->f_count++;
-			fp->f_msgcount++;
-			unp_rights++;
+
+		controlp = &(*controlp)->m_next;
+
+		if (CMSG_SPACE(datalen) < clen) {
+			clen -= CMSG_SPACE(datalen);
+			cm = (struct cmsghdr *)
+			    ((caddr_t)cm + CMSG_SPACE(datalen));
+			printf("Trying another.");
+		} else {
+			clen = 0;
+			cm = NULL;
 		}
 	}
-	return (0);
+
+out:
+	m_freem(control);
+
+	return (error);
 }
 
 static int	unp_defer, unp_gcing;
@@ -1249,28 +1327,50 @@
 	register struct mbuf *m0;
 	void (*op) __P((struct file *));
 {
-	register struct mbuf *m;
-	register struct file **rp;
-	register struct cmsghdr *cm;
-	register int i;
+	struct mbuf *m;
+	struct file **rp;
+	struct cmsghdr *cm;
+	void *data;
+	int i;
+	socklen_t clen, datalen;
 	int qfds;
 
 	while (m0) {
-		for (m = m0; m; m = m->m_next)
-			if (m->m_type == MT_CONTROL &&
-			    m->m_len >= sizeof(*cm)) {
-				cm = mtod(m, struct cmsghdr *);
-				if (cm->cmsg_level != SOL_SOCKET ||
-				    cm->cmsg_type != SCM_RIGHTS)
-					continue;
-				qfds = (cm->cmsg_len -
-					(CMSG_DATA(cm) - (u_char *)cm))
-						/ sizeof (struct file *);
-				rp = (struct file **)CMSG_DATA(cm);
-				for (i = 0; i < qfds; i++)
-					(*op)(*rp++);
-				break;		/* XXX, but saves time */
+		for (m = m0; m; m = m->m_next) {
+			if (m->m_type == MT_CONTROL)
+				continue;
+
+			cm = mtod(m, struct cmsghdr *);
+			clen = m->m_len;
+
+			while (cm != NULL) {
+				if (sizeof(*cm) > clen || cm->cmsg_len > clen)
+					break;
+
+				data = CMSG_DATA(cm);
+				datalen = (caddr_t)cm + cm->cmsg_len
+				    - (caddr_t)data;
+
+				/* DMXXX */ printf("Scanning (%d:%d) size %d (%d) in %d\n", cm->cmsg_level, cm->cmsg_type, datalen, CMSG_SPACE(datalen), clen);
+
+				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;
 	}
 }
Index: sys/netgraph/ng_socket.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/sys/netgraph/ng_socket.c,v
retrieving revision 1.26
diff -u -r1.26 ng_socket.c
--- sys/netgraph/ng_socket.c	2001/02/23 16:34:22	1.26
+++ sys/netgraph/ng_socket.c	2001/07/15 14:49:59
@@ -583,7 +583,7 @@
 	}
 
 	/* 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) {
 		TRAP_ERROR;
 		return (EINVAL);
@@ -591,7 +591,7 @@
 
 	/* Check that the FD given is legit. and change it to a pointer to a
 	 * struct file. */
-	fd = *(int *) (cm + 1);
+	fd = CMSG_DATA(cm);
 	if ((unsigned) fd >= fdp->fd_nfiles
 	    || (fp = fdp->fd_ofiles[fd]) == NULL) {
 		return (EBADF);
Index: sys/sys/domain.h
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/sys/sys/domain.h,v
retrieving revision 1.14
diff -u -r1.14 domain.h
--- sys/sys/domain.h	1999/12/29 04:24:40	1.14
+++ sys/sys/domain.h	2001/07/10 19:49:41
@@ -52,7 +52,7 @@
 	void	(*dom_init)		/* initialize domain data structures */
 		__P((void));
 	int	(*dom_externalize)	/* externalize access rights */
-		__P((struct mbuf *));
+		__P((struct mbuf *, struct mbuf **));
 	void	(*dom_dispose)		/* dispose of internalized rights */
 		__P((struct mbuf *));
 	struct	protosw *dom_protosw, *dom_protoswNPROTOSW;
Index: sys/sys/un.h
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/sys/sys/un.h,v
retrieving revision 1.17
diff -u -r1.17 un.h
--- sys/sys/un.h	1999/12/29 04:24:49	1.17
+++ sys/sys/un.h	2001/07/10 20:06:13
@@ -54,7 +54,7 @@
 		struct mbuf *nam, struct mbuf *control));
 int	unp_connect2 __P((struct socket *so, struct socket *so2));
 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));
 extern	struct pr_usrreqs uipc_usrreqs;
 #else /* !_KERNEL */
Index: usr.sbin/ppp/bundle.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/usr.sbin/ppp/bundle.c,v
retrieving revision 1.118
diff -u -r1.118 bundle.c
--- usr.sbin/ppp/bundle.c	2001/07/03 22:20:15	1.118
+++ usr.sbin/ppp/bundle.c	2001/07/15 15:05:11
@@ -1385,8 +1385,8 @@
     return;
   }
 
-  fd = (int *)(cmsg + 1);
-  nfd = (cmsg->cmsg_len - sizeof *cmsg) / sizeof(int);
+  fd = (int *)CMSG_DATA(cmsg);
+  nfd = ((caddr_t)cmsg + cmsg->cmsg_len - (caddr_t)fd) / sizeof(int);
 
   if (nfd < 2) {
     log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n",
@@ -1478,7 +1478,7 @@
 void
 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;
   char *lock;
   struct cmsghdr *cmsg;
@@ -1528,7 +1528,7 @@
     msg.msg_iovlen = 1;
     msg.msg_iov = iov;
     msg.msg_control = cmsgbuf;
-    msg.msg_controllen = sizeof *cmsg + sizeof(int) * nfd;
+    msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfd);
     msg.msg_flags = 0;
 
     cmsg = (struct cmsghdr *)cmsgbuf;
@@ -1537,7 +1537,7 @@
     cmsg->cmsg_type = SCM_RIGHTS;
 
     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++)
       expect += iov[f].iov_len;

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi? <200108071749.aa74603>