Stručne: Chyba PHP Out-of-Memory vzniká, keď chce skript vyžiadať viac pamäte, než povoľuje nastavenie memory_limit (štandardne 128 MB na požiadavku). PHP potom požiadavku ukončí fatálnou chybou a upratuje. Práve táto cesta ukončenia a upratovania bola pri CVE-2026-109618, jednej z dvoch zraniteľností PHP2Shell, chybná. Od PHP 8.5.12, 8.4.27, 8.3.36 a 8.2.35 je memory_limit mäkký limit, doplnený tvrdým limitom memory_hard_limit_percent.
Čo znamená „Allowed memory size exhausted“?
Známe chybové hlásenie znie približne: „Allowed memory size of 134217728 bytes exhausted (tried to allocate …)“. Prvé číslo je nastavený limit v bajtoch, tu 128 MB. Skript sa teda pokúsil obsadiť pamäť nad túto hranicu, napríklad pri načítaní veľkého súboru, obrovského dotazu do databázy alebo v nekonečnej slučke.
Pre rozhodovateľov dôležité: limit platí pre každý proces PHP a každú požiadavku, nie pre celý server. Chráni server pred tým, aby jediný chybný skript spotreboval všetku pamäť. Celkové zaťaženie vyplýva až z počtu súčasne bežiacich workerov. Pri 20 workeroch PHP-FPM s limitom 256 MB je to početne vyše 5 GB.
Ako PHP počíta pamäť
PHP spravuje pamäť pre požiadavky cez vlastného správcu pamäte, Zend Memory Manager. Získava väčšie bloky od operačného systému a interne ich rozdeľuje premenným, poliam a objektom. Voči tejto rezervovanej hodnote PHP kontroluje memory_limit. Pamäť, ktorú rozšírenie vyžiada priamo od operačného systému, sa podľa príručky v tomto počítaní neobjaví.
Hodnoty môžete zviditeľniť v kóde:
<?php
echo memory_get_usage(), PHP_EOL; // pamäť aktuálne obsadená skriptom
echo memory_get_usage(true), PHP_EOL; // rezervovaná správcom pamäte; voči tomu kontroluje memory_limit
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL; // doterajšia špičková hodnota
unset($liste);
memory_reset_peak_usage(); // vynulovanie špičkovej hodnoty, od PHP 8.2
Ako počítanie referencií a garbage collection pamäť opäť uvoľňujú, vysvetľuje stránka Správa pamäte v PHP.
Čo sa pri Out-of-Memory deje vnútri
Zjednodušene prebieha ukončenie pre nedostatok pamäte v týchto krokoch:
- Skript vyžiada pamäť, napríklad pre nový prvok poľa alebo pri načítaní údajov požiadavky.
- Správca pamäte skontroluje, či požiadavka prekračuje limit.
- Ak áno, PHP vyvolá fatálnu chybu a okamžite opustí prebiehajúce spracovanie, aj uprostred napoly vybavenej úlohy.
- Zaregistrované funkcie shutdown ešte bežia; mnohé aplikácie pomocou nich chybu zapisujú do logu.
- Nakoniec PHP požiadavku upratá a uvoľní jej pamäť. Worker je potom pripravený na ďalšiu požiadavku.
Kritickým bodom je krok 5. Upratovanie musí zvládnuť dátové štruktúry, ktoré boli pri ukončení vytvorené len napoly. Bežné ukončenie pre nedostatok pamäte sa podľa bezpečnostných zásad projektu PHP nepovažuje za bezpečnostnú zraniteľnosť, pokiaľ limit požiadavku odmietne a skončí iba aktuálna požiadavka. Pri CVE-2026-109618 bol práve tento predpoklad porušený: podľa php.net mohol stav Out-of-Memory prerušiť PHP v čase, keď boli interné údaje požiadavky inicializované len čiastočne, a upratovanie potom považovalo neplatné údaje za platné. Podrobnosti o zneužití nezverejňujeme; zaradenie zraniteľnosti je uvedené v CVE-2026-109618.
Nový mäkký a tvrdý limit pamäte
S bezpečnostnými vydaniami z 21. 10. 2026 projekt PHP správanie zmenil. Podľa príručky je memory_limit odvtedy mäkký limit: požiadavka, ktorá ho prekročí, sa môže vo väčšine prípadov ešte dokončiť, kým nasleduje fatálna chyba. Samostatný tvrdý limit obmedzuje, ako ďaleko to smie zájsť.
| Direktíva | Štandard | Zmeniteľná | Význam |
|---|---|---|---|
memory_limit |
128M | INI_ALL | Limit pamäte na požiadavku, -1 = bez limitu |
memory_hard_limit_percent |
nenastavená | INI_ALL | Tvrdý limit v percentách z memory_limit, nová od 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
post_max_size |
8M | INI_PERDIR | Maximálna veľkosť údajov POST |
upload_max_filesize |
2M | INI_PERDIR | Maximálna veľkosť nahraného súboru |
Príklad z príručky: pri memory_limit=128M a memory_hard_limit_percent=150 je tvrdý limit 192 MB. Príručka túto direktívu zároveň uvádza ako rozpoznávací znak: ak ju nejaká verzia PHP nepozná, týkajú sa jej CVE-2026-109618 a CVE-2026-109619. Rýchly test pre každú nainštalovanú verziu PHP:
php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) znamená: direktíva neznáma
Pri balíkoch z distribúcií s backportom zostáva rozhodujúcim dôkazom changelog balíka, ako je opísané v Správna kontrola verzie PHP a stavu záplat. Skontrolujte navyše binárku PHP-FPM osobitne, pretože môže mať inú verziu než príkazový riadok.
Limity pamäte a PHP2Shell: čo majú administrátori teraz dodržať
Prechodné opatrenia php.net k CVE-2026-109618 sa takmer všetky točia okolo pamäte a veľkostí požiadaviek. Znižujú riziko, ale aktualizáciu nenahrádzajú:
; Pool FPM, napr. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M ; 32M, ak sú potrebné nahrávania
php_admin_value[upload_max_filesize] = 6M ; držať pod post_max_size
Rozhodujúce sú tri body. Po prvé, žiadna aplikácia, žiadny adresár ani iný pool nesmie znova nastaviť konečný limit; php.net výslovne požaduje túto kontrolu. Po druhé, služba s memory_limit=-1 potrebuje limit zvonku, cez kontajner alebo cgroup, podľa php.net najlepšie tak, aby sa ukončil iba dotknutý worker. RLIMIT_AS a RLIMIT_DATA sú podľa php.net nevhodné. Po tretie, php.net odporúča limity na webovom serveri alebo proxy pre veľkosť požiadavky, počet polí, časti multipart, hlavičky a hĺbku vnorenia.
memory_limit=-1 bez limitu pamäte zvonku môže pri vysokom zaťažení server úplne ochromiť. Prechodné opatrenia nasadzujte iba ako balík a len do aktualizácie.
Ako nastaviť limit pomocou systemd, je uvedené v Limity pamäte so systemd a cgroups; trvalé riešenie na každodenné použitie opisuje Správne nastavenie memory_limit.
Ako PHP SOS konkrétne pomáha?
Prostredníctvom služby záplatovania PHP postupujeme takto:
- Kontrola stavu: Zisťujeme každú verziu PHP na serveri, osobitne pre CLI, FPM a modul Apache, a testujeme, či beží opravená verzia.
- Usporiadanie limitov pamäte: Kontrolujeme, kde všade sa
memory_limitnastavuje, a nastavujeme limity poolov a systému tak, aby k sebe pasovali. - Zabezpečenie prechodu: Kde je aktualizácia ešte zablokovaná, nasadzujeme opatrenia php.net kompletne a zamknuté proti prepísaniu.
- Dodanie dôkazu: Verzie, stavy balíkov a konfiguráciu pred zásahom a po ňom dostanete písomne.
Časté otázky
Čo znamená hlásenie „Allowed memory size exhausted“?
Skript chcel vyžiadať viac pamäte, než povoľuje memory_limit. PHP potom bežiacu požiadavku ukončí fatálnou chybou. Ostatné požiadavky a samotný server bežia ďalej.
Platí memory_limit pre celý server?
Nie, limit platí pre každý proces PHP a požiadavku. Ak beží 20 workerov FPM s limitom 256 MB, môžu spolu teoreticky obsadiť vyše 5 GB. Celkový limit sa preto musí nastaviť cez veľkosť poolu, systemd alebo kontajner.
Čo je memory_hard_limit_percent?
Nová direktíva, ktorá prišla s PHP 8.5.12, 8.4.27, 8.3.36 a 8.2.35. Nastavuje tvrdý limit ako percentuálnu hodnotu memory_limit, ktorá sa nikdy neprekročí. memory_limit samotný je odvtedy mäkký limit.
Chráni memory_limit=-1 pred PHP2Shell?
Iba čiastočne. php.net toto nastavenie uvádza ako prechodné opatrenie proti CVE-2026-109618, výslovne bez úplnej ochrany. Nevyhnutne potrebuje limit pamäte zvonku a aktualizácia zostáva povinná.