diff options
Diffstat (limited to 'usr/src/uts/common/fs/sockfs/socksubr.c')
| -rw-r--r-- | usr/src/uts/common/fs/sockfs/socksubr.c | 63 |
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), |
