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);
|
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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user