Modify ip6_get_prevhdr() to be able use it safely.
Instead of returning pointer to the previous header, return its offset. In frag6_input() use m_copyback() and determined offset to store next header instead of accessing to it by pointer and assuming that the memory is contiguous. In rip6_input() use offset returned by ip6_get_prevhdr() instead of calculating it from pointers arithmetic, because IP header can belong to another mbuf in the chain. Reported by: Maxime Villard <max at m00nbsd dot net> Reviewed by: kp MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D14158
This commit is contained in:
parent
f76883d64c
commit
68e0e5a673
@ -578,10 +578,8 @@ insert:
|
||||
/*
|
||||
* Store NXT to the original.
|
||||
*/
|
||||
{
|
||||
char *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */
|
||||
*prvnxtp = nxt;
|
||||
}
|
||||
m_copyback(m, ip6_get_prevhdr(m, offset), sizeof(uint8_t),
|
||||
(caddr_t)&nxt);
|
||||
|
||||
frag6_remque(q6);
|
||||
V_frag6_nfrags -= q6->ip6q_nfrag;
|
||||
|
@ -1711,49 +1711,39 @@ ip6_pullexthdr(struct mbuf *m, size_t off, int nxt)
|
||||
/*
|
||||
* Get pointer 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.
|
||||
*/
|
||||
char *
|
||||
int
|
||||
ip6_get_prevhdr(const struct mbuf *m, int off)
|
||||
{
|
||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
||||
struct ip6_ext ip6e;
|
||||
struct ip6_hdr *ip6;
|
||||
int len, nlen, nxt;
|
||||
|
||||
if (off == sizeof(struct ip6_hdr))
|
||||
return (&ip6->ip6_nxt);
|
||||
else {
|
||||
int len, nxt;
|
||||
struct ip6_ext *ip6e = NULL;
|
||||
return (offsetof(struct ip6_hdr, ip6_nxt));
|
||||
if (off < sizeof(struct ip6_hdr))
|
||||
panic("%s: off < sizeof(struct ip6_hdr)", __func__);
|
||||
|
||||
nxt = ip6->ip6_nxt;
|
||||
len = sizeof(struct ip6_hdr);
|
||||
while (len < off) {
|
||||
ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len);
|
||||
|
||||
switch (nxt) {
|
||||
case IPPROTO_FRAGMENT:
|
||||
len += sizeof(struct ip6_frag);
|
||||
break;
|
||||
case IPPROTO_AH:
|
||||
len += (ip6e->ip6e_len + 2) << 2;
|
||||
break;
|
||||
default:
|
||||
len += (ip6e->ip6e_len + 1) << 3;
|
||||
break;
|
||||
}
|
||||
nxt = ip6e->ip6e_nxt;
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
nxt = ip6->ip6_nxt;
|
||||
len = sizeof(struct ip6_hdr);
|
||||
nlen = 0;
|
||||
while (len < off) {
|
||||
m_copydata(m, len, sizeof(ip6e), (caddr_t)&ip6e);
|
||||
switch (nxt) {
|
||||
case IPPROTO_FRAGMENT:
|
||||
nlen = sizeof(struct ip6_frag);
|
||||
break;
|
||||
case IPPROTO_AH:
|
||||
nlen = (ip6e.ip6e_len + 2) << 2;
|
||||
break;
|
||||
default:
|
||||
nlen = (ip6e.ip6e_len + 1) << 3;
|
||||
}
|
||||
if (ip6e)
|
||||
return (&ip6e->ip6e_nxt);
|
||||
else
|
||||
return NULL;
|
||||
len += nlen;
|
||||
nxt = ip6e.ip6e_nxt;
|
||||
}
|
||||
return (len - nlen);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -364,7 +364,7 @@ void ip6_direct_input(struct mbuf *);
|
||||
void ip6_freepcbopts(struct ip6_pktopts *);
|
||||
|
||||
int ip6_unknown_opt(u_int8_t *, struct mbuf *, int);
|
||||
char * ip6_get_prevhdr(const struct mbuf *, int);
|
||||
int ip6_get_prevhdr(const struct mbuf *, int);
|
||||
int ip6_nexthdr(const struct mbuf *, int, int, int *);
|
||||
int ip6_lasthdr(const struct mbuf *, int, int, int *);
|
||||
|
||||
|
@ -325,12 +325,10 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
|
||||
RIP6STAT_INC(rip6s_nosockmcast);
|
||||
if (proto == IPPROTO_NONE)
|
||||
m_freem(m);
|
||||
else {
|
||||
char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
|
||||
else
|
||||
icmp6_error(m, ICMP6_PARAM_PROB,
|
||||
ICMP6_PARAMPROB_NEXTHEADER,
|
||||
prvnxtp - mtod(m, char *));
|
||||
}
|
||||
ip6_get_prevhdr(m, *offp));
|
||||
IP6STAT_DEC(ip6s_delivered);
|
||||
}
|
||||
return (IPPROTO_DONE);
|
||||
|
Loading…
x
Reference in New Issue
Block a user