array: Avoid issue when re-inserting existing element in value-based arrays

The insertion can cause the existing data to get reallocated/moved.  So
if the caller attempts to insert another copy of an existing element into
the array via its pointer, this can cause a undefined behavior or even
a use-after-free because the pointer might get invalid.

There is such a case in `mem_pool_t::get_existing()` since the referenced
commit.

Fixes: d4a0dd9f93 ("mem-pool: Fix issue with make-before-break reauth and multiple IKE_SAs")
This commit is contained in:
Tobias Brunner
2026-07-24 08:47:37 +02:00
parent 8b1f8e0e46
commit 588c7a80d1
2 changed files with 23 additions and 3 deletions
+21 -2
View File
@@ -310,11 +310,30 @@ void array_insert_enumerator(array_t *array, int idx, enumerator_t *enumerator)
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
} }
/**
* Check if the given pointer points to an array element
*/
static bool is_in_array(array_t *array, void *ptr)
{
return array->data && ptr >= array->data &&
ptr < array->data + get_size(array, array->head + array->count +
array->tail);
}
void array_insert(array_t *array, int idx, void *data) void array_insert(array_t *array, int idx, void *data)
{ {
if (idx < 0 || idx <= array_count(array)) if (idx < 0 || idx <= array_count(array))
{ {
void *pos; void *buf, *pos, *src = data;
/* create a local copy if the source is another element in the array.
* due to the resizing/moving, it might get invalid */
if (array->esize && is_in_array(array, data))
{
buf = alloca(array->esize);
memcpy(buf, data, array->esize);
src = buf;
}
if (idx < 0) if (idx < 0)
{ {
@@ -341,7 +360,7 @@ void array_insert(array_t *array, int idx, void *data)
pos = array->data + get_size(array, array->head + idx); pos = array->data + get_size(array, array->head + idx);
if (array->esize) if (array->esize)
{ {
memcpy(pos, data, get_size(array, 1)); memcpy(pos, src, array->esize);
} }
else else
{ {
+2 -1
View File
@@ -113,7 +113,8 @@ void array_remove_at(array_t *array, enumerator_t *enumerator);
* Insert an element to an array. * Insert an element to an array.
* *
* If the array is pointer based (esize = 0), the pointer itself is appended. * If the array is pointer based (esize = 0), the pointer itself is appended.
* Otherwise the element gets copied from the pointer. * Otherwise, the element gets copied from the pointer.
*
* The idx must be either within array_count() or one above to append the item. * The idx must be either within array_count() or one above to append the item.
* Passing -1 has the same effect as passing array_count(), i.e. appends the * Passing -1 has the same effect as passing array_count(), i.e. appends the
* item. It is always valid to pass idx 0 to prepend the item. * item. It is always valid to pass idx 0 to prepend the item.