summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel.spec6
-rw-r--r--netfilter-ipset-Fix-extension-alignment.patch481
-rw-r--r--netfilter-ipset-Fix-hash-type-expiration.patch30
-rw-r--r--netfilter-ipset-Fix-hash-type-expire-release-empty-h.patch47
4 files changed, 564 insertions, 0 deletions
diff --git a/kernel.spec b/kernel.spec
index 63f579ffc..00b006b17 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -613,6 +613,11 @@ Patch554: X.509-Fix-the-time-validation-ver-3.patch
Patch555: net_43.mbox
+#rhbz 1279189
+Patch556: netfilter-ipset-Fix-extension-alignment.patch
+Patch557: netfilter-ipset-Fix-hash-type-expiration.patch
+Patch558: netfilter-ipset-Fix-hash-type-expire-release-empty-h.patch
+
# END OF PATCH DEFINITIONS
%endif
@@ -2057,6 +2062,7 @@ fi
#
%changelog
* Mon Nov 16 2015 Josh Boyer <jwboyer@fedoraproject.org>
+- Fix ipset netfilter issues (rhbz 1279189)
- Add queued 4.3 net stable fixes
* Thu Nov 12 2015 Josh Boyer <jwboyer@fedoraproject.org>
diff --git a/netfilter-ipset-Fix-extension-alignment.patch b/netfilter-ipset-Fix-extension-alignment.patch
new file mode 100644
index 000000000..0a955e246
--- /dev/null
+++ b/netfilter-ipset-Fix-extension-alignment.patch
@@ -0,0 +1,481 @@
+From 55301931f78c0fdbb8f76dfdb3f914e9eef1f273 Mon Sep 17 00:00:00 2001
+From: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+Date: Sat, 7 Nov 2015 11:21:47 +0100
+Subject: [PATCH 1/3] netfilter: ipset: Fix extension alignment
+
+The data extensions in ipset lacked the proper memory alignment and
+thus could lead to kernel crash on several architectures. Therefore
+the structures have been reorganized and alignment attributes added
+where needed. The patch was tested on armv7h by Gerhard Wiesinger and
+on x86_64, sparc64 by Jozsef Kadlecsik.
+
+Reported-by: Gerhard Wiesinger <lists@wiesinger.com>
+Tested-by: Gerhard Wiesinger <lists@wiesinger.com>
+Tested-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_bitmap_gen.h | 17 +++-----
+ net/netfilter/ipset/ip_set_bitmap_ip.c | 14 ++-----
+ net/netfilter/ipset/ip_set_bitmap_ipmac.c | 64 ++++++++++++++-----------------
+ net/netfilter/ipset/ip_set_bitmap_port.c | 18 ++++-----
+ net/netfilter/ipset/ip_set_core.c | 14 ++++---
+ net/netfilter/ipset/ip_set_hash_gen.h | 11 ++++--
+ net/netfilter/ipset/ip_set_list_set.c | 5 ++-
+ 8 files changed, 65 insertions(+), 80 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index 48bb01edcf30..0e1f433cc4b7 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -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);
+
+diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
+index d05e759ed0fa..b0bc475f641e 100644
+--- a/net/netfilter/ipset/ip_set_bitmap_gen.h
++++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
+@@ -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)
+- mtype_ext_cleanup(set);
+- ip_set_free(map->extensions);
+- }
+- kfree(map);
++ if (set->dsize && set->extensions & IPSET_EXT_DESTROY)
++ mtype_ext_cleanup(set);
++ 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;
+diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c
+index 64a564334418..4783efff0bde 100644
+--- a/net/netfilter/ipset/ip_set_bitmap_ip.c
++++ b/net/netfilter/ipset/ip_set_bitmap_ip.c
+@@ -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);
+diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+index 1430535118fb..29dde208381d 100644
+--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c
++++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+@@ -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;
+diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c
+index 5338ccd5da46..7f0c733358a4 100644
+--- a/net/netfilter/ipset/ip_set_bitmap_port.c
++++ b/net/netfilter/ipset/ip_set_bitmap_port.c
+@@ -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;
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index 338b4047776f..cab4bc06cddd 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -364,25 +364,27 @@ add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[])
+ }
+
+ size_t
+-ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len)
++ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len,
++ size_t align)
+ {
+ enum ip_set_ext_id id;
+- size_t offset = len;
+ u32 cadt_flags = 0;
+
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (cadt_flags & IPSET_FLAG_WITH_FORCEADD)
+ set->flags |= IPSET_CREATE_FLAG_FORCEADD;
++ if (!align)
++ align = 1;
+ for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
+ if (!add_extension(id, cadt_flags, tb))
+ continue;
+- offset = ALIGN(offset, ip_set_extensions[id].align);
+- set->offset[id] = offset;
++ len = ALIGN(len, ip_set_extensions[id].align);
++ set->offset[id] = len;
+ set->extensions |= ip_set_extensions[id].type;
+- offset += ip_set_extensions[id].len;
++ len += ip_set_extensions[id].len;
+ }
+- return offset;
++ return ALIGN(len, align);
+ }
+ EXPORT_SYMBOL_GPL(ip_set_elem_len);
+
+diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
+index 691b54fcaf2a..4ff22194ce55 100644
+--- a/net/netfilter/ipset/ip_set_hash_gen.h
++++ b/net/netfilter/ipset/ip_set_hash_gen.h
+@@ -72,8 +72,9 @@ struct hbucket {
+ DECLARE_BITMAP(used, AHASH_MAX_TUNED);
+ u8 size; /* size of the array */
+ u8 pos; /* position of the first free entry */
+- unsigned char value[0]; /* the array of the values */
+-} __attribute__ ((aligned));
++ unsigned char value[0] /* the array of the values */
++ __aligned(__alignof__(u64));
++};
+
+ /* The hash table: the table size stored here in order to make resizing easy */
+ struct htable {
+@@ -1323,12 +1324,14 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
+ #endif
+ set->variant = &IPSET_TOKEN(HTYPE, 4_variant);
+ set->dsize = ip_set_elem_len(set, tb,
+- sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)));
++ sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)),
++ __alignof__(struct IPSET_TOKEN(HTYPE, 4_elem)));
+ #ifndef IP_SET_PROTO_UNDEF
+ } else {
+ set->variant = &IPSET_TOKEN(HTYPE, 6_variant);
+ set->dsize = ip_set_elem_len(set, tb,
+- sizeof(struct IPSET_TOKEN(HTYPE, 6_elem)));
++ sizeof(struct IPSET_TOKEN(HTYPE, 6_elem)),
++ __alignof__(struct IPSET_TOKEN(HTYPE, 6_elem)));
+ }
+ #endif
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 5a30ce6e8c90..bbede95c9f68 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -31,7 +31,7 @@ struct set_elem {
+ struct rcu_head rcu;
+ struct list_head list;
+ ip_set_id_t id;
+-};
++} __aligned(__alignof__(u64));
+
+ struct set_adt_elem {
+ ip_set_id_t id;
+@@ -618,7 +618,8 @@ list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
+ size = IP_SET_LIST_MIN_SIZE;
+
+ set->variant = &set_variant;
+- set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem));
++ set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem),
++ __alignof__(struct set_elem));
+ if (!init_list_set(net, set, size))
+ return -ENOMEM;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+--
+2.4.3
+
diff --git a/netfilter-ipset-Fix-hash-type-expiration.patch b/netfilter-ipset-Fix-hash-type-expiration.patch
new file mode 100644
index 000000000..16ba4387f
--- /dev/null
+++ b/netfilter-ipset-Fix-hash-type-expiration.patch
@@ -0,0 +1,30 @@
+From 7210b25e452780f0792e04dd9f84f3a02c582ab7 Mon Sep 17 00:00:00 2001
+From: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+Date: Sat, 7 Nov 2015 11:23:34 +0100
+Subject: [PATCH 2/3] netfilter: ipset: Fix hash:* type expiration
+
+Incorrect index was used when the data blob was shrinked at expiration,
+which could lead to falsely expired entries and memory leak when
+the comment extension was used too.
+
+Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+---
+ net/netfilter/ipset/ip_set_hash_gen.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
+index 4ff22194ce55..fa4f6374bb73 100644
+--- a/net/netfilter/ipset/ip_set_hash_gen.h
++++ b/net/netfilter/ipset/ip_set_hash_gen.h
+@@ -523,7 +523,7 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
+ continue;
+ data = ahash_data(n, j, dsize);
+ memcpy(tmp->value + d * dsize, data, dsize);
+- set_bit(j, tmp->used);
++ set_bit(d, tmp->used);
+ d++;
+ }
+ tmp->pos = d;
+--
+2.4.3
+
diff --git a/netfilter-ipset-Fix-hash-type-expire-release-empty-h.patch b/netfilter-ipset-Fix-hash-type-expire-release-empty-h.patch
new file mode 100644
index 000000000..1f0d86373
--- /dev/null
+++ b/netfilter-ipset-Fix-hash-type-expire-release-empty-h.patch
@@ -0,0 +1,47 @@
+From 03fdcf282c8fe212efae0d1229fb8594ffe60b17 Mon Sep 17 00:00:00 2001
+From: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+Date: Sat, 7 Nov 2015 11:24:51 +0100
+Subject: [PATCH 3/3] netfilter: ipset: Fix hash type expire: release empty
+ hash bucket block
+
+When all entries are expired/all slots are empty, release the bucket.
+
+Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+---
+ net/netfilter/ipset/ip_set_hash_gen.h | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
+index fa4f6374bb73..e5336ab36d67 100644
+--- a/net/netfilter/ipset/ip_set_hash_gen.h
++++ b/net/netfilter/ipset/ip_set_hash_gen.h
+@@ -476,7 +476,7 @@ static void
+ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
+ {
+ struct htable *t;
+- struct hbucket *n;
++ struct hbucket *n, *tmp;
+ struct mtype_elem *data;
+ u32 i, j, d;
+ #ifdef IP_SET_HASH_WITH_NETS
+@@ -511,9 +511,14 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
+ }
+ }
+ if (d >= AHASH_INIT_SIZE) {
+- struct hbucket *tmp = kzalloc(sizeof(*tmp) +
+- (n->size - AHASH_INIT_SIZE) * dsize,
+- GFP_ATOMIC);
++ if (d >= n->size) {
++ rcu_assign_pointer(hbucket(t, i), NULL);
++ kfree_rcu(n, rcu);
++ continue;
++ }
++ tmp = kzalloc(sizeof(*tmp) +
++ (n->size - AHASH_INIT_SIZE) * dsize,
++ GFP_ATOMIC);
+ if (!tmp)
+ /* Still try to delete expired elements */
+ continue;
+--
+2.4.3
+