Improve input validation for raw IPv4 socket using the IP_HDRINCL

option.

This issue was found by running syzkaller on OpenBSD.
Greg Steuck made me aware that the problem might also exist on FreeBSD.

Reported by:		Greg Steuck
MFC after:		1 month
Differential Revision:	https://reviews.freebsd.org/D18834
This commit is contained in:
tuexen 2019-02-12 10:17:21 +00:00
parent 1e690381ab
commit 6903958c2a

View File

@ -454,6 +454,8 @@ 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;
u_char opttype, optlen, *cp;
va_start(ap, so);
dst = va_arg(ap, u_long);
@ -528,6 +530,34 @@ rip_output(struct mbuf *m, struct socket *so, ...)
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);
for (; cnt > 0; cnt -= optlen, cp += optlen) {
opttype = cp[IPOPT_OPTVAL];
if (opttype == IPOPT_EOL)
break;
if (opttype == IPOPT_NOP) {
optlen = 1;
continue;
}
if (cnt < IPOPT_OLEN + sizeof(u_char)) {
INP_RUNLOCK(inp);
m_freem(m);
return (EINVAL);
}
optlen = cp[IPOPT_OLEN];
if (optlen < IPOPT_OLEN + sizeof(u_char) ||
optlen > cnt) {
INP_RUNLOCK(inp);
m_freem(m);
return (EINVAL);
}
}
/*
* This doesn't allow application to specify ID of zero,
* but we got this limitation from the beginning of history.