> 
> I will look later into the patch. But from a first look:
> the patch is bullshit. It opens up about 1000 security
> vulnerabilities because of double frees.

Yes - when I was going over the body of the code, I'd forgotten the
definition of SAFE_RETURN, which takes care of the frees. That was
carelessness on my part, I will admit.

> And: show me one system where memchr doesnt like zero as count. This
> would be a 100% misbehaviour and it is the libc programmers
> fault. If they don't write working libraries thats not our
> fault. (Hmm right now I am unsure if memchr is a gcc builtin
> function, too) And it is 100% assured that the buffer is zero
> terminated. All the complicated checks around the str* functions are
> not needed, cause those compares will fail on the terminating '\0'
> and stop. All the checks for more data aren't needed, cause the
> state maschine automaticly terminates if there is no data after a
> state swap.

Philosphical comment follows after.

I actually commented on where I was patching for this (to the effect
that it was probably overkill) and where there were other
problems. And there are other problems.

Line 233 does a memchr to find a new line. What happens if it fails?
Look at the two lines following. That portion of the submitted patch,
by any standard is not bogus nor bullshit.

  loc2 = memchr(loc + 1, '\n', rem);
  rem -= (loc2 - ptr) + 1;
  ptr = loc2 + 1;

That's bad code. 

Line 276 looks for a backslash in a submitted filename. If that
backslash is the last character, it will then call
safe_php_register_variable on an empty string. This is probably not a
good idea.

Line 308 assumes that loc2 (a pointer to a newline) is followed by at
least one more character before the terminating zero. It runs a while
loop, looking for newlines, always making this assumption. This is not
clever.

line 389 contains a peculiar if() statement which has some bits in it
which have no sense and should leave any competent programmer
wondering what in the hell the intention was. And it may well not work
in many cases.

Buf is the full line to be parsed. By the time you reach here, loc is
a pointer beyond the Content-Dispostion string and a lot else). It is
simply wrong code which happens to work.

It's not possible to guess the programmer's intention. I think it was
that either 

> Printing out 4 bytes after the terminating '\0' may crash. But its
> very unlikely and f.e. on linux, solaris it cannot happen. Maybe it
> could crash on *BSD, but thats untested.

I don't follow this at all. Unless you can be sure that this function
is always called with buf being an automatic variable of the caller,
or that it's a static global which is known not to end the data
segment, or that the memory allocate routines always add housekeeping
data after every malloced buffer, then you have no way of knowing if
buf+cnt+1 is part of the process data space. If it's not, an attempt
to read it will get a SEGV. Under Linux. Under Solaris. Under *BSD. 

And a philosophical note:

Adding extra checks to code seldom hurts.

1) It means that the next person looking at the code doesn't need to
   track all the execution paths to ensure that the following
   block of code will not cause problems.
2) Often it's cheaper to see if there's room for a string before
   initiating the search, so a check like that may be more efficient.
3) Most programmer's will spend more time looking at other people's
   code than writing new code. And every bit of that code which shows
   that the original author(s) have considered all the edge cases
   simply makes it easier for the next person.
4) Code which is 'very unlikely' to crash is code which is begging for
   a script kiddy to improve the odds. PHP is deployed on web servers
   and web servers are a popular target for defacement and/or DOS
   attacks. So the fact that you believe it's 'unlikely' that it can
   be caused to crash (instead of wanting code where it *will not*
   crash, does not speak well for the basic approach to coding. 
5) The entire php project has not released a working fix for an
   exploitable bug (it may stop the exploit, the code is still wide
   open to crashing). Worse, the entire world has been told that 4.1.2
   is a fix, and it contains, besides the points raised above, two
   attrocious non-working attempts to fix other problems (the
   memchar()+1 code). The response in the developers lists is:
   Version 4.2 has new code. The bad patch is fixed in CVS.
   This overlooks the fact that CERT and most other security services
   (like most of the Linux distributions) are putting out 4.1.2. And
   the attitude in the devlopers list appears to be a "Don't care,
   it's not my problem". I already had a previous response to the
   effect that a php server core-dumping wasn't really a problem. 


