Skip to content

Commit 002c448

Browse files
qsnUlrich Hecht
authored andcommitted
xfrm: delete x->tunnel as we delete x
[ Upstream commit b441cf3f8c4b8576639d20c8eb4aa32917602ecd ] The ipcomp fallback tunnels currently get deleted (from the various lists and hashtables) as the last user state that needed that fallback is destroyed (not deleted). If a reference to that user state still exists, the fallback state will remain on the hashtables/lists, triggering the WARN in xfrm_state_fini. Because of those remaining references, the fix in commit f75a2804da39 ("xfrm: destroy xfrm_state synchronously on net exit path") is not complete. We recently fixed one such situation in TCP due to defered freeing of skbs (commit 9b6412e6979f ("tcp: drop secpath at the same time as we currently drop dst")). This can also happen due to IP reassembly: skbs with a secpath remain on the reassembly queue until netns destruction. If we can't guarantee that the queues are flushed by the time xfrm_state_fini runs, there may still be references to a (user) xfrm_state, preventing the timely deletion of the corresponding fallback state. Instead of chasing each instance of skbs holding a secpath one by one, this patch fixes the issue directly within xfrm, by deleting the fallback state as soon as the last user state depending on it has been deleted. Destruction will still happen when the final reference is dropped. A separate lockdep class for the fallback state is required since we're going to lock x->tunnel while x is locked. Fixes: 9d4139c ("netns xfrm: per-netns xfrm_state_all list") Signed-off-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Ulrich Hecht <uli@kernel.org>
1 parent 921236f commit 002c448

6 files changed

Lines changed: 13 additions & 14 deletions

File tree

include/net/xfrm.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,6 @@ int xfrm_input_register_afinfo(const struct xfrm_input_afinfo *afinfo);
385385
int xfrm_input_unregister_afinfo(const struct xfrm_input_afinfo *afinfo);
386386

387387
void xfrm_flush_gc(void);
388-
void xfrm_state_delete_tunnel(struct xfrm_state *x);
389388

390389
struct xfrm_type {
391390
char *description;

net/ipv4/ipcomp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ static int ipcomp4_err(struct sk_buff *skb, u32 info)
5757
}
5858

5959
/* We always hold one tunnel user reference to indicate a tunnel */
60+
static struct lock_class_key xfrm_state_lock_key;
6061
static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
6162
{
6263
struct net *net = xs_net(x);
@@ -65,6 +66,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
6566
t = xfrm_state_alloc(net);
6667
if (!t)
6768
goto out;
69+
lockdep_set_class(&t->lock, &xfrm_state_lock_key);
6870

6971
t->id.proto = IPPROTO_IPIP;
7072
t->id.spi = x->props.saddr.a4;

net/ipv6/ipcomp6.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ static int ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
8383
return 0;
8484
}
8585

86+
static struct lock_class_key xfrm_state_lock_key;
8687
static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
8788
{
8889
struct net *net = xs_net(x);
@@ -91,6 +92,7 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
9192
t = xfrm_state_alloc(net);
9293
if (!t)
9394
goto out;
95+
lockdep_set_class(&t->lock, &xfrm_state_lock_key);
9496

9597
t->id.proto = IPPROTO_IPV6;
9698
t->id.spi = xfrm6_tunnel_alloc_spi(net, (xfrm_address_t *)&x->props.saddr);

net/ipv6/xfrm6_tunnel.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,8 @@ static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
344344
struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
345345
unsigned int i;
346346

347-
xfrm_flush_gc();
348347
xfrm_state_flush(net, 0, false, true);
348+
xfrm_flush_gc();
349349

350350
for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
351351
WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i]));

net/xfrm/xfrm_ipcomp.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,6 @@ void ipcomp_destroy(struct xfrm_state *x)
331331
struct ipcomp_data *ipcd = x->data;
332332
if (!ipcd)
333333
return;
334-
xfrm_state_delete_tunnel(x);
335334
mutex_lock(&ipcomp_resource_mutex);
336335
ipcomp_free_data(ipcd);
337336
mutex_unlock(&ipcomp_resource_mutex);

net/xfrm/xfrm_state.c

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ void __xfrm_state_destroy(struct xfrm_state *x, bool sync)
615615
}
616616
EXPORT_SYMBOL(__xfrm_state_destroy);
617617

618+
static void xfrm_state_delete_tunnel(struct xfrm_state *x);
618619
int __xfrm_state_delete(struct xfrm_state *x)
619620
{
620621
struct net *net = xs_net(x);
@@ -633,6 +634,8 @@ int __xfrm_state_delete(struct xfrm_state *x)
633634

634635
xfrm_dev_state_delete(x);
635636

637+
xfrm_state_delete_tunnel(x);
638+
636639
/* All xfrm_state objects are created by xfrm_state_alloc.
637640
* The xfrm_state_alloc call gives a reference, and that
638641
* is what we are dropping here.
@@ -736,10 +739,7 @@ int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync)
736739
err = xfrm_state_delete(x);
737740
xfrm_audit_state_delete(x, err ? 0 : 1,
738741
task_valid);
739-
if (sync)
740-
xfrm_state_put_sync(x);
741-
else
742-
xfrm_state_put(x);
742+
xfrm_state_put(x);
743743
if (!err)
744744
cnt++;
745745

@@ -2258,20 +2258,17 @@ void xfrm_flush_gc(void)
22582258
}
22592259
EXPORT_SYMBOL(xfrm_flush_gc);
22602260

2261-
/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
2262-
void xfrm_state_delete_tunnel(struct xfrm_state *x)
2261+
static void xfrm_state_delete_tunnel(struct xfrm_state *x)
22632262
{
22642263
if (x->tunnel) {
22652264
struct xfrm_state *t = x->tunnel;
22662265

2267-
if (atomic_read(&t->tunnel_users) == 2)
2266+
if (atomic_dec_return(&t->tunnel_users) == 1)
22682267
xfrm_state_delete(t);
2269-
atomic_dec(&t->tunnel_users);
2270-
xfrm_state_put_sync(t);
2268+
xfrm_state_put(t);
22712269
x->tunnel = NULL;
22722270
}
22732271
}
2274-
EXPORT_SYMBOL(xfrm_state_delete_tunnel);
22752272

22762273
int xfrm_state_mtu(struct xfrm_state *x, int mtu)
22772274
{
@@ -2428,8 +2425,8 @@ void xfrm_state_fini(struct net *net)
24282425
unsigned int sz;
24292426

24302427
flush_work(&net->xfrm.state_hash_work);
2431-
flush_work(&xfrm_state_gc_work);
24322428
xfrm_state_flush(net, 0, false, true);
2429+
flush_work(&xfrm_state_gc_work);
24332430

24342431
WARN_ON(!list_empty(&net->xfrm.state_all));
24352432

0 commit comments

Comments
 (0)