Commit 78296c97 authored by Eric Dumazet's avatar Eric Dumazet Committed by Pablo Neira Ayuso

netfilter: xt_socket: fix a stack corruption bug

As soon as extract_icmp6_fields() returns, its local storage (automatic
variables) is deallocated and can be overwritten.

Lets add an additional parameter to make sure storage is valid long
enough.

While we are at it, adds some const qualifiers.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Fixes: b64c9256 ("tproxy: added IPv6 support to the socket match")
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent cef9ed86
...@@ -243,12 +243,13 @@ static int ...@@ -243,12 +243,13 @@ static int
extract_icmp6_fields(const struct sk_buff *skb, extract_icmp6_fields(const struct sk_buff *skb,
unsigned int outside_hdrlen, unsigned int outside_hdrlen,
int *protocol, int *protocol,
struct in6_addr **raddr, const struct in6_addr **raddr,
struct in6_addr **laddr, const struct in6_addr **laddr,
__be16 *rport, __be16 *rport,
__be16 *lport) __be16 *lport,
struct ipv6hdr *ipv6_var)
{ {
struct ipv6hdr *inside_iph, _inside_iph; const struct ipv6hdr *inside_iph;
struct icmp6hdr *icmph, _icmph; struct icmp6hdr *icmph, _icmph;
__be16 *ports, _ports[2]; __be16 *ports, _ports[2];
u8 inside_nexthdr; u8 inside_nexthdr;
...@@ -263,12 +264,14 @@ extract_icmp6_fields(const struct sk_buff *skb, ...@@ -263,12 +264,14 @@ extract_icmp6_fields(const struct sk_buff *skb,
if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK) if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
return 1; return 1;
inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph), sizeof(_inside_iph), &_inside_iph); inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph),
sizeof(*ipv6_var), ipv6_var);
if (inside_iph == NULL) if (inside_iph == NULL)
return 1; return 1;
inside_nexthdr = inside_iph->nexthdr; inside_nexthdr = inside_iph->nexthdr;
inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) + sizeof(_inside_iph), inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) +
sizeof(*ipv6_var),
&inside_nexthdr, &inside_fragoff); &inside_nexthdr, &inside_fragoff);
if (inside_hdrlen < 0) if (inside_hdrlen < 0)
return 1; /* hjm: Packet has no/incomplete transport layer headers. */ return 1; /* hjm: Packet has no/incomplete transport layer headers. */
...@@ -315,10 +318,10 @@ xt_socket_get_sock_v6(struct net *net, const u8 protocol, ...@@ -315,10 +318,10 @@ xt_socket_get_sock_v6(struct net *net, const u8 protocol,
static bool static bool
socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par) socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
{ {
struct ipv6hdr *iph = ipv6_hdr(skb); struct ipv6hdr ipv6_var, *iph = ipv6_hdr(skb);
struct udphdr _hdr, *hp = NULL; struct udphdr _hdr, *hp = NULL;
struct sock *sk = skb->sk; struct sock *sk = skb->sk;
struct in6_addr *daddr = NULL, *saddr = NULL; const struct in6_addr *daddr = NULL, *saddr = NULL;
__be16 uninitialized_var(dport), uninitialized_var(sport); __be16 uninitialized_var(dport), uninitialized_var(sport);
int thoff = 0, uninitialized_var(tproto); int thoff = 0, uninitialized_var(tproto);
const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
...@@ -342,7 +345,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -342,7 +345,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
} else if (tproto == IPPROTO_ICMPV6) { } else if (tproto == IPPROTO_ICMPV6) {
if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr, if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
&sport, &dport)) &sport, &dport, &ipv6_var))
return false; return false;
} else { } else {
return false; return false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment