В ядре Linux устранена следующая уязвимость:
трассировка/user_events: исправлено использование после освобождения в user_event_mm_dup().
user_event_mm_dup() беспрепятственно просматривает список активаторов родительского mm под
rcu_read_lock() во время fork() (из copy_process()); это не занимает
событие_мьютекс:
rcu_read_lock();
list_for_each_entry_rcu(enabler, &old_mm->enablers, mm_enablers_link)
Enabler->event = user_event_get(orig->event);
user_event_enabler_destroy() удаляет активатор из этого списка с помощью
list_del_rcu(), а затем, не дожидаясь льготного периода, удаляет
ссылку user_event активатора с помощью user_event_put() и освобождает активатор
с помощью kfree(). Читатель, который загрузил активатор перед вызовом list_del_rcu().
по-прежнему можно пройти по нему, что приводит к двум случаям использования после освобождения:
- kfree(enabler) освобождает активатор, пока этот читатель разыменовывает
активатор->событие.
- user_event_put() может удалить последнюю ссылку на user_event, что
затем освобождается (через Destroy_user_event() в рабочей очереди), в то время как
тот же читатель выполняет для него user_event_get(orig->event). Оба доступны с помощью непривилегированной задачи, которая может открыть user_events_data:
один многопоточный процесс, который регистрирует активатор, а затем одновременно
отменяет его регистрацию и вызывает fork(), запуская гонку.
Об этом сообщает КАСАН.
slab-use-after-free в user_event_mm_dup() во время clone(), с
Предупреждение «refcount_t: добавление к 0» при освобождении user_event. Активатор use-after-free был найден первым; было сообщено об одном user_event
от XIAO WU, и более раннее исправление, предназначенное только для активатора, не устраняло эту проблему. Отложите как user_event_put(), так и kfree(enabler) на рабочий элемент.
поставлены в очередь с помощьюqueue_rcu_work(), поэтому они запускаются только после льготного периода RCU,
как только все читатели, идущие по списку помощников, закончат.
Пут должен работать
в контексте процесса, поскольку user_event_put() принимает event_mutex в последнем
ссылка, поэтому используется рабочая очередь, а не call_rcu(). Теперь разблокированный
put позволяет удалить заблокированный аргумент user_event_enabler_destroy();
все звонящие обновлены.
Показать оригинальное описание (EN)
In the Linux kernel, the following vulnerability has been resolved: tracing/user_events: Fix use-after-free in user_event_mm_dup() user_event_mm_dup() walks the parent mm's enabler list locklessly under rcu_read_lock() during fork() (from copy_process()); it does not take event_mutex: rcu_read_lock(); list_for_each_entry_rcu(enabler, &old_mm->enablers, mm_enablers_link) enabler->event = user_event_get(orig->event); user_event_enabler_destroy() removes an enabler from that list with list_del_rcu() and then, without waiting for a grace period, drops the enabler's user_event reference with user_event_put() and frees the enabler with kfree(). A reader that loaded the enabler before the list_del_rcu() can still be walking it, which leads to two use-after-frees: - kfree(enabler) frees the enabler while that reader dereferences enabler->event. - user_event_put() may drop the last reference to the user_event, which is then freed (via delayed_destroy_user_event() on a work queue), while the same reader does user_event_get(orig->event) on it. Both are reachable by an unprivileged task that can open user_events_data: one multithreaded process that registers an enabler and then concurrently unregisters it and calls fork() triggers the race. KASAN reports a slab-use-after-free in user_event_mm_dup() during clone(), with a "refcount_t: addition on 0" warning when the user_event is freed. The enabler use-after-free was found first; the user_event one was reported by XIAO WU, and the earlier enabler-only fix did not address it. Defer both the user_event_put() and the kfree(enabler) to a work item queued with queue_rcu_work(), so they run only after an RCU grace period, once all readers walking the enabler list have finished. The put must run in process context because user_event_put() takes event_mutex on the last reference, so a work queue is used rather than call_rcu(). The now-unlocked put lets the locked argument of user_event_enabler_destroy() be removed; all callers are updated.
Характеристики атаки
Последствия
Строка CVSS v3.1