diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2018-02-01 21:11:34 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2018-02-01 21:11:34 +0000 |
commit | cd27a87b337bf98a92c327538d63793d4d32ddce (patch) | |
tree | 2ea3f93e8677a68c546a46491ea26ed0f8618ab1 /sys/netinet6/ip6_input.c | |
parent | ea535cb97f3a7fafc0d7bd950aee42618c3f5c6e (diff) |
The function ip6_get_prevhdr() did return a pointer into a mbuf.
It was not guaranteed that the mbuf data was not somewhere else in
the chain. So return an offset and do a proper mbuf pulldown.
found by Maxime Villard; from NetBSD; with markus@; OK deraadt@
Diffstat (limited to 'sys/netinet6/ip6_input.c')
-rw-r--r-- | sys/netinet6/ip6_input.c | 44 |
1 files changed, 19 insertions, 25 deletions
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 6f07b36d9d3..b7dc6287e5a 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_input.c,v 1.210 2017/11/23 13:45:46 mpi Exp $ */ +/* $OpenBSD: ip6_input.c,v 1.211 2018/02/01 21:11:33 bluhm Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -1188,50 +1188,44 @@ ip6_pullexthdr(struct mbuf *m, size_t off, int nxt) } /* - * Get pointer to the previous header followed by the header + * Get offset to the previous header followed by the header * currently processed. - * XXX: This function supposes that - * M includes all headers, - * the next header field and the header length field of each header - * are valid, and - * the sum of each header length equals to OFF. - * Because of these assumptions, this function must be called very - * carefully. Moreover, it will not be used in the near future when - * we develop `neater' mechanism to process extension headers. */ -u_int8_t * +int ip6_get_prevhdr(struct mbuf *m, int off) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - if (off == sizeof(struct ip6_hdr)) - return (&ip6->ip6_nxt); - else { - int len, nxt; - struct ip6_ext *ip6e = NULL; + if (off == sizeof(struct ip6_hdr)) { + return offsetof(struct ip6_hdr, ip6_nxt); + } else if (off < sizeof(struct ip6_hdr)) { + panic("%s: off < sizeof(struct ip6_hdr)", __func__); + } else { + int len, nlen, nxt; + struct ip6_ext ip6e; nxt = ip6->ip6_nxt; len = sizeof(struct ip6_hdr); + nlen = 0; while (len < off) { - ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len); + m_copydata(m, len, sizeof(ip6e), (caddr_t)&ip6e); switch (nxt) { case IPPROTO_FRAGMENT: - len += sizeof(struct ip6_frag); + nlen = sizeof(struct ip6_frag); break; case IPPROTO_AH: - len += (ip6e->ip6e_len + 2) << 2; + nlen = (ip6e.ip6e_len + 2) << 2; break; default: - len += (ip6e->ip6e_len + 1) << 3; + nlen = (ip6e.ip6e_len + 1) << 3; break; } - nxt = ip6e->ip6e_nxt; + len += nlen; + nxt = ip6e.ip6e_nxt; } - if (ip6e) - return (&ip6e->ip6e_nxt); - else - return NULL; + + return (len - nlen); } } |