At present we use a rather awkward loop to invert CMSG_LEN() in order to determine how many fds we have been passed as anciliary data. We can do a bit better with some pointer trickery. This also lets us validate the number of fds we've been passed a bit more naturally. While we're there, allow an empty message (n == 0) because why not. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- passt-repair.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/passt-repair.c b/passt-repair.c index 3c358e27..64b926bd 100644 --- a/passt-repair.c +++ b/passt-repair.c @@ -77,7 +77,7 @@ int main(int argc, char **argv) struct cmsghdr *cmsg; struct msghdr msg; struct iovec iov; - size_t cmsg_len; + size_t fdlen; int op; prctl(PR_SET_DUMPABLE, 0); @@ -122,27 +122,15 @@ loop: if (!ret) /* Done */ _exit(0); - if (!cmsg || - cmsg->cmsg_len < CMSG_LEN(sizeof(int)) || - cmsg->cmsg_len > CMSG_LEN(sizeof(int) * SCM_MAX_FD) || - cmsg->cmsg_type != SCM_RIGHTS) + if (!cmsg || cmsg->cmsg_type != SCM_RIGHTS) die(1, "No/bad ancillary data from peer"); - /* No inverse formula for CMSG_LEN(x), and building one with CMSG_LEN(0) - * works but there's no guarantee it does. Search the whole domain. - */ - for (i = 1; i <= SCM_MAX_FD; i++) { - if (CMSG_LEN(sizeof(int) * i) == cmsg->cmsg_len) { - n = i; - break; - } - } - if (!n) { - cmsg_len = cmsg->cmsg_len; /* socklen_t is 'unsigned' on musl */ - die(1, "Invalid ancillary data length %zu from peer", cmsg_len); - } + fdlen = ((char *)cmsg + cmsg->cmsg_len) - (char *)CMSG_DATA(cmsg); + if (fdlen % sizeof(int) != 0 || fdlen > sizeof(fds)) + die(1, "Invalid SCM_RIGHTS payload length %zu from peer", fdlen); + n = fdlen / sizeof(int); - memcpy(fds, CMSG_DATA(cmsg), sizeof(int) * n); + memcpy(fds, CMSG_DATA(cmsg), fdlen); if (cmd != TCP_REPAIR_ON && cmd != TCP_REPAIR_OFF && cmd != TCP_REPAIR_OFF_NO_WP) -- 2.48.1