Commit 8a02bdd5 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Pablo Neira Ayuso

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: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 54451f60
...@@ -55,11 +55,15 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); ...@@ -55,11 +55,15 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("core IP set support"); MODULE_DESCRIPTION("core IP set support");
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET); MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
/* When the nfnl mutex is held: */ /* When the nfnl mutex or ip_set_ref_lock is held: */
#define ip_set_dereference(p) \ #define ip_set_dereference(p) \
rcu_dereference_protected(p, lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET)) rcu_dereference_protected(p, \
lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET) || \
lockdep_is_held(&ip_set_ref_lock))
#define ip_set(inst, id) \ #define ip_set(inst, id) \
ip_set_dereference((inst)->ip_set_list)[id] ip_set_dereference((inst)->ip_set_list)[id]
#define ip_set_ref_netlink(inst,id) \
rcu_dereference_raw((inst)->ip_set_list)[id]
/* The set types are implemented in modules and registered set types /* The set types are implemented in modules and registered set types
* can be found in ip_set_type_list. Adding/deleting types is * 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,7 +1255,7 @@ ip_set_dump_done(struct netlink_callback *cb)
struct ip_set_net *inst = struct ip_set_net *inst =
(struct ip_set_net *)cb->args[IPSET_CB_NET]; (struct ip_set_net *)cb->args[IPSET_CB_NET];
ip_set_id_t index = (ip_set_id_t)cb->args[IPSET_CB_INDEX]; ip_set_id_t index = (ip_set_id_t)cb->args[IPSET_CB_INDEX];
struct ip_set *set = ip_set(inst, index); struct ip_set *set = ip_set_ref_netlink(inst, index);
if (set->variant->uref) if (set->variant->uref)
set->variant->uref(set, cb, false); set->variant->uref(set, cb, false);
...@@ -1440,7 +1444,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1440,7 +1444,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
release_refcount: release_refcount:
/* If there was an error or set is done, release set */ /* If there was an error or set is done, release set */
if (ret || !cb->args[IPSET_CB_ARG0]) { if (ret || !cb->args[IPSET_CB_ARG0]) {
set = ip_set(inst, index); set = ip_set_ref_netlink(inst, index);
if (set->variant->uref) if (set->variant->uref)
set->variant->uref(set, cb, false); set->variant->uref(set, cb, false);
pr_debug("release set %s\n", set->name); pr_debug("release set %s\n", set->name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment