В ядре Linux устранена следующая уязвимость:
ntfs3: ограничение RESTART_TABLE обходчика свободной цепи в rt->used
Созданный образ диска NTFS3 запускает бесконечный цикл в ядре.
время монтажа, подвешивание монтажной нити и срабатывание мягкой блокировки
сторожевой таймер в течение ~22 секунд на многопроцессорных хостах (паника с
kernel.softlockup_panic=1). Ошибка доступна с настольного USB-накопителя.
автоматическое монтирование в дистрибутивах, где udisks2 маршрутизирует подпись NTFS
к драйверу ntfs3 в дереве (семейство Arch и возрастающая фракция
развертываний Fedora/openSUSE/RHEL); Руководство по классу CAP_SYS_ADMIN
монтировать в другом месте. Второй обходчик check_rstbl() повторяет односвязный код со свободным входом
список, возглавляемый rt->first_free, без верхней границы количества итераций:
для (выкл. = ff; выкл.;) {
если (выключено == RESTART_ENTRY_ALLOCATED)
вернуть ложь;
off = le32_to_cpu(*(__le32 *)Add2Ptr(rt, off));
если (выкл > ts - sizeof(__le32))
вернуть ложь;
}
Существующие охранники закрывают три выхода: конец списка (выключено == 0),
маркер использования (выключен == RESTART_ENTRY_ALLOCATED) и выход за пределы
(выкл > ts - sizeof(__le32)).
Ни один из трех не препятствует
цикл внутри границ. Созданный на диске RESTART_TABLE, свободная цепочка которого содержит
самоцикл или цикл A->B->A, смещения которого удовлетворяют:
- в диапазоне [sizeof(struct RESTART_TABLE), ts - sizeof(__le32)]
- (off - sizeof(struct RESTART_TABLE)) % rsize == 0
проходит все существующие защиты и навсегда вращает поток времени монтирования. Воспроизведено в UML путем ручной подделки образа NTFS3 размером 2 МБ, журнал которого
RESTART_TABLE first_free = 0x18 и чья запись по смещению 0x18
сохраняет 0x18 в качестве следующего указателя; монтирование подделанного образа с помощью
драйвер ntfs3 в дереве никогда не возвращается.
Привязал ходунка с помощью rt->used. Каждая запись на законном бесплатном
цепочка уникальна, а общее количество слотов равно ne = le16_to_cpu
(rt->используется). Обход, который посещает более чем ne слотов,
конструкция деформирована; отклонить его как поврежденный RESTART_TABLE.
После этого патча монтирование подделанного образа возвращается с -EINVAL.
и сообщение об ошибке log_replay, а также законное сообщение, созданное mkntfs.
изображения монтируются без проблем (проверено в той же обвязке UML).
Показать оригинальное описание (EN)
In the Linux kernel, the following vulnerability has been resolved: ntfs3: cap RESTART_TABLE free-chain walker at rt->used A crafted NTFS3 disk image triggers an in-kernel infinite loop at mount time, hanging the mounting thread and firing the soft-lockup watchdog within ~22s on multi-CPU hosts (panic with kernel.softlockup_panic=1). The bug is reachable from desktop USB auto-mount on distributions where udisks2 routes the NTFS signature to the in-tree ntfs3 driver (Arch family and an increasing fraction of Fedora / openSUSE / RHEL deployments); CAP_SYS_ADMIN-class manual mount elsewhere. check_rstbl()'s second walker iterates the free-entry singly-linked list headed by rt->first_free with no upper bound on iteration count: for (off = ff; off;) { if (off == RESTART_ENTRY_ALLOCATED) return false; off = le32_to_cpu(*(__le32 *)Add2Ptr(rt, off)); if (off > ts - sizeof(__le32)) return false; } The existing guards cover three exits: end-of-list (off == 0), the in-use marker (off == RESTART_ENTRY_ALLOCATED), and out-of-bounds (off > ts - sizeof(__le32)). None of the three prevents an in-bounds cycle. A crafted on-disk RESTART_TABLE whose free chain contains a self-loop or A->B->A cycle whose offsets satisfy: - in range [sizeof(struct RESTART_TABLE), ts - sizeof(__le32)] - (off - sizeof(struct RESTART_TABLE)) % rsize == 0 passes all existing guards and spins the mount-time thread forever. Reproduced in UML by hand-forging a 2 MB NTFS3 image whose journal RESTART_TABLE first_free = 0x18 and whose entry at offset 0x18 stores 0x18 as its next pointer; mount of the forged image with the in-tree ntfs3 driver never returns. Bound the walker by rt->used. Each entry on a legitimate free chain is unique, and the total slot count is ne = le16_to_cpu (rt->used). A traversal that visits more than ne slots is by construction malformed; reject it as a corrupt RESTART_TABLE. After this patch, mount of the forged image returns with -EINVAL and a log_replay failure message, and mkntfs-produced legitimate images mount cleanly (verified in the same UML harness).