Edit report at https://bugs.php.net/bug.php?id=64187&edit=1

 ID:                 64187
 Comment by:         nachms+php at gmail dot com
 Reported by:        nachms+php at gmail dot com
 Summary:            CGI/FastCGI truncates input to modulo 4GB
 Status:             Open
 Type:               Bug
 Package:            Streams related
 Operating System:   Linux
 PHP Version:        5.4.11
 Block user comment: N
 Private report:     N

 New Comment:

Due to lack of comments as mentioned above, I'm unsure what the problematic 
loop is needed for. However thinking more about it, perhaps it's needed for 
pipelining or multiplexing?

In which case, changing read_post_bytes in SAPI.h from int to long, and 
removing the uint cast from SG(request_info).content_length may be the correct 
solution.


Previous Comments:
------------------------------------------------------------------------
[2013-02-11 10:11:29] nachms+php at gmail dot com

In cgi_main.c, in sapi_cgi_read_post() and sapi_fcgi_read_post(), I found if I 
comment out the line: count_bytes = MIN(count_bytes, (uint) 
SG(request_info).content_length - SG(read_post_bytes));
Then the bug is fixed.

I'm not sure why the amount of bytes going to be read is bounded to 
read_post_bytes subtracted from the length. read() will only read the amount 
that it can, and it doesn't matter if you asked for too much, it will return 
what is available.

For FastCGI, I'm not familiar enough with fcgi_read() enough to know if the 
lack of bounding causes a problem or not. However, mod_php5 as an example 
doesn't bound it. And if bounding is needed, this code needs to make use of 
long or unsigned long instead of int and unit.

------------------------------------------------------------------------
[2013-02-11 02:37:29] nachms+php at gmail dot com

I think I found the bug in cgi_main.c:

static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
{
        uint read_bytes = 0;
        int tmp_read_bytes;

        count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - 
SG(read_post_bytes));
        while (read_bytes < count_bytes) {
                tmp_read_bytes = read(STDIN_FILENO, buffer + read_bytes, 
count_bytes - read_bytes);
                if (tmp_read_bytes <= 0) {
                        break;
                }
                read_bytes += tmp_read_bytes;
        }
        return read_bytes;
}

It looks like content_length, a long, is being truncated to a uint. I'll look 
into fixing this based on what mod_php5 does.

------------------------------------------------------------------------
[2013-02-11 01:57:46] nachms+php at gmail dot com

Description:
------------
I've tested sending huge amounts of data via PUT to PHP from 5.3.x through 
5.4.x via CGI, FastCGI, and mod_php for Apache, all on AMD64.

In all my tests, mod_php with Apache seems to be fine. However via CGI or 
FastCGI, PHP can only see the amount of data modulo 4294967296. Which seems to 
indicate that somewhere an int instead of a long is used in the the CGI 
processing code, but so far, I have been unable to find where exactly. All my 
builds are 64-bit, so that's not the issue.

To elaborate, via mod_php, if I send via HTTP PUT 4296015872 bytes, then PHP 
will see all of them. However, via CGI or FastCGI, PHP will only see 1048576 
bytes.

Test script:
---------------
<?php
print_r($_SERVER); //Print server variables so we can see Content-Length
 
$amount = 0;
$ifp = @fopen('php://input', 'rb');
if ($ifp)
{
  while (!feof($ifp))
  {
    set_time_limit(0);
    $buf = fread($ifp, 8192);
    if ($buf !== false) { $amount += strlen($buf); }
  }
  fclose($tfp);
  set_time_limit(0);
 
  echo 'Amount Read: ', $amount, "\n";
}

//Test via HTTP (Apache): 
http://paste.nachsoftware.com/Nach/TXmPR8289646bbb54bf40ce295115111acde1eYP
//Test via CGI (with FastCGI sharing results) 
http://paste.nachsoftware.com/Nach/MXNpV4ec2e499fc0941773aff51184e6e618d2lN

Expected result:
----------------
When tested with either of my C test programs, I expect to see 4296015872 
listed as the amount read.

Actual result:
--------------
With mod_php in Apache, I see 4296015872 which is correct. But with 
CGI/FastCGI, I see 1048576 as the amount read, which is 4296015872%4294967296, 
which indicates, somewhere a long is being converted to an int within the 
CGI/FastCGI code.


------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=64187&edit=1

Reply via email to