Linux kodola labojums, kas kodu maina tikai vienā rindā, aptur klusu datu zudumu, kas pastāvēja kopš 2023. gada jūlija. Problēmu reproducē neliela C programma: ja sistēmā ieslēgtas caurspīdīgās lielās lapas (THP) un process strādā zem cgroup atmiņas ierobežojuma, ieraksti pēc MADV_FREE izsaukuma var pazust bez jebkāda brīdinājuma. Kļūda nes apzīmējumu CVE-2026-97945.
Labojums kodolā nonāca uzreiz pēc Linux 7.3-rc3 izlaišanas 13. septembrī, x86/urgent sapludinājumā, par ko ziņoja Phoronix. Tas atzīmēts pārnešanai uz atbalstītajiem stabilajiem zariem. Linux 7.3 stabilā versija nāk šī oktobra otrajā pusē un nes labojumu līdzi.
Kur pazūd ieraksts
Aparatūras netīrības bits (dirty bit) procesora lapu tabulā norāda, ka lapā kopš pēdējās izrakstīšanas ir ierakstīts un tās saturs atšķiras no diska vai nulles. Pēc šī bita atmiņas atgūšana izšķir, vai lapu drīkst vienkārši izmest vai vispirms tā jāsaglabā.
Vaina ir funkcijā pmd_modify() uz x86. Mainot lielas lapas (PMD līmeņa) ieraksta atļaujas, tā veco vērtību maskē ar (_HPAGE_CHG_MASK & ~_PAGE_DIRTY) un tādā veidā nodzēš aparatūras netīrības bitu. Pēc tam izsauktā pmd_mksaveddirty() šo bitu parasti pārnes programmatūras bitā _PAGE_SAVED_DIRTY, kad lapu padara tikai lasāmu. Bits jau bija noņemts, tāpēc pārnest nav ko.
Blakus funkcijas to dara pareizi. pte_modify() savā maskā patur _PAGE_DIRTY_BITS. pud_modify() atstāj _HPAGE_CHG_MASK neskartu. Vienīgi pmd_modify() zaudēja netīrības stāvokli ikreiz, kad to izsauca uz rakstāmas netīras lielās lapas.
Kāpēc dati pazūd klusi
MADV_FREE pasaka kodolam, ka lapas saturs vairs nav vajadzīgs un atmiņu drīkst atbrīvot, kad rodas spiediens. Ja programma pēc tam atkal ieraksta tajā pašā apgabalā, aparatūra no jauna uzstāda netīrības bitu un lapai jāpaliek. Tieši to kļūda salauza. Reproducē to šāda secība: programma aizpilda PMD izmēra buferi, izsauc madvise(buf, size, MADV_FREE), vēlreiz tajā ieraksta un pēc tam ar mprotect pārslēdz atļaujas uz lasāmu un atpakaļ uz rakstāmu.
Otrajā mprotect izsaukumā pmd_modify() noņem netīrības bitu. Kad vēlāk rodas atmiņas spiediens, atgūšanas kods funkcijā __discard_anon_folio_pmd_locked() atrod lapu bez neviena netīrības bita un to atbrīvo, lai gan dati pēc MADV_FREE bija pārrakstīti. Nākamie lasījumi saņem svaigas, nullēm piepildītas lapas. NUMA mājieni paši vien izraisa to pašu zudumu, jo do_huge_pmd_numa_page() PMD atjauno caur to pašu pmd_modify().
Zudums ir kluss tāpēc, ka nekas neavarē. Nav ne kodola brīdinājuma, ne izejas koda, ne ieraksta žurnālā. Programma turpina darbu, bet daļa datu, ko tā uzskatīja par ierakstītiem, ir pazuduši. Defekts parādās tikai tad, kad vienlaikus sakrīt lielās lapas, MADV_FREE lietojums un atmiņas atgūšana, tāpēc tas trīs gadus palika nepamanīts parastās slodzēs.
Polars lietotāji zaudēja ražošanas datus
Kļūda nav teorētiska. Pašā kodola labojuma aprakstā norādīts, kas to pieteica un kādos apstākļos.
Daļa Polars (datu analītikas bibliotēkas) lietotāju šīs kļūdas dēļ ir zaudējuši ražošanas datus. Viņiem sagadījās tieši īstā lielo lapu, MADV_FREE un smaga atgūšanas spiediena kombinācija.
Linux kodola labojuma apraksts, CVE-2026-97945
Polars ir Rust valodā rakstīta DataFrame bibliotēka, kas datus tur atmiņā lielos blokos, tāpēc tur viegli sakrīt visi trīs nosacījumi. Skarti arī PMD izmēra failu THP. Tur mprotect vai NUMA mājiens, kas noņem netīrības bitu, nozīmē, ka pārrakstītie dati nekad netiek ierakstīti atpakaļ failā.
Kurš kodols skarts un ko darīt
Kļūda pastāv kodolos kopš 6.6. versijas. Ubuntu drošības izsekotājs 24.04 LTS un 26.04 LTS atzīmē kā ievainojamus ar labojumu izstrādē, bet 22.04 un vecākus kā neskartus, jo to kodoli ir pirms 6.6. Debian nestabilajā zarā labojums ir kodola pakotnē 7.2.7-1. Precīzu stāvokli savam kodolam var pārbaudīt Ubuntu un Debian izsekotājos.
Pārbaudīt, vai kļūda jau ir izpaudusies, no malas ir grūti, jo tā neatstāj pēdas. Riska zonā ir slodzes ar lielu atmiņas patēriņu zem cgroup vai konteineru ierobežojumiem, kur kodols bieži veic lapu atgūšanu. Tipisks piemērs ir datu apstrādes procesi atmiņā, kas tuvojas sava konteinera limitam.
Droša rīcība ir atjaunināt kodolu uz versiju ar labojumu. Kamēr tā nav, zudumu novērš caurspīdīgo lielo lapu izslēgšana, jo bez THP pmd_modify() uz lielām lapām netiek izsaukts. To dara ar echo never > /sys/kernel/mm/transparent_hugepage/enabled. Cena ir lēnāka atmiņas piekļuve slodzēs, kas no lielām lapām iegūst, tāpēc tas der tikai kā pagaidu solis līdz kodola atjauninājumam.
Kā izskatās labojums
Labojums patur _PAGE_DIRTY saglabātajā maskā, tāpat kā to jau dara pte_modify() un pud_modify(). Esošais pmd_mksaveddirty() un pmd_clear_saveddirty() pāris pēc tam pārnes netīrības stāvokli starp aparatūras bitu un programmatūras saglabāto bitu atkarībā no rakstīšanas atļaujas. Tāpēc paliek spēkā ēnu steka (shadow stack) kodēšana, kuras dēļ kodols šo bitu sākotnēji vispār pārvietoja. Visa izmaiņa ir viena koda rinda.
Avoti
- Linux Patched For Silent User-Space Data Loss Bug That’s Existed Since 2023 (Phoronix)
- CVE-2026-97945 (Ubuntu drošības izsekotājs)
- CVE-2026-97945 (Debian security tracker)
- CVE-2026-97945 ar pilnu kodola labojuma aprakstu (Rapid7)
- Polars DataFrame bibliotēka
Titulbildes foto: Liam Briese, Unsplash.
Komentāri
Šim rakstam vēl nav komentāru. Esi pirmais, kurš dalās ar savu viedokli.