Використання нульових посилань у ядрі Linux
Нещодавно було оголошено, що дослідники з команди Google Project Zero розробили метод використання вразливостей у ядрі Linux, спричинених рознаймуванням NULL-покажчика.
Досі проблеми ядра , пов'язані з рознаймуванням NULL-покажчиків, не отримували належної уваги , оскільки вважалося нереальним перетворювати такі проблеми на атаки, що призводять до ескалації привілеїв або виконання власного коду (відображення непривілейованих процесів у нижню область адресного простору заборонено).
Як правило, такі помилки призводять до генерації ядром попереджень oops, після чого проблемні завдання завершуються, а стан відновлюється без необхідності зупинки системи.
Новий метод атаки базується на обробці станів "oops" , які можуть призвести до збільшення значення лічильника посилань (refcount), що, у свою чергу, може призвести до переповнення лічильника та звільнення пам'яті, пов'язаної з refcount.
У цьому випадку експлуатація зводиться до маніпуляцій, типових для атак use-after-free (виникає ситуація, коли кількість посилань об’єкта стає нульовою, пам’ять звільняється, але насправді є робочі посилання, що вказують на звільнену пам’ять).
Наразі, коли ядро Linux ініціює розіменування null з контексту процесу, воно генерує oops , що відрізняється від паніки ядра. Паніка виникає, коли ядро визначає, що немає безпечного способу продовжити виконання і тому має припинити все виконання. Однак ядро не зупиняє все виконання під час oops; натомість ядро намагається відновитися якомога краще та продовжує виконання.
Розіменування вказівника NULL використовується тут як спосіб генерувати стан "oops" контрольованим способом. Проблема полягає в тому, що для досягнення 232-розрядного переповнення refcount потрібно приблизно 32 виклики статусу "ой".
З практичної точки зору, для виконання атаки з використанням запропонованого експлойту потрібно приблизно вісім днів безперервної генерації неналежних (OOP) станів . У разі успіху експлойт дозволяє виконати ваш код на рівні ядра.
Розіменування вказівника NULL, що використовується в експлойті, було виправлено в жовтні, але оскільки подібні проблеми не є рідкістю і раніше розглядалися як помилки, а не вразливості, розробники додадуть загальний захист до ядра Linux, щоб запобігти атакам, які маніпулюють створенням "oops" ."
У випадку завдання це означає відкидання існуючого стеку ядра та перехід безпосередньо до make_task_dead, який викликає do_exit. Ядро також опублікує в dmesg журнал «збоїв» і трасування ядра, що показує, у якому стані перебувало ядро, коли сталася помилка. Це може здатися дивним вибором, коли явно сталося пошкодження пам’яті; однак мета полягає в тому, щоб полегшити виявлення та реєстрацію помилок ядра згідно з філософією, що запущену систему набагато легше налагодити, ніж непрацюючу.
Зокрема , ядро 6.2 містить зміни для обмеження максимальної кількості помилок "oops" . Після досягнення ліміту, який за замовчуванням встановлено на 10 000 помилок (за бажанням ви можете змінити це за допомогою параметра oops_limit), ядро ініціює перехід у стан "паніки", а потім перезавантаження, яке не дозволить виконати кількість ітерацій, необхідну для скидання refcount до нуля.
Також планується, що обмеження буде перенесено на раніше випущені, але все ще підтримувані гілки ядра, а також пакети ядра популярних дистрибутивів.
Зрештою, якщо ви зацікавлені дізнатися більше про це , ви можете знайти подробиці за наступним посиланням.