В ядре Linux устранена следующая уязвимость:
fs/ntfs3: исправлена утечка информации при частичной распаковке LZNT в ni_read_frame().
ni_read_frame() распаковывает кадр LZNT $DATA в целевой объект vmapped.
страниц, а затем доверяет возвращаемому значению decompress_lznt():
unc_size = decompress_lznt(frame_ondisk, ondisk_size,frame_mem,
размер_рамки);
если ((ssize_t)unc_size <0) err = unc_size;
иначе, если (!unc_size || unc_size >frame_size) err = -EINVAL;
decompress_lznt() останавливается, как только сжатый поток исчерпан
(например, нулевой заголовок фрагмента) и возвращает фактическое количество байтов.
написал, что может быть намного меньше, чемframe_size. Байты между unc_size
иframe_size никогда не записываются. Единственный memset(), который следует за нулями
регион за пределами i_valid; когда кадр полностью лежит внутри файла
допустимый размер, который memset() не запускает, поэтому в пробеле сохраняется все, что было в
только что сопоставленные страницы.
Все страницы затем помечаются как обновленные и возвращаются.
в пространство пользователя, раскрывая неинициализированную (недавно освобожденную) страницу ядра
память. Созданный сжатый файл, поток которого распаковывается всего до нескольких
bytes пропускает остаток каждого кадра при простом чтении(2), что
достаточно, чтобы восстановить указатели ядра и победить KASLR. Обнулите хвост [unc_size,frame_size) сразу после успешного LZNT.
распакуйте, чтобы остаток считался нулевым.
Показать оригинальное описание (EN)
In the Linux kernel, the following vulnerability has been resolved: fs/ntfs3: fix info-leak on partial LZNT decompress in ni_read_frame() ni_read_frame() decompresses an LZNT $DATA frame into the vmapped target pages and then trusts decompress_lznt()'s return value: unc_size = decompress_lznt(frame_ondisk, ondisk_size, frame_mem, frame_size); if ((ssize_t)unc_size < 0) err = unc_size; else if (!unc_size || unc_size > frame_size) err = -EINVAL; decompress_lznt() stops as soon as the compressed stream is exhausted (e.g. a zero chunk header) and returns the number of bytes it actually wrote, which may be far less than frame_size. The bytes between unc_size and frame_size are never written. The only memset() that follows zeroes the region beyond i_valid; when the frame lies entirely within the file's valid size that memset() does not run, so the gap retains whatever was in the just-vmapped pages. All pages are then marked uptodate and returned to userspace, disclosing uninitialized (recently-freed) kernel page memory. A crafted compressed file whose stream decompresses to only a few bytes leaks the remainder of every frame on a plain read(2), which is enough to recover kernel pointers and defeat KASLR. Zero the [unc_size, frame_size) tail immediately after a successful LZNT decompress so the remainder reads back as zero.
Характеристики атаки
Последствия
Строка CVSS v3.1