Commit 95ad1f4a authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik

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: default avatarGerhard Wiesinger <lists@wiesinger.com>
Tested-by: default avatarGerhard Wiesinger <lists@wiesinger.com>
Tested-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
parent 212cd089
...@@ -421,7 +421,7 @@ extern void ip_set_free(void *members); ...@@ -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_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *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[], 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[], extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
struct ip_set_ext *ext); struct ip_set_ext *ext);
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#define mtype_gc IPSET_TOKEN(MTYPE, _gc) #define mtype_gc IPSET_TOKEN(MTYPE, _gc)
#define mtype MTYPE #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 static void
mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
...@@ -67,12 +67,9 @@ mtype_destroy(struct ip_set *set) ...@@ -67,12 +67,9 @@ mtype_destroy(struct ip_set *set)
del_timer_sync(&map->gc); del_timer_sync(&map->gc);
ip_set_free(map->members); ip_set_free(map->members);
if (set->dsize) { if (set->dsize && set->extensions & IPSET_EXT_DESTROY)
if (set->extensions & IPSET_EXT_DESTROY) mtype_ext_cleanup(set);
mtype_ext_cleanup(set); ip_set_free(map);
ip_set_free(map->extensions);
}
kfree(map);
set->data = NULL; set->data = NULL;
} }
...@@ -92,16 +89,14 @@ mtype_head(struct ip_set *set, struct sk_buff *skb) ...@@ -92,16 +89,14 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
{ {
const struct mtype *map = set->data; const struct mtype *map = set->data;
struct nlattr *nested; struct nlattr *nested;
size_t memsize = sizeof(*map) + map->memsize;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA); nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) if (!nested)
goto nla_put_failure; goto nla_put_failure;
if (mtype_do_head(skb, map) || if (mtype_do_head(skb, map) ||
nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
nla_put_net32(skb, IPSET_ATTR_MEMSIZE, nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)))
htonl(sizeof(*map) +
map->memsize +
set->dsize * map->elements)))
goto nla_put_failure; goto nla_put_failure;
if (unlikely(ip_set_put_flags(skb, set))) if (unlikely(ip_set_put_flags(skb, set)))
goto nla_put_failure; goto nla_put_failure;
......
...@@ -41,7 +41,6 @@ MODULE_ALIAS("ip_set_bitmap:ip"); ...@@ -41,7 +41,6 @@ MODULE_ALIAS("ip_set_bitmap:ip");
/* Type structure */ /* Type structure */
struct bitmap_ip { struct bitmap_ip {
void *members; /* the set members */ void *members; /* the set members */
void *extensions; /* data extensions */
u32 first_ip; /* host byte order, included in range */ u32 first_ip; /* host byte order, included in range */
u32 last_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 */ u32 elements; /* number of max elements in the set */
...@@ -49,6 +48,8 @@ struct bitmap_ip { ...@@ -49,6 +48,8 @@ struct bitmap_ip {
size_t memsize; /* members size */ size_t memsize; /* members size */
u8 netmask; /* subnet netmask */ u8 netmask; /* subnet netmask */
struct timer_list gc; /* garbage collection */ struct timer_list gc; /* garbage collection */
unsigned char extensions[0] /* data extensions */
__aligned(__alignof__(u64));
}; };
/* ADT structure for generic function args */ /* ADT structure for generic function args */
...@@ -224,13 +225,6 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, ...@@ -224,13 +225,6 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
map->members = ip_set_alloc(map->memsize); map->members = ip_set_alloc(map->memsize);
if (!map->members) if (!map->members)
return false; 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->first_ip = first_ip;
map->last_ip = last_ip; map->last_ip = last_ip;
map->elements = elements; map->elements = elements;
...@@ -316,13 +310,13 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -316,13 +310,13 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
pr_debug("hosts %u, elements %llu\n", pr_debug("hosts %u, elements %llu\n",
hosts, (unsigned long long)elements); 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) if (!map)
return -ENOMEM; return -ENOMEM;
map->memsize = bitmap_bytes(0, elements - 1); map->memsize = bitmap_bytes(0, elements - 1);
set->variant = &bitmap_ip; set->variant = &bitmap_ip;
set->dsize = ip_set_elem_len(set, tb, 0);
if (!init_map_ip(set, map, first_ip, last_ip, if (!init_map_ip(set, map, first_ip, last_ip,
elements, hosts, netmask)) { elements, hosts, netmask)) {
kfree(map); kfree(map);
......
...@@ -47,24 +47,26 @@ enum { ...@@ -47,24 +47,26 @@ enum {
/* Type structure */ /* Type structure */
struct bitmap_ipmac { struct bitmap_ipmac {
void *members; /* the set members */ void *members; /* the set members */
void *extensions; /* MAC + data extensions */
u32 first_ip; /* host byte order, included in range */ u32 first_ip; /* host byte order, included in range */
u32 last_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 */ u32 elements; /* number of max elements in the set */
size_t memsize; /* members size */ size_t memsize; /* members size */
struct timer_list gc; /* garbage collector */ struct timer_list gc; /* garbage collector */
unsigned char extensions[0] /* MAC + data extensions */
__aligned(__alignof__(u64));
}; };
/* ADT structure for generic function args */ /* ADT structure for generic function args */
struct bitmap_ipmac_adt_elem { struct bitmap_ipmac_adt_elem {
unsigned char ether[ETH_ALEN] __aligned(2);
u16 id; u16 id;
unsigned char *ether; u16 add_mac;
}; };
struct bitmap_ipmac_elem { struct bitmap_ipmac_elem {
unsigned char ether[ETH_ALEN]; unsigned char ether[ETH_ALEN];
unsigned char filled; unsigned char filled;
} __attribute__ ((aligned)); } __aligned(__alignof__(u64));
static inline u32 static inline u32
ip_to_id(const struct bitmap_ipmac *m, u32 ip) ip_to_id(const struct bitmap_ipmac *m, u32 ip)
...@@ -72,11 +74,11 @@ 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; return ip - m->first_ip;
} }
static inline struct bitmap_ipmac_elem * #define get_elem(extensions, id, dsize) \
get_elem(void *extensions, u16 id, size_t dsize) (struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
{
return (struct bitmap_ipmac_elem *)(extensions + id * dsize); #define get_const_elem(extensions, id, dsize) \
} (const struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
/* Common functions */ /* Common functions */
...@@ -88,10 +90,9 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e, ...@@ -88,10 +90,9 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
if (!test_bit(e->id, map->members)) if (!test_bit(e->id, map->members))
return 0; return 0;
elem = get_elem(map->extensions, e->id, dsize); elem = get_const_elem(map->extensions, e->id, dsize);
if (elem->filled == MAC_FILLED) if (e->add_mac && elem->filled == MAC_FILLED)
return !e->ether || return ether_addr_equal(e->ether, elem->ether);
ether_addr_equal(e->ether, elem->ether);
/* Trigger kernel to fill out the ethernet address */ /* Trigger kernel to fill out the ethernet address */
return -EAGAIN; return -EAGAIN;
} }
...@@ -103,7 +104,7 @@ bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize) ...@@ -103,7 +104,7 @@ bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)
if (!test_bit(id, map->members)) if (!test_bit(id, map->members))
return 0; return 0;
elem = get_elem(map->extensions, id, dsize); elem = get_const_elem(map->extensions, id, dsize);
/* Timer not started for the incomplete elements */ /* Timer not started for the incomplete elements */
return elem->filled == MAC_FILLED; return elem->filled == MAC_FILLED;
} }
...@@ -133,7 +134,7 @@ bitmap_ipmac_add_timeout(unsigned long *timeout, ...@@ -133,7 +134,7 @@ bitmap_ipmac_add_timeout(unsigned long *timeout,
* and we can reuse it later when MAC is filled out, * and we can reuse it later when MAC is filled out,
* possibly by the kernel * possibly by the kernel
*/ */
if (e->ether) if (e->add_mac)
ip_set_timeout_set(timeout, t); ip_set_timeout_set(timeout, t);
else else
*timeout = t; *timeout = t;
...@@ -150,7 +151,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, ...@@ -150,7 +151,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
elem = get_elem(map->extensions, e->id, dsize); elem = get_elem(map->extensions, e->id, dsize);
if (test_bit(e->id, map->members)) { if (test_bit(e->id, map->members)) {
if (elem->filled == MAC_FILLED) { if (elem->filled == MAC_FILLED) {
if (e->ether && if (e->add_mac &&
(flags & IPSET_FLAG_EXIST) && (flags & IPSET_FLAG_EXIST) &&
!ether_addr_equal(e->ether, elem->ether)) { !ether_addr_equal(e->ether, elem->ether)) {
/* memcpy isn't atomic */ /* memcpy isn't atomic */
...@@ -159,7 +160,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, ...@@ -159,7 +160,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
ether_addr_copy(elem->ether, e->ether); ether_addr_copy(elem->ether, e->ether);
} }
return IPSET_ADD_FAILED; return IPSET_ADD_FAILED;
} else if (!e->ether) } else if (!e->add_mac)
/* Already added without ethernet address */ /* Already added without ethernet address */
return IPSET_ADD_FAILED; return IPSET_ADD_FAILED;
/* Fill the MAC address and trigger the timer activation */ /* Fill the MAC address and trigger the timer activation */
...@@ -168,7 +169,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, ...@@ -168,7 +169,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
ether_addr_copy(elem->ether, e->ether); ether_addr_copy(elem->ether, e->ether);
elem->filled = MAC_FILLED; elem->filled = MAC_FILLED;
return IPSET_ADD_START_STORED_TIMEOUT; return IPSET_ADD_START_STORED_TIMEOUT;
} else if (e->ether) { } else if (e->add_mac) {
/* We can store MAC too */ /* We can store MAC too */
ether_addr_copy(elem->ether, e->ether); ether_addr_copy(elem->ether, e->ether);
elem->filled = MAC_FILLED; elem->filled = MAC_FILLED;
...@@ -191,7 +192,7 @@ bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map, ...@@ -191,7 +192,7 @@ bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
u32 id, size_t dsize) u32 id, size_t dsize)
{ {
const struct bitmap_ipmac_elem *elem = 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, return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
htonl(map->first_ip + id)) || htonl(map->first_ip + id)) ||
...@@ -213,7 +214,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -213,7 +214,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
{ {
struct bitmap_ipmac *map = set->data; struct bitmap_ipmac *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; 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); struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
u32 ip; u32 ip;
...@@ -231,7 +232,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -231,7 +232,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
return -EINVAL; return -EINVAL;
e.id = ip_to_id(map, ip); 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); return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
} }
...@@ -265,11 +266,10 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -265,11 +266,10 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
e.id = ip_to_id(map, ip); e.id = ip_to_id(map, ip);
if (tb[IPSET_ATTR_ETHER]) if (tb[IPSET_ATTR_ETHER]) {
e.ether = nla_data(tb[IPSET_ATTR_ETHER]); memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
else e.add_mac = 1;
e.ether = NULL; }
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
...@@ -300,13 +300,6 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, ...@@ -300,13 +300,6 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
map->members = ip_set_alloc(map->memsize); map->members = ip_set_alloc(map->memsize);
if (!map->members) if (!map->members)
return false; 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->first_ip = first_ip;
map->last_ip = last_ip; map->last_ip = last_ip;
map->elements = elements; map->elements = elements;
...@@ -361,14 +354,15 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -361,14 +354,15 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
if (elements > IPSET_BITMAP_MAX_RANGE + 1) if (elements > IPSET_BITMAP_MAX_RANGE + 1)
return -IPSET_ERR_BITMAP_RANGE_SIZE; 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) if (!map)
return -ENOMEM; return -ENOMEM;
map->memsize = bitmap_bytes(0, elements - 1); map->memsize = bitmap_bytes(0, elements - 1);
set->variant = &bitmap_ipmac; 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)) { if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
kfree(map); kfree(map);
return -ENOMEM; return -ENOMEM;
......
...@@ -35,12 +35,13 @@ MODULE_ALIAS("ip_set_bitmap:port"); ...@@ -35,12 +35,13 @@ MODULE_ALIAS("ip_set_bitmap:port");
/* Type structure */ /* Type structure */
struct bitmap_port { struct bitmap_port {
void *members; /* the set members */ void *members; /* the set members */
void *extensions; /* data extensions */
u16 first_port; /* host byte order, included in range */ u16 first_port; /* host byte order, included in range */
u16 last_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 */ u32 elements; /* number of max elements in the set */
size_t memsize; /* members size */ size_t memsize; /* members size */
struct timer_list gc; /* garbage collection */ struct timer_list gc; /* garbage collection */
unsigned char extensions[0] /* data extensions */
__aligned(__alignof__(u64));
}; };
/* ADT structure for generic function args */ /* ADT structure for generic function args */
...@@ -209,13 +210,6 @@ init_map_port(struct ip_set *set, struct bitmap_port *map, ...@@ -209,13 +210,6 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
map->members = ip_set_alloc(map->memsize); map->members = ip_set_alloc(map->memsize);
if (!map->members) if (!map->members)
return false; 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->first_port = first_port;
map->last_port = last_port; map->last_port = last_port;
set->timeout = IPSET_NO_TIMEOUT; set->timeout = IPSET_NO_TIMEOUT;
...@@ -232,6 +226,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -232,6 +226,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
{ {
struct bitmap_port *map; struct bitmap_port *map;
u16 first_port, last_port; u16 first_port, last_port;
u32 elements;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) || !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[], ...@@ -248,14 +243,15 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
last_port = tmp; 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) if (!map)
return -ENOMEM; return -ENOMEM;
map->elements = last_port - first_port + 1; map->elements = elements;
map->memsize = bitmap_bytes(0, map->elements); map->memsize = bitmap_bytes(0, map->elements);
set->variant = &bitmap_port; set->variant = &bitmap_port;
set->dsize = ip_set_elem_len(set, tb, 0);
if (!init_map_port(set, map, first_port, last_port)) { if (!init_map_port(set, map, first_port, last_port)) {
kfree(map); kfree(map);
return -ENOMEM; return -ENOMEM;
......
...@@ -364,25 +364,27 @@ add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[]) ...@@ -364,25 +364,27 @@ add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[])
} }
size_t 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; enum ip_set_ext_id id;
size_t offset = len;
u32 cadt_flags = 0; u32 cadt_flags = 0;
if (tb[IPSET_ATTR_CADT_FLAGS]) if (tb[IPSET_ATTR_CADT_FLAGS])
cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_WITH_FORCEADD) if (cadt_flags & IPSET_FLAG_WITH_FORCEADD)
set->flags |= IPSET_CREATE_FLAG_FORCEADD; set->flags |= IPSET_CREATE_FLAG_FORCEADD;
if (!align)
align = 1;
for (id = 0; id < IPSET_EXT_ID_MAX; id++) { for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
if (!add_extension(id, cadt_flags, tb)) if (!add_extension(id, cadt_flags, tb))
continue; continue;
offset = ALIGN(offset, ip_set_extensions[id].align); len = ALIGN(len, ip_set_extensions[id].align);
set->offset[id] = offset; set->offset[id] = len;
set->extensions |= ip_set_extensions[id].type; 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); EXPORT_SYMBOL_GPL(ip_set_elem_len);
......
...@@ -72,8 +72,9 @@ struct hbucket { ...@@ -72,8 +72,9 @@ struct hbucket {
DECLARE_BITMAP(used, AHASH_MAX_TUNED); DECLARE_BITMAP(used, AHASH_MAX_TUNED);
u8 size; /* size of the array */ u8 size; /* size of the array */
u8 pos; /* position of the first free entry */ u8 pos; /* position of the first free entry */
unsigned char value[0]; /* the array of the values */ unsigned char value[0] /* the array of the values */
} __attribute__ ((aligned)); __aligned(__alignof__(u64));
};
/* The hash table: the table size stored here in order to make resizing easy */ /* The hash table: the table size stored here in order to make resizing easy */
struct htable { struct htable {
...@@ -1323,12 +1324,14 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, ...@@ -1323,12 +1324,14 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
#endif #endif
set->variant = &IPSET_TOKEN(HTYPE, 4_variant); set->variant = &IPSET_TOKEN(HTYPE, 4_variant);
set->dsize = ip_set_elem_len(set, tb, 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 #ifndef IP_SET_PROTO_UNDEF
} else { } else {
set->variant = &IPSET_TOKEN(HTYPE, 6_variant); set->variant = &IPSET_TOKEN(HTYPE, 6_variant);
set->dsize = ip_set_elem_len(set, tb, 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 #endif
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
......
...@@ -31,7 +31,7 @@ struct set_elem { ...@@ -31,7 +31,7 @@ struct set_elem {
struct rcu_head rcu; struct rcu_head rcu;
struct list_head list; struct list_head list;
ip_set_id_t id; ip_set_id_t id;
}; } __aligned(__alignof__(u64));
struct set_adt_elem { struct set_adt_elem {
ip_set_id_t id; ip_set_id_t id;
...@@ -618,7 +618,8 @@ list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -618,7 +618,8 @@ list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
size = IP_SET_LIST_MIN_SIZE; size = IP_SET_LIST_MIN_SIZE;
set->variant = &set_variant; 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)) if (!init_list_set(net, set, size))
return -ENOMEM; return -ENOMEM;
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment