Aktuální situace: PHP2Shell. Dvě kritické zranitelnosti PHP (CVSS 9.2) umožňují spustit škodlivý kód bez přihlášení. Záplaty od 21. 10. 2026.Co nyní udělat →

memory_limit a Out-of-Memory: co se děje uvnitř

Co se stane, když skript PHP narazí na memory_limit? Mechanismus, nový pevný limit paměti od říjnových záplat a souvislost s CVE-2026-109618.

Stav 5 min čteníZnalosti o PHP

Stručně: Chyba PHP Out-of-Memory vzniká, když chce skript vyžádat více paměti, než povoluje nastavení memory_limit (standardně 128 MB na požadavek). PHP pak požadavek ukončí fatální chybou a uklidí. Právě tato cesta ukončení a úklidu byla chybná u CVE-2026-109618, jedné ze dvou zranitelností PHP2Shell. Od PHP 8.5.12, 8.4.27, 8.3.36 a 8.2.35 je memory_limit měkký limit, doplněný pevným limitem memory_hard_limit_percent.

Co znamená „Allowed memory size exhausted“?

Známé chybové hlášení zní v přeneseném smyslu: „Allowed memory size of 134217728 bytes exhausted (tried to allocate …)“. První číslo je nastavený limit v bajtech, zde 128 MB. Skript se tedy pokusil obsadit paměť nad tuto hranici, například při načítání velkého souboru, obrovském databázovém dotazu nebo kvůli nekonečné smyčce.

Pro rozhodovatele je důležité: limit platí pro každý proces PHP a každý požadavek, ne pro celý server. Chrání server před tím, aby jediný chybný skript spotřeboval veškerou paměť. Celkové zatížení vyplývá teprve z počtu současně běžících workerů. Při 20 workerech PHP-FPM s limitem 256 MB je to početně přes 5 GB.

Jak PHP počítá paměť

PHP spravuje paměť pro požadavky vlastním správcem paměti, Zend Memory Managerem. Ten získává větší bloky od operačního systému a vnitřně je rozděluje proměnným, polím a objektům. Proti této rezervované hodnotě PHP kontroluje memory_limit. Paměť, kterou si rozšíření vyžádá přímo u operačního systému, se podle příručky v tomto počítání neobjeví.

Hodnoty můžete zviditelnit v kódu:

<?php
echo memory_get_usage(), PHP_EOL;       // paměť aktuálně obsazená skriptem
echo memory_get_usage(true), PHP_EOL;   // rezervováno správcem paměti; proti tomu kontroluje memory_limit
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL;  // dosavadní maximum
unset($liste);
memory_reset_peak_usage();              // vynulovat maximum, od PHP 8.2

Jak počítání referencí a garbage collection paměť opět uvolňují, vysvětluje stránka Správa paměti v PHP.

Co se při Out-of-Memory děje uvnitř

Zjednodušeně probíhá ukončení kvůli paměti v těchto krocích:

  1. Skript si vyžádá paměť, například pro nový prvek pole nebo při načítání dat požadavku.
  2. Správce paměti zkontroluje, zda požadavek překračuje limit.
  3. Pokud ano, PHP vyvolá fatální chybu a okamžitě opustí probíhající zpracování, i uprostřed napůl hotového úkolu.
  4. Registrované shutdown funkce ještě proběhnou; mnoho aplikací v nich chybu zaprotokoluje.
  5. Na konci PHP požadavek uklidí a uvolní jeho paměť. Worker je poté připraven na další požadavek.

Choulostivým místem je krok 5. Úklid si musí poradit s datovými strukturami, které byly při ukončení teprve napůl vytvořeny. Běžné ukončení kvůli paměti se podle bezpečnostní politiky projektu PHP nepovažuje za bezpečnostní zranitelnost, pokud limit požadavek odmítne a skončí jen aktuální požadavek. U CVE-2026-109618 byl právě tento předpoklad porušen: podle php.net mohl stav nedostatku paměti přerušit PHP ve chvíli, kdy byla interní data požadavku inicializována jen částečně, a úklid pak zacházel s neplatnými daty jako s platnými. Podrobnosti zneužití nezveřejňujeme; zařazení zranitelnosti najdete v CVE-2026-109618.

Nový měkký a pevný limit paměti

S bezpečnostními vydáními z 21. 10. 2026 projekt PHP chování změnil. Podle příručky je memory_limit od té doby měkký limit: požadavek, který jej překročí, smí být ve většině případů ještě dokončen, než následuje fatální chyba. Samostatný pevný limit určuje, jak daleko to smí zajít.

