Date: Fri, 27 Oct 2017 19:27:05 +0000 (UTC) From: Michael Tuexen <tuexen@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r325046 - head/sys/netinet Message-ID: <201710271927.v9RJR5Pi022878@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: tuexen Date: Fri Oct 27 19:27:05 2017 New Revision: 325046 URL: https://svnweb.freebsd.org/changeset/base/325046 Log: Fix parsing error when processing cmsg in SCTP send calls. Thei bug is related to a signed/unsigned mismatch. This should most likely fix the issue in sctp_sosend reported by Dmitry Vyukov on the freebsd-hackers mailing list and found by running syzkaller. Modified: head/sys/netinet/sctp_output.c Modified: head/sys/netinet/sctp_output.c ============================================================================== --- head/sys/netinet/sctp_output.c Fri Oct 27 17:21:43 2017 (r325045) +++ head/sys/netinet/sctp_output.c Fri Oct 27 19:27:05 2017 (r325046) @@ -3465,32 +3465,35 @@ static int sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize) { struct cmsghdr cmh; - int tlen, at, found; struct sctp_sndinfo sndinfo; struct sctp_prinfo prinfo; struct sctp_authinfo authinfo; + int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off; + int found; - tlen = SCTP_BUF_LEN(control); - at = 0; - found = 0; /* * Independent of how many mbufs, find the c_type inside the control * structure and copy out the data. */ - while (at < tlen) { - if ((tlen - at) < (int)CMSG_ALIGN(sizeof(cmh))) { + found = 0; + tot_len = SCTP_BUF_LEN(control); + for (off = 0; off < tot_len; off += CMSG_ALIGN(cmh.cmsg_len)) { + rem_len = tot_len - off; + if (rem_len < (int)CMSG_ALIGN(sizeof(cmh))) { /* There is not enough room for one more. */ return (found); } - m_copydata(control, at, sizeof(cmh), (caddr_t)&cmh); + m_copydata(control, off, sizeof(cmh), (caddr_t)&cmh); if (cmh.cmsg_len < CMSG_ALIGN(sizeof(cmh))) { /* We dont't have a complete CMSG header. */ return (found); } - if (((int)cmh.cmsg_len + at) > tlen) { + if ((cmh.cmsg_len > INT_MAX) || ((int)cmh.cmsg_len > rem_len)) { /* We don't have the complete CMSG. */ return (found); } + cmsg_data_len = (int)cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh)); + cmsg_data_off = off + CMSG_ALIGN(sizeof(cmh)); if ((cmh.cmsg_level == IPPROTO_SCTP) && ((c_type == cmh.cmsg_type) || ((c_type == SCTP_SNDRCV) && @@ -3498,11 +3501,14 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *co (cmh.cmsg_type == SCTP_PRINFO) || (cmh.cmsg_type == SCTP_AUTHINFO))))) { if (c_type == cmh.cmsg_type) { - if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < cpsize) { + if (cpsize > INT_MAX) { return (found); } + if (cmsg_data_len < (int)cpsize) { + return (found); + } /* It is exactly what we want. Copy it out. */ - m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), (int)cpsize, (caddr_t)data); + m_copydata(control, cmsg_data_off, (int)cpsize, (caddr_t)data); return (1); } else { struct sctp_sndrcvinfo *sndrcvinfo; @@ -3516,10 +3522,10 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *co } switch (cmh.cmsg_type) { case SCTP_SNDINFO: - if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct sctp_sndinfo)) { + if (cmsg_data_len < (int)sizeof(struct sctp_sndinfo)) { return (found); } - m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct sctp_sndinfo), (caddr_t)&sndinfo); + m_copydata(control, cmsg_data_off, sizeof(struct sctp_sndinfo), (caddr_t)&sndinfo); sndrcvinfo->sinfo_stream = sndinfo.snd_sid; sndrcvinfo->sinfo_flags = sndinfo.snd_flags; sndrcvinfo->sinfo_ppid = sndinfo.snd_ppid; @@ -3527,10 +3533,10 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *co sndrcvinfo->sinfo_assoc_id = sndinfo.snd_assoc_id; break; case SCTP_PRINFO: - if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct sctp_prinfo)) { + if (cmsg_data_len < (int)sizeof(struct sctp_prinfo)) { return (found); } - m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct sctp_prinfo), (caddr_t)&prinfo); + m_copydata(control, cmsg_data_off, sizeof(struct sctp_prinfo), (caddr_t)&prinfo); if (prinfo.pr_policy != SCTP_PR_SCTP_NONE) { sndrcvinfo->sinfo_timetolive = prinfo.pr_value; } else { @@ -3539,10 +3545,10 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *co sndrcvinfo->sinfo_flags |= prinfo.pr_policy; break; case SCTP_AUTHINFO: - if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh))) < sizeof(struct sctp_authinfo)) { + if (cmsg_data_len < (int)sizeof(struct sctp_authinfo)) { return (found); } - m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), sizeof(struct sctp_authinfo), (caddr_t)&authinfo); + m_copydata(control, cmsg_data_off, sizeof(struct sctp_authinfo), (caddr_t)&authinfo); sndrcvinfo->sinfo_keynumber_valid = 1; sndrcvinfo->sinfo_keynumber = authinfo.auth_keynumber; break; @@ -3552,7 +3558,6 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *co found = 1; } } - at += CMSG_ALIGN(cmh.cmsg_len); } return (found); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201710271927.v9RJR5Pi022878>