Odebrany

CVE-2026-93241

opublikowano:
modyfikacja:
Ocena CVSS
n/a
Brak oceny

>_ Opis

Tłumaczenie automatyczne – może zawierać nieścisłości.

W jądrze Linuksa usunięto następującą lukę:

memcg: pomiń funkcje Reclaim i Oom Killer w przypadku umierających zadań po zakończeniu oom_reaper

W Meta widzimy przypadki, w których zabita praca OOM utknęła w
ścieżkę wyjściową na kilka godzin. W jednym konkretnym przypadku zadanie utknęło
przez ponad 8 godzin i musiałem ręcznie usunąć limity memory.max
aby umożliwić zakończenie procesu.

Zadanie było zadaniem pojedynczego procesu i miało ~ 55 GiB pamięci.max i zswap
włączone. Miał prawie 0 anonów w pamięci i ~ 111 GiB w skompresowanym formacie zswap
do ~51 GiB puli zswap (tj. prawie cała pamięć.current była zswap).
Na LRU nie pozostało już nic do odzyskania.

Podczas dalszej inspekcji zaobserwowałem, że utknęło około 20 tys. wątków tego procesu
następujący stos:

[<0>] mem_cgroup_out_of_memory+0x4e/0xa0
[<0>] opłata_memcg+0x8bf/0x990
[<0>] mem_cgroup_swapin_charge_folio+0x4e/0x80
[<0>] __read_swap_cache_async+0x10c/0x260
[<0>] swapin_readahead+0x116/0x3f0
[<0>] do_swap_page+0x13c/0x1ce0
[<0>] handle_mm_fault+0x61d/0x11f0
[<0>] do_user_addr_fault+0x3e7/0x6d0
[<0>] exc_page_fault+0x8f/0x110
[<0>] asm_exc_page_fault+0x22/0x30
[<0>] __get_user_8+0x14/0x20
[<0>] futex_cleanup+0x27/0x1c0
[<0>] futex_exit_release+0x47/0x60
[<0>] do_exit+0x107/0x940
[<0>] do_group_exit+0x81/0xa0
[<0>] get_signal+0x2b1/0x6e0
[<0>] arch_do_signal_or_restart+0x1a/0x1c0
[<0>] exit_to_user_mode_loop+0xa8/0x1c0
[<0>] do_syscall_64+0x152/0x250
[<0>] wpis_SYSCALL_64_after_hwframe+0x4b/0x53

Dodatkowo dmesg został wypełniony komunikatem „Brak pamięci i brak możliwości zabicia
procesy..." wiadomości.

Nie mam pojęcia, dlaczego oom Reaper nie był w stanie zebrać/odmapować procesu. Mój
przypuszczam, że skoro oom reaper próbuje uzyskać mmap_lock w trybie odczytu
ograniczoną liczbę razy, a potem się poddaje, może być taki wątek
proces, który w tym czasie miał mmap_lock w trybie zapisu.

Moje początkowe podejrzenie dotyczyło błędu futex_cleanup i strony jądra
nieskończone próby usterek i ładowania, ale zostało to pominięte w poprzednim
dyskusje dotyczyły podobnego problemu [1].

Moja obecna teoria jest taka, że jest to po prostu powolna serializacja
oom_lock. W przeciwieństwie do alokatora stron, kod ładowania memcg pobiera oom_lock
bez „próbowania”. Chociaż kod memcg oom używa mutex_lock_killable(), uwaga
że na stosie wywołań get_signal() zużywa SIGKILL (lub
sigdelset(SIGKILL)) przed wywołaniem funkcji do_group_exit(). Więc to
mutex_lock_killable() jest tutaj po prostu mutex_lock(). Dlatego 10 s
tysiące wątków czeka na oom_lock i otrzymują je jeden po drugim
-EFAULT z get_user() w kodzie czyszczącym futex i wyskakuje.

Dyskusja w [1] doprowadziła do zatwierdzenia a75ffa26122b („memcg, oom: nie omijaj
oom zabójca dla umierających zadań”), który kieruje umierające zadania na ścieżkę OOM
dokładnie tak, aby oom_reaper mógł zebrać mm i zwolnić pamięć
asynchronicznie. Ale żniwiarz wymaga najlepszego wysiłku i jednego strzału: jeśli nie może
weź mmap_lock do odczytu (np. wątek rodzeństwa przechowuje go do zapisu) to
ustawia MMF_OOM_SKIP i nigdy nie próbuje ponownie, pozostawiając tylko lodowiec
oom_lock-serializowany dren synchroniczny.

Po ustawieniu MMF_OOM_SKIP nie będzie już więcej asynchronicznego odzyskiwania
mm, więc umierające zadanie szarżujące na niego nie ma na co czekać:
zwalnia pamięć dopiero po zakończeniu zamykania. Uruchomienie odzyskiwania i
zabójca OOM (bez ofiary) jest wtedy bezcelowy i robi to przez 10 sekund
tysięcy wychodzących wątków serializuje je za oom_lock.
Więc zanim odzyskasz, jeśli obecny jest ofiarą OOM, której żniwiarka się skończyła, ponieś porażkę
opłata.

Reprodukowana z 20 tys. wątków, z których każdy posiada własną, solidną główkę futex
zswapped page, OOM-group-killed, podczas gdy rodzeństwo trzyma mmap_lock do zapisu
więc żniwiarz poddaje się i ustawia MMF_OOM_SKIP. Testowane na next-20260728 i
linia bazowa pokazuje czas wyjścia ~90 sekund, natomiast w przypadku łatki czas wyjścia
skrócony do ~3 sekund.

>_ Referencje

Dane podatności pochodzą z oficjalnych źródeł (CVE® List / NVD). Opisy po polsku są tłumaczone automatycznie i mogą zawierać nieścisłości – na stronie rekordu można wyświetlić wersję angielską.

This product uses the NVD API but is not endorsed or certified by the NVD.

Copyright © 1999–2026, The MITRE Corporation. CVE is a registered trademark and the CVE logo is a registered trademark of The MITRE Corporation.

CVE Usage: MITRE hereby grants you a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Common Vulnerabilities and Exposures (CVE®). Any copy you make for such purposes is authorized provided that you reproduce MITRE's copyright designation and this license in any such copy. ALL DOCUMENTS AND THE INFORMATION CONTAINED THEREIN PROVIDED BY MITRE ARE PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND.

NVD Terms of Use / CVE® Terms of Use / nvd.nist.gov / cve.org