php / php-src

The PHP Interpreter
https://www.php.net
Other
37.93k stars 7.72k forks source link

php-fpm: zend_mm_heap corrupted with cgi-fcgi request #15395

Open verfriemelt-dot-org opened 4 weeks ago

verfriemelt-dot-org commented 4 weeks ago

Description

after making a request with a HTTP_AUTHORIZATION header, a subsequent cgi-fcgi -bind -connect 127.0.0.1:9000 will fail and cause heap corruption + SIGABRT on the child process.

poc:

$ docker run --rm -it --entrypoint bash php:fpm
# apt-get update && apt-get install tzdata locales libfcgi0ldbl -y
# php-fpm &
[1] 706
[13-Aug-2024 21:41:57] NOTICE: fpm is running, pid 706
[13-Aug-2024 21:41:57] NOTICE: ready to handle connections

# HTTP_AUTHORIZATION="Basic Zm9vOg==" SCRIPT_NAME=/ SCRIPT_FILENAME=/ REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 - foo 13/Aug/2024:21:42:21 +0000 "GET /" 404
Status: 404 Not Found
X-Powered-By: PHP/8.3.10
Content-type: text/html; charset=UTF-8

File not found.

with that, the setup is complete and you can now trigger the bug with this running in the container:

# cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 -  13/Aug/2024:21:42:39 +0000 "- " 200
X-Powered-By: PHP/8.3.10
Content-type: text/html; charset=UTF-8

# cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 - 0 B* 13/Aug/2024:21:42:40 +0000 "- " 200
zend_mm_heap corrupted
[13-Aug-2024 21:42:40] WARNING: [pool www] child 707 exited on signal 6 (SIGABRT) after 42.713030 seconds from start
[13-Aug-2024 21:42:40] NOTICE: [pool www] child 712 started

you might need to retry to hit the correct child which served the previous request.

this seems to affect at least all php 8 versions starting with 8.0.0 i did not check older version though.

root@abbd54a452e3:/var/www/html# [13-Aug-2024 21:44:47] NOTICE: fpm is running, pid 876
[13-Aug-2024 21:44:47] NOTICE: ready to handle connections
HTTP_AUTHORIZATION="Basic Zm9vOg==" SCRIPT_NAME=/ SCRIPT_FILENAME=/ REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 - foo 13/Aug/2024:21:44:50 +0000 "GET /" 404
Primary script unknownStatus: 404 Not Found
X-Powered-By: PHP/8.0.0
Content-type: text/html; charset=UTF-8

File not found.
root@abbd54a452e3:/var/www/html# cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 -  13/Aug/2024:21:44:54 +0000 "- " 200
X-Powered-By: PHP/8.0.0
Content-type: text/html; charset=UTF-8

root@abbd54a452e3:/var/www/html# cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 - 0��& 13/Aug/2024:21:44:55 +0000 "- " 200
zend_mm_heap corrupted
[13-Aug-2024 21:44:55] WARNING: [pool www] child 877 exited with code 1 after 8.593094 seconds from start
root@abbd54a452e3:/var/www/html# [13-Aug-2024 21:44:55] NOTICE: [pool www] child 882 started

we use the connect to the port 9000 as a liveness probe for kubernetes like this:

livenessProbe:
    initialDelaySeconds: 10
    exec:
        command:
            - /usr/bin/cgi-fcgi -bind -connect 127.0.0.1:9000

and we noticed a service with that setup failing due to the command returning a non-zero exit code and the thus the pod being restarted while the service receives requests with HTTP_AUTH headers. the bug can not be triggered without the HTTP_AUTHORIZATION request. and it looks like memory contents might get dumped into the log too :thinking:

PHP Version

PHP 8.3.10

Operating System

debian

verfriemelt-dot-org commented 4 weeks ago

oldest version i could test was 7.1.33 and the bug is present there as well.

devnexen commented 4 weeks ago

So it seems, it is the auth password part which triggers the fault, with ASAN we can see it crashes on request shutdown, root cause seems to be the auth data handling.

verfriemelt-dot-org commented 4 weeks ago

just to be clear, this example is just with an user, because that was enough. the same fault will happen, if you provider user and password!

devnexen commented 4 weeks ago

I cannot reproduce with a password, do you have an example where it crashes still ?

verfriemelt-dot-org commented 4 weeks ago

so within our k8s setup it definitley crashed with a password provided.

using foo:bar as credentials, you are right, the poc will not trigger the crash:

root@7bf33716acfb:/var/www/html# HTTP_AUTHORIZATION="Basic Zm9vOmJhcgo=" SCRIPT_NAME=/ SCRIPT_FILENAME=/ REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 - foo 14/Aug/2024:20:05:07 +0000 "GET /" 404
Status: 404 Not Found
X-Powered-By: PHP/8.3.10
Content-type: text/html; charset=UTF-8

File not found.
root@7bf33716acfb:/var/www/html#
root@7bf33716acfb:/var/www/html# cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 - 0 �y 14/Aug/2024:20:05:11 +0000 "- " 200
X-Powered-By: PHP/8.3.10
Content-type: text/html; charset=UTF-8

but still dump out a weird user into the log :thinking: notice the 0 �y

verfriemelt-dot-org commented 4 weeks ago

here is an example which triggered the heap corruption:

root@edfc0d8d4ee2:/var/www/html# php-fpm &
[1] 706
root@edfc0d8d4ee2:/var/www/html# [14-Aug-2024 20:09:03] NOTICE: fpm is running, pid 706
[14-Aug-2024 20:09:03] NOTICE: ready to handle connections
root@edfc0d8d4ee2:/var/www/html# HTTP_AUTHORIZATION="Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" SCRIPT_NAME=/ SCRIPT_FILENAME=/ REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 - Aladdin 14/Aug/2024:20:09:07 +0000 "GET /" 404
Status: 404 Not Found
X-Powered-By: PHP/8.3.10
Content-type: text/html; charset=UTF-8

File not found.
root@edfc0d8d4ee2:/var/www/html# cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 -  14/Aug/2024:20:09:14 +0000 "- " 200
X-Powered-By: PHP/8.3.10
Content-type: text/html; charset=UTF-8

root@edfc0d8d4ee2:/var/www/html# cgi-fcgi -bind -connect 127.0.0.1:9000
127.0.0.1 - P��# 14/Aug/2024:20:09:17 +0000 "- " 200
zend_mm_heap corrupted
[14-Aug-2024 20:09:17] WARNING: [pool www] child 707 exited on signal 6 (SIGABRT) after 14.328219 seconds from start
root@edfc0d8d4ee2:/var/www/html# [14-Aug-2024 20:09:17] NOTICE: [pool www] child 712 started
devnexen commented 4 weeks ago

I could reproduce the dangling display in my side. I use your example, only I build my own php inside the container.