When sending IPv4 packets on a SOCK_RAW socket using the IP_HDRINCL option,

ensure that the ip_hl field is valid. Furthermore, ensure that the complete
IPv4 header is contained in the first mbuf. Finally, move the length checks
before relying on them when accessing fields of the IPv4 header.
Reported by:		jtl@
Reviewed by:		jtl@
MFC after:		1 week
Differential Revision:	https://reviews.freebsd.org/D19181
This commit is contained in:
Michael Tuexen 2019-04-13 10:47:47 +00:00
parent f7ab01581a
commit 20a6a3a7a7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=346182

View File

@ -453,7 +453,7 @@ rip_output(struct mbuf *m, struct socket *so, ...)
u_long dst;
int flags = ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0) |
IP_ALLOWBROADCAST;
int cnt;
int cnt, hlen;
u_char opttype, optlen, *cp;
va_start(ap, so);
@ -509,33 +509,40 @@ rip_output(struct mbuf *m, struct socket *so, ...)
m_freem(m);
return(EMSGSIZE);
}
INP_RLOCK(inp);
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
if (m->m_len < hlen) {
m = m_pullup(m, hlen);
if (m == NULL)
return (EINVAL);
ip = mtod(m, struct ip *);
}
INP_RLOCK(inp);
/*
* Don't allow both user specified and setsockopt options,
* and don't allow packet length sizes that will crash.
*/
if ((hlen < sizeof (*ip))
|| ((hlen > sizeof (*ip)) && inp->inp_options)
|| (ntohs(ip->ip_len) != m->m_pkthdr.len)) {
INP_RUNLOCK(inp);
m_freem(m);
return (EINVAL);
}
error = prison_check_ip4(inp->inp_cred, &ip->ip_src);
if (error != 0) {
INP_RUNLOCK(inp);
m_freem(m);
return (error);
}
/*
* Don't allow both user specified and setsockopt options,
* and don't allow packet length sizes that will crash.
*/
if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options)
|| (ntohs(ip->ip_len) != m->m_pkthdr.len)
|| (ntohs(ip->ip_len) < (ip->ip_hl << 2))) {
INP_RUNLOCK(inp);
m_freem(m);
return (EINVAL);
}
/*
* Don't allow IP options which do not have the required
* structure as specified in section 3.1 of RFC 791 on
* pages 15-23.
*/
cp = (u_char *)(ip + 1);
cnt = (ip->ip_hl << 2) - sizeof (struct ip);
cnt = hlen - sizeof (struct ip);
for (; cnt > 0; cnt -= optlen, cp += optlen) {
opttype = cp[IPOPT_OPTVAL];
if (opttype == IPOPT_EOL)