Direktiva Výchozí Lze měnit Význam
memory_limit 128M INI_ALL limit paměti na požadavek, -1 = bez limitu
memory_hard_limit_percent nenastaveno INI_ALL pevný limit v procentech z memory_limit, nové od 8.5.12, 8.4.27, 8.3.36, 8.2.35
post_max_size 8M INI_PERDIR maximální velikost dat POST
upload_max_filesize 2M INI_PERDIR maximální velikost nahraného souboru

Příklad z příručky: při memory_limit=128M a memory_hard_limit_percent=150 leží pevný limit na 192 MB. Příručka tuto direktivu zároveň uvádí jako poznávací znamení: pokud ji verze PHP nezná, je CVE-2026-109618 a CVE-2026-109619 postižena. Rychlý test pro každou nainstalovanou verzi PHP:

php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) znamená: direktiva neznámá

U balíčků z distribucí s backportem zůstává rozhodujícím důkazem changelog balíčku, jak popisuje článek Správná kontrola verze PHP a stavu záplat. Zkontrolujte navíc samostatně binárku PHP-FPM, protože může mít jinou verzi než příkazová řádka.

Limity paměti a PHP2Shell: čeho si nyní všímat

Přechodná opatření php.net k CVE-2026-109618 se téměř všechna točí kolem paměti a velikostí požadavků. Snižují riziko, ale aktualizaci nenahrazují:

; pool FPM, např. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M        ; 32M, pokud jsou nutná nahrávání
php_admin_value[upload_max_filesize] = 6M  ; držet pod post_max_size

Rozhodující jsou tři body. Zaprvé, žádná aplikace, žádný adresář ani jiný pool nesmí znovu nastavit konečný limit; php.net tuto kontrolu výslovně vyžaduje. Zadruhé, služba s memory_limit=-1 potřebuje limit zvenčí, přes kontejner nebo cgroup, podle php.net nejlépe tak, aby se ukončil jen dotčený worker. RLIMIT_AS a RLIMIT_DATA jsou podle php.net nevhodné. Zatřetí, php.net doporučuje limity na webovém serveru nebo proxy pro velikost požadavku, počet polí, části multipart, hlavičky a hloubku vnoření.

Důležité

memory_limit=-1 bez limitu paměti zvenčí může při vysoké zátěži server úplně ochromit. Přechodná opatření nastavujte jen jako balík a jen do aktualizace.

Jak limit nastavit pomocí systemd, najdete v článku Limity paměti pomocí systemd a cgroups; trvalé řešení pro každodenní provoz popisuje článek Správné nastavení memory_limit.

Jak konkrétně pomáhá PHP SOS?

Prostřednictvím služby záplatování PHP postupujeme takto:

  • Zkontrolovat stav: Zjistíme každou verzi PHP na serveru, odděleně pro CLI, FPM a modul Apache, a otestujeme, zda běží opravená verze.
  • Uspořádat limity paměti: Zkontrolujeme, kde všude se memory_limit nastavuje, a nastavíme limity poolů a systému tak, aby si odpovídaly.
  • Zajistit přechodné období: Kde je aktualizace ještě blokována, nastavíme opatření php.net kompletně a zablokovaná proti přepsání.
  • Dodat doklad: Verze, stavy balíčků a konfiguraci před zásahem a po něm obdržíte písemně.

Časté dotazy

Co znamená hlášení „Allowed memory size exhausted“?

Skript chtěl vyžádat více paměti, než povoluje memory_limit. PHP pak probíhající požadavek ukončí fatální chybou. Ostatní požadavky i samotný server běží dál.

Platí memory_limit pro celý server?

Ne, limit platí pro každý proces PHP a požadavek. Pokud běží 20 workerů FPM s limitem 256 MB, mohou teoreticky společně obsadit přes 5 GB. Celkový limit je proto nutné nastavit přes velikost poolu, systemd nebo kontejner.

Co je memory_hard_limit_percent?

Nová direktiva, která přišla s PHP 8.5.12, 8.4.27, 8.3.36 a 8.2.35. Nastavuje pevný limit jako procento z memory_limit, který se nikdy nepřekročí. memory_limit je od té doby měkký limit.

Chrání memory_limit=-1 před PHP2Shell?

Jen částečně. php.net toto nastavení uvádí jako přechodné opatření proti CVE-2026-109618, výslovně bez úplné ochrany. Nutně potřebuje limit paměti zvenčí a aktualizace zůstává povinná.

Zdroje

Okamžitý kontakt

Každá hodina se počítá. Napište nám hned.

Stručně popište systém, verzi PHP a pozorování. Ozveme se, vyjasníme situaci a budeme pracovat na dálku, dokud nebude incident uzavřen a zdokumentován.

Okamžitá pomoc