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

Commit e75cb467 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

Merge branch 'master' of git://blackhole.kfki.hu/nf



Jozsef Kadlecsik says:
====================
Please apply the next bugfixes against the nf tree.

- Fix extensions alignment in ipset: Gerhard Wiesinger reported
  that the missing data aligments lead to crash on non-intel
  architecture. The patch was tested on armv7h by Gerhard Wiesinger
  and on x86_64 and sparc64 by me.
- An incorrect index at the hash:* types could lead to
  falsely early expired entries and memory leak when the comment
  extension was used too.
- Release empty hash bucket block when all entries are expired or
  all slots are empty instead of shrinkig the data part to zero.
====================

Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parents b4865988 0aae24eb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -421,7 +421,7 @@ extern void ip_set_free(void *members);
extern int ip_set_get_ipaddr4(struct nlattr *nla,  __be32 *ipaddr);
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
extern size_t ip_set_elem_len(struct ip_set *set, struct nlattr *tb[],
			      size_t len);
			      size_t len, size_t align);
extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
				 struct ip_set_ext *ext);

+6 −11
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
#define mtype_gc		IPSET_TOKEN(MTYPE, _gc)
#define mtype			MTYPE

#define get_ext(set, map, id)	((map)->extensions + (set)->dsize * (id))
#define get_ext(set, map, id)	((map)->extensions + ((set)->dsize * (id)))

static void
mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
@@ -67,12 +67,9 @@ mtype_destroy(struct ip_set *set)
		del_timer_sync(&map->gc);

	ip_set_free(map->members);
	if (set->dsize) {
		if (set->extensions & IPSET_EXT_DESTROY)
	if (set->dsize && set->extensions & IPSET_EXT_DESTROY)
		mtype_ext_cleanup(set);
		ip_set_free(map->extensions);
	}
	kfree(map);
	ip_set_free(map);

	set->data = NULL;
}
@@ -92,16 +89,14 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
{
	const struct mtype *map = set->data;
	struct nlattr *nested;
	size_t memsize = sizeof(*map) + map->memsize;

	nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
	if (!nested)
		goto nla_put_failure;
	if (mtype_do_head(skb, map) ||
	    nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
	    nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
			  htonl(sizeof(*map) +
				map->memsize +
				set->dsize * map->elements)))
	    nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)))
		goto nla_put_failure;
	if (unlikely(ip_set_put_flags(skb, set)))
		goto nla_put_failure;
+4 −10
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@ MODULE_ALIAS("ip_set_bitmap:ip");
/* Type structure */
struct bitmap_ip {
	void *members;		/* the set members */
	void *extensions;	/* data extensions */
	u32 first_ip;		/* host byte order, included in range */
	u32 last_ip;		/* host byte order, included in range */
	u32 elements;		/* number of max elements in the set */
@@ -49,6 +48,8 @@ struct bitmap_ip {
	size_t memsize;		/* members size */
	u8 netmask;		/* subnet netmask */
	struct timer_list gc;	/* garbage collection */
	unsigned char extensions[0]	/* data extensions */
		__aligned(__alignof__(u64));
};

/* ADT structure for generic function args */
@@ -224,13 +225,6 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
	map->members = ip_set_alloc(map->memsize);
	if (!map->members)
		return false;
	if (set->dsize) {
		map->extensions = ip_set_alloc(set->dsize * elements);
		if (!map->extensions) {
			kfree(map->members);
			return false;
		}
	}
	map->first_ip = first_ip;
	map->last_ip = last_ip;
	map->elements = elements;
@@ -316,13 +310,13 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
	pr_debug("hosts %u, elements %llu\n",
		 hosts, (unsigned long long)elements);

	map = kzalloc(sizeof(*map), GFP_KERNEL);
	set->dsize = ip_set_elem_len(set, tb, 0, 0);
	map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
	if (!map)
		return -ENOMEM;

