aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2014-07-01 06:23:12 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2014-07-14 06:00:16 -0400
commit38e029f14a9702f71d5953246df9f722bca49017 (patch)
treeca7c55906f83d30277e75791b9eff8d25ba7272b /net
parente688a7f8c6cb7a18aae7e55ccdd175f0ad9e69c0 (diff)
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>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_tables_api.c30
1 files changed, 23 insertions, 7 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index a27a7c56e7c3..ac03d748360e 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -278,6 +278,8 @@ static int nf_tables_dump_tables(struct sk_buff *skb,
278 int family = nfmsg->nfgen_family; 278 int family = nfmsg->nfgen_family;
279 279
280 rcu_read_lock(); 280 rcu_read_lock();
281 cb->seq = net->nft.base_seq;
282
281 list_for_each_entry_rcu(afi, &net->nft.af_info, list) { 283 list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
282 if (family != NFPROTO_UNSPEC && family != afi->family) 284 if (family != NFPROTO_UNSPEC && family != afi->family)
283 continue; 285 continue;
@@ -295,6 +297,8 @@ static int nf_tables_dump_tables(struct sk_buff *skb,
295 NLM_F_MULTI, 297 NLM_F_MULTI,
296 afi->family, table) < 0) 298 afi->family, table) < 0)
297 goto done; 299 goto done;
300
301 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
298cont: 302cont:
299 idx++; 303 idx++;
300 } 304 }
@@ -767,6 +771,8 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
767 int family = nfmsg->nfgen_family; 771 int family = nfmsg->nfgen_family;
768 772
769 rcu_read_lock(); 773 rcu_read_lock();
774 cb->seq = net->nft.base_seq;
775
770 list_for_each_entry_rcu(afi, &net->nft.af_info, list) { 776 list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
771 if (family != NFPROTO_UNSPEC && family != afi->family) 777 if (family != NFPROTO_UNSPEC && family != afi->family)
772 continue; 778 continue;
@@ -784,6 +790,8 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
784 NLM_F_MULTI, 790 NLM_F_MULTI,
785 afi->family, table, chain) < 0) 791 afi->family, table, chain) < 0)
786 goto done; 792 goto done;
793
794 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
787cont: 795cont:
788 idx++; 796 idx++;
789 } 797 }
@@ -1555,10 +1563,10 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
1555 unsigned int idx = 0, s_idx = cb->args[0]; 1563 unsigned int idx = 0, s_idx = cb->args[0];
1556 struct net *net = sock_net(skb->sk); 1564 struct net *net = sock_net(skb->sk);
1557 int family = nfmsg->nfgen_family; 1565 int family = nfmsg->nfgen_family;
1558 u8 genctr = ACCESS_ONCE(net->nft.genctr);
1559 u8 gencursor = ACCESS_ONCE(net->nft.gencursor);
1560 1566
1561 rcu_read_lock(); 1567 rcu_read_lock();
1568 cb->seq = net->nft.base_seq;
1569
1562 list_for_each_entry_rcu(afi, &net->nft.af_info, list) { 1570 list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
1563 if (family != NFPROTO_UNSPEC && family != afi->family) 1571 if (family != NFPROTO_UNSPEC && family != afi->family)
1564 continue; 1572 continue;
@@ -1579,6 +1587,8 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
1579 NLM_F_MULTI | NLM_F_APPEND, 1587 NLM_F_MULTI | NLM_F_APPEND,
1580 afi->family, table, chain, rule) < 0) 1588 afi->family, table, chain, rule) < 0)
1581 goto done; 1589 goto done;
1590
1591 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1582cont: 1592cont:
1583 idx++; 1593 idx++;
1584 } 1594 }
@@ -1588,10 +1598,6 @@ cont:
1588done: 1598done:
1589 rcu_read_unlock(); 1599 rcu_read_unlock();
1590 1600
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
1595 cb->args[0] = idx; 1601 cb->args[0] = idx;
1596 return skb->len; 1602 return skb->len;
1597} 1603}
@@ -2244,6 +2250,8 @@ static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
2244 return skb->len; 2250 return skb->len;
2245 2251
2246 rcu_read_lock(); 2252 rcu_read_lock();
2253 cb->seq = ctx->net->nft.base_seq;
2254
2247 list_for_each_entry_rcu(set, &ctx->table->sets, list) { 2255 list_for_each_entry_rcu(set, &ctx->table->sets, list) {
2248 if (idx < s_idx) 2256 if (idx < s_idx)
2249 goto cont; 2257 goto cont;
@@ -2252,6 +2260,7 @@ static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
2252 cb->args[0] = idx; 2260 cb->args[0] = idx;
2253 goto done; 2261 goto done;
2254 } 2262 }
2263 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
2255cont: 2264cont:
2256 idx++; 2265 idx++;
2257 } 2266 }
@@ -2272,6 +2281,8 @@ static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb,
2272 return skb->len; 2281 return skb->len;
2273 2282
2274 rcu_read_lock(); 2283 rcu_read_lock();
2284 cb->seq = ctx->net->nft.base_seq;
2285
2275 list_for_each_entry_rcu(table, &ctx->afi->tables, list) { 2286 list_for_each_entry_rcu(table, &ctx->afi->tables, list) {
2276 if (cur_table) { 2287 if (cur_table) {
2277 if (cur_table != table) 2288 if (cur_table != table)
@@ -2290,6 +2301,7 @@ static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb,
2290 cb->args[2] = (unsigned long) table; 2301 cb->args[2] = (unsigned long) table;
2291 goto done; 2302 goto done;
2292 } 2303 }
2304 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
2293cont: 2305cont:
2294 idx++; 2306 idx++;
2295 } 2307 }
@@ -2314,6 +2326,8 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
2314 return skb->len; 2326 return skb->len;
2315 2327
2316 rcu_read_lock(); 2328 rcu_read_lock();
2329 cb->seq = net->nft.base_seq;
2330
2317 list_for_each_entry_rcu(afi, &net->nft.af_info, list) { 2331 list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
2318 if (cur_family) { 2332 if (cur_family) {
2319 if (afi->family != cur_family) 2333 if (afi->family != cur_family)
@@ -2344,6 +2358,7 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
2344 cb->args[3] = afi->family; 2358 cb->args[3] = afi->family;
2345 goto done; 2359 goto done;
2346 } 2360 }
2361 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
2347cont: 2362cont:
2348 idx++; 2363 idx++;
2349 } 2364 }
@@ -3361,7 +3376,7 @@ static int nf_tables_commit(struct sk_buff *skb)
3361 struct nft_set *set; 3376 struct nft_set *set;
3362 3377
3363 /* Bump generation counter, invalidate any dump in progress */ 3378 /* Bump generation counter, invalidate any dump in progress */
3364 net->nft.genctr++; 3379 while (++net->nft.base_seq == 0);
3365 3380
3366 /* A new generation has just started */ 3381 /* A new generation has just started */
3367 net->nft.gencursor = gencursor_next(net); 3382 net->nft.gencursor = gencursor_next(net);
@@ -3966,6 +3981,7 @@ static int nf_tables_init_net(struct net *net)
3966{ 3981{
3967 INIT_LIST_HEAD(&net->nft.af_info); 3982 INIT_LIST_HEAD(&net->nft.af_info);
3968 INIT_LIST_HEAD(&net->nft.commit_list); 3983 INIT_LIST_HEAD(&net->nft.commit_list);
3984 net->nft.base_seq = 1;
3969 return 0; 3985 return 0;
3970} 3986}
3971 3987