1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-40639 Open SYS_REFCURSOR crash, if many cursors inside a function

Problem:

If:
- A routine A() opened a SYS_REFCURSOR with a function B() in the SELECT list
- The function B() also opened some SYS_REFCURSORs

Then reallocation of the cursor array THD::m_statement_cursors could happen
during the execution of B(), so all sp_cursor_array_element pointers inside
sp_instr_copen_by_ref::exec_core() of routine A() became invalid.

Fix:

Chaging the data type of sp_cursor_array:
- from Dynamic_array<sp_cursor_array_element>
- to Dynamic_array<sp_cursor_array_element*>

So now only reallocations of the array of cursor pointers happen,
while sp_cursor_array_element instances always stay on their originally
allocated memory positions.

Note:
sp_cursor_array_element instances are allocated using the standart C++ "new"
and deleted using the standard C++ "delete". Using a MEM_ROOT does not
seem to be relevant here.
This commit is contained in:
Alexander Barkov
2026-08-14 11:04:12 +04:00
parent f51edd8933
commit 91156c3de5
5 changed files with 134 additions and 12 deletions

View File

@@ -442,3 +442,56 @@ END$
a
116
SET @@max_open_cursors = DEFAULT;
#
# MDEV-40639 Open SYS_REFCURSOR crash, if many cursors inside a function
#
CREATE FUNCTION trigger_realloc() RETURNS INT
BEGIN
DECLARE c1 SYS_REFCURSOR;
DECLARE c2 SYS_REFCURSOR;
DECLARE c3 SYS_REFCURSOR;
DECLARE c4 SYS_REFCURSOR;
DECLARE c5 SYS_REFCURSOR;
DECLARE c6 SYS_REFCURSOR;
DECLARE c7 SYS_REFCURSOR;
DECLARE c8 SYS_REFCURSOR;
DECLARE c9 SYS_REFCURSOR;
DECLARE c10 SYS_REFCURSOR;
DECLARE c11 SYS_REFCURSOR;
DECLARE c12 SYS_REFCURSOR;
DECLARE c13 SYS_REFCURSOR;
DECLARE c14 SYS_REFCURSOR;
DECLARE c15 SYS_REFCURSOR;
DECLARE c16 SYS_REFCURSOR;
DECLARE c17 SYS_REFCURSOR;
OPEN c1 FOR SELECT 1;
OPEN c2 FOR SELECT 1;
OPEN c3 FOR SELECT 1;
OPEN c4 FOR SELECT 1;
OPEN c5 FOR SELECT 1;
OPEN c6 FOR SELECT 1;
OPEN c7 FOR SELECT 1;
OPEN c8 FOR SELECT 1;
OPEN c9 FOR SELECT 1;
OPEN c10 FOR SELECT 1;
OPEN c11 FOR SELECT 1;
OPEN c12 FOR SELECT 1;
OPEN c13 FOR SELECT 1;
OPEN c14 FOR SELECT 1;
OPEN c15 FOR SELECT 1;
OPEN c16 FOR SELECT 1;
OPEN c17 FOR SELECT 1;
RETURN 1;
END;
$$
CREATE PROCEDURE trigger_uaf()
BEGIN
DECLARE c SYS_REFCURSOR;
OPEN c FOR SELECT trigger_realloc();
END;
$$
SET SESSION max_open_cursors= 100;
CALL trigger_uaf();
SET SESSION max_open_cursors= DEFAULT;
DROP PROCEDURE trigger_uaf;
DROP FUNCTION trigger_realloc;

View File

@@ -466,3 +466,64 @@ BEGIN NOT ATOMIC
END$
delimiter ;$
SET @@max_open_cursors = DEFAULT;
--echo #
--echo # MDEV-40639 Open SYS_REFCURSOR crash, if many cursors inside a function
--echo #
DELIMITER $$;
# Function that forces cursor array reallocation (17 > default 16 slots)
CREATE FUNCTION trigger_realloc() RETURNS INT
BEGIN
DECLARE c1 SYS_REFCURSOR;
DECLARE c2 SYS_REFCURSOR;
DECLARE c3 SYS_REFCURSOR;
DECLARE c4 SYS_REFCURSOR;
DECLARE c5 SYS_REFCURSOR;
DECLARE c6 SYS_REFCURSOR;
DECLARE c7 SYS_REFCURSOR;
DECLARE c8 SYS_REFCURSOR;
DECLARE c9 SYS_REFCURSOR;
DECLARE c10 SYS_REFCURSOR;
DECLARE c11 SYS_REFCURSOR;
DECLARE c12 SYS_REFCURSOR;
DECLARE c13 SYS_REFCURSOR;
DECLARE c14 SYS_REFCURSOR;
DECLARE c15 SYS_REFCURSOR;
DECLARE c16 SYS_REFCURSOR;
DECLARE c17 SYS_REFCURSOR;
OPEN c1 FOR SELECT 1;
OPEN c2 FOR SELECT 1;
OPEN c3 FOR SELECT 1;
OPEN c4 FOR SELECT 1;
OPEN c5 FOR SELECT 1;
OPEN c6 FOR SELECT 1;
OPEN c7 FOR SELECT 1;
OPEN c8 FOR SELECT 1;
OPEN c9 FOR SELECT 1;
OPEN c10 FOR SELECT 1;
OPEN c11 FOR SELECT 1;
OPEN c12 FOR SELECT 1;
OPEN c13 FOR SELECT 1;
OPEN c14 FOR SELECT 1;
OPEN c15 FOR SELECT 1;
OPEN c16 FOR SELECT 1;
OPEN c17 FOR SELECT 1;
RETURN 1;
END;
$$
CREATE PROCEDURE trigger_uaf()
BEGIN
DECLARE c SYS_REFCURSOR;
OPEN c FOR SELECT trigger_realloc();
END;
$$
DELIMITER ;$$
SET SESSION max_open_cursors= 100;
CALL trigger_uaf();
SET SESSION max_open_cursors= DEFAULT;
DROP PROCEDURE trigger_uaf;
DROP FUNCTION trigger_realloc;

