Trenutno stanje: PHP2Shell. Dvije kritične PHP ranjivosti (CVSS 9.2) omogućuju zlonamjerni kod bez prijave. Zakrpe od 21. 10. 2026.Što sada učiniti →

Postaviti granice memorije pomoću systemd-a i cgroupa

php.net kao prijelaznu mjeru za PHP2Shell preporučuje memory_limit=-1 i granicu memorije izvan PHP-a. Evo kako tu granicu postaviti pomoću systemd-a i cgroupa, a da jedan worker ne povuče cijelu uslugu.

Stanje 5 min čitanjaOjačavanje i konfiguracija

Ukratko: Za prijelaznu mjeru za PHP2Shell memory_limit=-1 PHP-FPM treba granicu memorije izvan PHP-a. Pod systemd-om postavljate je pomoću MemoryHigh= kao kočnice i MemoryMax= kao tvrde gornje granice u dopunskoj datoteci za FPM uslugu. ulimit, LimitAS= ili LimitDATA= za to su prema php.net-u neprikladni. Provjerite i OOMPolicy= kako jedan worker ne bi prekinuo cijelu uslugu.

Preporuka koja se isprva čini začuđujućom

Među prijelaznim mjerama koje je php.net 21. listopada 2026. objavio za PHP2Shell nalazi se jedna zbog koje su mnogi administratori zastali: memory_limit=-1, dakle bez granice memorije u samom PHP-u. Godinama se suprotno smatralo dobrom praksom.

Veza s opisom ranjivosti nameće se sama. Kod CVE-2026-109618 stanje nedostatka memorije (out of memory) može prekinuti PHP dok su podaci zahtjeva tek djelomično inicijalizirani. Prijelazna mjera seli granicu memorije iz PHP-a u operacijski sustav. php.net je izričito veže uz dva uvjeta: vrijednost mora biti zaključana od nadjačavanja, a granica mora dolaziti putem kontejnera ili cgroupa, a ne putem RLIMIT_AS ili RLIMIT_DATA.

Tko provede samo prvu polovicu, ima poslužitelj bez ikakve granice memorije. Ovaj članak pokazuje drugu polovicu. Ni zajedno mjera ne prestaje biti prijelaz: ranjivost je otklonjena tek s PHP-om 8.5.12, 8.4.27, 8.3.36, 8.2.35 ili potvrđenim backportom.

cgroupe u dvije rečenice

Control Groups, skraćeno cgroupe, funkcija su Linux jezgre koja grupira procese i ograničava njihove resurse. systemd za svaku uslugu automatski izrađuje vlastitu cgroup i svi procesi usluge, kod FPM usluge dakle master i svi workeri, pripadaju joj.

Opcije memorije u systemd-u postavljaju vrijednosti kontrolera memorije cgroup v2. Koristi li Vaš sustav cgroup v2, pokazuje kratka naredba:

# "cgroup2fs" znači: cgroup v2 je aktivan
stat -fc %T /sys/fs/cgroup/

Aktualne verzije uobičajenih distribucija zadano koriste cgroup v2. Ako naredba pokaže nešto drugo, to razjasnite prije prelaska, jer dokumentacija systemd-a stare v1 opcije opisuje kao zastarjele.

Postaviti systemd MemoryMax za PHP-FPM

Granica ide u dopunsku datoteku, takozvani drop-in. Tako unit datoteka paketa ostaje nepromijenjena i ažuriranje ne prepisuje Vašu postavku. Nazivi usluga razlikuju se po distribuciji; primjer koristi Debian i Ubuntu s PHP-om 8.3.

# Otvara uređivač za drop-in: sudo systemctl edit php8.3-fpm
# Rezultat: /etc/systemd/system/php8.3-fpm.service.d/override.conf
[Service]
MemoryAccounting=yes
MemoryHigh=1536M
MemoryMax=2G
MemorySwapMax=0
OOMPolicy=continue

Opcije ukratko, prema dokumentaciji systemd-a:

Opcija Učinak Napomena za PHP-FPM
MemoryHigh= granica prigušenja: procesi se snažno usporavaju, memorija se vraća stvarna upravljačka veličina, malo ispod MemoryMax
MemoryMax= apsolutna granica: ako se ne može održati, u usluzi postaje aktivan OOM killer posljednja linija obrane
MemorySwapMax= granica za izmještanje 0 sprječava da usluga umjesto toga pobjegne u swap
OOMPolicy= ponašanje nakon OOM događaja: continue, stop ili kill continue ostavlja preostale workere da rade
LimitAS=, LimitDATA= rlimiti po procesu prema php.net-u neprikladni za ovu mjeru

OOMPolicy= zaslužuje osobitu pažnju. Kod stop ili kill systemd nakon OOM događaja prekida cijelu uslugu i sve web-stranice te FPM usluge ispadaju. Koja vrijednost vrijedi bez vlastitog navoda, određuje zadana vrijednost sustava DefaultOOMPolicy=. Zato provjerite djelotvornu vrijednost umjesto da je pretpostavite.

Zatim ponovno pokrenite uslugu i u poolu zaključajte memory_limit:

sudo systemctl restart php8.3-fpm
systemctl show php8.3-fpm -p MemoryHigh -p MemoryMax -p MemorySwapMax -p OOMPolicy -p MemoryCurrent
; Datoteka poola, npr. /etc/php/8.3/fpm/pool.d/seite1.conf
php_admin_value[memory_limit] = -1

Kako funkcionira zaključavanje, opisuje članak php_admin_value: zaključati postavke od nadjačavanja.

Pronaći pravu vrijednost

