<feed xmlns='http://www.w3.org/2005/Atom'>
<title>snuffleupagus/src, branch optim85</title>
<subtitle>Security module for php7 and php8 - Killing bugclasses and virtual-patching the rest! 
</subtitle>
<id>http://git.dustri.org/snuffleupagus/atom?h=optim85</id>
<link rel='self' href='http://git.dustri.org/snuffleupagus/atom?h=optim85'/>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/'/>
<updated>2026-05-09T23:01:43Z</updated>
<entry>
<title>Prevent opcache from inlining functions with return-value rules on PHP 8.5+</title>
<updated>2026-05-09T23:01:43Z</updated>
<author>
<name>jvoisin</name>
</author>
<published>2026-05-09T23:01:43Z</published>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/commit/?id=5f754c32df4bd8643d62babf6f805defe59c8c92'/>
<id>urn:sha1:5f754c32df4bd8643d62babf6f805defe59c8c92</id>
<content type='text'>
PHP 8.5's opcache optimizer can inline trivial user functions (constant
return values), completely eliminating the DO_UCALL opcode. When this
happens, zend_execute_ex is never invoked and snuffleupagus's
return-value monitoring hooks never fire.

Fix this by setting ZEND_ACC_HAS_TYPE_HINTS on monitored functions'
op_arrays during compilation (via sp_op_array_handler). This flag is
checked by opcache's zend_try_inline_call() and prevents inlining.
For 0-arg functions — the only ones eligible for inlining — there are
no RECV opcodes, so the runtime impact is zero.

To enable sp_op_array_handler when return-value rules are configured,
the extension now registers itself as a zend extension and sets
ZEND_COMPILE_HANDLE_OP_ARRAY (previously only done for global_strict).

The disabled_function_echo_2 test is updated to use separate echo
statements and opcache.optimization_level=0, since opcache's echo
merging is a compile-time string concatenation that cannot be prevented
per-function.

