summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/sockfs/socksubr.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/fs/sockfs/socksubr.c')
-rw-r--r--usr/src/uts/common/fs/sockfs/socksubr.c63
1 files changed, 59 insertions, 4 deletions
diff --git a/usr/src/uts/common/fs/sockfs/socksubr.c b/usr/src/uts/common/fs/sockfs/socksubr.c
index 2c010343bb..e686978fd0 100644
--- a/usr/src/uts/common/fs/sockfs/socksubr.c
+++ b/usr/src/uts/common/fs/sockfs/socksubr.c
@@ -23,8 +23,8 @@
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015, Joyent, Inc. All rights reserved.
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
- * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
* Copyright 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
#include <sys/types.h>
@@ -962,7 +962,46 @@ so_closefds(void *control, t_uscalar_t controllen, int oldflg,
(int)CMSG_CONTENTLEN(cmsg),
startoff - (int)sizeof (struct cmsghdr));
}
- startoff -= cmsg->cmsg_len;
+ startoff -= ROUNDUP_cmsglen(cmsg->cmsg_len);
+ }
+}
+
+/*
+ * Handle truncation of a cmsg when the receive buffer is not big enough.
+ * Adjust the cmsg_len header field in the last cmsg that will be included in
+ * the buffer to reflect the number of bytes included.
+ */
+void
+so_truncatecmsg(void *control, t_uscalar_t controllen, uint_t maxlen)
+{
+ struct cmsghdr *cmsg;
+ uint_t len = 0;
+
+ if (control == NULL)
+ return;
+
+ for (cmsg = control;
+ CMSG_VALID(cmsg, control, (uintptr_t)control + controllen);
+ cmsg = CMSG_NEXT(cmsg)) {
+
+ len += ROUNDUP_cmsglen(cmsg->cmsg_len);
+
+ if (len > maxlen) {
+ /*
+ * This cmsg is the last one that will be included in
+ * the truncated buffer.
+ */
+ socklen_t diff = len - maxlen;
+
+ if (diff < CMSG_CONTENTLEN(cmsg)) {
+ dprint(1, ("so_truncatecmsg: %d -> %d\n",
+ cmsg->cmsg_len, cmsg->cmsg_len - diff));
+ cmsg->cmsg_len -= diff;
+ } else {
+ cmsg->cmsg_len = sizeof (struct cmsghdr);
+ }
+ break;
+ }
}
}
@@ -1282,8 +1321,24 @@ so_opt2cmsg(mblk_t *mp, void *opt, t_uscalar_t optlen, int oldflg,
cmsg->cmsg_level = tohp->level;
cmsg->cmsg_type = tohp->name;
- cmsg->cmsg_len = (socklen_t)(_TPI_TOPT_DATALEN(tohp) +
- sizeof (struct cmsghdr));
+ cmsg->cmsg_len = (socklen_t)sizeof (struct cmsghdr);
+ if (tohp->level == IPPROTO_IP &&
+ (tohp->name == IP_RECVTOS ||
+ tohp->name == IP_RECVTTL)) {
+ /*
+ * The data for these is a uint8_t but, in
+ * order to maintain alignment for any
+ * following TPI primitives in the message,
+ * there will be some trailing padding bytes
+ * which are included in the TPI_TOPT_DATALEN.
+ * For these types, we set the cmsg_len
+ * explicitly to the correct value.
+ */
+ cmsg->cmsg_len += (socklen_t)sizeof (uint8_t);
+ } else {
+ cmsg->cmsg_len +=
+ (socklen_t)(_TPI_TOPT_DATALEN(tohp));
+ }
/* copy content to control data part */
bcopy(&tohp[1], CMSG_CONTENT(cmsg),