Trenutno stanje: PHP2Shell. Dve kritični ranljivosti PHP (CVSS 9,2) omogočata izvedbo škodljive kode brez prijave. Popravki od 21. 10. 2026.Kaj je zdaj treba storiti →

Nastavitev pomnilniških mej s systemd in cgroups

php.net kot prehodni ukrep za PHP2Shell priporoča memory_limit=-1 in pomnilniško mejo zunaj PHP. Tako to mejo nastavite s systemd in cgroups, ne da bi en sam delavec potegnil za seboj celotno storitev.

Stanje 5 min branjaUtrjevanje in konfiguracija

Na kratko: Za prehodni ukrep PHP2Shell memory_limit=-1 PHP-FPM potrebuje pomnilniško mejo zunaj PHP. Pod systemd jo nastavite z MemoryHigh= kot zavoro in MemoryMax= kot trdo zgornjo mejo v dopolnilni datoteki za storitev FPM. ulimit, LimitAS= ali LimitDATA= so za to po php.net neprimerni. Preverite še OOMPolicy=, da en sam delavec ne konča celotne storitve.

Priporočilo, ki sprva preseneti

Med prehodnimi ukrepi, ki jih je php.net 21. oktobra 2026 objavil za PHP2Shell, je eden, ki je številne skrbnike presenetil: memory_limit=-1, torej brez pomnilniške meje v samem PHP. Leta je veljalo nasprotno kot dobra praksa.

Povezava z opisom ranljivosti je očitna. Pri CVE-2026-109618 lahko stanje brez pomnilnika (out-of-memory) prekine PHP, medtem ko so podatki zahteve inicializirani le delno. Prehodni ukrep pomnilniško mejo iz PHP preseli v operacijski sistem. php.net ga izrecno veže na dva pogoja: vrednost mora biti zaklenjena pred prepisovanjem, meja pa mora priti prek vsebnika ali cgroup, ne prek RLIMIT_AS ali RLIMIT_DATA.

Kdor izvede samo prvo polovico, ima strežnik brez kakršne koli pomnilniške meje. Ta prispevek pokaže drugo polovico. Tudi skupaj ukrep ostaja prehod: ranljivost je odpravljena šele s PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 ali potrjenim backportom.

cgroups v dveh stavkih

Control Groups, na kratko cgroups, so funkcija jedra Linux, ki procese združuje v skupine in omejuje njihove vire. systemd za vsako storitev samodejno ustvari lasten cgroup in vsi procesi storitve, pri storitvi FPM torej master in vsi delavci, mu pripadajo.

Pomnilniške možnosti systemd nastavljajo vrednosti krmilnika pomnilnika cgroup v2. Ali vaš sistem uporablja cgroup v2, pokaže kratek ukaz:

# "cgroup2fs" pomeni: cgroup v2 je aktiven
stat -fc %T /sys/fs/cgroup/

Aktualne različice običajnih distribucij privzeto uporabljajo cgroup v2. Če ukaz pokaže kaj drugega, to razjasnite pred prehodom, saj dokumentacija systemd stare možnosti v1 opisuje kot zastarele.

Nastavitev systemd MemoryMax za PHP-FPM

Meja pride v dopolnilno datoteko, tako imenovani drop-in. Tako datoteka enote paketa ostane nespremenjena in posodobitev vaše nastavitve ne prepiše. Imena storitev se po distribuciji razlikujejo; primer uporablja Debian in Ubuntu s PHP 8.3.

# Odpre urejevalnik 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

Možnosti v pregledu, po dokumentaciji systemd:

Možnost Učinek Namig za PHP-FPM
MemoryHigh= meja dušenja: procesi se močno zavirajo, pomnilnik se vrača pravi krmilni parameter, nekoliko pod MemoryMax
MemoryMax= absolutna meja: če je ni mogoče držati, se v storitvi aktivira OOM-killer zadnja obrambna linija
MemorySwapMax= meja za izmenjavo 0 prepreči, da bi storitev namesto tega zaplavala v swap
OOMPolicy= obnašanje po dogodku OOM: continue, stop ali kill continue pusti preostale delavce teči naprej
LimitAS=, LimitDATA= rlimiti na proces po php.net za ta ukrep neprimerni

OOMPolicy= si zasluži posebno pozornost. Pri stop ali kill systemd po dogodku OOM konča celotno storitev in vse spletne strani te storitve FPM odpovedo. Katera vrednost velja brez lastne navedbe, določa sistemska privzeta vrednost DefaultOOMPolicy=. Veljavno vrednost zato preverite, namesto da jo predpostavljate.

Nato storitev znova zaženite in v poolu zaklenite 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 zaklepanje deluje, opisuje php_admin_value: zaklepanje nastavitev pred prepisovanjem.

Iskanje prave vrednosti

Prekratka meja povzroča prekinitve v običajnem delovanju, preveč radodarna komaj ščiti. Izhodišče je dejanska poraba.

  1. Opazujte trenutno pomnilniško potrebo vseh procesov FPM več dni, tudi ob konicah obremenitve.
  2. Ugotovite tipično potrebo delavca in jo pomnožite s pm.max_children vseh poolov storitve.
  3. Načrtujte pribitek za proces master, OPcache in konice.
  4. MemoryHigh= nastavite tik nad izmerjeno konico, MemoryMax= z nekaj razmika nad tem.
  5. Vrednosti po enem tednu popravite glede na meritve in dogodke OOM.
