php / php/php-src

Segfault in PHP-FPM with tracing JIT (opcache.jit=1205) due to stale base pointer in rbp (Regression in 8.5.5)

Abierto
#22,084 7 comentarios 9 reacciones 1 asignado Ver en GitHub

@arnaud-lb ya está trabajando en esto.

Desde el 26/8/2026.

Bug Category: JIT SAPI: fpm
Lenguaje dominante
C
Estrellas
40.4k
Forks
8.2k
Merge medio
2 d 13 h
PR fusionados (30 d)
96

Descripción

Description

After upgrading from PHP 8.5.4 to 8.5.5, php-fpm workers started segfaulting deterministically under normal web traffic. Issue persists on 8.5.6. Only tracing JIT (opcache.jit=1205) is affected; function JIT (1235) and disabled JIT both work fine.

Environment
  • PHP 8.5.5 and 8.5.6 (official php:8.5.6-fpm Docker image, Debian Trixie base)
  • x86_64
  • Application: Nette Framework + Dibi 5.1.1 + ext/mysqli, MariaDB 11.8
JIT configuration matrix
opcache.jit Result
1205 (tracing) Workers segfault within seconds of receiving traffic
1235 (function) Stable
off Stable

PHP 8.5.4 with opcache.jit=1205 was stable. Regression introduced in 8.5.5, not resolved in 8.5.6.

opcache config
opcache.enable=1
opcache.memory_consumption=256
opcache.jit=1205
opcache.jit_buffer_size=128M
Crash signature (host dmesg)

Repeated segfaults at a small, stable set of offsets in the php-fpm binary (binary base changes due to ASLR; offsets are consistent):

php-fpm[294862]: segfault at 7e3e1bc12bc0 ip ...4c9466 ... error 4 in php-fpm[4c9466,...+801000]
php-fpm[515992]: segfault at 702b7efcdf8c ip ...4bc8a6 ... error 4 in php-fpm[4bc8a6,...+801000]
php-fpm[521652]: segfault at 7b4425b40ca0 ip ...4bc17b ... error 4 in php-fpm[4bc17b,...+801000]
php-fpm[529400]: segfault at 72f91dc4c1c0 ip ...4c9421 ... error 4 in php-fpm[4c9421,...+801000]

error 4 = user-mode read fault on unmapped page. Fault addresses are high (7e…, 7b…, 72…), consistent with reads through a stale pointer.

Disassembly at crash offsets

Official Docker image is stripped, so all faulting offsets fall under the preceding exported symbol opcache_preloading@@Base. The actual crashing code is unexported, almost certainly JIT-generated VM handler inlines.

Faulting instruction at 4c9466 (inside a tight loop):

4c9460: mov    (%rax),%esi             ; load 32-bit index from source
4c9462: add    $0x4,%rax               ; advance source pointer
4c9466: mov    0x0(%rbp,%rsi,4),%esi   ; <-- FAULT: rbp[rsi*4]

Faulting instruction at 4c9421:

4c940d: movslq -0x2c(%rdx),%rdi
4c9411: cmp    %r8d,0x74(%r15)         ; bounds check vs. value at r15+0x74
4c9415: jb     4c94b7 <...>            ; branch if below
4c941b: mov    0x1c(%rdx),%eax         ; load constant index (op_array slot?)
4c941e: mov    0x10(%rdx),%esi
4c9421: mov    0x0(%rbp,%rax,4),%eax   ; <-- FAULT: rbp[rax*4]

Both faulting instructions are mov [rbp + reg*4], reg32 — 32-bit indexed loads consistent with PHP literal/constant pool lookup (op_array->literals is a zval[] accessed by 32-bit indices from zend_op operands). The rbp register holds what appears to be a stale base pointer pointing into freed memory.

Hypothesis

JIT-compiled tracing code appears to hold a base pointer (possibly op_array->literals) across a point where the underlying memory is freed or moved, then dereferences it via a stable 32-bit index from the opcode stream. Maintainers will know better — this is only a guess based on the instruction pattern.

Possibly related: GH-21395 (UAF in JIT, fixed in 8.5.5). The fix may be incomplete, or it may have introduced an adjacent regression. Tracing-only failure (function JIT works) strongly suggests a tracing-specific bug, e.g. in trace recording / side-exit assumptions about value lifetimes.

Reproduction

Plain web traffic against the application is enough; workers crash within seconds. Happy to provide:

  • The specific application code paths (Nette controller, Dibi queries)
  • Larger dmesg samples
  • strace / ltrace output
  • A core dump (can be arranged if you can guide on getting useful symbols from the official php-fpm image)
  • Test with opcache.jit_buffer_size reduced, or specific opcache.jit_* tuning

Switching to opcache.jit=1235 is a viable workaround for now.

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.