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:
@@ -310,11 +310,30 @@ void array_insert_enumerator(array_t *array, int idx, enumerator_t *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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -341,7 +360,7 @@ void array_insert(array_t *array, int idx, void *data)
|
||||
pos = array->data + get_size(array, array->head + idx);
|
||||
if (array->esize)
|
||||
{
|
||||
memcpy(pos, data, get_size(array, 1));
|
||||
memcpy(pos, src, array->esize);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -113,7 +113,8 @@ void array_remove_at(array_t *array, enumerator_t *enumerator);
|
||||
* Insert an element to an array.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
|
||||
Reference in New Issue
Block a user