Skip to content

Commit e75cb46

Browse files
committed
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: Pablo Neira Ayuso <pablo@netfilter.org>
2 parents b486598 + 0aae24e commit e75cb46

File tree

8 files changed

+75
-85
lines changed

8 files changed

+75
-85
lines changed

include/linux/netfilter/ipset/ip_set.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ extern void ip_set_free(void *members);
421421
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
422422
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
423423
extern size_t ip_set_elem_len(struct ip_set *set, struct nlattr *tb[],
424-
size_t len);
424+
size_t len, size_t align);
425425
extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
426426
struct ip_set_ext *ext);
427427

net/netfilter/ipset/ip_set_bitmap_gen.h

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
#define mtype_gc IPSET_TOKEN(MTYPE, _gc)
3434
#define mtype MTYPE
3535

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

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

6969
ip_set_free(map->members);
70-
if (set->dsize) {
71-
if (set->extensions & IPSET_EXT_DESTROY)
72-
mtype_ext_cleanup(set);
73-
ip_set_free(map->extensions);
74-
}
75-
kfree(map);
70+
if (set->dsize && set->extensions & IPSET_EXT_DESTROY)
71+
mtype_ext_cleanup(set);
72+
ip_set_free(map);
7673

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

9694
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
9795
if (!nested)
9896
goto nla_put_failure;
9997
if (mtype_do_head(skb, map) ||
10098
nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
101-
nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
102-
htonl(sizeof(*map) +
103-
map->memsize +
104-
set->dsize * map->elements)))
99+
nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)))
105100
goto nla_put_failure;
106101
if (unlikely(ip_set_put_flags(skb, set)))
107102
goto nla_put_failure;

net/netfilter/ipset/ip_set_bitmap_ip.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,15 @@ MODULE_ALIAS("ip_set_bitmap:ip");
4141
/* Type structure */
4242
struct bitmap_ip {
4343
void *members; /* the set members */
44-
void *extensions; /* data extensions */
4544
u32 first_ip; /* host byte order, included in range */
4645
u32 last_ip; /* host byte order, included in range */
4746
u32 elements; /* number of max elements in the set */
4847
u32 hosts; /* number of hosts in a subnet */
4948
size_t memsize; /* members size */
5049
u8 netmask; /* subnet netmask */
5150
struct timer_list gc; /* garbage collection */
51+
unsigned char extensions[0] /* data extensions */
52+
__aligned(__alignof__(u64));
5253
};
5354

5455
/* ADT structure for generic function args */
@@ -224,13 +225,6 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
224225
map->members = ip_set_alloc(map->memsize);
225226
if (!map->members)
226227
return false;
227-
if (set->dsize) {
228-
map->extensions = ip_set_alloc(set->dsize * elements);
229-
if (!map->extensions) {
230-
kfree(map->members);
231-
return false;
232-
}
233-
}
234228
map->first_ip = first_ip;
235229
map->last_ip = last_ip;
236230
map->elements = elements;
@@ -316,13 +310,13 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
316310
pr_debug("hosts %u, elements %llu\n",
317311
hosts, (unsigned long long)elements);
318312

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

