When a NAT helper is unlocked conntrack/NAT may deadlock because of
the following lock sequence:
.. ip_nat_helper_unregister
-> ip_ct_selective_cleanup
-> get_next_corpse (ip_conntrack_lock)
-> kill_helper (ip_nat_lock)
.. ip_nat_fn (ip_nat_lock)
-> ip_nat_setup_info
-> ip_conntrack_alter_reply (ip_conntrack_lock)
Taking ip_nat_lock in kill_helper() is unnecessary since the helper assigned
to a connection is immutable and new connections can't have the helper that
is beeing unloaded assigned since it is already removed from the global list.
Reported by <doublefacer007@gmail.com>.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
static int
kill_helper(struct ip_conntrack *i, void *helper)
{
- int ret;
-
- READ_LOCK(&ip_nat_lock);
- ret = (i->nat.info.helper == helper);
- READ_UNLOCK(&ip_nat_lock);
-
- return ret;
+ return (i->nat.info.helper == helper);
}
void ip_nat_helper_unregister(struct ip_nat_helper *me)