В ядре Linux устранена следующая уязвимость:
sunrpc: дождитесь обратного вызова рукопожатия TLS в полете, когда отмена проигрывает гонку
Когда wait_for_completion_interruptible_timeout() в
svc_tcp_handshake() возвращает 0 (тайм-аут) или -ERESTARTSYS (сигнал) и
tls_handshake_cancel() затем возвращает false, Handshake_complete() имеет
выиграл гонку отмены: он установил HANDSHAKE_F_REQ_COMPLETED и
собирается вызвать svc_tcp_handshake_done(), но обратный вызов
побочных эффектов на xpt_flags и svsk->sk_handshake_done нет
все же преданный. Текущий код немедленно считывает xpt_flags, чтобы решить, нужно ли
сессия прошла успешно. Результат двух гонок.
Если обратный вызов выполнил set_bit(XPT_TLS_SESSION), но еще не
clear_bit(XPT_HANDSHAKE), svc_tcp_handshake() видит сеанс,
ставит транспорт в очередь и возвращается. svc_xprt_received(), тогда
очищает XPT_BUSY, рабочий поток подхватывает транспорт,
диспетчер в svc_handle_xprt() замечает, что XPT_HANDSHAKE все еще установлен,
и xpo_handshake вызывается второй раз. Это svc_tcp_handshake()
вызывает init_completion(&svsk->sk_handshake_done), в то время как исходный
обратный вызов одновременно вызывает для него Complete_all(), повреждая
встроенный swait_queue. Если обратный вызов установил HANDSHAKE_F_REQ_COMPLETED, но еще не
введён svc_tcp_handshake_done(), svc_tcp_handshake() читает
XPT_TLS_SESSION очищается и разрывает соединение, хотя
рукопожатие вот-вот увенчается успехом.
Подождите, пока обратный вызов зафиксируется, прежде чем проверять xpt_flags.
завершение гарантированно сработает, потому что Handshake_complete()
вызывает svc_tcp_handshake_done() безоговорочно после установки
HANDSHAKE_F_REQ_COMPLETED.
Показать оригинальное описание (EN)
In the Linux kernel, the following vulnerability has been resolved: sunrpc: wait for in-flight TLS handshake callback when cancel loses race When wait_for_completion_interruptible_timeout() in svc_tcp_handshake() returns 0 (timeout) or -ERESTARTSYS (signal) and tls_handshake_cancel() then returns false, handshake_complete() has won the cancellation race: it has set HANDSHAKE_F_REQ_COMPLETED and is about to invoke svc_tcp_handshake_done(), but the callback's side effects on xpt_flags and on svsk->sk_handshake_done have not yet committed. The current code reads xpt_flags immediately to decide whether the session succeeded. Two races result. If the callback has executed set_bit(XPT_TLS_SESSION) but not yet clear_bit(XPT_HANDSHAKE), svc_tcp_handshake() sees a session, enqueues the transport, and returns. svc_xprt_received() then clears XPT_BUSY, a worker thread picks the transport up, the dispatcher in svc_handle_xprt() observes XPT_HANDSHAKE still set, and xpo_handshake is invoked a second time. That svc_tcp_handshake() calls init_completion(&svsk->sk_handshake_done) while the original callback concurrently calls complete_all() on it, corrupting the embedded swait_queue. If the callback has set HANDSHAKE_F_REQ_COMPLETED but not yet entered svc_tcp_handshake_done(), svc_tcp_handshake() reads XPT_TLS_SESSION as clear and tears the connection down even though the handshake is about to succeed. Wait for the callback to commit before inspecting xpt_flags. The completion is guaranteed to fire because handshake_complete() invokes svc_tcp_handshake_done() unconditionally once it has set HANDSHAKE_F_REQ_COMPLETED.
Характеристики атаки
Последствия
Строка CVSS v3.1