	map->memsize = bitmap_bytes(0, elements - 1);
	set->variant = &bitmap_ip;
	set->dsize = ip_set_elem_len(set, tb, 0);
	if (!init_map_ip(set, map, first_ip, last_ip,
			 elements, hosts, netmask)) {
		kfree(map);
+29 −35
Original line number Diff line number Diff line
@@ -47,24 +47,26 @@ enum {
/* Type structure */
struct bitmap_ipmac {
	void *members;		/* the set members */
	void *extensions;	/* MAC + data extensions */
	u32 first_ip;		/* host byte order, included in range */
	u32 last_ip;		/* host byte order, included in range */
	u32 elements;		/* number of max elements in the set */
	size_t memsize;		/* members size */
	struct timer_list gc;	/* garbage collector */
	unsigned char extensions[0]	/* MAC + data extensions */
		__aligned(__alignof__(u64));
};

/* ADT structure for generic function args */
struct bitmap_ipmac_adt_elem {
	unsigned char ether[ETH_ALEN] __aligned(2);
	u16 id;
	unsigned char *ether;
	u16 add_mac;
};

struct bitmap_ipmac_elem {
	unsigned char ether[ETH_ALEN];
	unsigned char filled;
} __attribute__ ((aligned));
} __aligned(__alignof__(u64));

static inline u32
ip_to_id(const struct bitmap_ipmac *m, u32 ip)
@@ -72,11 +74,11 @@ ip_to_id(const struct bitmap_ipmac *m, u32 ip)
	return ip - m->first_ip;
}

static inline struct bitmap_ipmac_elem *
get_elem(void *extensions, u16 id, size_t dsize)
{
	return (struct bitmap_ipmac_elem *)(extensions + id * dsize);
}
#define get_elem(extensions, id, dsize)		\
	(struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))

#define get_const_elem(extensions, id, dsize)	\
	(const struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))

/* Common functions */

