Praegune olukord: PHP2Shell. Kaks kriitilist PHP turvaauku (CVSS 9,2) lubavad kahjulikku koodi ilma sisselogimata. Paigad alates 21.10.2026.Mida nüüd teha →

Mälupiiride seadmine systemd ja cgroup'idega

php.net soovitab PHP2Shelli üleminekumeetmena memory_limit=-1 ja PHP-st väljaspool asuvat mälupiiri. Nii seate selle piiri systemd ja cgroup'idega, ilma et üks töölisprotsess kogu teenuse kaasa tõmbaks.

Seis Lugemisaeg 5 minKarastamine ja seadistus

Lühidalt: PHP2Shelli üleminekumeetme memory_limit=-1 jaoks vajab PHP-FPM PHP-st väljaspool asuvat mälupiiri. systemd all seate selle sättega MemoryHigh= pidurina ja MemoryMax= kõva ülempiirina FPM-teenuse täienduskaustas. ulimit, LimitAS= või LimitDATA= ei sobi selleks php.net'i järgi. Kontrollige lisaks OOMPolicy=, et üks töölisprotsess ei lõpetaks kogu teenust.

Soovitus, mis esmalt hämmastab

php.net'i 21. oktoobril 2026 PHP2Shelli kohta avaldatud üleminekumeetmete hulgas on üks, mis pani paljud administraatorid imestama: memory_limit=-1, see tähendab mälupiiri puudumist PHP-s endas. Aastaid peeti vastupidist heaks tavaks.

Seos augu kirjeldusega on ilmne. CVE-2026-109618 puhul võib mälupuuduse olek PHP katkestada, kui päringuandmed on vaid osaliselt lähtestatud. Üleminekumeede nihutab mälupiiri PHP-st välja operatsioonisüsteemi. php.net seob selle otsesõnu kahe tingimusega: väärtus peab olema ülekirjutamise vastu lukustatud ja piir peab tulema konteineri või cgroup'i kaudu, mitte RLIMIT_AS või RLIMIT_DATA kaudu.

Kes rakendab ainult esimese poole, on saanud serveri ilma ühegi mälupiirita. See artikkel näitab teist poolt. Ka koos jääb meede üleminekuks: auk on parandatud alles versioonidega PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 või kinnitatud tagasiportimisega.

cgroup'id kahes lauses

Control Groups, lühidalt cgroup'id, on Linuxi tuuma funktsioon, mis rühmitab protsesse ja piirab nende ressursse. systemd loob iga teenuse jaoks automaatselt oma cgroup'i ja kõik teenuse protsessid, FPM-teenuse puhul peaprotsess ja kõik töölised, kuuluvad sinna.

systemd mälusuvandid seavad cgroup v2 mälukontrolleri väärtusi. Kas teie süsteem kasutab cgroup v2, näitab lühike käsk:

# "cgroup2fs" tähendab: cgroup v2 on aktiivne
stat -fc %T /sys/fs/cgroup/

Levinumate distributsioonide praegused versioonid kasutavad cgroup v2 vaikimisi. Kui käsk näitab midagi muud, selgitage see enne ümberlülitust, sest systemd dokumentatsioon kirjeldab vanu v1-suvandeid aegunutena.

systemd MemoryMax seadmine PHP-FPM-ile

Piir läheb täienduskausta, nn drop-in'i. Nii jääb paketi unit-fail muutmata ja uuendus teie sätet üle ei kirjuta. Teenuste nimed erinevad distributsiooniti; näide kasutab Debiani ja Ubuntut PHP 8.3-ga.

# Avab drop-in'i redaktori: sudo systemctl edit php8.3-fpm
# Tulemus: /etc/systemd/system/php8.3-fpm.service.d/override.conf
[Service]
MemoryAccounting=yes
MemoryHigh=1536M
MemoryMax=2G
MemorySwapMax=0
OOMPolicy=continue

