summaryrefslogtreecommitdiff
path: root/sys/netinet/ip_divert.c
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2024-03-05 09:45:14 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2024-03-05 09:45:14 +0000
commitd1f2708733770b9b12d19d819f1c2bfefd08abf8 (patch)
treee8c41df3f29d0df400fb013949e0ce667d187f3a /sys/netinet/ip_divert.c
parent0d74db870fbb2e84118058701a42d7be9da72d6d (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.c28
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