Skip to content

Commit 38e029f

Browse files
committed
netfilter: nf_tables: set NLM_F_DUMP_INTR if netlink dumping is stale
An updater may interfer with the dumping of any of the object lists. Fix this by using a per-net generation counter and use the nl_dump_check_consistent() interface so the NLM_F_DUMP_INTR flag is set to notify userspace that it has to restart the dump since an updater has interfered. This patch also replaces the existing consistency checking code in the rule dumping path since it is broken. Basically, the value that the dump callback returns is not propagated to userspace via netlink_dump_start(). Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent e688a7f commit 38e029f

File tree

2 files changed

+24
-8
lines changed

2 files changed

+24
-8
lines changed

include/net/netns/nftables.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ struct netns_nftables {
1313
struct nft_af_info *inet;
1414
struct nft_af_info *arp;
1515
struct nft_af_info *bridge;
16+
unsigned int base_seq;
1617
u8 gencursor;
17-
u8 genctr;
1818
};
1919

2020
#endif

net/netfilter/nf_tables_api.c

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ static int nf_tables_dump_tables(struct sk_buff *skb,
278278
int family = nfmsg->nfgen_family;
279279

280280
rcu_read_lock();
281+
cb->seq = net->nft.base_seq;
282+
281283
list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
282284
if (family != NFPROTO_UNSPEC && family != afi->family)
283285
continue;
@@ -295,6 +297,8 @@ static int nf_tables_dump_tables(struct sk_buff *skb,
295297
NLM_F_MULTI,
296298
afi->family, table) < 0)
297299
goto done;
300+
301+
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
298302
cont:
299303
idx++;
300304
}
@@ -767,6 +771,8 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
767771
int family = nfmsg->nfgen_family;
768772

769773
rcu_read_lock();
774+
cb->seq = net->nft.base_seq;
775+
770776
list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
771777
if (family != NFPROTO_UNSPEC && family != afi->family)
772778
continue;
@@ -784,6 +790,8 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
784790
NLM_F_MULTI,
785791
afi->family, table, chain) < 0)
786792
goto done;
793+
794+
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
787795
cont:
788796
idx++;
789797
}
@@ -1555,10 +1563,10 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
15551563
unsigned int idx = 0, s_idx = cb->args[0];
15561564
struct net *net = sock_net(skb->sk);
15571565
int family = nfmsg->nfgen_family;
1558-
u8 genctr = ACCESS_ONCE(net->nft.genctr);
1559-
u8 gencursor = ACCESS_ONCE(net->nft.gencursor);
15601566

15611567
rcu_read_lock();
1568+
cb->seq = net->nft.base_seq;
1569+
15621570
list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
15631571
if (family != NFPROTO_UNSPEC && family != afi->family)
15641572
continue;
@@ -1579,6 +1587,8 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
15791587
NLM_F_MULTI | NLM_F_APPEND,
15801588
afi->family, table, chain, rule) < 0)
15811589
goto done;
1590+
1591+
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
15821592
cont:
15831593
idx++;
15841594
}
@@ -1588,10 +1598,6 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
15881598
done:
15891599
rcu_read_unlock();
15901600

1591-
/* Invalidate this dump, a transition to the new generation happened */
1592-
if (gencursor != net->nft.gencursor || genctr != net->nft.genctr)
1593-
return -EBUSY;
1594-
15951601
cb->args[0] = idx;
15961602
return skb->len;
15971603
}
@@ -2244,6 +2250,8 @@ static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
22442250
return skb->len;
22452251

22462252
rcu_read_lock();
2253+
cb->seq = ctx->net->nft.base_seq;
2254+
22472255
list_for_each_entry_rcu(set, &ctx->table->sets, list) {
22482256
if (idx < s_idx)
22492257
goto cont;
@@ -2252,6 +2260,7 @@ static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
22522260
cb->args[0] = idx;
22532261
goto done;
22542262
}
2263+
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
22552264
cont:
22562265
idx++;
22572266
}
@@ -2272,6 +2281,8 @@ static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb,
22722281
return skb->len;
22732282

22742283
rcu_read_lock();
2284+
cb->seq = ctx->net->nft.base_seq;
2285+
22752286
list_for_each_entry_rcu(table, &ctx->afi->tables, list) {
22762287
if (cur_table) {
22772288
if (cur_table != table)
@@ -2290,6 +2301,7 @@ static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb,
22902301
cb->args[2] = (unsigned long) table;
22912302
goto done;
22922303
}
2304+
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
22932305
cont:
22942306
idx++;
22952307
}
@@ -2314,6 +2326,8 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
23142326
return skb->len;
23152327

23162328
rcu_read_lock();
2329+
cb->seq = net->nft.base_seq;
2330+
23172331
list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
23182332
if (cur_family) {
23192333
if (afi->family != cur_family)
@@ -2344,6 +2358,7 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
23442358
cb->args[3] = afi->family;
23452359
goto done;
23462360
}
2361+
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
23472362
cont:
23482363
idx++;
23492364
}
@@ -3361,7 +3376,7 @@ static int nf_tables_commit(struct sk_buff *skb)
33613376
struct nft_set *set;
33623377

33633378
/* Bump generation counter, invalidate any dump in progress */
3364-
net->nft.genctr++;
3379+
while (++net->nft.base_seq == 0);
33653380

33663381
/* A new generation has just started */
33673382
net->nft.gencursor = gencursor_next(net);
@@ -3966,6 +3981,7 @@ static int nf_tables_init_net(struct net *net)
39663981
{
39673982
INIT_LIST_HEAD(&net->nft.af_info);
39683983
INIT_LIST_HEAD(&net->nft.commit_list);
3984+
net->nft.base_seq = 1;
39693985
return 0;
39703986
}
39713987

0 commit comments

Comments
 (0)