Commit 7b1f9f4933 for strongswan.org

commit 7b1f9f493327b9c5f31d7b3118787a0c6b0ca7b1
Author: Tobias Brunner <tobias@strongswan.org>
Date:   Thu Sep 10 15:41:18 2026 +0200

    shunt-manager: Ignore uninstalls during shutdown to avoid deadlock

    The policies are flushed and the manager disabled before the plugins
    are unloaded.  So any plugin (e.g. bypass-lan) that tries to uninstall
    shunt policies at that time caused a deadlock as the call would just
    block on the condvar.  The check is put inside the loop in case a thread
    is waiting there for an `install()` call to complete while `flush()` is
    concurrently called and then the thread in `flush()` is woken first.

    Using `broadcast()` also fixes an issue if multiple threads are waiting
    in `uninstall()`.

    A new check in `flush()` prevents a deadlock due to a potential second
    call.

    Fixes: 6dca323ae0ea ("shunt-manager: Fix potential race between install and uninstall")

diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c
index 843642ac1d..a0acfe6040 100644
--- a/src/libcharon/sa/shunt_manager.c
+++ b/src/libcharon/sa/shunt_manager.c
@@ -251,7 +251,7 @@ METHOD(shunt_manager_t, install, bool,
 		entry_destroy(entry);
 	}
 	this->installing--;
-	this->condvar->signal(this->condvar);
+	this->condvar->broadcast(this->condvar);
 	this->lock->unlock(this->lock);
 	return success;
 }
@@ -379,6 +379,11 @@ METHOD(shunt_manager_t, uninstall, bool,
 	this->lock->write_lock(this->lock);
 	while (this->installing)
 	{
+		if (this->installing == INSTALL_DISABLED)
+		{	/* flush() has been called, policy is already uninstalled */
+			this->lock->unlock(this->lock);
+			return TRUE;
+		}
 		this->condvar->wait(this->condvar, this->lock);
 	}
 	enumerator = this->shunts->create_enumerator(this->shunts);
@@ -441,6 +446,11 @@ METHOD(shunt_manager_t, flush, void,
 	entry_t *entry;

 	this->lock->write_lock(this->lock);
+	if (this->installing == INSTALL_DISABLED)
+	{
+		this->lock->unlock(this->lock);
+		return;
+	}
 	while (this->installing)
 	{
 		this->condvar->wait(this->condvar, this->lock);