diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2018-10-30 17:43:42 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-11-03 08:28:01 -0400 |
commit | 8a02bdd50b2ecb6d62121d2958d3ea186cc88ce7 (patch) | |
tree | da24e01ea80e6ecccc657fe8891ae5925874d58c | |
parent | 54451f60c8fa061af9051a53be9786393947367c (diff) |
netfilter: ipset: Fix calling ip_set() macro at dumping
The ip_set() macro is called when either ip_set_ref_lock held only
or no lock/nfnl mutex is held at dumping. Take this into account
properly. Also, use Pablo's suggestion to use rcu_dereference_raw(),
the ref_netlink protects the set.
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | net/netfilter/ipset/ip_set_core.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 68db946df151..1577f2f76060 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
@@ -55,11 +55,15 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | |||
55 | MODULE_DESCRIPTION("core IP set support"); | 55 | MODULE_DESCRIPTION("core IP set support"); |
56 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET); | 56 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET); |
57 | 57 | ||
58 | /* When the nfnl mutex is held: */ | 58 | /* When the nfnl mutex or ip_set_ref_lock is held: */ |
59 | #define ip_set_dereference(p) \ | 59 | #define ip_set_dereference(p) \ |
60 | rcu_dereference_protected(p, lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET)) | 60 | rcu_dereference_protected(p, \ |
61 | lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET) || \ | ||
62 | lockdep_is_held(&ip_set_ref_lock)) | ||
61 | #define ip_set(inst, id) \ | 63 | #define ip_set(inst, id) \ |
62 | ip_set_dereference((inst)->ip_set_list)[id] | 64 | ip_set_dereference((inst)->ip_set_list)[id] |
65 | #define ip_set_ref_netlink(inst,id) \ | ||
66 | rcu_dereference_raw((inst)->ip_set_list)[id] | ||
63 | 67 | ||
64 | /* The set types are implemented in modules and registered set types | 68 | /* The set types are implemented in modules and registered set types |
65 | * can be found in ip_set_type_list. Adding/deleting types is | 69 | * can be found in ip_set_type_list. Adding/deleting types is |
@@ -1251,7 +1255,7 @@ ip_set_dump_done(struct netlink_callback *cb) | |||
1251 | struct ip_set_net *inst = | 1255 | struct ip_set_net *inst = |
1252 | (struct ip_set_net *)cb->args[IPSET_CB_NET]; | 1256 | (struct ip_set_net *)cb->args[IPSET_CB_NET]; |
1253 | ip_set_id_t index = (ip_set_id_t)cb->args[IPSET_CB_INDEX]; | 1257 | ip_set_id_t index = (ip_set_id_t)cb->args[IPSET_CB_INDEX]; |
1254 | struct ip_set *set = ip_set(inst, index); | 1258 | struct ip_set *set = ip_set_ref_netlink(inst, index); |
1255 | 1259 | ||
1256 | if (set->variant->uref) | 1260 | if (set->variant->uref) |
1257 | set->variant->uref(set, cb, false); | 1261 | set->variant->uref(set, cb, false); |
@@ -1440,7 +1444,7 @@ next_set: | |||
1440 | release_refcount: | 1444 | release_refcount: |
1441 | /* If there was an error or set is done, release set */ | 1445 | /* If there was an error or set is done, release set */ |
1442 | if (ret || !cb->args[IPSET_CB_ARG0]) { | 1446 | if (ret || !cb->args[IPSET_CB_ARG0]) { |
1443 | set = ip_set(inst, index); | 1447 | set = ip_set_ref_netlink(inst, index); |
1444 | if (set->variant->uref) | 1448 | if (set->variant->uref) |
1445 | set->variant->uref(set, cb, false); | 1449 | set->variant->uref(set, cb, false); |
1446 | pr_debug("release set %s\n", set->name); | 1450 | pr_debug("release set %s\n", set->name); |