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:
Andrey V. Elsukov 2018-02-05 09:22:07 +00:00
parent f76883d64c
commit 68e0e5a673
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=328876
4 changed files with 30 additions and 44 deletions

View File

@ -578,10 +578,8 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
/*
* 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;

View File

@ -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);
}
/*

View File

@ -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 *);

View File

@ -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);