Skip to content

Commit

Permalink
netfilter: nf_tables: use READ_ONCE and WRITE_ONCE for shared generat…
Browse files Browse the repository at this point in the history
…ion id access

The generation ID is bumped from the commit path while holding the
mutex, however, netlink dump operations rely on RCU.

This patch also adds missing cb->base_eq initialization in
nf_tables_dump_set().

Fixes: 38e029f ("netfilter: nf_tables: set NLM_F_DUMP_INTR if netlink dumping is stale")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Pablo Neira Ayuso committed Aug 10, 2022
1 parent f329a0e commit 3400278
Showing 1 changed file with 13 additions and 7 deletions.
20 changes: 13 additions & 7 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,7 @@ static int nf_tables_dump_tables(struct sk_buff *skb,

rcu_read_lock();
nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
cb->seq = READ_ONCE(nft_net->base_seq);

list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (family != NFPROTO_UNSPEC && family != table->family)
Expand Down Expand Up @@ -1705,7 +1705,7 @@ static int nf_tables_dump_chains(struct sk_buff *skb,

rcu_read_lock();
nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
cb->seq = READ_ONCE(nft_net->base_seq);

list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (family != NFPROTO_UNSPEC && family != table->family)
Expand Down Expand Up @@ -3149,7 +3149,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb,

rcu_read_lock();
nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
cb->seq = READ_ONCE(nft_net->base_seq);

list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (family != NFPROTO_UNSPEC && family != table->family)
Expand Down Expand Up @@ -4133,7 +4133,7 @@ static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)

rcu_read_lock();
nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
cb->seq = READ_ONCE(nft_net->base_seq);

list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (ctx->family != NFPROTO_UNSPEC &&
Expand Down Expand Up @@ -5061,6 +5061,8 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)

rcu_read_lock();
nft_net = nft_pernet(net);
cb->seq = READ_ONCE(nft_net->base_seq);

list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (dump_ctx->ctx.family != NFPROTO_UNSPEC &&
dump_ctx->ctx.family != table->family)
Expand Down Expand Up @@ -6941,7 +6943,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)

rcu_read_lock();
nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
cb->seq = READ_ONCE(nft_net->base_seq);

list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (family != NFPROTO_UNSPEC && family != table->family)
Expand Down Expand Up @@ -7873,7 +7875,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb,

rcu_read_lock();
nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
cb->seq = READ_ONCE(nft_net->base_seq);

list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (family != NFPROTO_UNSPEC && family != table->family)
Expand Down Expand Up @@ -8806,6 +8808,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
struct nft_trans_elem *te;
struct nft_chain *chain;
struct nft_table *table;
unsigned int base_seq;
LIST_HEAD(adl);
int err;

Expand Down Expand Up @@ -8855,9 +8858,12 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
* Bump generation counter, invalidate any dump in progress.
* Cannot fail after this point.
*/
while (++nft_net->base_seq == 0)
base_seq = READ_ONCE(nft_net->base_seq);
while (++base_seq == 0)
;

WRITE_ONCE(nft_net->base_seq, base_seq);

/* step 3. Start new generation, rules_gen_X now in use. */
net->nft.gencursor = nft_gencursor_next(net);

Expand Down

0 comments on commit 3400278

Please sign in to comment.