This is a bit ugly, but it's the less awful solution to be able to hook return
values.
</content>
</entry>
<entry>
<title>Skip a test on ≥PHP8.5</title>
<updated>2026-05-09T22:09:44Z</updated>
<author>
<name>jvoisin</name>
</author>
<published>2026-05-09T22:09:44Z</published>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/commit/?id=0cc8e708ebbff02abe7e3c2d0dc0660585ccd98c'/>
<id>urn:sha1:0cc8e708ebbff02abe7e3c2d0dc0660585ccd98c</id>
<content type='text'>
PHP is now optimizing `echo A,B,C` into `echo A B C`, so the test is pointless.
</content>
</entry>
<entry>
<title>Reduce the lifetime of cryptographic material</title>
<updated>2026-04-24T10:17:05Z</updated>
<author>
<name>jvoisin</name>
</author>
<published>2026-04-24T10:17:05Z</published>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/commit/?id=5f53903197021fcc8332a7f44c29fbea8d2c2060'/>
<id>urn:sha1:5f53903197021fcc8332a7f44c29fbea8d2c2060</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Fix a possible null-deref in sp_stream_wrapper_register</title>
<updated>2026-04-24T10:15:45Z</updated>
<author>
<name>jvoisin</name>
</author>
<published>2026-04-24T10:15:45Z</published>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/commit/?id=138e97baf135fb0ae765d8899f564d6b10211830'/>
<id>urn:sha1:138e97baf135fb0ae765d8899f564d6b10211830</id>
<content type='text'>
`protocol_name` can be NULL if `zend_parse_parameters_ex` fails (it uses
`ZEND_PARSE_PARAMS_QUIET`), but it was then unconditionally passed to
`strcasecmp`.
</content>
</entry>
<entry>
<title>Fix an spprintf undefined behaviour</title>
<updated>2026-04-24T10:14:01Z</updated>
<author>
<name>jvoisin</name>
</author>
<published>2026-04-24T10:14:01Z</published>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/commit/?id=314b10154495b91eca684124275407b8186bb762'/>
<id>urn:sha1:314b10154495b91eca684124275407b8186bb762</id>
<content type='text'>
`getenv("REMOTE_ADDR")` can return NULL, and it is passed directly to
`spprintf`. While `spprintf` might handle `NULL` gracefully, it's not always
the case.
</content>
</entry>
<entry>
<title>Fix a memory leak in sp_log_disable/sp_log_disable_ret</title>
<updated>2026-04-24T09:50:40Z</updated>
<author>
<name>jvoisin</name>
</author>
<published>2026-04-24T09:50:40Z</published>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/commit/?id=36179282f5f52a7e54be34964b4afd4fd0194e4f'/>
<id>urn:sha1:36179282f5f52a7e54be34964b4afd4fd0194e4f</id>
<content type='text'>
php_raw_url_encode returned a new zend_string, but the old arg_value_dup is
never released. Also arg_value_dup was reassigned, leaking the initial
zend_string_init allocation.
</content>
</entry>
<entry>
<title>Address multiple sign issues in ifilter</title>
<updated>2026-04-24T09:32:35Z</updated>
<author>
<name>jvoisin</name>
</author>
<published>2026-04-24T09:32:35Z</published>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/commit/?id=56447f425f0fa241e0005df0e620bda97eb06340'/>
<id>urn:sha1:56447f425f0fa241e0005df0e620bda97eb06340</id>
<content type='text'>
`sp_is_dangerous_char[(int)*p]` is indexed by `(int)*p`. If char is signed
(default on x86), values 0x80–0xFF produce negative indices into the array,
causing an out-of-bounds read. The `sp_server_encode` function has the same
issue.
</content>
</entry>
<entry>
<title>Fix a possible null-pointer dereference in cookies encryption</title>
<updated>2026-04-24T09:29:18Z</updated>
<author>
<name>jvoisin</name>
</author>
<published>2026-04-24T09:29:18Z</published>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/commit/?id=237131c6f02ce1bca8c5a41b25c274ff2c34e751'/>
<id>urn:sha1:237131c6f02ce1bca8c5a41b25c274ff2c34e751</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Fix a type confusion on cookie encryption</title>
<updated>2026-04-24T09:09:54Z</updated>
<author>
<name>jvoisin</name>
</author>
<published>2026-04-24T09:09:54Z</published>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/commit/?id=c0ea33d05dfb503f60a842372c336d12b23259ba'/>
<id>urn:sha1:c0ea33d05dfb503f60a842372c336d12b23259ba</id>
<content type='text'>
Cookies can be arrays (session_id[]=x), and
we called `Z_STRLEN_P(pDest)` without checking if `Z_TYPE_P(pDest) == IS_STRING`,
leading to a type confusion, leaking at least `HashTable-&gt;arData`, and the rest
of the code is going to corrupt some stuff, leading to a crash.

While exploitation can't be ruled out, it looks stupidly harder. The array will
be decoded as base64 into another variable, decrypted, and have this value
written back to the array. To obtain a controlled read, an attacker would have
to bruteforce decryption to find an encrypted value that could be properly
decrypted, as we're using authenticated encryption. The next steps are
depending on the heap's layout, which should be pretty deterministic/simple as
cookie decryption happens at RINIT. But since the heap overflow is happening in
the cookies, odds are that they're stored somewhere with other data like
POST/GET/… and thus nothing super-duper juicy. While remote heap exploitation
in PHP have been done in the past, this primitive looks a tad too limited to
yield something powerful enough to pop a shell.

Reported-by: Vozec
</content>
</entry>
<entry>
<title>Add a test for validate idempotence of (un)serialize</title>
<updated>2026-03-29T19:16:47Z</updated>
<author>
<name>jvoisin</name>
</author>
<published>2026-03-29T19:16:47Z</published>
<link rel='alternate' type='text/html' href='http://git.dustri.org/snuffleupagus/commit/?id=75446f7bf62d3390fc8e9c6b578431a8991fc60b'/>
<id>urn:sha1:75446f7bf62d3390fc8e9c6b578431a8991fc60b</id>
<content type='text'>
</content>
</entry>
</feed>
