[Devel] [PATCH RHEL7 COMMIT] ms/netfilter: x_tables: check for bogus target offset

Konstantin Khorenko khorenko at virtuozzo.com
Mon Jun 27 04:35:36 PDT 2016


The commit is pushed to "branch-rh7-3.10.0-327.18.2.vz7.14.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.18.2.vz7.14.21
------>
commit c54135d37b6237aed18d0353d3d95fc96a3e71cd
Author: Cyrill Gorcunov <gorcunov at virtuozzo.com>
Date:   Mon Jun 27 15:35:35 2016 +0400

    ms/netfilter: x_tables: check for bogus target offset
    
    ML: ce683e5f9d045e5d67d1312a42b359cb2ab2a13c
    
    gorcunov@: Drop check for xt_entry
    
    From: Florian Westphal <fw at strlen.de>
    
    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 at strlen.de>
    Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>
    Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
    
    https://jira.sw.ru/browse/PSBM-49001
    
    Reviewed-by: Vladimir Davydov <vdavydov at virtuozzo.com>
---
 net/ipv4/netfilter/arp_tables.c | 8 ++++++++
 net/ipv4/netfilter/ip_tables.c  | 8 ++++++++
 net/ipv6/netfilter/ip6_tables.c | 8 ++++++++
 3 files changed, 24 insertions(+)

diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index fbfa74e..e2a53cb 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -603,6 +603,10 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
 	if (err)
 		return err;
 
+	/* target start is within the ip/ip6/arpt_entry struct */
+	if (e->target_offset < ((const void *)e->elems - (const void *)e))
+		return -EINVAL;
+
 	/* Check hooks & underflows */
 	for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
 		if (!(valid_hooks & (1 << h)))
@@ -1261,6 +1265,10 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
 	if (ret)
 		return ret;
 
+	/* target start is within the ip/ip6/arpt_entry struct */
+	if (e->target_offset < ((const void *)e->elems - (const void *)e))
+		return -EINVAL;
+
 	off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
 	entry_offset = (void *)e - (void *)base;
 
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 07370e5..a95135f 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -754,6 +754,10 @@ check_entry_size_and_hooks(struct ipt_entry *e,
 	if (err)
 		return err;
 
+	/* target start is within the ip/ip6/arpt_entry struct */
+	if (e->target_offset < ((const void *)e->elems - (const void *)e))
+		return -EINVAL;
+
 	/* Check hooks & underflows */
 	for (h = 0; h < NF_INET_NUMHOOKS; h++) {
 		if (!(valid_hooks & (1 << h)))
@@ -1508,6 +1512,10 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
 	if (ret)
 		return ret;
 
+	/* target start is within the ip/ip6/arpt_entry struct */
+	if (e->target_offset < ((const void *)e->elems - (const void *)e))
+		return -EINVAL;
+
 	off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
 	entry_offset = (void *)e - (void *)base;
 	j = 0;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 43919b8..8d053b2 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -763,6 +763,10 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
 	if (err)
 		return err;
 
+	/* target start is within the ip/ip6/arpt_entry struct */
+	if (e->target_offset < ((const void *)e->elems - (const void *)e))
+		return -EINVAL;
+
 	/* Check hooks & underflows */
 	for (h = 0; h < NF_INET_NUMHOOKS; h++) {
 		if (!(valid_hooks & (1 << h)))
@@ -1517,6 +1521,10 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
 	if (ret)
 		return ret;
 
+	/* target start is within the ip/ip6/arpt_entry struct */
+	if (e->target_offset < ((const void *)e->elems - (const void *)e))
+		return -EINVAL;
+
 	off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
 	entry_offset = (void *)e - (void *)base;
 	j = 0;


More information about the Devel mailing list