| From 6ddec6a83123c3aafb5282c637c845ec5c29eddc Mon Sep 17 00:00:00 2001 |
| From: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> |
| Date: Tue, 30 Oct 2018 22:43:42 +0100 |
| Subject: netfilter: ipset: Fix calling ip_set() macro at dumping |
| |
| [ Upstream commit 8a02bdd50b2ecb6d62121d2958d3ea186cc88ce7 ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/netfilter/ipset/ip_set_core.c | 12 ++++++++---- |
| 1 file 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>"); |
| MODULE_DESCRIPTION("core IP set support"); |
| 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) \ |
| - 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) \ |
| 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 |
| * can be found in ip_set_type_list. Adding/deleting types is |
| @@ -1251,7 +1255,7 @@ ip_set_dump_done(struct netlink_callback *cb) |
| struct ip_set_net *inst = |
| (struct ip_set_net *)cb->args[IPSET_CB_NET]; |
| 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) |
| set->variant->uref(set, cb, false); |
| @@ -1440,7 +1444,7 @@ next_set: |
| release_refcount: |
| /* If there was an error or set is done, release set */ |
| if (ret || !cb->args[IPSET_CB_ARG0]) { |
| - set = ip_set(inst, index); |
| + set = ip_set_ref_netlink(inst, index); |
| if (set->variant->uref) |
| set->variant->uref(set, cb, false); |
| pr_debug("release set %s\n", set->name); |
| -- |
| 2.17.1 |
| |