php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #49286 php://input (php_stream_input_read) is broken
Submitted: 2009-08-18 12:03 UTC Modified: 2009-08-20 12:44 UTC
From: jost_boekemeier at users dot sf dot net Assigned:
Status: Closed Package: Filesystem function related
PHP Version: 5.*, 6 (2009-08-20) OS: *
Private report: No CVE-ID:
 [2009-08-18 12:03 UTC] jost_boekemeier at users dot sf dot net
Description:
------------
You are right, when calling fopen("php://input", "r") PHP version 5 may crash or hang. Please do not use it until this PHP5 bug is fixed.

I have looked at php 5.2.5. In php_fopen_wrapper.c line 81 it reads the raw_post_data and then increments the SG(read_post_bytes) even though it hasn't read anything. The result is that SG(read_post_bytes) is twice the CONTENT_LENGTH size, causing all sorts of strage side effects later on.


Reproduce code:
---------------
Current code from http://svn.php.net/viewvc/php/php-src/trunk/ext/standard/php_fopen_wrapper.c?revision=276986&view=markup

if(SG(request_info).raw_post_data) { /* data has already been read by a post handler */
read_bytes = SG(request_info).raw_post_data_length - *position;

...

SG(read_post_bytes) += read_bytes;



Suggested fix; make read_bytes a local var:

size_t read_bytes = SG(request_info).raw_post_data_length - *position;
^^^^^^^

Expected result:
----------------
SG(read_post_bytes) == CONTENT_LENGTH

Actual result:
--------------
SG(read_post_bytes) 2 times CONTENT_LENGTH

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-08-19 06:39 UTC] jost_boekemeier at users dot sf dot net
diff -u /home/jost/php-5.2.5/ext/standard/php_fopen_wrapper.c\~ /home/jost/php-
5.2.5/ext/standard/php_fopen_wrapper.c
--- /home/jost/php-5.2.5/ext/standard/php_fopen_wrapper.c~	2007-10-04 
15:31:11.000000000 +0200
+++ /home/jost/php-5.2.5/ext/standard/php_fopen_wrapper.c	2009-08-19 
08:26:01.000000000 +0200
@@ -78,7 +78,7 @@
 
 	if(!stream->eof) {
 		if(SG(request_info).raw_post_data) { /* data has already been read by a post 
handler */
-			read_bytes = SG(request_info).raw_post_data_length - *position;
+			size_t read_bytes = SG(request_info).raw_post_data_length - *position;
 			if(read_bytes <= count) {
 				stream->eof = 1;
 			} else {
@@ -86,7 +86,9 @@
 			}
 			if(read_bytes) {
 				memcpy(buf, SG(request_info).raw_post_data + *position, read_bytes);
+				*position += read_bytes;
 			}
+			return read_bytes;
 		} else if(sapi_module.read_post) {
 			read_bytes = sapi_module.read_post(buf, count TSRMLS_CC);
 			if(read_bytes <= 0){

Diff finished.  Wed Aug 19 08:26:08 2009
 [2009-08-19 11:44 UTC] jani@php.net
First of all: Not all people follow all the mailing lists in the world. You need to provide a test case before we start applying any patches. So far you haven't shown any bug here.
 [2009-08-20 09:59 UTC] jost_boekemeier at users dot sf dot net
A simple test case (for those who can't read code):

REDIRECT_STATUS="200" CONTENT_TYPE="application/x-www-form-urlencoded" 
SCRIPT_FILENAME="test.php" REQUEST_METHOD="POST" 
GATEWAY_INTERFACE="CGI/1.1" CONTENT_LENGTH="1" strace /usr/bin/php-cgi.bin 
</dev/zero

<?php
$file = fopen("php://input", "r");
$str = fread($file, 1024);
fclose($file);
?>


=>


read(0, "\0"..., 1)                     = 1
...
read(3, "<?php\n$file = fopen(\"php://input\""..., 4096) = 88
_llseek(3, 0, [0], SEEK_SET)            = 0
setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={30, 0}}, NULL) = 0
rt_sigaction(SIGPROF, {0x81ff8c0, [PROF], SA_RESTART}, {0x81ff8c0, [PROF], 
SA_RESTART}, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [PROF], NULL, 8) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbfd94038) = -1 ENOTTY (Inappropriate 
ioctl for device)
read(3, "<?php\n$file = fopen(\"php://input\""..., 8192) = 88
read(3, ""..., 4096)                    = 0
read(3, ""..., 8192)                    = 0
close(3)                                = 0
write(1, "X-Powered-By: PHP/5.2.6"..., 23X-Powered-By: PHP/5.2.6) = 23
write(1, "\r\n"..., 2
)                  = 2
write(1, "Content-type: text/html"..., 23Content-type: text/html) = 23
write(1, "\r\n"..., 2
)                  = 2
write(1, "\r\n"..., 2
)                  = 2
write(1, "\n\n"..., 2

)                  = 2
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 
3999) = 3999
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 
3999) = 3999
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 
3999) = 3999
....
 [2009-08-20 11:30 UTC] jani@php.net
Thanks for FINALLY providing the test case. It's not about being able to read code, it's about getting dozens of bogus reports daily and interpreting which are really valid AND not yet fixed in repo. You failed in so many ways when you reported this bug that in your shoes, I'd be a little less arrogant. Chances to getting anything fixed are much higher with little bit of respect..
 [2009-08-20 12:40 UTC] svn@php.net
Automatic comment from SVN on behalf of jani
Revision: http://svn.php.net/viewvc/?view=revision&revision=287507
Log: - Fixed bug #49286 (php://input (php_stream_input_read) is broken)
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Wed Apr 16 04:02:11 2014 UTC