View File

@@ -48,8 +48,11 @@ bool sp_cursor::check_for_open(THD *thd, bool check_open_cursor_counter) const
*/
Type_ref_null sp_cursor_array::append(THD *thd)
{
if (Dynamic_array::append(sp_cursor_array_element()))
sp_cursor_array_element *elem= new sp_cursor_array_element();
if (!elem || Dynamic_array::append(elem))
{
if (!elem)
my_error(ER_OUTOFMEMORY, MYF(0), (int) sizeof(sp_cursor_array_element));
DBUG_ASSERT(thd->is_error());
return Type_ref_null();
}
@@ -70,7 +73,7 @@ sp_cursor_array_element *sp_cursor_array::get_cursor_by_ref(THD *thd,
{
Type_ref_null ref= ref_field->val_ref(thd);
if (ref < (ulonglong) elements())
return &at((size_t) ref.value());// "ref" points to an initialized sp_cursor
return at((size_t) ref.value());// "ref" points to an initialized sp_cursor
if (!for_open)
return nullptr;
@@ -88,8 +91,8 @@ sp_cursor_array_element *sp_cursor_array::get_cursor_by_ref(THD *thd,
ref_field->store_ref(ref, true/*no_conversions*/))
return nullptr;
at((size_t) ref.value()).reset(thd, 1/*ref count*/);
return &at((size_t) ref.value());
at((size_t) ref.value())->reset(thd, 1/*ref count*/);
return at((size_t) ref.value());
}
#endif // MYSQL_SERVER

View File

@@ -193,14 +193,14 @@ public:
};
class sp_cursor_array: public Dynamic_array<sp_cursor_array_element>
class sp_cursor_array: public Dynamic_array<sp_cursor_array_element*>
{
protected:
Type_ref_null find_unused()
{
for (size_t i= 0 ; i < size(); i++)
{
if (!at(i).is_open() && !at(i).ref_count())
if (!at(i)->is_open() && !at(i)->ref_count())
return Type_ref_null((ulonglong) i);
}
return Type_ref_null();
@@ -220,20 +220,20 @@ public:
ULonglong_null ref_count(ulonglong offset) const
{
return offset < elements() ?
ULonglong_null((ulonglong) at((size_t) offset).ref_count()) :
ULonglong_null((ulonglong) at((size_t) offset)->ref_count()) :
ULonglong_null();
}
void ref_count_inc(ulonglong offset)
{
if (offset < elements())
at((size_t) offset).ref_count_inc();
at((size_t) offset)->ref_count_inc();
}
void ref_count_dec(THD *thd, ulonglong offset)
{
if (offset < elements())
at((size_t) offset).ref_count_dec(thd);
at((size_t) offset)->ref_count_dec(thd);
}
void ref_count_update(THD *thd, const Type_ref_null &old_value,
@@ -281,13 +281,18 @@ public:
{
for (uint i= 0; i < (uint) size(); i++)
{
if (at(i).is_open())
at(i).close(thd);
if (at(i)->is_open())
at(i)->close(thd);
}
}
void free(THD *thd)
{
close(thd);
for (uint i= 0; i < (uint) size(); i++)
{
DBUG_ASSERT(at(i));
delete at(i);
}
free_memory();
}
};

View File

@@ -109,7 +109,7 @@ sp_cursor *Sp_rcontext_handler_local::get_cursor(THD *thd, uint offset) const
sp_cursor *Sp_rcontext_handler_statement::get_cursor(THD *thd, uint offset) const
{
return &thd->statement_cursors()->at(offset);
return thd->statement_cursors()->at(offset);
}
sp_cursor *Sp_rcontext_handler_statement::get_cursor_by_ref(THD *thd,