# Pomnilnik vseh procesov PHP-FPM v MB (Resident Set Size)
ps -C php-fpm8.3 -o rss= | awk '{s+=$1} END {printf "%.0f MB\n", s/1024}'
# Tekoči pregled vseh cgroups, razvrščen po pomnilniku
systemd-cgtop -m

Vrednost za memory_limit si pred prehodom zabeležite. Po posodobitvi se lahko vrnete k fiksni meji v PHP; kako jo smiselno izberete, piše pod Pravilna nastavitev memory_limit.

Spremljanje: kdaj meja deluje

Pomnilniška meja, katere sprožitve nihče ne opazi, je tihi vir napak. Jedro šteje dogodke OOM za vsak cgroup, systemd in dnevnik jedra pa jih zabeležita.

# Števec OOM cgroupa storitve (pot pri cgroup v2)
cat /sys/fs/cgroup/system.slice/php8.3-fpm.service/memory.events
# Sporočila OOM-killerja v dnevniku jedra
journalctl -k --since "-1 day" | grep -i "out of memory"

Če števec oom_kill narašča, jedro končuje delavce. To lahko kaže na prekratko mejo, napačno aplikacijo ali nenavadne zahteve. V trenutnih razmerah se take dogodke splača primerjati z dostopnimi dnevniki ob istem času.

Pomembno

Pomnilniška meja je prehodni ukrep in posodobitve PHP ne nadomešča. Posodobitev načrtujte vzporedno in nato znova zaženite vse procese PHP. Vsi prehodni ukrepi v pregledu so pod Takojšnji ukrepi, če popravka še ne morete namestiti.

Kaj se ob pomanjkanju pomnilnika dogaja v notranjosti PHP, pojasnjuje memory_limit in out-of-memory. Pri Apache z mod_php enaka tehnika velja za storitev Apache, vendar si PHP potem mejo deli s samim spletnim strežnikom.

Sklep: druge polovice ne pozabite

memory_limit=-1 je upravičen prehodni ukrep samo skupaj z zunanjo mejo. systemd to mejo omogoči z nekaj vrsticami: MemoryHigh kot zavora, MemoryMax kot trda zgornja meja, MemorySwapMax proti umiku v swap in zavestno izbran OOMPolicy. Izmerite vnaprej, opazujte potem in imejte v mislih, da si vsi pooli ene storitve mejo delijo.

Predvsem pa: načrtujte konec ukrepa. Po posodobitvi na popravljeno različico PHP se vrnite k fiksnemu memory_limit. Mejo cgroup lahko obdržite kot dodatno zaščito pred ušlimi procesi.

Kako PHP SOS pomaga konkretno?

  • Merjenje: zajamemo pomnilniško potrebo vaših storitev PHP in iz tega izpeljemo ustrezne meje.
  • Izvedba: nastavimo drop-ine z MemoryHigh, MemoryMax in ustreznim OOMPolicy, v poolu zaklenemo memory_limit in storitve nadzorovano znova zaženemo.
  • Opazovanje: dogodke OOM vključimo v spremljanje in vrednosti popravimo.
  • Pot do popravka: prek storitve popravljanja PHP namestimo posodobitev in nato prehodne vrednosti urejeno umaknemo.

Pogosta vprašanja

Zakaj naj bo memory_limit nastavljen na -1? Ali ni to nevarno?

Samo po sebi bi bilo. php.net memory_limit=-1 kot prehodni ukrep izrecno priporoča skupaj z mejo pomnilnika prek vsebnika ali cgroup. Omejitev se tako iz PHP preseli v operacijski sistem. Brez te zunanje meje vrednosti ne nastavljajte.

Ali lahko namesto tega uporabim ulimit ali LimitAS=?

Ne. php.net izrecno odsvetuje RLIMIT_AS in RLIMIT_DATA, prav ti meji pa nastavljajo ulimit -v, LimitAS= in LimitDATA=. Dokumentacija systemd poleg tega opozarja, da LimitAS= omejuje naslovni prostor, ne porabe pomnilnika.

Kaj se zgodi, ko PHP-FPM doseže mejo?

Pri MemoryHigh jedro procese zavira in vrača pomnilnik. Pri MemoryMax se znotraj storitve aktivira OOM-killer in konča en proces, običajno velikega delavca. Ali se potem ustavi celotna storitev, ureja OOMPolicy=.

Ali meja velja za vsak pool posebej?

Ne. Vsi pooli ene storitve FPM si delijo en cgroup in s tem skupno mejo. Ločene meje za vsako spletno stran zahtevajo ločene storitve FPM ali vsebnike.

Kako mejo nastavim v Dockerju ali Kubernetesu?

Prek omejitve pomnilnika vsebnika, na primer z možnostjo --memory pri docker run ali resources.limits.memory v Kubernetesu. Oba prav tako uporabljata cgroups. Načelo ostaja enako: meja zunaj PHP, memory_limit v PHP zaklenjen.

Viri

Takojšnji stik

Vsaka ura šteje. Pišite nam zdaj.

Na kratko opišite sistem, različico PHP in opažanje. Odzovemo se, razjasnimo stanje in delamo na daljavo, dokler incident ni zaključen in dokumentiran.

Takojšnja pomoč