Actuele situatie: PHP2Shell. Twee kritieke PHP-kwetsbaarheden (CVSS 9.2) maken schadelijke code zonder inloggen mogelijk. Patches sinds 21-10-2026.Wat u nu moet doen →

Geheugengrenzen instellen met systemd en cgroups

php.net adviseert als PHP2Shell-overbruggingsmaatregel memory_limit=-1 en een geheugengrens buiten PHP. Zo stelt u die grens in met systemd en cgroups, zonder dat één worker de hele service meesleept.

Stand 6 min. leestijdHardening en configuratie

Kort gezegd: Voor de PHP2Shell-overbruggingsmaatregel memory_limit=-1 heeft PHP-FPM een geheugengrens buiten PHP nodig. Onder systemd stelt u die in met MemoryHigh= als rem en MemoryMax= als harde bovengrens in een aanvullend bestand voor de FPM-service. ulimit, LimitAS= of LimitDATA= zijn daarvoor volgens php.net ongeschikt. Controleer bovendien OOMPolicy=, zodat één enkele worker niet de hele service beëindigt.

Een advies dat eerst verbaast

Onder de overbruggingsmaatregelen die php.net op 21 oktober 2026 over PHP2Shell heeft gepubliceerd, staat er één waar veel beheerders van opkeken: memory_limit=-1, dus geen geheugengrens in PHP zelf. Jarenlang gold het tegendeel als goede praktijk.

Een verband met de beschrijving van de kwetsbaarheid ligt voor de hand. Bij CVE-2026-109618 kan een out-of-memory-toestand PHP onderbreken terwijl verzoekgegevens maar deels zijn geïnitialiseerd. De overbruggingsmaatregel verplaatst de geheugengrens uit PHP naar het besturingssysteem. php.net koppelt haar uitdrukkelijk aan twee voorwaarden: de waarde moet tegen overschrijven zijn vergrendeld en de grens moet via container of cgroup komen, niet via RLIMIT_AS of RLIMIT_DATA.

Wie alleen de eerste helft doorvoert, heeft een server zonder enige geheugengrens. Dit artikel toont de tweede helft. Ook samen blijft de maatregel een overbrugging: verholpen is de kwetsbaarheid pas met PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 of een bevestigde backport.

cgroups in twee zinnen uitgelegd

Control groups, kortweg cgroups, zijn een functie van de Linux-kernel die processen groepeert en hun resources begrenst. systemd maakt voor elke service automatisch een eigen cgroup aan en alle processen van de service, bij de FPM-service dus master en alle workers, horen erbij.

De geheugenopties van systemd stellen waarden van de cgroup-v2-geheugencontroller in. Of uw systeem cgroup v2 gebruikt, toont een korte opdracht:

# "cgroup2fs" betekent: cgroup v2 is actief
stat -fc %T /sys/fs/cgroup/

Actuele versies van de gangbare distributies gebruiken standaard cgroup v2. Toont de opdracht iets anders, zoek dat dan vóór de omschakeling uit, want de systemd-documentatie beschrijft de oude v1-opties als verouderd.

systemd MemoryMax voor PHP-FPM instellen

De grens komt in een aanvullend bestand, een zogeheten drop-in. Zo blijft het unitbestand van het pakket ongewijzigd en overschrijft een update uw instelling niet. Servicenamen verschillen per distributie; het voorbeeld gebruikt Debian en Ubuntu met PHP 8.3.

# Opent een editor voor de drop-in: sudo systemctl edit php8.3-fpm
# Resultaat: /etc/systemd/system/php8.3-fpm.service.d/override.conf
[Service]
MemoryAccounting=yes
MemoryHigh=1536M
MemoryMax=2G
MemorySwapMax=0
OOMPolicy=continue

De opties in één oogopslag, volgens de documentatie van systemd:

Optie Werking Aanwijzing voor PHP-FPM
MemoryHigh= Remgrens: processen worden sterk afgeremd, geheugen wordt teruggehaald de eigenlijke stuurgrootheid, iets onder MemoryMax
MemoryMax= absolute grens: is ze niet te houden, dan wordt de OOM-killer in de service actief laatste verdedigingslinie
MemorySwapMax= Grens voor uitwisselen naar schijf 0 voorkomt dat de service in plaats daarvan naar swap uitwijkt
OOMPolicy= Gedrag na een OOM-gebeurtenis: continue, stop of kill continue laat de overige workers doorlopen
LimitAS=, LimitDATA= rlimits per proces volgens php.net voor deze maatregel ongeschikt

OOMPolicy= verdient bijzondere aandacht. Bij stop of kill beëindigt systemd na een OOM-gebeurtenis de hele service en vallen alle websites van deze FPM-service uit. Welke waarde zonder eigen opgave geldt, bepaalt de systeemstandaard DefaultOOMPolicy=. Controleer de werkzame waarde daarom in plaats van haar aan te nemen.

Herstart daarna de service en vergrendel in de pool memory_limit:

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

Hoe het vergrendelen werkt, beschrijft php_admin_value: instellingen tegen overschrijven vergrendelen.

De juiste waarde vinden

Een te krappe grens veroorzaakt afbrekingen in normaal bedrijf, een te ruime beschermt nauwelijks. Uitgangspunt is het werkelijke verbruik.

  1. Het actuele geheugengebruik van alle FPM-processen enkele dagen observeren, ook bij belastingspieken.
  2. De typische behoefte van een worker vaststellen en vermenigvuldigen met pm.max_children van alle pools van de service.
  3. Een toeslag inplannen voor het masterproces, OPcache en pieken.
  4. MemoryHigh= net boven de gemeten piekwaarde instellen, MemoryMax= met wat marge daarboven.
  5. Waarden na een week bijstellen aan de hand van de metingen en OOM-gebeurtenissen.
