Skip to content

Commit 7892032

Browse files
edumazetdavem330
authored andcommitted
ip6_gre: fix ip6gre_err() invalid reads
Andrey Konovalov reported out of bound accesses in ip6gre_err() If GRE flags contains GRE_KEY, the following expression *(((__be32 *)p) + (grehlen / 4) - 1) accesses data ~40 bytes after the expected point, since grehlen includes the size of IPv6 headers. Let's use a "struct gre_base_hdr *greh" pointer to make this code more readable. p[1] becomes greh->protocol. grhlen is the GRE header length. Fixes: c12b395 ("gre: Support GRE over IPv6") Signed-off-by: Eric Dumazet <[email protected]> Reported-by: Andrey Konovalov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d71b789 commit 7892032

File tree

1 file changed

+21
-19
lines changed

1 file changed

+21
-19
lines changed

net/ipv6/ip6_gre.c

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -367,35 +367,37 @@ static void ip6gre_tunnel_uninit(struct net_device *dev)
367367

368368

369369
static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
370-
u8 type, u8 code, int offset, __be32 info)
370+
u8 type, u8 code, int offset, __be32 info)
371371
{
372-
const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data;
373-
__be16 *p = (__be16 *)(skb->data + offset);
374-
int grehlen = offset + 4;
372+
const struct gre_base_hdr *greh;
373+
const struct ipv6hdr *ipv6h;
374+
int grehlen = sizeof(*greh);
375375
struct ip6_tnl *t;
376+
int key_off = 0;
376377
__be16 flags;
378+
__be32 key;
377379

378-
flags = p[0];
379-
if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
380-
if (flags&(GRE_VERSION|GRE_ROUTING))
381-
return;
382-
if (flags&GRE_KEY) {
383-
grehlen += 4;
384-
if (flags&GRE_CSUM)
385-
grehlen += 4;
386-
}
380+
if (!pskb_may_pull(skb, offset + grehlen))
381+
return;
382+
greh = (const struct gre_base_hdr *)(skb->data + offset);
383+
flags = greh->flags;
384+
if (flags & (GRE_VERSION | GRE_ROUTING))
385+
return;
386+
if (flags & GRE_CSUM)
387+
grehlen += 4;
388+
if (flags & GRE_KEY) {
389+
key_off = grehlen + offset;
390+
grehlen += 4;
387391
}
388392

389-
/* If only 8 bytes returned, keyed message will be dropped here */
390-
if (!pskb_may_pull(skb, grehlen))
393+
if (!pskb_may_pull(skb, offset + grehlen))
391394
return;
392395
ipv6h = (const struct ipv6hdr *)skb->data;
393-
p = (__be16 *)(skb->data + offset);
396+
greh = (const struct gre_base_hdr *)(skb->data + offset);
397+
key = key_off ? *(__be32 *)(skb->data + key_off) : 0;
394398

395399
t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr,
396-
flags & GRE_KEY ?
397-
*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
398-
p[1]);
400+
key, greh->protocol);
399401
if (!t)
400402
return;
401403

0 commit comments

Comments
 (0)