Suvandite ülevaade systemd dokumentatsiooni järgi:

Suvand Mõju Märkus PHP-FPM-i kohta
MemoryHigh= piduripiir: protsesse pidurdatakse tugevalt, mälu võetakse tagasi tegelik juhtsuurus, veidi MemoryMax all
MemoryMax= absoluutne piir: kui seda ei suudeta hoida, aktiveerub teenuses OOM-killer viimane kaitseliin
MemorySwapMax= väljalaadimise piir 0 takistab teenusel selle asemel swapi poole põigata
OOMPolicy= käitumine pärast OOM-sündmust: continue, stop või kill continue laseb ülejäänud töölistel edasi töötada
LimitAS=, LimitDATA= rlimitid protsessi kohta php.net'i järgi selle meetme jaoks sobimatud

OOMPolicy= väärib erilist tähelepanu. Väärtuse stop või kill korral lõpetab systemd pärast OOM-sündmust kogu teenuse ja kõik selle FPM-teenuse veebisaidid kukuvad välja. Millist väärtust kasutatakse ilma oma määranguta, määrab süsteemi vaikesäte DefaultOOMPolicy=. Kontrollige kehtivat väärtust seetõttu, selle asemel et seda eeldada.

Seejärel taaskäivitage teenus ja lukustage poolis memory_limit:

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

Kuidas lukustamine töötab, kirjeldab php_admin_value: sätete kaitsmine ülekirjutamise eest.

Õige väärtuse leidmine

Liiga napp piir tekitab katkestusi tavatöös, liiga helde ei kaitse peaaegu üldse. Lähtekoht on tegelik tarbimine.

  1. Jälgige kõigi FPM-protsesside tegelikku mälutarvet mõne päeva jooksul, ka koormushetkedel.
  2. Selgitage välja ühe töölise tüüpiline vajadus ja korrutage see teenuse kõigi poolide pm.max_children väärtustega.
  3. Planeerige juurde peaprotsessi, OPcache'i ja tippude jaoks.
  4. Seadke MemoryHigh= mõõdetud tipuväärtusest napilt kõrgemale, MemoryMax= veidi kaugemale selle kohale.
  5. Kohandage väärtusi nädala pärast mõõtmiste ja OOM-sündmuste põhjal.
# Kõigi PHP-FPM-protsesside mälu MB-des (Resident Set Size)
ps -C php-fpm8.3 -o rss= | awk '{s+=$1} END {printf "%.0f MB\n", s/1024}'
# Kõigi cgroup'ide jooksev ülevaade mälu järgi sorteeritult
systemd-cgtop -m

memory_limit väärtuse märkige enne ümberlülitust üles. Pärast uuendust saate pöörduda tagasi PHP kindla piiri juurde; kuidas seda mõistlikult valida, on kirjas artiklis memory_limit õige seadistamine.

Seire: millal piir rakendub

Mälupiir, mille rakendumist keegi ei märka, on vaikne veaallikas. Tuum loendab OOM-sündmusi cgroup'i kaupa ning systemd ja tuumaprotokoll märgivad need üles.

# Teenuse cgroup'i OOM-loendur (tee cgroup v2 korral)
cat /sys/fs/cgroup/system.slice/php8.3-fpm.service/memory.events
# OOM-killeri teated tuumaprotokollis
journalctl -k --since "-1 day" | grep -i "out of memory"

Kui loendur oom_kill kasvab, lõpetab tuum töölisi. See võib viidata liiga napile piirile, vigasele rakendusele või ebatavalistele päringutele. Praeguses olukorras tasub selliseid sündmusi samaaegsete pöördusprotokollidega võrrelda.

Oluline

Mälupiir on üleminekumeede ega asenda PHP uuendust. Planeerige uuendus paralleelselt ja taaskäivitage seejärel kõik PHP protsessid. Kõik üleminekumeetmed ülevaatlikult on lehel Kiirmeetmed, kui te ei saa veel paikama hakata.

