git: e196b12f4d4d - main - ipsec: Drain async ipsec_offload work when destroying a vnet

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Fri, 30 Aug 2024 13:08:32 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=e196b12f4d4d13982d42cf7841b77dca1405effa

commit e196b12f4d4d13982d42cf7841b77dca1405effa
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-08-30 00:44:45 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-08-30 13:08:20 +0000

    ipsec: Drain async ipsec_offload work when destroying a vnet
    
    The ipsec_offload code in some cases releases object references in an
    asynchronous context where it needs to set the current VNET.  Make sure
    that all such work completes before the VNET is actually destroyed,
    otherwise a use-after-free is possible.
    
    Reported by:    KASAN
    Reviewed by:    kib
    Fixes:          ef2a572bf6bd ("ipsec_offload: kernel infrastructure")
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D46483
---
 sys/netipsec/ipsec_offload.c | 2 +-
 sys/netipsec/key.c           | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/sys/netipsec/ipsec_offload.c b/sys/netipsec/ipsec_offload.c
index bbf98ac7a676..1ff91ec585c2 100644
--- a/sys/netipsec/ipsec_offload.c
+++ b/sys/netipsec/ipsec_offload.c
@@ -386,7 +386,7 @@ ipsec_accel_sa_newkey_impl(struct secasvar *sav)
 
 	TASK_INIT(&tq->install_task, 0, ipsec_accel_sa_newkey_act, tq);
 	tq->sav = sav;
-	tq->install_vnet = curthread->td_vnet;	/* XXXKIB liveness */
+	tq->install_vnet = curthread->td_vnet;
 	taskqueue_enqueue(taskqueue_thread, &tq->install_task);
 }
 
diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c
index 5a3e5727bc2e..ad1d6164f158 100644
--- a/sys/netipsec/key.c
+++ b/sys/netipsec/key.c
@@ -8713,6 +8713,9 @@ key_vnet_destroy(void *arg __unused)
 	}
 	SAHTREE_WUNLOCK();
 
+	/* Wait for async work referencing this VNET to finish. */
+	ipsec_accel_sync();
+
 	key_freesah_flushed(&sahdrainq);
 	hashdestroy(V_sphashtbl, M_IPSEC_SP, V_sphash_mask);
 	hashdestroy(V_savhashtbl, M_IPSEC_SA, V_savhash_mask);