At any rate, since you don't like to see any patches which aren't
provable necessary, here's a reduced set (although I simply can't, in
good conscience leave in quoted strings and magic-number string
lengths in code.

Version 2:
--- rfc1867.c.save      Sun Mar  3 16:45:36 2002
+++ rfc1867.c   Sun Mar  3 17:26:28 2002
@@ -152,8 +152,11 @@
                                }
                                break;
                        case 1:                 /* Check content-disposition */
-                               while (strncasecmp(ptr, "Content-Disposition: 
form-data;", 31)) {
-                                       if (rem < 31) {
+                               /* let the complier do the counting */
+#define CONT_DISP "Content-Disposition: form-data;"
+
+                               while (strncasecmp(ptr, CONT_DISP, strlen(CONT_DISP))) 
+{
+                                       if (rem < strlen(CONT_DISP)) {
                                                SAFE_RETURN;
                                        }
                                        if (ptr[1] == '\n') {
@@ -162,20 +165,22 @@
                                                SAFE_RETURN;
                                        }
                                        /* some other headerfield found, skip it */
-                                       loc = (char *) memchr(ptr, '\n', rem)+1;
+                                       loc = (char *) memchr(ptr, '\n', rem);
                                        if (!loc) {
                                                /* broken */
                                                php_error(E_WARNING, "File Upload Mime 
headers garbled ptr: [%c%c%c%c%c]", *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 
4));
                                                SAFE_RETURN;
                                        }
+                                       ++loc;
                                        while (*loc == ' ' || *loc == '\t') {
                                                /* other field is folded, skip it */
-                                               loc = (char *) memchr(loc, '\n', 
rem-(loc-ptr))+1;
+                                               loc = (char *) memchr(loc, '\n', 
+rem-(loc-ptr));
                                                if (!loc) {
                                                        /* broken */
                                                        php_error(E_WARNING, "File 
Upload Mime headers garbled ptr: [%c%c%c%c%c]", *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 
3), *(ptr + 4));
                                                        SAFE_RETURN;
                                                }
+                                               ++loc;
                                        }
                                        rem -= (loc - ptr);
                                        ptr = loc;
@@ -200,10 +205,12 @@
                                        php_error(E_WARNING, "File Upload Mime headers 
garbled ptr: [%c%c%c%c%c]", *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4));
                                        SAFE_RETURN;
                                }
-                               name = strstr(ptr, " name=");
+
+#define NAME_EQUAL " name="
+                               name = strstr(ptr, NAME_EQUAL);
                                ptr = loc;
                                if (name && name < loc) {
-                                       name += 6;
+                                       name += strlen(NAME_EQUAL);
                                        if ( *name == '\"' ) { 
                                                name++;
                                                s = memchr(name, '\"', loc - name);
@@ -211,7 +218,10 @@
                                                s = strpbrk(name, " 
\t()<>@,;:\\\"/[]?=\r\n");
                                        }
                                        if (!s) {
-                                               php_error(E_WARNING, "File Upload Mime 
headers garbled name: [%c%c%c%c%c]", *name, *(name + 1), *(name + 2), *(name + 3), 
*(name + 4));
+                                               /* we don't know what's left in the 
+buffer, so don't
+                                                * try to print it (used to print 
+name[0..4])
+                                                */
+                                               php_error(E_WARNING, "File Upload Mime 
+headers garbled name: ");
                                                SAFE_RETURN;
                                        }
                                        
@@ -230,7 +240,11 @@
                                         * below. fix moved there and restored
                                         * pre 4.0.6 code here
                                         */
-                                       loc2 = memchr(loc + 1, '\n', rem);
+
+                                       if ((loc2 = memchr(loc + 1, '\n', rem)) == 0) {
+                                               php_error(E_WARNING, "Garbled file 
+upload headers");
+                                               SAFE_RETURN;
+                                       }
                                        rem -= (loc2 - ptr) + 1;
                                        ptr = loc2 + 1;
                                        /* is_arr_upload is true when name of file 
upload field
@@ -250,12 +264,13 @@
                                        php_error(E_WARNING, "File upload error - no 
name component in content disposition");
                                        SAFE_RETURN;
                                }
-                               filename = strstr(s, "filename=\"");
+#define FILEN_EQ "filename=\""
+                               filename = strstr(s, FILEN_EQ);
                                if (filename && filename < loc) {
-                                       filename += 10;
+                                       filename += strlen(FILEN_EQ);
                                        s = memchr(filename, '\"', loc - filename);
-                                       if (!s) {
-                                               php_error(E_WARNING, "File Upload Mime 
headers garbled filename: [%c%c%c%c%c]", *filename, *(filename + 1), *(filename + 2), 
*(filename + 3), *(filename + 4));
+                                       if (!s || strlen(s) == 0) {
+                                               php_error(E_WARNING, "File Upload Mime 
+headers garbled filename");
                                                SAFE_RETURN;
                                        }
                                        if (filenamebuf) {
@@ -274,6 +289,11 @@
                                                sprintf(lbuf, "%s_name", namebuf);
                                        }
                                        s = strrchr(filenamebuf, '\\');
+                                       if (s && s[1] == 0) {
+                                               /* ends in a trailing backslash */
+                                               php_error(E_WARNING, "File Upload Mime 
+headers garbled filename");
+                        SAFE_RETURN;
+                                       }
                                        if (s && s > filenamebuf) {
                                                safe_php_register_variable(lbuf, s+1, 
NULL, 0 TSRMLS_CC);
                                        } else {
@@ -294,24 +314,33 @@
 
                                        state = 3;
                                        s = "";
+#define CONT_TYPE "Content-Type:"
                                        if ((loc2 - loc) > 2) {
-                                               if (!strncasecmp(loc + 1, 
"Content-Type:", 13)) {
+                                               /* loc => newline, loc2 to next 
+newline */
+                                               if (!strncasecmp(loc + 1, CONT_TYPE, 
+strlen(CONT_TYPE))) {
                                                        c = *(loc2 - 1);
                                                        *(loc2 - 1) = '\0';
-                                                       s = loc+15;
+                                                       s = loc+strlen(CONT_TYPE) + 2;
                                                }
                                                /* end of header fix fixed and moved 
here
                                                 * find the double newline that marks 
the
                                                 * end of the headers
                                                 */
+
+                                               if (rem < 2) {
+                                                       php_error(E_WARNING, "File 
+Upload Mime headers garbled header3");
+                                                       SAFE_RETURN;
+                                               }
+                                                       
                                                loc3 = loc2;
-                                               while (loc3[2] != '\n') {
+
+                                               while ((cnt - (loc3 - buf) >= 2) && 
+loc3[2] != '\n') {
                                                        
                                                        /* empty line as end of 
headers not yet found */
                                                        loc3 = memchr(loc3 + 1, '\n', 
rem-(loc3-ptr)-1);
                                                        if (loc3==NULL) {
-                                                               php_error(E_WARNING, 
"File Upload Mime headers garbled header3: [%c%c%c%c%c]", *loc2, *(loc2 + 1), *(loc2 + 
2), *(loc2 + 3), *(loc2 + 4));
-                                                               SAFE_RETURN;
+                                                               php_error(E_WARNING, 
+"File Upload Mime headers garbled header3");
+                                                       SAFE_RETURN;
                                                        }
                                                }
                                                rem -= (loc3 - ptr) + 3;
@@ -388,8 +417,8 @@
                                while (loc) {
                                        if (!strncmp(loc, boundary, len)
 #if NEW_BOUNDARY_CHECK
-                                               && (loc-2>buf && *(loc-2)=='-' && 
*(loc-1)=='-') /* ensure boundary is prefixed with -- */
-                                               && (loc-2==buf || *(loc-3)=='\n') /* 
ensure beginning of line */
+                                               && *(loc-2)=='-' && *(loc-1)=='-' /* 
+ensure boundary is prefixed with -- */
+                                               && *(loc-3)=='\n') /* ensure beginning 
+of line */
 #endif
                                                ) {
                                                break;


-- 
Jim Segrave           [EMAIL PROTECTED]

-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to