Mis juhtub PHP sees mälupuuduse korral, selgitab memory_limit ja Out-of-Memory. Apache'i puhul mod_php-ga kehtib sama tehnika Apache'i teenuse kohta, ent PHP jagab piiri siis veebiserveri endaga.

Kokkuvõte: ärge unustage teist poolt

memory_limit=-1 on põhjendatav üleminekumeede ainult koos välise piiriga. systemd teeb selle piiri võimalikuks mõne reaga: MemoryHigh pidurina, MemoryMax kõva ülempiirina, MemorySwapMax swapi poole põikamise vastu ja teadlikult valitud OOMPolicy. Mõõtke enne, jälgige pärast ja pidage meeles, et ühe teenuse kõik poolid jagavad piiri.

Peamine aga: planeerige meetme lõpp. Pärast uuendust parandatud PHP versioonile pöörduge tagasi kindla memory_limit juurde. cgroup'i piiri võite säilitada täiendava kaitsena väljaulatuvate protsesside vastu.

Kuidas PHP SOS konkreetselt aitab?

  • Mõõta: kaardistame teie PHP teenuste mälutarbe ja tuletame sellest sobivad piirid.
  • Rakendada: seame drop-in'id sätetega MemoryHigh, MemoryMax ja sobiva OOMPolicy, lukustame poolis memory_limit ja taaskäivitame teenused kontrollitult.
  • Jälgida: põimime OOM-sündmused seiresse ja kohandame väärtusi.
  • Viia paigani: PHP paigateenuse kaudu paigaldame uuenduse ja võtame üleminekuväärtused seejärel korrapäraselt tagasi.

Korduma kippuvad küsimused

Miks peab memory_limit olema -1? Kas see pole ohtlik?

Üksi oleks. php.net soovitab memory_limit=-1 üleminekumeetmena otsesõnu koos mälupiiriga konteineri või cgroup'i kaudu. Piiramine liigub niimoodi PHP-st välja operatsioonisüsteemi. Ilma selle välise piirita ei tohiks väärtust seada.

Kas saan selle asemel kasutada ulimit'i või LimitAS=?

Ei. php.net soovitab RLIMIT_AS-i ja RLIMIT_DATA-t otsesõnu mitte kasutada ning just neid piire seavad ulimit -v, LimitAS= ja LimitDATA=. systemd dokumentatsioon juhib lisaks tähelepanu, et LimitAS= piirab aadressiruumi, mitte mälukasutust.

Mis juhtub, kui PHP-FPM piirini jõuab?

MemoryHigh puhul pidurdab tuum protsesse ja võtab mälu tagasi. MemoryMax puhul aktiveerub teenuse sees OOM-killer ja lõpetab ühe protsessi, enamasti suure töölise. Kas kogu teenus pärast seda peatub, reguleerib OOMPolicy=.

Kas piir kehtib iga pooli kohta eraldi?

Ei. Ühe FPM-teenuse kõik poolid jagavad ühte cgroup'i ja seega ühist piiri. Veebisaitide kaupa eraldi piirid vajavad eraldi FPM-teenuseid või konteinereid.

Kuidas seada piir Dockeris või Kubernetes'es?

Konteineri mälupiirangu kaudu, näiteks valikuga --memory käsus docker run või resources.limits.memory Kubernetes'es. Mõlemad kasutavad samuti cgroup'e. Põhimõte jääb samaks: piir väljaspool PHP-d, memory_limit PHP-s lukustatud.

Allikad

Kohene kontakt

Iga tund loeb. Kirjutage meile kohe.

Kirjeldage lühidalt süsteemi, PHP versiooni ja tähelepanekut. Võtame teiega ühendust, selgitame olukorra välja ja töötame kaugtööna, kuni intsident on lõpetatud ja dokumenteeritud.

Kohene abi