Page MenuHomeFreeBSD

D35375.diff
No OneTemporary

D35375.diff

diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -2193,22 +2193,20 @@
fdesc = p->p_fd;
error = 0;
control = *controlp;
- clen = control->m_len;
*controlp = NULL;
initial_controlp = controlp;
- for (cm = mtod(control, struct cmsghdr *); cm != NULL;) {
- if (sizeof(*cm) > clen || cm->cmsg_level != SOL_SOCKET
- || cm->cmsg_len > clen || cm->cmsg_len < sizeof(*cm)) {
- error = EINVAL;
- goto out;
- }
- data = CMSG_DATA(cm);
- datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
+ for (clen = control->m_len, cm = mtod(control, struct cmsghdr *),
+ data = CMSG_DATA(cm);
+ clen >= sizeof(*cm) && cm->cmsg_level == SOL_SOCKET &&
+ clen >= cm->cmsg_len && cm->cmsg_len >= sizeof(*cm) &&
+ (char *)cm + cm->cmsg_len >= (char *)data;
+
+ clen -= min(CMSG_SPACE(datalen), clen),
+ cm = (struct cmsghdr *) ((char *)cm + CMSG_SPACE(datalen)),
+ data = CMSG_DATA(cm)) {
+ datalen = (char *)cm + cm->cmsg_len - (char *)data;
switch (cm->cmsg_type) {
- /*
- * Fill in credential information.
- */
case SCM_CREDS:
*controlp = sbcreatecontrol(NULL, sizeof(*cmcred),
SCM_CREDS, SOL_SOCKET, M_WAITOK);
@@ -2228,7 +2226,7 @@
case SCM_RIGHTS:
oldfds = datalen / sizeof (int);
if (oldfds == 0)
- break;
+ continue;
/* On some machines sizeof pointer is bigger than
* sizeof int, so we need to check if data fits into
* single mbuf. We could allocate several mbufs, and
@@ -2334,17 +2332,10 @@
goto out;
}
- if (*controlp != NULL)
- controlp = &(*controlp)->m_next;
- if (CMSG_SPACE(datalen) < clen) {
- clen -= CMSG_SPACE(datalen);
- cm = (struct cmsghdr *)
- ((caddr_t)cm + CMSG_SPACE(datalen));
- } else {
- clen = 0;
- cm = NULL;
- }
+ controlp = &(*controlp)->m_next;
}
+ if (clen > 0)
+ error = EINVAL;
out:
if (error != 0 && initial_controlp != NULL)
diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c
--- a/tests/sys/kern/unix_passfd_test.c
+++ b/tests/sys/kern/unix_passfd_test.c
@@ -744,14 +744,14 @@
}
/*
- * Verify that we can handle empty rights messages. Try sending two SCM_RIGHTS
- * messages with a single call, one empty and one containing a single FD.
+ * Verify that we can handle empty rights messages.
*/
ATF_TC_WITHOUT_HEAD(empty_rights_message);
ATF_TC_BODY(empty_rights_message, tc)
{
struct iovec iov;
struct msghdr msghdr;
+ struct cmsghdr cmsg;
char *cm, message[CMSG_SPACE(0) + CMSG_SPACE(sizeof(int))];
ssize_t len;
int error, fd[2], putfd;
@@ -759,21 +759,40 @@
domainsocketpair(fd);
devnull(&putfd);
+ memset(&msghdr, 0, sizeof(msghdr));
+ iov.iov_base = NULL;
+ iov.iov_len = 0;
+ msghdr.msg_iov = &iov;
+ msghdr.msg_iovlen = 1;
+
+ /*
+ * Try sending incorrect empty message. On 64-bit platforms, where
+ * CMSG_SPACE(0) > sizeof(struct cmsghdr), this will exercise
+ * an edge case.
+ */
+ cmsg = (struct cmsghdr ){
+ .cmsg_len = sizeof(struct cmsghdr), /* not CMSG_LEN(0)! */
+ .cmsg_level = SOL_SOCKET,
+ .cmsg_type = SCM_RIGHTS,
+ };
+ msghdr.msg_control = &cmsg;
+ msghdr.msg_controllen = CMSG_SPACE(0);
+
+ len = sendmsg(fd[0], &msghdr, 0);
+ if (CMSG_LEN(0) != sizeof(struct cmsghdr))
+ ATF_REQUIRE(len == -1 && errno == EINVAL);
+ else
+ ATF_REQUIRE(len == 0);
+
/*
- * First, try sending an empty message followed by a non-empty message.
+ * Try sending an empty message followed by a non-empty message.
*/
cm = message;
putfds(cm, -1, 0);
cm += CMSG_SPACE(0);
putfds(cm, putfd, 1);
-
- memset(&msghdr, 0, sizeof(msghdr));
- iov.iov_base = NULL;
- iov.iov_len = 0;
msghdr.msg_control = message;
msghdr.msg_controllen = sizeof(message);
- msghdr.msg_iov = &iov;
- msghdr.msg_iovlen = 1;
len = sendmsg(fd[0], &msghdr, 0);
ATF_REQUIRE_MSG(len == 0, "sendmsg failed: %s", strerror(errno));

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 23, 2:47 PM (2 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17269199
Default Alt Text
D35375.diff (3 KB)

Event Timeline