]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
netfilter: x_tables: check for bogus target offset
authorFlorian Westphal <fw@strlen.de>
Fri, 1 Apr 2016 12:17:28 +0000 (14:17 +0200)
committerChuck Anderson <chuck.anderson@oracle.com>
Fri, 30 Sep 2016 06:05:39 +0000 (23:05 -0700)
Orabug: 24690280
CVE: CVE-2016-3134

[ Upstream commit ce683e5f9d045e5d67d1312a42b359cb2ab2a13c ]

We're currently asserting that targetoff + targetsize <= nextoff.

Extend it to also check that targetoff is >= sizeof(xt_entry).
Since this is generic code, add an argument pointing to the start of the
match/target, we can then derive the base structure size from the delta.

We also need the e->elems pointer in a followup change to validate matches.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
(cherry picked from commit 451e4403bc4abc51539376d4314baa739ab9e996)
Signed-off-by: Brian Maly <brian.maly@oracle.com>
include/linux/netfilter/x_tables.h
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv6/netfilter/ip6_tables.c
net/netfilter/x_tables.c

index 81843aa42a15f0b72a2fedbe288a74fc9114f2de..726f4dd63671322ad5599a28a463526eb6254747 100644 (file)
@@ -239,7 +239,7 @@ void xt_unregister_match(struct xt_match *target);
 int xt_register_matches(struct xt_match *match, unsigned int n);
 void xt_unregister_matches(struct xt_match *match, unsigned int n);
 
-int xt_check_entry_offsets(const void *base,
+int xt_check_entry_offsets(const void *base, const char *elems,
                           unsigned int target_offset,
                           unsigned int next_offset);
 
@@ -435,7 +435,7 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
                                unsigned int *size);
 int xt_compat_target_to_user(const struct xt_entry_target *t,
                             void __user **dstptr, unsigned int *size);
-int xt_compat_check_entry_offsets(const void *base,
+int xt_compat_check_entry_offsets(const void *base, const char *elems,
                                  unsigned int target_offset,
                                  unsigned int next_offset);
 
index d865edf7ae659e87d260240d9569f3ac26402aa4..53315ee89dcd9ea4ffae81510261935e918c9715 100644 (file)
@@ -581,7 +581,8 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
        if (!arp_checkentry(&e->arp))
                return -EINVAL;
 
-       err = xt_check_entry_offsets(e, e->target_offset, e->next_offset);
+       err = xt_check_entry_offsets(e, e->elems, e->target_offset,
+                                    e->next_offset);
        if (err)
                return err;
 
@@ -1246,7 +1247,7 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
        if (!arp_checkentry(&e->arp))
                return -EINVAL;
 
-       ret = xt_compat_check_entry_offsets(e, e->target_offset,
+       ret = xt_compat_check_entry_offsets(e, e->elems, e->target_offset,
                                            e->next_offset);
        if (ret)
                return ret;
index a355ebbaacf22795331cf8ed4d5a2a3b81f4706f..fb00670ef2d81bf3bb47b8c62cee8d2e511ad424 100644 (file)
@@ -741,7 +741,8 @@ check_entry_size_and_hooks(struct ipt_entry *e,
        if (!ip_checkentry(&e->ip))
                return -EINVAL;
 
-       err = xt_check_entry_offsets(e, e->target_offset, e->next_offset);
+       err = xt_check_entry_offsets(e, e->elems, e->target_offset,
+                                    e->next_offset);
        if (err)
                return err;
 
@@ -1511,7 +1512,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
        if (!ip_checkentry(&e->ip))
                return -EINVAL;
 
-       ret = xt_compat_check_entry_offsets(e,
+       ret = xt_compat_check_entry_offsets(e, e->elems,
                                            e->target_offset, e->next_offset);
        if (ret)
                return ret;
index 7157bf5e5c8a000dfb4d854c5cfd70d3cd9b7af6..c09dbcc30f82524ba6bb7f6e592561cdf2d53617 100644 (file)
@@ -755,7 +755,8 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
        if (!ip6_checkentry(&e->ipv6))
                return -EINVAL;
 
-       err = xt_check_entry_offsets(e, e->target_offset, e->next_offset);
+       err = xt_check_entry_offsets(e, e->elems, e->target_offset,
+                                    e->next_offset);
        if (err)
                return err;
 
@@ -1526,7 +1527,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
        if (!ip6_checkentry(&e->ipv6))
                return -EINVAL;
 
-       ret = xt_compat_check_entry_offsets(e,
+       ret = xt_compat_check_entry_offsets(e, e->elems,
                                            e->target_offset, e->next_offset);
        if (ret)
                return ret;
index de38ea6f07387e018e34c50d10fdb408be02fcc6..10b3ceadba1f0410efb3d578b9fff0cb2b299240 100644 (file)
@@ -548,14 +548,17 @@ struct compat_xt_standard_target {
        compat_uint_t verdict;
 };
 
-/* see xt_check_entry_offsets */
-int xt_compat_check_entry_offsets(const void *base,
+int xt_compat_check_entry_offsets(const void *base, const char *elems,
                                  unsigned int target_offset,
                                  unsigned int next_offset)
 {
+       long size_of_base_struct = elems - (const char *)base;
        const struct compat_xt_entry_target *t;
        const char *e = base;
 
+       if (target_offset < size_of_base_struct)
+               return -EINVAL;
+
        if (target_offset + sizeof(*t) > next_offset)
                return -EINVAL;
 
@@ -579,12 +582,16 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets);
  * xt_check_entry_offsets - validate arp/ip/ip6t_entry
  *
  * @base: pointer to arp/ip/ip6t_entry
+ * @elems: pointer to first xt_entry_match, i.e. ip(6)t_entry->elems
  * @target_offset: the arp/ip/ip6_t->target_offset
  * @next_offset: the arp/ip/ip6_t->next_offset
  *
  * validates that target_offset and next_offset are sane.
  * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version.
  *
+ * This function does not validate the targets or matches themselves, it
+ * only tests that all the offsets and sizes are correct.
+ *
  * The arp/ip/ip6t_entry structure @base must have passed following tests:
  * - it must point to a valid memory location
  * - base to base + next_offset must be accessible, i.e. not exceed allocated
@@ -593,12 +600,18 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets);
  * Return: 0 on success, negative errno on failure.
  */
 int xt_check_entry_offsets(const void *base,
+                          const char *elems,
                           unsigned int target_offset,
                           unsigned int next_offset)
 {
+       long size_of_base_struct = elems - (const char *)base;
        const struct xt_entry_target *t;
        const char *e = base;
 
+       /* target start is within the ip/ip6/arpt_entry struct */
+       if (target_offset < size_of_base_struct)
+               return -EINVAL;
+
        if (target_offset + sizeof(*t) > next_offset)
                return -EINVAL;