Hi,
Deep in ip6_hbhchcheck() may modify the mbuf pointer. Instead of
having dangling pointer that we must not use, pass pointer to mbuf
pointer and keep it consistent in the caller.
ok?
bluhm
Index: netinet6/ip6_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.246
diff -u -p -r1.246 ip6_input.c
--- netinet6/ip6_input.c 28 Jun 2022 08:24:29 -0000 1.246
+++ netinet6/ip6_input.c 28 Jun 2022 10:51:43 -0000
@@ -122,7 +122,7 @@ uint8_t ip6_soiikey[IP6_SOIIKEY_LEN];
int ip6_ours(struct mbuf **, int *, int, int);
int ip6_local(struct mbuf **, int *, int, int);
int ip6_check_rh0hdr(struct mbuf *, int *);
-int ip6_hbhchcheck(struct mbuf *, int *, int *);
+int ip6_hbhchcheck(struct mbuf **, int *, int *);
int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int);
int ip6_sysctl_soiikey(void *, size_t *, void *, size_t);
@@ -424,7 +424,7 @@ ip6_input_if(struct mbuf **mp, int *offp
if (ip6_mforwarding && ip6_mrouter[ifp->if_rdomain]) {
int error;
- nxt = ip6_hbhchcheck(m, offp, &ours);
+ nxt = ip6_hbhchcheck(&m, offp, &ours);
if (nxt == IPPROTO_DONE)
goto out;
@@ -544,7 +544,7 @@ ip6_input_if(struct mbuf **mp, int *offp
goto bad;
}
- nxt = ip6_hbhchcheck(m, offp, &ours);
+ nxt = ip6_hbhchcheck(&m, offp, &ours);
if (nxt == IPPROTO_DONE)
goto out;
@@ -586,7 +586,7 @@ ip6_local(struct mbuf **mp, int *offp, i
{
NET_ASSERT_WLOCKED();
- nxt = ip6_hbhchcheck(*mp, offp, NULL);
+ nxt = ip6_hbhchcheck(mp, offp, NULL);
if (nxt == IPPROTO_DONE)
return IPPROTO_DONE;
@@ -597,13 +597,13 @@ ip6_local(struct mbuf **mp, int *offp, i
}
int
-ip6_hbhchcheck(struct mbuf *m, int *offp, int *oursp)
+ip6_hbhchcheck(struct mbuf **mp, int *offp, int *oursp)
{
struct ip6_hdr *ip6;
u_int32_t plen, rtalert = ~0;
int nxt;
- ip6 = mtod(m, struct ip6_hdr *);
+ ip6 = mtod(*mp, struct ip6_hdr *);
/*
* Process Hop-by-Hop options header if it's contained.
@@ -615,12 +615,11 @@ ip6_hbhchcheck(struct mbuf *m, int *offp
if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
struct ip6_hbh *hbh;
- if (ip6_hopopts_input(&plen, &rtalert, &m, offp)) {
+ if (ip6_hopopts_input(&plen, &rtalert, mp, offp))
goto bad; /* m have already been freed */
- }
/* adjust pointer */
- ip6 = mtod(m, struct ip6_hdr *);
+ ip6 = mtod(*mp, struct ip6_hdr *);
/*
* if the payload length field is 0 and the next header field
@@ -634,13 +633,13 @@ ip6_hbhchcheck(struct mbuf *m, int *offp
* (non-zero) payload length to the variable plen.
*/
ip6stat_inc(ip6s_badoptions);
- icmp6_error(m, ICMP6_PARAM_PROB,
+ icmp6_error(*mp, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
(caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
goto bad;
}
- IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
- sizeof(struct ip6_hbh));
+ IP6_EXTHDR_GET(hbh, struct ip6_hbh *, *mp,
+ sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
if (hbh == NULL) {
ip6stat_inc(ip6s_tooshort);
goto bad;
@@ -662,18 +661,18 @@ ip6_hbhchcheck(struct mbuf *m, int *offp
* Trim mbufs if longer than we expect.
* Drop packet if shorter than we expect.
*/
- if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
+ if ((*mp)->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
ip6stat_inc(ip6s_tooshort);
- m_freem(m);
+ m_freemp(mp);
goto bad;
}
- if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) {
- if (m->m_len == m->m_pkthdr.len) {
- m->m_len = sizeof(struct ip6_hdr) + plen;
- m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen;
+ if ((*mp)->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) {
+ if ((*mp)->m_len == (*mp)->m_pkthdr.len) {
+ (*mp)->m_len = sizeof(struct ip6_hdr) + plen;
+ (*mp)->m_pkthdr.len = sizeof(struct ip6_hdr) + plen;
} else {
- m_adj(m,
- sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len);
+ m_adj((*mp), sizeof(struct ip6_hdr) + plen -
+ (*mp)->m_pkthdr.len);
}
}
@@ -760,19 +759,18 @@ int
ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, struct mbuf **mp,
int *offp)
{
- struct mbuf *m = *mp;
int off = *offp, hbhlen;
struct ip6_hbh *hbh;
/* validation of the length of the header */
- IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
+ IP6_EXTHDR_GET(hbh, struct ip6_hbh *, *mp,
sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
if (hbh == NULL) {
ip6stat_inc(ip6s_tooshort);
return -1;
}
hbhlen = (hbh->ip6h_len + 1) << 3;
- IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
+ IP6_EXTHDR_GET(hbh, struct ip6_hbh *, *mp, sizeof(struct ip6_hdr),
hbhlen);
if (hbh == NULL) {
ip6stat_inc(ip6s_tooshort);
@@ -781,12 +779,11 @@ ip6_hopopts_input(u_int32_t *plenp, u_in
off += hbhlen;
hbhlen -= sizeof(struct ip6_hbh);
- if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh),
+ if (ip6_process_hopopts(*mp, (u_int8_t *)hbh + sizeof(struct ip6_hbh),
hbhlen, rtalertp, plenp) < 0)
return (-1);
*offp = off;
- *mp = m;
return (0);
}