Open abgandar opened 3 months ago
sorry @cmb69 was unaware you were editing labels too :)
I have been just reading about this on Apache devel mailing list and it is actually Apache httpd regression in 2.4.61 - https://bz.apache.org/bugzilla/show_bug.cgi?id=69203 .
I'm just checking if there's anything we can do on PHP-FPM side, test the recent patches for this issue and potentially agree on some better solution for the future. In addition I will be setting up some integration tests to prevent this getting released in the future.
I have two almost identical systems. One has the problem, one does not. I fixed the issue using abgandar's workaround for which I am very grateful! (Later note: i realised that one server is ARM and the other is x86.)
The only difference in the Apache versions is the build date.
System 1 ARM (no issue)
Rocky Linux 9.4
Server version: Apache/2.4.57 (Rocky Linux)
Server built: Feb 7 2024 00:00:00
PHP 8.0.30 (fpm-fcgi) (built: Aug 3 2023 17:13:08)
Zend Engine v4.0.30, Copyright (c) Zend Technologies
with Zend OPcache v8.0.30, Copyright (c), by Zend Technologies
System 2 x86 (has issue)
Rocky Linux 9.4
Server version: Apache/2.4.57 (Rocky Linux)
Server built: Aug 5 2024 00:00:00
PHP 8.2.13 (fpm-fcgi) (built: Nov 21 2023 09:55:59)
Zend Engine v4.2.13, Copyright (c) Zend Technologies
with Zend OPcache v8.2.13, Copyright (c), by Zend Technologies
Description
Problem
I use Apache + PHP-FPM to serve PHP files sitting in the server's document root. Some PHP files have spaces and UTF-8 encoded special characters (umlauts, accents) in their file names. Files without spaces or umlauts are served correctly, but files with any of those lead to a 404 with PHP-FPM responding 'Primary script unknown'.
This appears to be due to the way Apache passes the SCRIPT_FILENAME variable: it seems to prefix the physical file name by proxy:fcgi:// and then URL encodes the file name following. So the correctly resolved file name "/docroot/my file.php" gets passed as "proxy:fcgi://my.server/docroot/my%20file.php". PHP-FPM removes the prefix and host name, but then tries to find the file "/docroot/my%20file.php", which doesn't exist.
This seems to me to be related to #12996: the fix to that bug was to URL decode PATH_INFO, but it does not cover the case where the physical script file (SCRIPT_FILENAME) is also URL encoded. So it just URL decodes the bit after the file name.
Symptoms
Using the following PHP-FPM access log format
when requesting the URL
I get logs like this
Note the request (%r) is URL decoded, but the ORIG_SCRIPT_FILENAME is not. The file "/var/htdocs/files/test me.php" exists and is readable by the php-fpm user. Files without the space work fine. I use ORIG_SCRIPT_FILENAME because PHP-FPM unsets SCRIPT_FILENAME when reporting a 404 error (hence the empty %f), but saves the value in ORIG_SCRIPT_FILENAME.
Setup
I'm using PHP 8.3.10 with Apache/2.4.62 (FreeBSD) OpenSSL/3.2.2 on FreeBSD 14.1-STABLE (both built from ports).
Relevant Apache config:
My PHP-FPM setup is stock with UNIX socket at /var/run/php-fpm.sock and access logging as per above.
I have had this setup unchanged for several years and PHP and Apache versions. I'm pretty sure this worked about half a year ago, but can't say when precisely this broke (and if it was a change on the Apache or PHP side).
Workaround
As a workaround, I can make everything run just fine by forcing Apache to unescape the SCRIPT_FILENAME variable before passing it to PHP-FPM:
I don't know what that does to PATH_INFO stuff as I don't use that.
Solution(?)
Since fpm_main.c already does a lot of gymnastics to fix Apache's botched inputs, it may be better to unescape the SCRIPT_FILENAME when removing the "proxy:fcgi://" prefix in fpm_main.c.
Unfortunately, I don't fully understand all the logic there, and am not familiar enough with PHP sources to confidently propose a fix.
PHP Version
PHP 8.3.10
Operating System
FreeBSD 14.1-STABLE