php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #37496 FastCGI output buffer overrun
Submitted: 2006-05-18 13:01 UTC Modified: 2006-05-25 06:41 UTC
From: gacek at intertele dot pl Assigned: dmitry
Status: Closed Package: CGI/CLI related
PHP Version: 5CVS-2006-05-18 (snap) OS: Linux
Private report: No CVE-ID:
 [2006-05-18 13:01 UTC] gacek at intertele dot pl

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-05-22 07:03 UTC] gacek at intertele dot pl
Actually, these are two bugs:
1. Interrupted flush_cgi() does not reset request->out_pos.
Thus we must check flush_cgi return code and stop filling buffer if flush_cgi fails.
2. In fcgi_request structure there is additional "reserve" allocated after out_buf. It's of sizeof(fcgi_header)+sizeof(_fcgi_end_reuest) afair.
But at certain fcgi_write str lengths, there were three consecutive operations on buffer:

close_packet() - ads 8-byte padding
open_packet()  - ads header
fcgi_flush()   - calls close_packet(), which ads 8-byte padding again

Last call might overrun buffer+reserve up to 7 bytes, smashing env table pointer.
Changing first close_packet to fcgi_flush() eliminates this risk.

Patch against 5.1.4 below:

diff -ru php-5.1.4/sapi/cgi/fastcgi.c php-5.1.4-patched/sapi/cgi/fastcgi.c
--- php-5.1.4/sapi/cgi/fastcgi.c        2006-05-03 17:39:16.000000000 +0200
+++ php-5.1.4-patched/sapi/cgi/fastcgi.c        2006-05-22 08:40:56.000000000 +0200
@@ -813,7 +813,10 @@
                }
                memcpy(req->out_pos, str, limit);
                req->out_pos += limit;
-               fcgi_flush(req, 0);
+               if (!fcgi_flush(req, 0)) {
+                       req->keep = 0;
+                       return -1;
+               }
                open_packet(req, type);
                memcpy(req->out_pos, str + limit, len - limit);
                req->out_pos += len - limit;
@@ -821,12 +824,19 @@
                int pos = 0;
                int pad;
 
-               close_packet(req);
+               if (!fcgi_flush(req, 0)) {
+                       req->keep = 0;
+                       return -1;
+               }
+
                while ((len - pos) > 0xffff) {
                        open_packet(req, type);
                        fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
                        req->out_hdr = NULL;
-                       fcgi_flush(req, 0);
+                       if (!fcgi_flush(req, 0)) {
+                               req->keep = 0;
+                               return -1;
+                       }
                        if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
                                req->keep = 0;
                                return -1;
@@ -840,7 +850,10 @@
                open_packet(req, type);
                fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
                req->out_hdr = NULL;
-               fcgi_flush(req, 0);
+               if (!fcgi_flush(req, 0)) {
+                       req->keep = 0;
+                       return -1;
+               }
                if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
                        req->keep = 0;
                        return -1;
 [2006-05-22 09:27 UTC] dmitry@php.net
The patch is partially commited into HEAD, PHP_5_2 and PHP_5_1. Did bug go away?
 [2006-05-24 09:12 UTC] gacek at intertele dot pl
Bug has gone.
 [2006-05-24 12:44 UTC] gacek at intertele dot pl
Unfortunately your fix introduced another bug:

"limit" variable goes negative if free buffer length < sizeof(fcgi_header) and req->out_hdr is NULL.

memcpy crashes, when copying region with negative length.

Change condition:
} else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {

to:

} else if (limit > 0 && len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
 [2006-05-25 06:41 UTC] dmitry@php.net
Thank you for your help.

Fixed in CVS HEAD, PHP_5_2 and PHP_5_1.
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Sun Apr 20 15:01:54 2014 UTC