Skip to content

Commit 4d80ecd

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for you net tree, they are: 1) Restore __GFP_NORETRY in xt_table allocations to mitigate effects of large memory allocation requests, from Michal Hocko. 2) Release IPv6 fragment queue in case of error in fragmentation header, this is a follow up to amend patch 83f1999, from Subash Abhinov Kasiviswanathan. 3) Flowtable infrastructure depends on NETFILTER_INGRESS as it registers a hook for each flowtable, reported by John Crispin. 4) Missing initialization of info->priv in xt_cgroup version 1, from Cong Wang. 5) Give a chance to garbage collector to run after scheduling flowtable cleanup. 6) Releasing flowtable content on nft_flow_offload module removal is not required at all, there is not dependencies between this module and flowtables, remove it. 7) Fix missing xt_rateest_mutex grabbing for hash insertions, also from Cong Wang. 8) Move nf_flow_table_cleanup() routine to flowtable core, this patch is a dependency for the next patch in this list. 9) Flowtable resources are not properly released on removal from the control plane. Fix this resource leak by scheduling removal of all entries and explicit call to the garbage collector. 10) nf_ct_nat_offset() declaration is dead code, this function prototype is not used anywhere, remove it. From Taehee Yoo. 11) Fix another flowtable resource leak on entry insertion failures, this patch also fixes a possible use-after-free. Patch from Felix Fietkau. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents a2e5790 + 0ff90b6 commit 4d80ecd

File tree

15 files changed

+97
-79
lines changed

15 files changed

+97
-79
lines changed

include/net/netfilter/nf_conntrack.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,6 @@ static inline bool nf_ct_kill(struct nf_conn *ct)
213213
return nf_ct_delete(ct, 0, 0);
214214
}
215215

216-
/* These are for NAT. Icky. */
217-
extern s32 (*nf_ct_nat_offset)(const struct nf_conn *ct,
218-
enum ip_conntrack_dir dir,
219-
u32 seq);
220-
221216
/* Set all unconfirmed conntrack as dying */
222217
void nf_ct_unconfirmed_destroy(struct net *);
223218