@@ -88,10 +90,9 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,

	if (!test_bit(e->id, map->members))
		return 0;
	elem = get_elem(map->extensions, e->id, dsize);
	if (elem->filled == MAC_FILLED)
		return !e->ether ||
		       ether_addr_equal(e->ether, elem->ether);
	elem = get_const_elem(map->extensions, e->id, dsize);
	if (e->add_mac && elem->filled == MAC_FILLED)
		return ether_addr_equal(e->ether, elem->ether);
	/* Trigger kernel to fill out the ethernet address */
	return -EAGAIN;
}
@@ -103,7 +104,7 @@ bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)

	if (!test_bit(id, map->members))
		return 0;
	elem = get_elem(map->extensions, id, dsize);
	elem = get_const_elem(map->extensions, id, dsize);
	/* Timer not started for the incomplete elements */
	return elem->filled == MAC_FILLED;
}
@@ -133,7 +134,7 @@ bitmap_ipmac_add_timeout(unsigned long *timeout,
		 * and we can reuse it later when MAC is filled out,
		 * possibly by the kernel
		 */
		if (e->ether)
		if (e->add_mac)
			ip_set_timeout_set(timeout, t);
		else
			*timeout = t;
@@ -150,7 +151,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
	elem = get_elem(map->extensions, e->id, dsize);
	if (test_bit(e->id, map->members)) {
		if (elem->filled == MAC_FILLED) {
			if (e->ether &&
			if (e->add_mac &&
			    (flags & IPSET_FLAG_EXIST) &&
			    !ether_addr_equal(e->ether, elem->ether)) {
				/* memcpy isn't atomic */
@@ -159,7 +160,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
				ether_addr_copy(elem->ether, e->ether);
			}
			return IPSET_ADD_FAILED;
		} else if (!e->ether)
		} else if (!e->add_mac)
			/* Already added without ethernet address */
			return IPSET_ADD_FAILED;
		/* Fill the MAC address and trigger the timer activation */
@@ -168,7 +169,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
		ether_addr_copy(elem->ether, e->ether);
		elem->filled = MAC_FILLED;
		return IPSET_ADD_START_STORED_TIMEOUT;
	} else if (e->ether) {
	} else if (e->add_mac) {
		/* We can store MAC too */
		ether_addr_copy(elem->ether, e->ether);
		elem->filled = MAC_FILLED;
@@ -191,7 +192,7 @@ bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
		     u32 id, size_t dsize)
{
	const struct bitmap_ipmac_elem *elem =
		get_elem(map->extensions, id, dsize);
		get_const_elem(map->extensions, id, dsize);

	return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
			       htonl(map->first_ip + id)) ||
@@ -213,7 +214,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
{
	struct bitmap_ipmac *map = set->data;
	ipset_adtfn adtfn = set->variant->adt[adt];
	struct bitmap_ipmac_adt_elem e = { .id = 0 };
	struct bitmap_ipmac_adt_elem e = { .id = 0, .add_mac = 1 };
	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
	u32 ip;

@@ -231,7 +232,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
		return -EINVAL;

	e.id = ip_to_id(map, ip);
	e.ether = eth_hdr(skb)->h_source;
	memcpy(e.ether, eth_hdr(skb)->h_source, ETH_ALEN);

	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
@@ -265,11 +266,10 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
		return -IPSET_ERR_BITMAP_RANGE;

	e.id = ip_to_id(map, ip);
	if (tb[IPSET_ATTR_ETHER])
		e.ether = nla_data(tb[IPSET_ATTR_ETHER]);
	else
		e.ether = NULL;

	if (tb[IPSET_ATTR_ETHER]) {
		memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
		e.add_mac = 1;
	}
	ret = adtfn(set, &e, &ext, &ext, flags);

	return ip_set_eexist(ret, flags) ? 0 : ret;
@@ -300,13 +300,6 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
	map->members = ip_set_alloc(map->memsize);
	if (!map->members)
		return false;
	if (set->dsize) {
		map->extensions = ip_set_alloc(set->dsize * elements);
		if (!map->extensions) {
			kfree(map->members);
			return false;
		}
	}
	map->first_ip = first_ip;
	map->last_ip = last_ip;
	map->elements = elements;
@@ -361,14 +354,15 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
	if (elements > IPSET_BITMAP_MAX_RANGE + 1)
		return -IPSET_ERR_BITMAP_RANGE_SIZE;

	map = kzalloc(sizeof(*map), GFP_KERNEL);
	set->dsize = ip_set_elem_len(set, tb,
				     sizeof(struct bitmap_ipmac_elem),
				     __alignof__(struct bitmap_ipmac_elem));
	map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
	if (!map)
		return -ENOMEM;

	map->memsize = bitmap_bytes(0, elements - 1);
	set->variant = &bitmap_ipmac;
	set->dsize = ip_set_elem_len(set, tb,
				     sizeof(struct bitmap_ipmac_elem));
	if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
		kfree(map);
		return -ENOMEM;
+7 −11
Original line number Diff line number Diff line
@@ -35,12 +35,13 @@ MODULE_ALIAS("ip_set_bitmap:port");
/* Type structure */
struct bitmap_port {
	void *members;		/* the set members */
	void *extensions;	/* data extensions */
	u16 first_port;		/* host byte order, included in range */
	u16 last_port;		/* host byte order, included in range */
	u32 elements;		/* number of max elements in the set */
	size_t memsize;		/* members size */
	struct timer_list gc;	/* garbage collection */
	unsigned char extensions[0]	/* data extensions */
		__aligned(__alignof__(u64));
};

/* ADT structure for generic function args */
@@ -209,13 +210,6 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
	map->members = ip_set_alloc(map->memsize);
	if (!map->members)
		return false;
	if (set->dsize) {
		map->extensions = ip_set_alloc(set->dsize * map->elements);
		if (!map->extensions) {
			kfree(map->members);
			return false;
		}
	}
	map->first_port = first_port;
	map->last_port = last_port;
	set->timeout = IPSET_NO_TIMEOUT;
@@ -232,6 +226,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
{
	struct bitmap_port *map;
	u16 first_port, last_port;
	u32 elements;

	if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -248,14 +243,15 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
		last_port = tmp;
	}

	map = kzalloc(sizeof(*map), GFP_KERNEL);
	elements = last_port - first_port + 1;
	set->dsize = ip_set_elem_len(set, tb, 0, 0);
	map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
	if (!map)
		return -ENOMEM;

	map->elements = last_port - first_port + 1;
	map->elements = elements;
	map->memsize = bitmap_bytes(0, map->elements);
	set->variant = &bitmap_port;
	set->dsize = ip_set_elem_len(set, tb, 0);
	if (!init_map_port(set, map, first_port, last_port)) {
		kfree(map);
		return -ENOMEM;
Loading