Preuska granica izaziva prekide u redovitom radu, preširoka jedva štiti. Polazište je stvarna potrošnja.

  1. Nekoliko dana promatrati trenutačnu potrebu za memorijom svih FPM procesa, i u vršnim opterećenjima.
  2. Utvrditi tipičnu potrebu jednog workera i pomnožiti je s pm.max_children svih poolova usluge.
  3. Predvidjeti dodatak za master proces, OPcache i vrhove.
  4. MemoryHigh= postaviti malo iznad izmjerenog vrha, MemoryMax= s malim razmakom iznad toga.
  5. Nakon tjedan dana vrijednosti dotjerati prema mjerenjima i OOM događajima.
# Memorija svih PHP-FPM procesa u MB (Resident Set Size)
ps -C php-fpm8.3 -o rss= | awk '{s+=$1} END {printf "%.0f MB\n", s/1024}'
# Tekući pregled svih cgroupa poredanih po memoriji
systemd-cgtop -m

Vrijednost za memory_limit prije prelaska trebali biste zabilježiti. Nakon ažuriranja možete se vratiti na čvrstu granicu u PHP-u; kako je smisleno odabrati, piše u članku Pravilno postaviti memory_limit.

Nadzirati: kada granica djeluje

Granica memorije čije aktiviranje nitko ne primijeti tihi je izvor pogrešaka. Jezgra broji OOM događaje po cgroupi, a systemd i zapisnik jezgre bilježe ih.

# OOM brojač cgroupe usluge (putanja kod cgroup v2)
cat /sys/fs/cgroup/system.slice/php8.3-fpm.service/memory.events
# Poruke OOM killera u zapisniku jezgre
journalctl -k --since "-1 day" | grep -i "out of memory"

Ako brojač oom_kill raste, jezgra prekida workere. To može upućivati na preusku granicu, na pogrešnu aplikaciju ili na neobične zahtjeve. U aktualnoj situaciji isplati se takve događaje uskladiti s pristupnim zapisnicima iz istog vremena.

Važno

Granica memorije je prijelazna mjera i ne zamjenjuje PHP ažuriranje. Planirajte ažuriranje paralelno i nakon njega ponovno pokrenite sve PHP procese. Sve prijelazne mjere ukratko nalaze se na stranici Hitne mjere ako još ne možete zakrpati.

Što se unutar PHP-a događa pri nedostatku memorije, objašnjava memory_limit i Out-of-Memory. Kod Apachea s mod_php-om ista tehnika vrijedi za Apache uslugu, ali PHP tada granicu dijeli sa samim web-poslužiteljem.

Zaključak: ne zaboraviti drugu polovicu

memory_limit=-1 opravdana je prijelazna mjera samo zajedno s vanjskom granicom. systemd tu granicu omogućuje s nekoliko redaka: MemoryHigh kao kočnicu, MemoryMax kao tvrdu gornju granicu, MemorySwapMax protiv bijega u swap i svjesno odabran OOMPolicy. Izmjerite prije, promatrajte poslije i imajte na umu da svi poolovi jedne usluge dijele granicu.

Ponajprije pak: planirajte kraj mjere. Nakon ažuriranja na ispravljenu verziju PHP-a vraćate se na čvrst memory_limit. cgroup granicu možete zadržati kao dodatno osiguranje od otrgnutih procesa.

Kako PHP SOS konkretno pomaže?

  • Mjeriti: bilježimo potrebe za memorijom Vaših PHP usluga i iz toga izvodimo prikladne granice.
  • Provesti: postavljamo drop-inove s MemoryHigh, MemoryMax i prikladnim OOMPolicy, zaključavamo memory_limit u poolu i kontrolirano ponovno pokrećemo usluge.
  • Promatrati: OOM događaje uključujemo u nadzor i dotjerujemo vrijednosti.
  • Dovesti do zakrpe: putem PHP Patch usluge provodimo ažuriranje i nakon toga uredno povlačimo prijelazne vrijednosti.

Česta pitanja

Zašto memory_limit treba biti -1? Nije li to opasno?

Samo za sebe bilo bi. php.net memory_limit=-1 kao prijelaznu mjeru izričito preporučuje zajedno s granicom memorije putem kontejnera ili cgroupa. Ograničenje se time iz PHP-a seli u operacijski sustav. Bez te vanjske granice ne biste smjeli postaviti tu vrijednost.

Mogu li umjesto toga koristiti ulimit ili LimitAS=?

Ne. php.net izričito odgovara od RLIMIT_AS i RLIMIT_DATA, a upravo te granice postavljaju ulimit -v, LimitAS= i LimitDATA=. Dokumentacija systemd-a uz to upozorava da LimitAS= ograničava adresni prostor, a ne potrošnju memorije.

Što se događa kad PHP-FPM dosegne granicu?

Kod MemoryHigh jezgra usporava procese i vraća memoriju. Kod MemoryMax unutar usluge postaje aktivan OOM killer i prekida jedan proces, najčešće velikog workera. Zaustavlja li se nakon toga cijela usluga, određuje OOMPolicy=.

Vrijedi li granica za svaki pool zasebno?

Ne. Svi poolovi jedne FPM usluge dijele jednu cgroup i time zajedničku granicu. Odvojene granice po web-stranici traže odvojene FPM usluge ili kontejnere.

Kako postaviti granicu u Dockeru ili Kubernetesu?

Putem ograničenja memorije kontejnera, primjerice opcijom --memory kod docker run ili resources.limits.memory u Kubernetesu. Oba također koriste cgroupe. Načelo ostaje isto: granica izvan PHP-a, memory_limit u PHP-u zaključan.

Izvori

Hitni kontakt

Svaki sat se računa. Pišite nam odmah.

Ukratko opišite sustav, verziju PHP-a i opažanje. Javit ćemo Vam se, razjasniti situaciju i raditi na daljinu dok incident nije zaključen i dokumentiran.

Hitna pomoć