Commit daf8e3b2 authored by Hyunwoo Kim's avatar Hyunwoo Kim Committed by Steffen Klassert
Browse files

xfrm: Fix work re-schedule after cancel in xfrm_nat_keepalive_net_fini()



After cancel_delayed_work_sync() is called from
xfrm_nat_keepalive_net_fini(), xfrm_state_fini() flushes remaining
states via __xfrm_state_delete(), which calls
xfrm_nat_keepalive_state_updated() to re-schedule nat_keepalive_work.

The following is a simple race scenario:

           cpu0                             cpu1

cleanup_net() [Round 1]
  ops_undo_list()
    xfrm_net_exit()
      xfrm_nat_keepalive_net_fini()
        cancel_delayed_work_sync(nat_keepalive_work);
      xfrm_state_fini()
        xfrm_state_flush()
          xfrm_state_delete(x)
            __xfrm_state_delete(x)
              xfrm_nat_keepalive_state_updated(x)
                schedule_delayed_work(nat_keepalive_work);
  rcu_barrier();
  net_complete_free();
  net_passive_dec(net);
    llist_add(&net->defer_free_list, &defer_free_list);

cleanup_net() [Round 2]
  rcu_barrier();
  net_complete_free()
    kmem_cache_free(net_cachep, net);
                                     nat_keepalive_work()
                                       // on freed net

To prevent this, cancel_delayed_work_sync() is replaced with
disable_delayed_work_sync().

Fixes: f531d13b ("xfrm: support sending NAT keepalives in ESP in UDP states")
Signed-off-by: default avatarHyunwoo Kim <imv4bel@gmail.com>
Reviewed-by: default avatarSabrina Dubroca <sd@queasysnail.net>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 904eaf90
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -261,7 +261,7 @@ int __net_init xfrm_nat_keepalive_net_init(struct net *net)

int xfrm_nat_keepalive_net_fini(struct net *net)
{
	cancel_delayed_work_sync(&net->xfrm.nat_keepalive_work);
	disable_delayed_work_sync(&net->xfrm.nat_keepalive_work);
	return 0;
}