Raise an exception if ar_table is converted to st_table during iteration

ar_table may be converted to st_table by `ar_force_convert_table`.
If the conversion occurs during the iteration of ar_table, the iteration
may lead to memory corruption.

This change prevents the catastrophy by throwing an exception when the
conversion is detected.

This issue is reported by [SuperS](https://hackerone.com/superss)
This commit is contained in:
Yusuke Endoh 2023-11-08 17:09:33 +09:00
Родитель c3ab946e86
Коммит a787e0d649
1 изменённых файлов: 11 добавлений и 0 удалений

11
hash.c
Просмотреть файл

@ -811,6 +811,14 @@ ar_add_direct_with_hash(VALUE hash, st_data_t key, st_data_t val, st_hash_t hash
} }
} }
static void
ensure_ar_table(VALUE hash)
{
if (!RHASH_AR_TABLE_P(hash)) {
rb_raise(rb_eRuntimeError, "hash representation was changed during iteration");
}
}
static int static int
ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg) ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg)
{ {
@ -822,6 +830,7 @@ ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_c
ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i); ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
enum st_retval retval = (*func)(pair->key, pair->val, arg, 0); enum st_retval retval = (*func)(pair->key, pair->val, arg, 0);
ensure_ar_table(hash);
/* pair may be not valid here because of theap */ /* pair may be not valid here because of theap */
switch (retval) { switch (retval) {
@ -896,6 +905,7 @@ ar_foreach_check(VALUE hash, st_foreach_check_callback_func *func, st_data_t arg
hint = ar_hint(hash, i); hint = ar_hint(hash, i);
retval = (*func)(key, pair->val, arg, 0); retval = (*func)(key, pair->val, arg, 0);
ensure_ar_table(hash);
hash_verify(hash); hash_verify(hash);
switch (retval) { switch (retval) {
@ -956,6 +966,7 @@ ar_update(VALUE hash, st_data_t key,
old_key = key; old_key = key;
retval = (*func)(&key, &value, arg, existing); retval = (*func)(&key, &value, arg, existing);
/* pair can be invalid here because of theap */ /* pair can be invalid here because of theap */
ensure_ar_table(hash);
switch (retval) { switch (retval) {
case ST_CONTINUE: case ST_CONTINUE: