summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2015-02-15 19:03:45 -0800
committerBen Hutchings <ben@decadent.org.uk>2015-05-09 23:16:18 +0100
commit9420e955c943fca376b90be12af248b7299780ac (patch)
tree6e7f6a76ce4a601687aa995b8779df9393297117 /net
parent1e5bf5ca07dd5cb37b491074e6050b5633bf4c5a (diff)
netfilter: xt_socket: fix a stack corruption bug
commit 78296c97ca1fd3b104f12e1f1fbc06c46635990b upstream. 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: Eric Dumazet <edumazet@google.com> Fixes: b64c9256a9b76 ("tproxy: added IPv6 support to the socket match") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/xt_socket.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index fe39f7e913df..c4706be65add 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -205,12 +205,13 @@ static int
extract_icmp6_fields(const struct sk_buff *skb,
unsigned int outside_hdrlen,
int *protocol,
- struct in6_addr **raddr,
- struct in6_addr **laddr,
+ const struct in6_addr **raddr,
+ const struct in6_addr **laddr,
__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;
__be16 *ports, _ports[2];
u8 inside_nexthdr;
@@ -224,12 +225,15 @@ extract_icmp6_fields(const struct sk_buff *skb,
if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
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)
return 1;
inside_nexthdr = inside_iph->nexthdr;
- inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) + sizeof(_inside_iph), &inside_nexthdr);
+ inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) +
+ sizeof(*ipv6_var),
+ &inside_nexthdr);
if (inside_hdrlen < 0)
return 1; /* hjm: Packet has no/incomplete transport layer headers. */
@@ -256,10 +260,10 @@ extract_icmp6_fields(const struct sk_buff *skb,
static bool
socket_mt6_v1(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 sock *sk;
- struct in6_addr *daddr, *saddr;
+ const struct in6_addr *daddr, *saddr;
__be16 dport, sport;
int thoff, tproto;
const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
@@ -283,7 +287,7 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
} else if (tproto == IPPROTO_ICMPV6) {
if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
- &sport, &dport))
+ &sport, &dport, &ipv6_var))
return false;
} else {
return false;