323318
map->memsize = bitmap_bytes(0, elements - 1);
324319
set->variant = &bitmap_ip;
325-
set->dsize = ip_set_elem_len(set, tb, 0);
326320
if (!init_map_ip(set, map, first_ip, last_ip,
327321
elements, hosts, netmask)) {
328322
kfree(map);

net/netfilter/ipset/ip_set_bitmap_ipmac.c

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -47,36 +47,38 @@ enum {
4747
/* Type structure */
4848
struct bitmap_ipmac {
4949
void *members; /* the set members */
50-
void *extensions; /* MAC + data extensions */
5150
u32 first_ip; /* host byte order, included in range */
5251
u32 last_ip; /* host byte order, included in range */
5352
u32 elements; /* number of max elements in the set */
5453
size_t memsize; /* members size */
5554
struct timer_list gc; /* garbage collector */
55+
unsigned char extensions[0] /* MAC + data extensions */
56+
__aligned(__alignof__(u64));
5657
};
5758

5859
/* ADT structure for generic function args */
5960
struct bitmap_ipmac_adt_elem {
61+
unsigned char ether[ETH_ALEN] __aligned(2);
6062
u16 id;
61-
unsigned char *ether;
63+
u16 add_mac;
6264
};
6365

6466
struct bitmap_ipmac_elem {
6567
unsigned char ether[ETH_ALEN];
6668
unsigned char filled;
67-
} __attribute__ ((aligned));
69+
} __aligned(__alignof__(u64));
6870

6971
static inline u32
7072
ip_to_id(const struct bitmap_ipmac *m, u32 ip)
7173
{
7274
return ip - m->first_ip;
7375
}
7476

75-
static inline struct bitmap_ipmac_elem *
76-
get_elem(void *extensions, u16 id, size_t dsize)
77-
{
78-
return (struct bitmap_ipmac_elem *)(extensions + id * dsize);
79-
}
77+
#define get_elem(extensions, id, dsize) \
78+
(struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
79+
80+
#define get_const_elem(extensions, id, dsize) \
81+
(const struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
8082

8183
/* Common functions */
8284

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

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

104105
if (!test_bit(id, map->members))
105106
return 0;
106-
elem = get_elem(map->extensions, id, dsize);
107+
elem = get_const_elem(map->extensions, id, dsize);
107108
/* Timer not started for the incomplete elements */
108109
return elem->filled == MAC_FILLED;
109110
}
@@ -133,7 +134,7 @@ bitmap_ipmac_add_timeout(unsigned long *timeout,
133134
* and we can reuse it later when MAC is filled out,
134135
* possibly by the kernel
135136
*/
136-
if (e->ether)
137+
if (e->add_mac)
137138
ip_set_timeout_set(timeout, t);
138139
else
139140
*timeout = t;
@@ -150,7 +151,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
150151
elem = get_elem(map->extensions, e->id, dsize);
151152
if (test_bit(e->id, map->members)) {
152153
if (elem->filled == MAC_FILLED) {
153-
if (e->ether &&
154+
if (e->add_mac &&
154155
(flags & IPSET_FLAG_EXIST) &&
155156
!ether_addr_equal(e->ether, elem->ether)) {
156157
/* memcpy isn't atomic */
@@ -159,7 +160,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
159160
ether_addr_copy(elem->ether, e->ether);
160161
}
161162
return IPSET_ADD_FAILED;
162-
} else if (!e->ether)
163+
} else if (!e->add_mac)
163164
/* Already added without ethernet address */
164165
return IPSET_ADD_FAILED;
165166
/* Fill the MAC address and trigger the timer activation */
@@ -168,7 +169,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
168169
ether_addr_copy(elem->ether, e->ether);
169170
elem->filled = MAC_FILLED;
170171
return IPSET_ADD_START_STORED_TIMEOUT;
171-
} else if (e->ether) {
172+
} else if (e->add_mac) {
172173
/* We can store MAC too */
173174
ether_addr_copy(elem->ether, e->ether);
174175
elem->filled = MAC_FILLED;
@@ -191,7 +192,7 @@ bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
191192
u32 id, size_t dsize)
192193
{
193194
const struct bitmap_ipmac_elem *elem =
194-
get_elem(map->extensions, id, dsize);
195+
get_const_elem(map->extensions, id, dsize);
195196

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

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

233234
e.id = ip_to_id(map, ip);
234-
e.ether = eth_hdr(skb)->h_source;
235+
memcpy(e.ether, eth_hdr(skb)->h_source, ETH_ALEN);
235236

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

267268
e.id = ip_to_id(map, ip);
268-
if (tb[IPSET_ATTR_ETHER])
269-
e.ether = nla_data(tb[IPSET_ATTR_ETHER]);
270-
else
271-
e.ether = NULL;
272-
269+
if (tb[IPSET_ATTR_ETHER]) {
270+
memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
271+
e.add_mac = 1;
272+
}
273273
ret = adtfn(set, &e, &ext, &ext, flags);
274274

275275
return ip_set_eexist(ret, flags) ? 0 : ret;
@@ -300,13 +300,6 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
300300
map->members = ip_set_alloc(map->memsize);
301301
if (!map->members)
302302
return false;
303-
if (set->dsize) {
304-
map->extensions = ip_set_alloc(set->dsize * elements);
305-
if (!map->extensions) {
306-
kfree(map->members);
307-
return false;
308-
}
309-
}
310303
map->first_ip = first_ip;
311304
map->last_ip = last_ip;
312305
map->elements = elements;
@@ -361,14 +354,15 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
361354
if (elements > IPSET_BITMAP_MAX_RANGE + 1)
362355
return -IPSET_ERR_BITMAP_RANGE_SIZE;
363356

364-
map = kzalloc(sizeof(*map), GFP_KERNEL);
357+
set->dsize = ip_set_elem_len(set, tb,
358+
sizeof(struct bitmap_ipmac_elem),
359+
__alignof__(struct bitmap_ipmac_elem));
360+
map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
365361
if (!map)
366362
return -ENOMEM;
367363

368364
map->memsize = bitmap_bytes(0, elements - 1);
369365
set->variant = &bitmap_ipmac;
370-
set->dsize = ip_set_elem_len(set, tb,
371-
sizeof(struct bitmap_ipmac_elem));
372366
if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
373367
kfree(map);
374368
return -ENOMEM;

net/netfilter/ipset/ip_set_bitmap_port.c

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@ MODULE_ALIAS("ip_set_bitmap:port");
3535
/* Type structure */
3636
struct bitmap_port {
3737
void *members; /* the set members */
38-
void *extensions; /* data extensions */
3938
u16 first_port; /* host byte order, included in range */
4039
u16 last_port; /* host byte order, included in range */
4140
u32 elements; /* number of max elements in the set */
4241
size_t memsize; /* members size */
4342
struct timer_list gc; /* garbage collection */
43+
unsigned char extensions[0] /* data extensions */
44+
__aligned(__alignof__(u64));
4445
};
4546

4647
/* ADT structure for generic function args */
@@ -209,13 +210,6 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
209210
map->members = ip_set_alloc(map->memsize);
210211
if (!map->members)
211212
return false;
212-
if (set->dsize) {
213-
map->extensions = ip_set_alloc(set->dsize * map->elements);
214-
if (!map->extensions) {
215-
kfree(map->members);
216-
return false;
217-
}
218-
}
219213
map->first_port = first_port;
220214
map->last_port = last_port;
221215
set->timeout = IPSET_NO_TIMEOUT;
@@ -232,6 +226,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
232226
{
233227
struct bitmap_port *map;
234228
u16 first_port, last_port;
229+
u32 elements;
235230

236231
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
237232
!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[],
248243
last_port = tmp;
249244
}
250245

251-
map = kzalloc(sizeof(*map), GFP_KERNEL);
246+
elements = last_port - first_port + 1;
247+
set->dsize = ip_set_elem_len(set, tb, 0, 0);
248+
map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
252249
if (!map)
253250
return -ENOMEM;
254251

255-
map->elements = last_port - first_port + 1;
252+
map->elements = elements;
256253
map->memsize = bitmap_bytes(0, map->elements);
257254
set->variant = &bitmap_port;
258-
set->dsize = ip_set_elem_len(set, tb, 0);
259255
if (!init_map_port(set, map, first_port, last_port)) {
260256
kfree(map);
261257
return -ENOMEM;

net/netfilter/ipset/ip_set_core.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -364,25 +364,27 @@ add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[])
364364
}
365365

366366
size_t
367-
ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len)
367+
ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len,
368+
size_t align)
368369
{
369370
enum ip_set_ext_id id;
370-
size_t offset = len;
371371
u32 cadt_flags = 0;
372372

373373
if (tb[IPSET_ATTR_CADT_FLAGS])
374374
cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
375375
if (cadt_flags & IPSET_FLAG_WITH_FORCEADD)
376376
set->flags |= IPSET_CREATE_FLAG_FORCEADD;
377+
if (!align)
378+
align = 1;
377379
for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
378380
if (!add_extension(id, cadt_flags, tb))
379381
continue;
380-
offset = ALIGN(offset, ip_set_extensions[id].align);
381-
set->offset[id] = offset;
382+
len = ALIGN(len, ip_set_extensions[id].align);
383+
set->offset[id] = len;
382384
set->extensions |= ip_set_extensions[id].type;
383-
offset += ip_set_extensions[id].len;
385+
len += ip_set_extensions[id].len;
384386
}
385-
return offset;
387+
return ALIGN(len, align);
386388
}
387389
EXPORT_SYMBOL_GPL(ip_set_elem_len);
388390

0 commit comments

Comments
 (0)