[PATCH xt-addons] xt_geoip: fix possible out-of-bounds access

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



It is possible for geoip_bsearch() to pick mid == sizeof(subnets).

Consider a set with a single entry and a "address to test"
higher than the range:

1st call: lo = 0, hi = 1 -> mid will be 0
2nd call: lo = 1, hi = 1 -> mid will be 1

On the 2nd call, we'll examine random data.

Fix is to use the maximum valid index instead of the number of elements
in the first geoip_bsearch call.
---
 extensions/xt_geoip.c |   16 +++++++++-------
 1 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/extensions/xt_geoip.c b/extensions/xt_geoip.c
index 4c6b29f..5b2e237 100644
--- a/extensions/xt_geoip.c
+++ b/extensions/xt_geoip.c
@@ -33,7 +33,7 @@ struct geoip_country_kernel {
 	struct list_head list;
 	struct geoip_subnet *subnets;
 	atomic_t ref;
-	unsigned int count;
+	unsigned int max;
 	unsigned short cc;
 };
 
@@ -51,24 +51,26 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr)
 	if (copy_from_user(&umem, umem_ptr, sizeof(umem)) != 0)
 		return ERR_PTR(-EFAULT);
 
+	if (umem.count == 0)
+		return ERR_PTR(-EINVAL);
+
 	p = kmalloc(sizeof(struct geoip_country_kernel), GFP_KERNEL);
 	if (p == NULL)
 		return ERR_PTR(-ENOMEM);
 
-	p->count   = umem.count;
-	p->cc      = umem.cc;
-
-	s = vmalloc(p->count * sizeof(struct geoip_subnet));
+	s = vmalloc(umem.count * sizeof(struct geoip_subnet));
 	if (s == NULL) {
 		ret = -ENOMEM;
 		goto free_p;
 	}
 	if (copy_from_user(s, (const void __user *)(unsigned long)umem.subnets,
-	    p->count * sizeof(struct geoip_subnet)) != 0) {
+	    umem.count * sizeof(struct geoip_subnet)) != 0) {
 		ret = -EFAULT;
 		goto free_s;
 	}
 
+	p->max     = umem.count - 1;	/* last valid index in ->subnets[] */
+	p->cc      = umem.cc;
 	p->subnets = s;
 	atomic_set(&p->ref, 1);
 	INIT_LIST_HEAD(&p->list);
@@ -163,7 +165,7 @@ xt_geoip_mt(const struct sk_buff *skb, struct xt_action_param *par)
 			continue;
 		}
 
-		if (geoip_bsearch(node->subnets, ip, 0, node->count)) {
+		if (geoip_bsearch(node->subnets, ip, 0, node->max)) {
 			rcu_read_unlock();
 			return !(info->flags & XT_GEOIP_INV);
 		}
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux