diff options
Diffstat (limited to 'kernel/ip_set.c')
-rw-r--r-- | kernel/ip_set.c | 76 |
1 files changed, 70 insertions, 6 deletions
diff --git a/kernel/ip_set.c b/kernel/ip_set.c index a525518..c4fcc69 100644 --- a/kernel/ip_set.c +++ b/kernel/ip_set.c @@ -20,7 +20,6 @@ #include <linux/skbuff.h> #include <linux/random.h> #include <linux/jhash.h> -#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/errno.h> #include <asm/uaccess.h> #include <asm/bitops.h> @@ -30,10 +29,10 @@ #include <linux/semaphore.h> #endif #include <linux/spinlock.h> -#include <linux/vmalloc.h> #define ASSERT_READ_LOCK(x) #define ASSERT_WRITE_LOCK(x) +#include <linux/netfilter.h> #include <linux/netfilter_ipv4/ip_set.h> static struct list_head set_type_list; /* all registered sets */ @@ -235,10 +234,10 @@ ip_set_testip_kernel(ip_set_id_t index, && follow_bindings(index, set, ip)); read_unlock_bh(&ip_set_lock); - return res; + return (res < 0 ? 0 : res); } -void +int ip_set_addip_kernel(ip_set_id_t index, const struct sk_buff *skb, const u_int32_t *flags) @@ -268,9 +267,11 @@ ip_set_addip_kernel(ip_set_id_t index, && set->type->retry && (res = set->type->retry(set)) == 0) goto retry; + + return res; } -void +int ip_set_delip_kernel(ip_set_id_t index, const struct sk_buff *skb, const u_int32_t *flags) @@ -294,6 +295,8 @@ ip_set_delip_kernel(ip_set_id_t index, && flags[i] && follow_bindings(index, set, ip)); read_unlock_bh(&ip_set_lock); + + return res; } /* Register and deregister settype */ @@ -358,6 +361,29 @@ ip_set_unregister_set_type(struct ip_set_type *set_type) } +ip_set_id_t +__ip_set_get_byname(const char *name, struct ip_set **set) +{ + ip_set_id_t i, index = IP_SET_INVALID_ID; + + for (i = 0; i < ip_set_max; i++) { + if (ip_set_list[i] != NULL + && SETNAME_EQ(ip_set_list[i]->name, name)) { + __ip_set_get(i); + index = i; + *set = ip_set_list[i]; + break; + } + } + return index; +} + +void __ip_set_put_byid(ip_set_id_t index) +{ + if (ip_set_list[index]) + __ip_set_put(index); +} + /* * Userspace routines */ @@ -490,7 +516,16 @@ ip_set_addip(ip_set_id_t index, const void *data, size_t size) { + struct ip_set *set = ip_set_list[index]; + + IP_SET_ASSERT(set); + if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) { + ip_set_printk("data length wrong (want %zu, have %zu)", + set->type->reqsize, + size - sizeof(struct ip_set_req_adt)); + return -EINVAL; + } return __ip_set_addip(index, data + sizeof(struct ip_set_req_adt), size - sizeof(struct ip_set_req_adt)); @@ -506,6 +541,13 @@ ip_set_delip(ip_set_id_t index, int res; IP_SET_ASSERT(set); + + if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) { + ip_set_printk("data length wrong (want %zu, have %zu)", + set->type->reqsize, + size - sizeof(struct ip_set_req_adt)); + return -EINVAL; + } write_lock_bh(&set->lock); res = set->type->delip(set, data + sizeof(struct ip_set_req_adt), @@ -526,6 +568,13 @@ ip_set_testip(ip_set_id_t index, int res; IP_SET_ASSERT(set); + + if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) { + ip_set_printk("data length wrong (want %zu, have %zu)", + set->type->reqsize, + size - sizeof(struct ip_set_req_adt)); + return -EINVAL; + } res = __ip_set_testip(set, data + sizeof(struct ip_set_req_adt), size - sizeof(struct ip_set_req_adt), @@ -805,6 +854,7 @@ ip_set_create(const char *name, int res = 0; DP("setname: %s, typename: %s, id: %u", name, typename, restore); + /* * First, and without any locks, allocate and initialize * a normal base set structure. @@ -848,6 +898,14 @@ ip_set_create(const char *name, } read_unlock_bh(&ip_set_lock); + /* Check request size */ + if (size != set->type->header_size) { + ip_set_printk("data length wrong (want %zu, have %zu)", + set->type->header_size, + size); + goto put_out; + } + /* * Without holding any locks, create private part. */ @@ -1007,7 +1065,9 @@ ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index) u_int32_t from_ref; DP("set: %s to %s", from->name, to->name); - /* Features must not change. Artifical restriction. */ + /* Features must not change. + * Not an artifical restriction anymore, as we must prevent + * possible loops created by swapping in setlist type of sets. */ if (from->type->features != to->type->features) return -ENOEXEC; @@ -1916,6 +1976,7 @@ static struct nf_sockopt_ops so_set = { }; static int max_sets, hash_size; + module_param(max_sets, int, 0600); MODULE_PARM_DESC(max_sets, "maximal number of sets"); module_param(hash_size, int, 0600); @@ -1958,6 +2019,7 @@ static int __init ip_set_init(void) vfree(ip_set_hash); return res; } + return 0; } @@ -1976,6 +2038,8 @@ EXPORT_SYMBOL(ip_set_unregister_set_type); EXPORT_SYMBOL(ip_set_get_byname); EXPORT_SYMBOL(ip_set_get_byindex); EXPORT_SYMBOL(ip_set_put); +EXPORT_SYMBOL(__ip_set_get_byname); +EXPORT_SYMBOL(__ip_set_put_byid); EXPORT_SYMBOL(ip_set_addip_kernel); EXPORT_SYMBOL(ip_set_delip_kernel); |