# Geheugen van alle PHP-FPM-processen in MB (Resident Set Size)
ps -C php-fpm8.3 -o rss= | awk '{s+=$1} END {printf "%.0f MB\n", s/1024}'
# Doorlopend overzicht van alle cgroups gesorteerd op geheugen
systemd-cgtop -m

De waarde van memory_limit vóór de omschakeling moet u noteren. Na de update kunt u terugkeren naar een vaste grens in PHP; hoe u die zinvol kiest, staat onder memory_limit juist instellen.

Bewaken: wanneer de grens ingrijpt

Een geheugengrens waarvan niemand merkt dat ze wordt geraakt, is een stille foutenbron. De kernel telt OOM-gebeurtenissen per cgroup en systemd en het kernellogboek noteren ze.

# OOM-teller van de cgroup van de service (pad bij cgroup v2)
cat /sys/fs/cgroup/system.slice/php8.3-fpm.service/memory.events
# Meldingen van de OOM-killer in het kernellogboek
journalctl -k --since "-1 day" | grep -i "out of memory"

Stijgt de teller oom_kill, dan beëindigt de kernel workers. Dat kan wijzen op een te krappe grens, op een foutieve applicatie of op ongebruikelijke verzoeken. In de huidige situatie loont het om zulke gebeurtenissen af te stemmen op de toegangslogs van hetzelfde moment.

Belangrijk

De geheugengrens is een overbruggingsmaatregel en vervangt de PHP-update niet. Plan de update parallel en herstart daarna alle PHP-processen. Alle overbruggingsmaatregelen in één oogopslag staan onder Noodmaatregelen als u nog niet kunt patchen.

Wat er binnenin PHP bij geheugentekort gebeurt, legt memory_limit en out-of-memory uit. Bij Apache met mod_php geldt dezelfde techniek voor de Apache-service, al deelt PHP de grens dan met de webserver zelf.

Conclusie: de tweede helft niet vergeten

memory_limit=-1 is alleen samen met een buitenste grens een verdedigbare overbruggingsmaatregel. systemd maakt die grens met een paar regels mogelijk: MemoryHigh als rem, MemoryMax als harde bovengrens, MemorySwapMax tegen het uitwijken naar swap en een bewust gekozen OOMPolicy. Meet vooraf, observeer achteraf en houd in de gaten dat alle pools van een service de grens delen.

Vooral echter: plan het einde van de maatregel. Na de update naar een verholpen PHP-versie keert u terug naar een vaste memory_limit. De cgroup-grens kunt u als extra beveiliging tegen uitdijende processen houden.

Hoe helpt PHP SOS concreet?

  • Meten: wij leggen de geheugenbehoefte van uw PHP-services vast en leiden daaruit passende grenzen af.
  • Doorvoeren: wij plaatsen drop-ins met MemoryHigh, MemoryMax en een passende OOMPolicy, vergrendelen memory_limit in de pool en herstarten de services gecontroleerd.
  • Observeren: OOM-gebeurtenissen nemen wij op in de bewaking en wij bepalen de waarden bij.
  • Naar de patch leiden: via de PHP-patchservice voeren wij de update door en nemen wij de overbruggingswaarden daarna ordelijk terug.

Veelgestelde vragen

Waarom moet memory_limit op -1 staan? Is dat niet gevaarlijk?

Op zichzelf wel. php.net adviseert memory_limit=-1 als overbruggingsmaatregel uitdrukkelijk samen met een geheugengrens via container of cgroup. De begrenzing verhuist daarmee uit PHP naar het besturingssysteem. Zonder deze buitenste grens moet u de waarde niet instellen.

Kan ik in plaats daarvan ulimit of LimitAS= gebruiken?

Nee. php.net raadt RLIMIT_AS en RLIMIT_DATA uitdrukkelijk af, en precies deze grenzen stellen ulimit -v, LimitAS= en LimitDATA= in. De systemd-documentatie wijst er bovendien op dat LimitAS= de adresruimte begrenst, niet het geheugengebruik.

Wat gebeurt er als PHP-FPM de grens bereikt?

Bij MemoryHigh remt de kernel de processen af en haalt geheugen terug. Bij MemoryMax wordt binnen de service de OOM-killer actief en beëindigt een proces, meestal een grote worker. Of daarna de hele service stopt, regelt OOMPolicy=.

Geldt de grens voor elke pool afzonderlijk?

Nee. Alle pools van één FPM-service delen één cgroup en dus één gemeenschappelijke grens. Gescheiden grenzen per website vereisen gescheiden FPM-services of containers.

Hoe stel ik de grens in bij Docker of Kubernetes?

Via de geheugenbegrenzing van de container, bijvoorbeeld de optie --memory bij docker run of resources.limits.memory in Kubernetes. Beide gebruiken eveneens cgroups. Het uitgangspunt blijft gelijk: grens buiten PHP, memory_limit in PHP vergrendeld.

Bronnen

Direct contact

Elk uur telt. Schrijf ons nu.

Beschrijf kort het systeem, de PHP-versie en wat u opmerkt. Wij nemen contact op, brengen de situatie in kaart en werken op afstand tot het incident is afgerond en gedocumenteerd.

Directe hulp