Commit c52fd0c518 for strongswan.org

commit c52fd0c518ffa7e7d29da767103c7150bb40e7a2
Author: Tobias Brunner <tobias@strongswan.org>
Date:   Mon Jul 13 16:10:39 2026 +0200

    ha: Fix offset checks in HA address pool

    This applies some of the same fixes found in the previous commit but also
    ensures that the offsets are valid before accessing the bitmask.  Because
    of an off-by-one error in the latter, the last address could get released
    incorrectly (the pool constructor explicitly excludes it).

    Fixes: 98d03438706f ("Implemented a HA enabled in-memory address pool")

diff --git a/src/libcharon/plugins/ha/ha_attribute.c b/src/libcharon/plugins/ha/ha_attribute.c
index 103d1a9378..ebe5ad4a36 100644
--- a/src/libcharon/plugins/ha/ha_attribute.c
+++ b/src/libcharon/plugins/ha/ha_attribute.c
@@ -86,7 +86,7 @@ static host_t* offset2host(pool_t *pool, int offset)
 	host_t *host;
 	uint32_t *pos;

-	if (offset > pool->size)
+	if (offset >= pool->size)
 	{
 		return NULL;
 	}
@@ -132,13 +132,21 @@ static int host2offset(pool_t *pool, host_t *addr)
 	}
 	hosti = ntohl(*(uint32_t*)(host.ptr));
 	basei = ntohl(*(uint32_t*)(base.ptr));
-	if (hosti > basei + pool->size)
+	if (hosti - basei >= pool->size)
 	{
 		return -1;
 	}
 	return hosti - basei;
 }

+/**
+ * Check if the given offset is valid for the size of the pool
+ */
+static bool valid_offset(pool_t *pool, int offset)
+{
+	return offset > 0 && offset < pool->size - 1;
+}
+
 /**
  * Find a pool by its name
  */
@@ -201,7 +209,8 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
 				for (bit = 0; bit < 8; bit++)
 				{
 					tmp_offset = byte * 8 + bit;
-					if (!(pool->mask[byte] & 1 << bit) &&
+					if (valid_offset(pool, tmp_offset) &&
+						!(pool->mask[byte] & 1 << bit) &&
 						responsible_for(this, tmp_offset))
 					{
 						offset = tmp_offset;
@@ -261,7 +270,7 @@ METHOD(attribute_provider_t, release_address, bool,
 			continue;
 		}
 		offset = host2offset(pool, address);
-		if (offset > 0 && offset < pool->size)
+		if (valid_offset(pool, offset))
 		{
 			pool->mask[offset / 8] &= ~(1 << (offset % 8));
 			DBG1(DBG_CFG, "released address %H to HA pool '%s'", address, name);
@@ -286,7 +295,7 @@ METHOD(ha_attribute_t, reserve, void,
 	if (pool)
 	{
 		offset = host2offset(pool, address);
-		if (offset > 0 && offset < pool->size)
+		if (valid_offset(pool, offset))
 		{
 			pool->mask[offset / 8] |= 1 << (offset % 8);
 			DBG1(DBG_CFG, "reserved address %H in HA pool '%s'", address, name);