include/net/netfilter/nf_flow_table.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct nf_flowtable_type {
1414
struct list_head list;
1515
int family;
1616
void (*gc)(struct work_struct *work);
17+
void (*free)(struct nf_flowtable *ft);
1718
const struct rhashtable_params *params;
1819
nf_hookfn *hook;
1920
struct module *owner;
@@ -89,12 +90,15 @@ struct flow_offload *flow_offload_alloc(struct nf_conn *ct,
8990
void flow_offload_free(struct flow_offload *flow);
9091

9192
int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
92-
void flow_offload_del(struct nf_flowtable *flow_table, struct flow_offload *flow);
9393
struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table,
9494
struct flow_offload_tuple *tuple);
9595
int nf_flow_table_iterate(struct nf_flowtable *flow_table,
9696
void (*iter)(struct flow_offload *flow, void *data),
9797
void *data);
98+
99+
void nf_flow_table_cleanup(struct net *net, struct net_device *dev);
100+
101+
void nf_flow_table_free(struct nf_flowtable *flow_table);
98102
void nf_flow_offload_work_gc(struct work_struct *work);
99103
extern const struct rhashtable_params nf_flow_offload_rhash_params;
100104

net/ipv4/netfilter/Kconfig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ endif # NF_TABLES
8080

8181
config NF_FLOW_TABLE_IPV4
8282
tristate "Netfilter flow table IPv4 module"
83-
depends on NF_CONNTRACK && NF_TABLES
84-
select NF_FLOW_TABLE
83+
depends on NF_FLOW_TABLE
8584
help
8685
This option adds the flow table IPv4 support.
8786

net/ipv4/netfilter/nf_flow_table_ipv4.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ static struct nf_flowtable_type flowtable_ipv4 = {
260260
.family = NFPROTO_IPV4,
261261
.params = &nf_flow_offload_rhash_params,
262262
.gc = nf_flow_offload_work_gc,
263+
.free = nf_flow_table_free,
263264
.hook = nf_flow_offload_ip_hook,
264265
.owner = THIS_MODULE,
265266
};

net/ipv6/netfilter/Kconfig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ endif # NF_TABLES
7373

7474
config NF_FLOW_TABLE_IPV6
7575
tristate "Netfilter flow table IPv6 module"
76-
depends on NF_CONNTRACK && NF_TABLES
77-
select NF_FLOW_TABLE
76+
depends on NF_FLOW_TABLE
7877
help
7978
This option adds the flow table IPv6 support.
8079

net/ipv6/netfilter/nf_conntrack_reasm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
264264
* this case. -DaveM
265265
*/
266266
pr_debug("end of fragment not rounded to 8 bytes.\n");
267+
inet_frag_kill(&fq->q, &nf_frags);
267268
return -EPROTO;
268269
}
269270
if (end > fq->q.len) {

net/ipv6/netfilter/nf_flow_table_ipv6.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ static struct nf_flowtable_type flowtable_ipv6 = {
253253
.family = NFPROTO_IPV6,
254254
.params = &nf_flow_offload_rhash_params,
255255
.gc = nf_flow_offload_work_gc,
256+
.free = nf_flow_table_free,
256257
.hook = nf_flow_offload_ipv6_hook,
257258
.owner = THIS_MODULE,
258259
};

net/netfilter/Kconfig

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -666,16 +666,18 @@ endif # NF_TABLES
666666

667667
config NF_FLOW_TABLE_INET
668668
tristate "Netfilter flow table mixed IPv4/IPv6 module"
669-
depends on NF_FLOW_TABLE_IPV4 && NF_FLOW_TABLE_IPV6
670-
select NF_FLOW_TABLE
669+
depends on NF_FLOW_TABLE_IPV4
670+
depends on NF_FLOW_TABLE_IPV6
671671
help
672672
This option adds the flow table mixed IPv4/IPv6 support.
673673

674674
To compile it as a module, choose M here.
675675

676676
config NF_FLOW_TABLE
677677
tristate "Netfilter flow table module"
678-
depends on NF_CONNTRACK && NF_TABLES
678+
depends on NETFILTER_INGRESS
679+
depends on NF_CONNTRACK
680+
depends on NF_TABLES
679681
help
680682
This option adds the flow table core infrastructure.
681683

net/netfilter/nf_flow_table.c

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <linux/netfilter.h>
55
#include <linux/rhashtable.h>
66
#include <linux/netdevice.h>
7+
#include <net/netfilter/nf_tables.h>
78
#include <net/netfilter/nf_flow_table.h>
89
#include <net/netfilter/nf_conntrack.h>
910
#include <net/netfilter/nf_conntrack_core.h>
@@ -124,7 +125,9 @@ void flow_offload_free(struct flow_offload *flow)
124125
dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_cache);
125126
dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_cache);
126127
e = container_of(flow, struct flow_offload_entry, flow);
127-
kfree(e);
128+
nf_ct_delete(e->ct, 0, 0);
129+
nf_ct_put(e->ct);
130+
kfree_rcu(e, rcu_head);
128131
}
129132
EXPORT_SYMBOL_GPL(flow_offload_free);
130133

@@ -148,22 +151,18 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
148151
}
149152
EXPORT_SYMBOL_GPL(flow_offload_add);
150153

151-
void flow_offload_del(struct nf_flowtable *flow_table,
152-
struct flow_offload *flow)
154+
static void flow_offload_del(struct nf_flowtable *flow_table,
155+
struct flow_offload *flow)
153156
{
154-
struct flow_offload_entry *e;
155-
156157
rhashtable_remove_fast(&flow_table->rhashtable,
157158
&flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
158159
*flow_table->type->params);
159160
rhashtable_remove_fast(&flow_table->rhashtable,
160161
&flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
161162
*flow_table->type->params);
162163

163-
e = container_of(flow, struct flow_offload_entry, flow);
164-
kfree_rcu(e, rcu_head);
164+
flow_offload_free(flow);
165165
}
166-
EXPORT_SYMBOL_GPL(flow_offload_del);
167166

