Systemd monitors and parses the contents of /proc/self/mountinfo, and passes each mountpoint path to mount_setup_unit(), which passes it to unit_name_from_path(), which passes it to unit_name_path_escape(). Unit_name_path_escape() passes the mountpoint path to strdupa(), which is similar to strdup() but allocates memory on the stack (via alloca()), not in the heap (via malloc()).
As a result, if the total path length of this mountpoint exceeds 8MB (the default RLIMIT_STACK), then systemd crashes with a segmentation fault that also crashes the entire operating system (a kernel panic, because systemd is the “global init”, PID 1).
To je toho, root (alebo kto este moze mountovat FS s 8MB cestou?) moze zhodit system.
Prikaz `shutdown` alebo `cat /dev/urandom > /proc/1/mem` funguju podobne. Na podobny efekt staci fork bomba skoro vsade aj bez roota. Alebo alokovanie dost pamati, nech system zacne masivne swapovat. Alebo vytazenie I/O cez zapisy na disk. Alebo broadcastovanie vela sprav cez DBus.
Ze z toho niekto urobil CV Enhancement 2021-33910 este neznamena, ze je to nejaka vazna diera.
To je IT hantýrka. Stack je viceznacny pojem ktery je nutno holt kontextově uchopit :-/
Uplne bych moc nezral ty hyperkorektne presné přednášky od kakademiku na českých VŠ. Jsou i přednášející kteří toho maji taky dost. Realita tam venku v oboru je trochu jiná.
22. 7. 2021, 17:04 editováno autorem komentáře
Je to jako programový stack - běží nějaký program (systemd-init) a ten má nějaký stack na kterém si program může alokovat paměť (většinou se to používá pro lokální proměnné funkcí - řeší se to pouze pointerem na stack (E)SP). Alternativou je pak ještě heap, kde si také může alokovat paměť - většinou přes systémová volání malloc().
Pro lepší popis např:
http://www.c-jump.com/CIS77/ASM/Stack/lecture.html
To je hodně krátkozraký pohled. V podstatě jakákoli deklarace lokální proměnné je svým způsobem zároveň alokace, protože se příslušná část zásobníku vyhradí pro tuto proměnnou. A totéž pak můžu udělat i dynamicky pomocí zmíněného makra alloca()
. Je to rychlé, jednoduché a pohodlné, dokonce se ani nemusím starat o uvolnění (s trochou nadsázky by se to dalo označit za RIIA). A bohužel je až příliš snadné zapomenout na to, kde vlastně se ten blok alokuje a jak a že zásobník může být poměrně malý (u jednoho programu, kde používám hodně threadů jsem šel až na 16KB).
Když před dávnými lety Ulrich Drepper použil v resolveru alloca()
s parametrem, který byl efektivně něco jako 56 krát počet lokálních IPv6 adres, dalo se ještě chápat, že si v době, kdy to psal, neuvědomil, že by IPv6 adres mohlo být víc než pár. To, že někdo použil v systemd alloca()
s parametrem ovlivnitelným zvenku ještě v roce 2015, je alarmující.
prekvapuje me ne-znalost IT mladochu..
STACK je zasobnik - pamet ktera slouzi k predavani argumentu, dale to slouzi jako lokalni pracovni prostor pro aktualne bezici funkci. Po navratu z funkce je (E)SP registr obnoven, a kontext (co se promennych tyce) je vracen volajici funkci.
8 MB limit stacku je to, na co natrefite po chvilce behu nekonecne rekurze - protoze je prostor fixni, a kazde volani uklada par systemovych registru, tato pamet po mnoha iteracich dojde a chovani systemu je sestrelit danej proces, protoze se ma za to, ze se zblaznil.
Alternativne na to muzete natrefit, kdyz si udelate ve funkci velkou lokalni alokaci:
funkce () { int velkepole[2500000]; ... }
Linuxové jádro je třicet let starý a kontinuálně vyvíjený projekt, takže zásadní změna koncepce není prakticky proveditelná. Nemluvě o tom, že mikrokernel opravdu není tak jednoznačná výhra, jak se jeho věrozvěstové snaží tvrdit (a nelze si nevšimnout, že jich postupem času spíš ubývá). Oproti tomu systemd byl projekt, který vznikl na zelené louce a autory nic nenutilo použít pro kořenový proces použít "kitchen sink approach", to bylo jen a pouze kvůli jejich pohodlí. Což je mimochodem jev, který je patrný i na mnoha jiných aspektech toho projektu, viz třeba postoj Lennarta Poetteringa ke sdíleným dynamickým knihovnám.
Mimochodem, zrovna tahle chyba nebyla moc dobře zvolený příklad, tohle je dost core kód, u kterého si vůbec nejsem jistý, jestli by nebyl v jádře i u mikrokernelu.
Oproti tomu systemd byl projekt, který vznikl na zelené louce a autory nic nenutilo použít pro kořenový proces použít "kitchen sink approach", to bylo jen a pouze kvůli jejich pohodlí.
Jenže nejspíš díky tomuhle přístupu tady vůbec systemd máme. Ti, co se dohadují, jak to má být správně, se ještě nedohodli, natož aby vznikl použitelný kód. A to třicet let staré linuxové jádro je tady s námi stále podle mne především díky tomu, že i Linux má přesně tenhle silně pragmatický přístup – neřeší, jak to má být ideálně, ale zajímá ho jenom to, aby to fungovalo. (Aby si to někde nevyložil špatně – to neznamená, že by připouštěl prasárny, které se jednou pěkně vymstí. Právě naopak, tenhle pragmatický přístup s sebou nese spoustu požadavků na kvalitu kódu i architektury. Ale je to dost výběrové – nedbá se na dodržování všech myslitelných pravidel, nýbrž se důsledně dbá na dodržování některých pravidel a na některá se z vysoka kašle.)
viz třeba postoj Lennarta Poetteringa ke sdíleným dynamickým knihovnám
Ano, to je další ukázka téhož. Na jedné straně tady máme krásný teoretický koncept sdílených dynamických knihoven, jenže v praxi vývojáři i uživatelé chtějí Docker.
Na tuhle chybu jsem ukázal schválně, protože byla objevena ve stejné firmě, dost možná stejnými nástroji a v rámci stejné akce.