Ad

CVE-2026-89493

HIGH CVSS 3.1: 8,8 EPSS 0.65%
Обновлено 14 сентября 2026
Linux
Параметр Значение
CVSS 8,8 (HIGH)
Поставщик Linux
Публичный эксплойт Нет

В ядре Linux устранена следующая уязвимость: ocfs2: проверить rl_used на соответствие rl_count в валидаторе блока refcount ocfs2_find_refcount_rec_in_rl() просматривает массив записей счетчика ссылок на диске с: for (; я <le16_to_cpu(rb->rf_records.rl_used); i++) { запись = &rb->rf_records.rl_recs[i]; ... rl_recs[] находится в одном блоке метаданных (4096 байт в общем конфигурации), поэтому его реальная емкость фиксируется ocfs2_refcount_recs_per_rb(sb) (247 записей для блока размером 4 КБ с 16-байтовый ocfs2_refcount_rec). rl_used и rl_count читаются напрямую. с диска с помощью ocfs2_validate_refcount_block() и никогда не проверяются эту мощность, ни друг против друга, до любого рефсчета/рефлинка/CoW операция проходит по массиву. Созданный (или поврежденный) блок счетчика ссылок с rl_used == 0xffff делает цикл выше проходит далеко за конец блока, разыменовывая rl_recs[i] для i до 65534. Полученный индекс затем передается брату или сестре. ocfs2_insert_refcount_rec(), чья вставка-сдвиг выполняет: если (индекс <le16_to_cpu(rf_list->rl_used)) memmove(&rf_list->rl_recs[индекс + 1], &rf_list->rl_recs[индекс], (le16_to_cpu(rf_list->rl_used) - индекс) * sizeof(struct ocfs2_refcount_rec)); т. е. memmove() размером до (0xffff - индекс) * 16 байт (~ 1 МБ) из смещение уже за блоком.

Это доступно по обычной рефссылке. (FICLONE) против созданного/поврежденного образа ocfs2: прикрепление экстента чей cpos сортирует каждую реальную запись на листе, заставляет искать убежать до конца вместо того, чтобы вернуться до начала матча. Модель атакующего является локальным: CAP_SYS_ADMIN монтирует созданный или поврежденный образ ocfs2 или необработанная запись на блочное устройство, поддерживающее уже смонтированную файловую систему ocfs2. ocfs2_validate_refcount_block() уже проверяет ECC блока, подпись, rf_blkno и rf_fs_generation, но никогда rl_count/rl_used относительно фактической емкости блока на диске. Это тот самый класс пробел, который ocfs2_validate_extent_block() (fs/ocfs2/alloc.c) уже закрывается для заголовка родственного списка экстентов, который проверяет как емкость записи, так и и «использованная» привязка до того, как какой-либо код пройдет через h_list.l_recs[]: if (le16_to_cpu(eb->h_list.l_count) != ocfs2_extent_recs_per_eb(sb)) { rc = ocfs2_error(...); выйти под залог; } if (le16_to_cpu(eb->h_list.l_next_free_rec) > le16_to_cpu(eb->h_list.l_count)) { rc = ocfs2_error(...); выйти под залог; } Добавьте эквивалентную пару проверок в ocfs2_validate_refcount_block(): отклонить блок refcount, чей rl_count не соответствует фиксированному значению для каждого блока емкость, возвращаемая функцией ocfs2_refcount_recs_per_rb(), и отклонить rl_used > rl_count.

Обе проверки пропускаются, если установлено OCFS2_REFCOUNT_TREE_FL. потому что в этом случае одни и те же байты объединения содержат ocfs2_extent_list (rf_list), а не список записей счетчика ссылок (rf_records) – этот макет уже проверено отдельно с помощью ocfs2_validate_extent_block(), когда ссылочный блок экстентов читается. Это отражает существующую Охранник "!(rb->rf_flags & OCFS2_REFCOUNT_TREE_FL)" используется где-то в этом документе. файл (например, ocfs2_get_refcount_rec()), чтобы решить, будет ли rf_records или rf_list — действующий член союза. При этом поддельный rl_used/rl_count перехватывается в блоке. время проверки (ocfs2_error()), соответствующее любому другому повреждению проверьте эту функцию, вместо того, чтобы управлять чтением за пределами границ ocfs2_find_refcount_rec_in_rl() и последующий memmove() за пределами границ в ocfs2_insert_refcount_rec().

Проверено на основе созданного образа в сборке KASAN v6.19 (KASAN_GENERIC): воспроизведение одной и той же рефссылки (FICLONE) надежно попало в отчет KASAN в __ocfs2_increase_refcount()/ocfs2_insert_refcount_rec() до этого патча, и не создает отчет, как только ocfs2_validate_refcount_block() отклоняет подделанный rl_used/rl_count.

Показать оригинальное описание (EN)

In the Linux kernel, the following vulnerability has been resolved: ocfs2: validate rl_used against rl_count in refcount block validator ocfs2_find_refcount_rec_in_rl() walks the on-disk refcount record array with: for (; i < le16_to_cpu(rb->rf_records.rl_used); i++) { rec = &rb->rf_records.rl_recs[i]; ... rl_recs[] lives in a single metadata block (4096 bytes on the common configuration), so its real capacity is fixed by ocfs2_refcount_recs_per_rb(sb) (247 records for a 4K block with the 16-byte ocfs2_refcount_rec). rl_used and rl_count are both read directly off disk by ocfs2_validate_refcount_block() and are never checked against that capacity, nor against each other, before any refcount/reflink/CoW operation walks the array. A crafted (or corrupted) refcount block with rl_used == 0xffff makes the loop above walk far past the end of the block, dereferencing rl_recs[i] for i up to 65534. The resulting index is then handed to the sibling ocfs2_insert_refcount_rec(), whose insert-shift does: if (index < le16_to_cpu(rf_list->rl_used)) memmove(&rf_list->rl_recs[index + 1], &rf_list->rl_recs[index], (le16_to_cpu(rf_list->rl_used) - index) * sizeof(struct ocfs2_refcount_rec)); i.e. a memmove() of up to (0xffff - index) * 16 bytes (~1 MiB) from an offset already past the block. This is reachable from an ordinary reflink (FICLONE) against a crafted/corrupted ocfs2 image: attaching an extent whose cpos sorts past every real record in the leaf forces the lookup to run off the end instead of returning early on a match. The attacker model is local: CAP_SYS_ADMIN mounting a crafted or corrupted ocfs2 image, or a raw write to the block device backing an already-mounted ocfs2 filesystem. ocfs2_validate_refcount_block() already validates the block's ECC, signature, rf_blkno and rf_fs_generation, but never rl_count/rl_used against the block's actual on-disk capacity. This is the same class of gap that ocfs2_validate_extent_block() (fs/ocfs2/alloc.c) already closes for the sibling extent-list header, which checks both the record capacity and the "used" bound before any code walks h_list.l_recs[]: if (le16_to_cpu(eb->h_list.l_count) != ocfs2_extent_recs_per_eb(sb)) { rc = ocfs2_error(...); goto bail; } if (le16_to_cpu(eb->h_list.l_next_free_rec) > le16_to_cpu(eb->h_list.l_count)) { rc = ocfs2_error(...); goto bail; } Add the equivalent pair of checks to ocfs2_validate_refcount_block(): reject a refcount block whose rl_count does not match the fixed per-block capacity returned by ocfs2_refcount_recs_per_rb(), and reject rl_used > rl_count. Both checks are skipped when OCFS2_REFCOUNT_TREE_FL is set, because in that case the same union bytes hold an ocfs2_extent_list (rf_list), not the refcount record list (rf_records) -- that layout is already validated separately by ocfs2_validate_extent_block() when the referenced extent block is read. This mirrors the existing "!(rb->rf_flags & OCFS2_REFCOUNT_TREE_FL)" guard used elsewhere in this file (e.g. ocfs2_get_refcount_rec()) to decide whether rf_records or rf_list is the live member of the union. With this in place, a forged rl_used/rl_count is caught at block validation time (ocfs2_error()), consistent with every other corruption check in this function, instead of driving an out-of-bounds read in ocfs2_find_refcount_rec_in_rl() and a subsequent out-of-bounds memmove() in ocfs2_insert_refcount_rec(). Verified against a crafted image on a v6.19 KASAN (KASAN_GENERIC) build: replaying the same reflink (FICLONE) reliably hit a KASAN report in __ocfs2_increase_refcount()/ocfs2_insert_refcount_rec() before this patch, and triggers no report once ocfs2_validate_refcount_block() rejects the forged rl_used/rl_count.

Характеристики атаки

Способ атаки
По сети
Атака возможна удалённо
Сложность
Низкая
Легко эксплуатировать
Нужны права
Низкие
Нужны базовые права
Участие пользователя
Не требуется
Не нужно действие пользователя

Последствия

Конфиденциальность
Высокое
Полная утечка данных
Целостность
Высокое
Полная модификация данных
Доступность
Высокое
Полный отказ в обслуживании

Строка CVSS v3.1