168167
struct flow_offload_tuple_rhash *
169168
flow_offload_lookup(struct nf_flowtable *flow_table,
@@ -174,15 +173,6 @@ flow_offload_lookup(struct nf_flowtable *flow_table,
174173
}
175174
EXPORT_SYMBOL_GPL(flow_offload_lookup);
176175

177-
static void nf_flow_release_ct(const struct flow_offload *flow)
178-
{
179-
struct flow_offload_entry *e;
180-
181-
e = container_of(flow, struct flow_offload_entry, flow);
182-
nf_ct_delete(e->ct, 0, 0);
183-
nf_ct_put(e->ct);
184-
}
185-
186176
int nf_flow_table_iterate(struct nf_flowtable *flow_table,
187177
void (*iter)(struct flow_offload *flow, void *data),
188178
void *data)
@@ -231,19 +221,16 @@ static inline bool nf_flow_is_dying(const struct flow_offload *flow)
231221
return flow->flags & FLOW_OFFLOAD_DYING;
232222
}
233223

234-
void nf_flow_offload_work_gc(struct work_struct *work)
224+
static int nf_flow_offload_gc_step(struct nf_flowtable *flow_table)
235225
{
236226
struct flow_offload_tuple_rhash *tuplehash;
237-
struct nf_flowtable *flow_table;
238227
struct rhashtable_iter hti;
239228
struct flow_offload *flow;
240229
int err;
241230

242-
flow_table = container_of(work, struct nf_flowtable, gc_work.work);
243-
244231
err = rhashtable_walk_init(&flow_table->rhashtable, &hti, GFP_KERNEL);
245232
if (err)
246-
goto schedule;
233+
return 0;
247234

248235
rhashtable_walk_start(&hti);
249236

@@ -261,15 +248,22 @@ void nf_flow_offload_work_gc(struct work_struct *work)
261248
flow = container_of(tuplehash, struct flow_offload, tuplehash[0]);
262249

263250
if (nf_flow_has_expired(flow) ||
264-
nf_flow_is_dying(flow)) {
251+
nf_flow_is_dying(flow))
265252
flow_offload_del(flow_table, flow);
266-
nf_flow_release_ct(flow);
267-
}
268253
}
269254
out:
270255
rhashtable_walk_stop(&hti);
271256
rhashtable_walk_exit(&hti);
272-
schedule:
257+
258+
return 1;
259+
}
260+
261+
void nf_flow_offload_work_gc(struct work_struct *work)
262+
{
263+
struct nf_flowtable *flow_table;
264+
265+
flow_table = container_of(work, struct nf_flowtable, gc_work.work);
266+
nf_flow_offload_gc_step(flow_table);
273267
queue_delayed_work(system_power_efficient_wq, &flow_table->gc_work, HZ);
274268
}
275269
EXPORT_SYMBOL_GPL(nf_flow_offload_work_gc);
@@ -425,5 +419,35 @@ int nf_flow_dnat_port(const struct flow_offload *flow,
425419
}
426420
EXPORT_SYMBOL_GPL(nf_flow_dnat_port);
427421

422+
static void nf_flow_table_do_cleanup(struct flow_offload *flow, void *data)
423+
{
424+
struct net_device *dev = data;
425+
426+
if (dev && flow->tuplehash[0].tuple.iifidx != dev->ifindex)
427+
return;
428+
429+
flow_offload_dead(flow);
430+
}
431+
432+
static void nf_flow_table_iterate_cleanup(struct nf_flowtable *flowtable,
433+
void *data)
434+
{
435+
nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, data);
436+
flush_delayed_work(&flowtable->gc_work);
437+
}
438+
439+
void nf_flow_table_cleanup(struct net *net, struct net_device *dev)
440+
{
441+
nft_flow_table_iterate(net, nf_flow_table_iterate_cleanup, dev);
442+
}
443+
EXPORT_SYMBOL_GPL(nf_flow_table_cleanup);
444+
445+
void nf_flow_table_free(struct nf_flowtable *flow_table)
446+
{
447+
nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL);
448+
WARN_ON(!nf_flow_offload_gc_step(flow_table));
449+
}
450+
EXPORT_SYMBOL_GPL(nf_flow_table_free);
451+
428452
MODULE_LICENSE("GPL");
429453
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");

net/netfilter/nf_flow_table_inet.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ static struct nf_flowtable_type flowtable_inet = {
2424
.family = NFPROTO_INET,
2525
.params = &nf_flow_offload_rhash_params,
2626
.gc = nf_flow_offload_work_gc,
27+
.free = nf_flow_table_free,
2728
.hook = nf_flow_offload_inet_hook,
2829
.owner = THIS_MODULE,
2930
};

net/netfilter/nf_tables_api.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5006,13 +5006,13 @@ void nft_flow_table_iterate(struct net *net,
50065006
struct nft_flowtable *flowtable;
50075007
const struct nft_table *table;
50085008

5009-
rcu_read_lock();
5010-
list_for_each_entry_rcu(table, &net->nft.tables, list) {
5011-
list_for_each_entry_rcu(flowtable, &table->flowtables, list) {
5009+
nfnl_lock(NFNL_SUBSYS_NFTABLES);
5010+
list_for_each_entry(table, &net->nft.tables, list) {
5011+
list_for_each_entry(flowtable, &table->flowtables, list) {
50125012
iter(&flowtable->data, data);
50135013
}
50145014
}
5015-
rcu_read_unlock();
5015+
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
50165016
}
50175017
EXPORT_SYMBOL_GPL(nft_flow_table_iterate);
50185018

@@ -5399,17 +5399,12 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
53995399
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
54005400
}
54015401

5402-
static void nft_flowtable_destroy(void *ptr, void *arg)
5403-
{
5404-
kfree(ptr);
5405-
}
5406-
54075402
static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable)
54085403
{
54095404
cancel_delayed_work_sync(&flowtable->data.gc_work);
54105405
kfree(flowtable->name);
5411-
rhashtable_free_and_destroy(&flowtable->data.rhashtable,
5412-
nft_flowtable_destroy, NULL);
5406+
flowtable->data.type->free(&flowtable->data);
5407+
rhashtable_destroy(&flowtable->data.rhashtable);
54135408
module_put(flowtable->data.type->owner);
54145409
}
54155410

net/netfilter/nft_flow_offload.c

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -194,22 +194,6 @@ static struct nft_expr_type nft_flow_offload_type __read_mostly = {
194194
.owner = THIS_MODULE,
195195
};
196196

197-
static void flow_offload_iterate_cleanup(struct flow_offload *flow, void *data)
198-
{
199-
struct net_device *dev = data;
200-
201-
if (dev && flow->tuplehash[0].tuple.iifidx != dev->ifindex)
202-
return;
203-
204-
flow_offload_dead(flow);
205-
}
206-
207-
static void nft_flow_offload_iterate_cleanup(struct nf_flowtable *flowtable,
208-
void *data)
209-
{
210-
nf_flow_table_iterate(flowtable, flow_offload_iterate_cleanup, data);
211-
}
212-
213197
static int flow_offload_netdev_event(struct notifier_block *this,
214198
unsigned long event, void *ptr)
215199
{
@@ -218,7 +202,7 @@ static int flow_offload_netdev_event(struct notifier_block *this,
218202
if (event != NETDEV_DOWN)
219203
return NOTIFY_DONE;
220204

221-
nft_flow_table_iterate(dev_net(dev), nft_flow_offload_iterate_cleanup, dev);
205+
nf_flow_table_cleanup(dev_net(dev), dev);
222206

223207
return NOTIFY_DONE;
224208
}
@@ -246,14 +230,8 @@ static int __init nft_flow_offload_module_init(void)
246230

247231
static void __exit nft_flow_offload_module_exit(void)
248232
{
249-
struct net *net;
250-
251233
nft_unregister_expr(&nft_flow_offload_type);
252234
unregister_netdevice_notifier(&flow_offload_netdev_notifier);
253-
rtnl_lock();
254-
for_each_net(net)
255-
nft_flow_table_iterate(net, nft_flow_offload_iterate_cleanup, NULL);
256-
rtnl_unlock();
257235
}
258236

259237
module_init(nft_flow_offload_module_init);

net/netfilter/x_tables.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,12 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
10081008
if ((size >> PAGE_SHIFT) + 2 > totalram_pages)
10091009
return NULL;
10101010

1011-
info = kvmalloc(sz, GFP_KERNEL);
1011+
/* __GFP_NORETRY is not fully supported by kvmalloc but it should
1012+
* work reasonably well if sz is too large and bail out rather
1013+
* than shoot all processes down before realizing there is nothing
1014+
* more to reclaim.
1015+
*/
1016+
info = kvmalloc(sz, GFP_KERNEL | __GFP_NORETRY);
10121017
if (!info)
10131018
return NULL;
10141019

0 commit comments

Comments
 (0)