Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d14b171 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Patrick McHardy
Browse files

netfilter: ipset: fix adding ranges to hash types



When ranges are added to hash types, the elements may trigger rehashing
the set. However, the last successfully added element was not kept track
so the adding started again with the first element after the rehashing.

Bug reported by Mr Dash Four.

Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent c1e2e043
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -244,7 +244,7 @@ struct ip_set_type_variant {
	 *			zero for no match/success to add/delete
	 *			zero for no match/success to add/delete
	 *			positive for matching element */
	 *			positive for matching element */
	int (*uadt)(struct ip_set *set, struct nlattr *tb[],
	int (*uadt)(struct ip_set *set, struct nlattr *tb[],
		    enum ipset_adt adt, u32 *lineno, u32 flags);
		    enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);


	/* Low level add/del/test functions */
	/* Low level add/del/test functions */
	ipset_adtfn adt[IPSET_ADT_MAX];
	ipset_adtfn adt[IPSET_ADT_MAX];
+19 −3
Original line number Original line Diff line number Diff line
@@ -5,6 +5,11 @@
#include <linux/jhash.h>
#include <linux/jhash.h>
#include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_timeout.h>


#define CONCAT(a, b, c)		a##b##c
#define TOKEN(a, b, c)		CONCAT(a, b, c)

#define type_pf_next		TOKEN(TYPE, PF, _elem)

/* Hashing which uses arrays to resolve clashing. The hash table is resized
/* Hashing which uses arrays to resolve clashing. The hash table is resized
 * (doubled) when searching becomes too long.
 * (doubled) when searching becomes too long.
 * Internally jhash is used with the assumption that the size of the
 * Internally jhash is used with the assumption that the size of the
@@ -54,6 +59,7 @@ struct ip_set_hash {
	u32 initval;		/* random jhash init value */
	u32 initval;		/* random jhash init value */
	u32 timeout;		/* timeout value, if enabled */
	u32 timeout;		/* timeout value, if enabled */
	struct timer_list gc;	/* garbage collection when timeout enabled */
	struct timer_list gc;	/* garbage collection when timeout enabled */
	struct type_pf_next next; /* temporary storage for uadd */
#ifdef IP_SET_HASH_WITH_NETMASK
#ifdef IP_SET_HASH_WITH_NETMASK
	u8 netmask;		/* netmask value for subnets to store */
	u8 netmask;		/* netmask value for subnets to store */
#endif
#endif
@@ -217,6 +223,7 @@ ip_set_hash_destroy(struct ip_set *set)
#define type_pf_data_netmask	TOKEN(TYPE, PF, _data_netmask)
#define type_pf_data_netmask	TOKEN(TYPE, PF, _data_netmask)
#define type_pf_data_list	TOKEN(TYPE, PF, _data_list)
#define type_pf_data_list	TOKEN(TYPE, PF, _data_list)
#define type_pf_data_tlist	TOKEN(TYPE, PF, _data_tlist)
#define type_pf_data_tlist	TOKEN(TYPE, PF, _data_tlist)
#define type_pf_data_next	TOKEN(TYPE, PF, _data_next)


#define type_pf_elem		TOKEN(TYPE, PF, _elem)
#define type_pf_elem		TOKEN(TYPE, PF, _elem)
#define type_pf_telem		TOKEN(TYPE, PF, _telem)
#define type_pf_telem		TOKEN(TYPE, PF, _telem)
@@ -346,6 +353,9 @@ type_pf_resize(struct ip_set *set, bool retried)
	return 0;
	return 0;
}
}


static inline void
type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d);

/* Add an element to a hash and update the internal counters when succeeded,
/* Add an element to a hash and update the internal counters when succeeded,
 * otherwise report the proper error code. */
 * otherwise report the proper error code. */
static int
static int
@@ -372,8 +382,11 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
		}
		}


	ret = type_pf_elem_add(n, value);
	ret = type_pf_elem_add(n, value);
	if (ret != 0)
	if (ret != 0) {
		if (ret == -EAGAIN)
			type_pf_data_next(h, d);
		goto out;
		goto out;
	}


#ifdef IP_SET_HASH_WITH_NETS
#ifdef IP_SET_HASH_WITH_NETS
	add_cidr(h, d->cidr, HOST_MASK);
	add_cidr(h, d->cidr, HOST_MASK);
@@ -589,7 +602,7 @@ type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
	     enum ipset_adt adt, const struct ip_set_adt_opt *opt);
	     enum ipset_adt adt, const struct ip_set_adt_opt *opt);
static int
static int
type_pf_uadt(struct ip_set *set, struct nlattr *tb[],
type_pf_uadt(struct ip_set *set, struct nlattr *tb[],
	     enum ipset_adt adt, u32 *lineno, u32 flags);
	     enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);


static const struct ip_set_type_variant type_pf_variant = {
static const struct ip_set_type_variant type_pf_variant = {
	.kadt	= type_pf_kadt,
	.kadt	= type_pf_kadt,
@@ -821,8 +834,11 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
		goto out;
		goto out;
	}
	}
	ret = type_pf_elem_tadd(n, d, timeout);
	ret = type_pf_elem_tadd(n, d, timeout);
	if (ret != 0)
	if (ret != 0) {
		if (ret == -EEXIST)
			type_pf_data_next(h, d);
		goto out;
		goto out;
	}


#ifdef IP_SET_HASH_WITH_NETS
#ifdef IP_SET_HASH_WITH_NETS
	add_cidr(h, d->cidr, HOST_MASK);
	add_cidr(h, d->cidr, HOST_MASK);
+1 −1
Original line number Original line Diff line number Diff line
@@ -236,7 +236,7 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,


static int
static int
bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
	       enum ipset_adt adt, u32 *lineno, u32 flags)
	       enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
{
	struct bitmap_ip *map = set->data;
	struct bitmap_ip *map = set->data;
	ipset_adtfn adtfn = set->variant->adt[adt];
	ipset_adtfn adtfn = set->variant->adt[adt];
+1 −1
Original line number Original line Diff line number Diff line
@@ -365,7 +365,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,


static int
static int
bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
		  enum ipset_adt adt, u32 *lineno, u32 flags)
		  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
{
	const struct bitmap_ipmac *map = set->data;
	const struct bitmap_ipmac *map = set->data;
	ipset_adtfn adtfn = set->variant->adt[adt];
	ipset_adtfn adtfn = set->variant->adt[adt];
+1 −1
Original line number Original line Diff line number Diff line
@@ -231,7 +231,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,


static int
static int
bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
		 enum ipset_adt adt, u32 *lineno, u32 flags)
		 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
{
	struct bitmap_port *map = set->data;
	struct bitmap_port *map = set->data;
	ipset_adtfn adtfn = set->variant->adt[adt];
	ipset_adtfn adtfn = set->variant->adt[adt];
Loading