diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2024-03-05 09:45:14 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2024-03-05 09:45:14 +0000 |
commit | d1f2708733770b9b12d19d819f1c2bfefd08abf8 (patch) | |
tree | e8c41df3f29d0df400fb013949e0ce667d187f3a /sys/netinet/ip_divert.c | |
parent | 0d74db870fbb2e84118058701a42d7be9da72d6d (diff) |
Validate IPv4 packet options in divert output.
When sending raw packets over divert socket, IP options were not
validated. Fragment code tries to copy them and crashes. Raw IP
output has a similar feature, but uses rip_chkhdr() to prevent
invalid packets from userland. Call this funtion also from
divert_output() for strict user input validation.
Reported-by: syzbot+b1ba3a2a8ef13e5b4698@syzkaller.appspotmail.com
OK dlg@ deraadt@ mvs@
Diffstat (limited to 'sys/netinet/ip_divert.c')
-rw-r--r-- | sys/netinet/ip_divert.c | 28 |
1 files changed, 14 insertions, 14 deletions
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index d5ee3004bcb..9c050bb12cc 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_divert.c,v 1.94 2024/02/11 18:14:26 mvs Exp $ */ +/* $OpenBSD: ip_divert.c,v 1.95 2024/03/05 09:45:13 bluhm Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -100,21 +100,19 @@ divert_output(struct inpcb *inp, struct mbuf *m, struct mbuf *nam, if ((error = in_nam2sin(nam, &sin))) goto fail; - /* Do basic sanity checks. */ - if (m->m_pkthdr.len < sizeof(struct ip)) + if (m->m_pkthdr.len > IP_MAXPACKET) { + error = EMSGSIZE; goto fail; - if ((m = m_pullup(m, sizeof(struct ip))) == NULL) { - /* m_pullup() has freed the mbuf, so just return. */ - divstat_inc(divs_errors); - return (ENOBUFS); } - ip = mtod(m, struct ip *); - if (ip->ip_v != IPVERSION) + + m = rip_chkhdr(m, NULL); + if (m == NULL) { + error = EINVAL; goto fail; + } + + ip = mtod(m, struct ip *); off = ip->ip_hl << 2; - if (off < sizeof(struct ip) || ntohs(ip->ip_len) < off || - m->m_pkthdr.len < ntohs(ip->ip_len)) - goto fail; dir = (sin->sin_addr.s_addr == INADDR_ANY ? PF_OUT : PF_IN); @@ -135,8 +133,10 @@ divert_output(struct inpcb *inp, struct mbuf *m, struct mbuf *nam, min_hdrlen = 0; break; } - if (min_hdrlen && m->m_pkthdr.len < off + min_hdrlen) + if (min_hdrlen && m->m_pkthdr.len < off + min_hdrlen) { + error = EINVAL; goto fail; + } m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED_PACKET; @@ -181,7 +181,7 @@ divert_output(struct inpcb *inp, struct mbuf *m, struct mbuf *nam, fail: m_freem(m); divstat_inc(divs_errors); - return (error ? error : EINVAL); + return (error); } void |