You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ext/phar: Phar::webPhar() 301 redirect keeps PATH_INFO on the CGI SAPIs when a rewrite callback routes to the index #25112
Follow-up to #25093 (PR #25104), which fixes the non-CGI side of the same Location header. This one is not a memory-safety problem; it produces a wrong redirect target.
Drafted with an LLM; I reviewed it and checked every claim against the source myself.
In Phar::webPhar(), the request path is truncated right after the phar's file name before the entry is appended to the Location header, but only when not_cgi is set:
if (not_cgi) {
tmp=strstr(path_info, basename) +fname_len; /* the offset #25104 fixes */sa=*tmp;
*tmp='\0';
}
On cgi, cgi-fcgi, fpm-fcgi and litespeed, not_cgi is 0 and path_info is SCRIPT_NAME . PATH_INFO, so it is never truncated and the Location keeps PATH_INFO.
It only surfaces when a rewrite callback collapses a non-empty PATH_INFO to "" or "/", which is how a front controller routes every request to the index. webPhar() then takes the direct-request branch, entry becomes /index.php, the entry is found, and a 301 is emitted. Without a rewrite callback the result is already correct: an absent PATH_INFO leaves path_info equal to SCRIPT_NAME, and PATH_INFO of / is absorbed by the trailing-slash branch.
With the phar at /sub/app.phar, SCRIPT_NAME=/sub/app.phar, PATH_INFO=/foo, and a rewrite callback returning "/":
Expected: Location: /sub/app.phar/index.php
Actual: Location: /sub/app.phar/foo/index.php
The next request arrives with PATH_INFO=/foo/index.php, the callback returns "/" again, and the path grows on each hop, so the client loops.
The function already computes the correct prefix in pt: the _server branch sets it to SCRIPT_NAME, and the other two branches truncate right after the file name. pt is still allocated at the 301, since it is only freed on the bail-out paths above it and after the redirect. Using pt to build the Location would cover every SAPI and remove the strstr/poke/restore around it, but it changes the header on the CGI SAPIs, so it looked worth reporting separately rather than folding into #25104.
I have not written a patch for this one.
PHP Version
Observed by reading ext/phar/phar_object.c on PHP-8.4, PHP-8.5 and master; the if (not_cgi) guard is identical on all three.
Activity