[PHP-DEV] CVS update: php3/functions From: zeev (php-dev <email protected>)
Date: 04/24/98

Date: Friday April 24, 1998 @ 13:32
Author: zeev

Update of /repository/php3/functions
In directory asf:/tmp/cvs-serv12992/functions

Modified Files:
        mime.c post.c
Log Message:
File upload fixes.
* *Security*. Three easily exploitable buffer overflows (no bounds checking whatsoever) fixed.
  Any other such overflows lurking in the dark?
* Hopefully fixed the boundary check to comply with the RFC, at least to some extent.
  The new checks will be compiled if NEW_BOUNDARY_CHECK is defined to 1 (it is by default).
  This ensures that the boundary is on the beginning of a line, and is prefixed with --

Index: php3/functions/mime.c
diff -c php3/functions/mime.c:1.47 php3/functions/mime.c:1.48
*** php3/functions/mime.c:1.47 Fri Apr 24 12:05:23 1998
--- php3/functions/mime.c Fri Apr 24 13:32:20 1998
***************
*** 22,28 ****
     | |
     +----------------------------------------------------------------------+
   */
! /* $Id: mime.c,v 1.47 1998/04/24 16:05:23 zeev Exp $ */
  #ifdef THREAD_SAFE
  #include "tls.h"
  #endif
--- 22,28 ----
     | |
     +----------------------------------------------------------------------+
   */
! /* $Id: mime.c,v 1.48 1998/04/24 17:32:20 zeev Exp $ */
  #ifdef THREAD_SAFE
  #include "tls.h"
  #endif
***************
*** 34,39 ****
--- 34,42 ----
  #include "mime.h"
  
  
+ #define NEW_BOUNDARY_CHECK 1
+ #define SAFE_RETURN { if (namebuf) efree(namebuf); if (filenamebuf) efree(filenamebuf); if (lbuf) efree(lbuf); return; }
+
  /*
   * Split raw mime stream up into appropriate components
   */
***************
*** 42,52 ****
          char *ptr, *loc, *loc2, *s, *name, *filename, *u, *fn;
          int len, state = 0, Done = 0, rem, urem;
          long bytes, max_file_size = 0;
! char namebuf[128], filenamebuf[128], lbuf[256];
          FILE *fp;
          int itype;
          TLS_VARS;
!
          ptr = buf;
          rem = cnt;
          len = strlen(boundary);
--- 45,55 ----
          char *ptr, *loc, *loc2, *s, *name, *filename, *u, *fn;
          int len, state = 0, Done = 0, rem, urem;
          long bytes, max_file_size = 0;
! char *namebuf=NULL, *filenamebuf=NULL, *lbuf=NULL;
          FILE *fp;
          int itype;
          TLS_VARS;
!
          ptr = buf;
          rem = cnt;
          len = strlen(boundary);
***************
*** 56,61 ****
--- 59,65 ----
                                  loc = memchr(ptr, *boundary, cnt);
                                  if (loc) {
                                          if (!strncmp(loc, boundary, len)) {
+
                                                  state = 1;
                                                  rem -= (loc - ptr) + len + 2;
                                                  ptr = loc + len + 2;
***************
*** 69,78 ****
                                  break;
                          case 1: /* Check content-disposition */
                                  if (strncasecmp(ptr, "Content-Disposition: form-data;", 31)) {
! if (rem < 31)
! return;
                                          php3_error(E_WARNING, "File Upload Mime headers garbled [%c%c%c%c%c]", *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4));
! return;
                                  }
                                  loc = memchr(ptr, '\n', rem);
                                  name = strstr(ptr, " name=\"");
--- 73,83 ----
                                  break;
                          case 1: /* Check content-disposition */
                                  if (strncasecmp(ptr, "Content-Disposition: form-data;", 31)) {
! if (rem < 31) {
! SAFE_RETURN;
! }
                                          php3_error(E_WARNING, "File Upload Mime headers garbled [%c%c%c%c%c]", *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4));
! SAFE_RETURN;
                                  }
                                  loc = memchr(ptr, '\n', rem);
                                  name = strstr(ptr, " name=\"");
***************
*** 81,97 ****
                                          s = memchr(name, '\"', loc - name);
                                          if (!s) {
                                                  php3_error(E_WARNING, "File Upload Mime headers garbled [%c%c%c%c%c]", *name, *(name + 1), *(name + 2), *(name + 3), *(name + 4));
! return;
                                          }
! strncpy(namebuf, name, s - name);
! namebuf[s - name] = '\0';
                                          state = 2;
                                          loc2 = memchr(loc + 1, '\n', rem);
                                          rem -= (loc2 - ptr) + 1;
                                          ptr = loc2 + 1;
                                  } else {
                                          php3_error(E_WARNING, "File upload error - no name component in content disposition");
! return;
                                  }
                                  filename = strstr(s, " filename=\"");
                                  if (filename && filename < loc) {
--- 86,102 ----
                                          s = memchr(name, '\"', loc - name);
                                          if (!s) {
                                                  php3_error(E_WARNING, "File Upload Mime headers garbled [%c%c%c%c%c]", *name, *(name + 1), *(name + 2), *(name + 3), *(name + 4));
! SAFE_RETURN;
                                          }
! namebuf = estrndup(name, s-name);
! lbuf = emalloc(s-name + MAX(MAX(sizeof("_name"),sizeof("_size")),sizeof("_type")));
                                          state = 2;
                                          loc2 = memchr(loc + 1, '\n', rem);
                                          rem -= (loc2 - ptr) + 1;
                                          ptr = loc2 + 1;
                                  } else {
                                          php3_error(E_WARNING, "File upload error - no name component in content disposition");
! SAFE_RETURN;
                                  }
                                  filename = strstr(s, " filename=\"");
                                  if (filename && filename < loc) {
***************
*** 99,108 ****
                                          s = memchr(filename, '\"', loc - filename);
                                          if (!s) {
                                                  php3_error(E_WARNING, "File Upload Mime headers garbled [%c%c%c%c%c]", *filename, *(filename + 1), *(filename + 2), *(filename + 3), *(filename + 4));
! return;
                                          }
! strncpy(filenamebuf, filename, s - filename);
! filenamebuf[s - filename] = '\0';
                                          sprintf(lbuf, "%s_name", namebuf);
                                          s = strrchr(filenamebuf, '\\');
                                          if (s && s > filenamebuf) {
--- 104,112 ----
                                          s = memchr(filename, '\"', loc - filename);
                                          if (!s) {
                                                  php3_error(E_WARNING, "File Upload Mime headers garbled [%c%c%c%c%c]", *filename, *(filename + 1), *(filename + 2), *(filename + 3), *(filename + 4));
! SAFE_RETURN;
                                          }
! filenamebuf = estrndup(filename, s-filename);
                                          sprintf(lbuf, "%s_name", namebuf);
                                          s = strrchr(filenamebuf, '\\');
                                          if (s && s > filenamebuf) {
***************
*** 136,142 ****
                                  }
                                  if (!loc) {
                                          php3_error(E_WARNING, "File Upload Field Data garbled");
! return;
                                  }
                                  *(loc - 4) = '\0';
  
--- 140,146 ----
                                  }
                                  if (!loc) {
                                          php3_error(E_WARNING, "File Upload Field Data garbled");
! SAFE_RETURN;
                                  }
                                  *(loc - 4) = '\0';
  
***************
*** 166,180 ****
                                  loc = memchr(ptr, *boundary, rem);
                                  u = ptr;
                                  while (loc) {
! if (!strncmp(loc, boundary, len))
                                                  break;
                                          u = loc + 1;
                                          urem = rem - (loc - ptr) - 1;
                                          loc = memchr(u, *boundary, urem);
                                  }
                                  if (!loc) {
                                          php3_error(E_WARNING, "File Upload Error - No Mime boundary found after start of file header");
! return;
                                  }
                                  fn = tempnam(php3_ini.upload_tmp_dir, "php");
                                  if (max_file_size && ((loc - ptr - 4) > max_file_size)) {
--- 170,190 ----
                                  loc = memchr(ptr, *boundary, rem);
                                  u = ptr;
                                  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 */
! #endif
! ) {
                                                  break;
+ }
                                          u = loc + 1;
                                          urem = rem - (loc - ptr) - 1;
                                          loc = memchr(u, *boundary, urem);
                                  }
                                  if (!loc) {
                                          php3_error(E_WARNING, "File Upload Error - No Mime boundary found after start of file header");
! SAFE_RETURN;
                                  }
                                  fn = tempnam(php3_ini.upload_tmp_dir, "php");
                                  if (max_file_size && ((loc - ptr - 4) > max_file_size)) {
***************
*** 188,194 ****
                                          fp = fopen(fn, "w");
                                          if (!fp) {
                                                  php3_error(E_WARNING, "File Upload Error - Unable to open temporary file [%s]", fn);
! return;
                                          }
                                          bytes = fwrite(ptr, 1, loc - ptr - 4, fp);
                                          fclose(fp);
--- 198,204 ----
                                          fp = fopen(fn, "w");
                                          if (!fp) {
                                                  php3_error(E_WARNING, "File Upload Error - Unable to open temporary file [%s]", fn);
! SAFE_RETURN;
                                          }
                                          bytes = fwrite(ptr, 1, loc - ptr - 4, fp);
                                          fclose(fp);
***************
*** 205,210 ****
--- 215,221 ----
                                  break;
                  }
          }
+ SAFE_RETURN;
  }
  
  /*
Index: php3/functions/post.c
diff -c php3/functions/post.c:1.92 php3/functions/post.c:1.93
*** php3/functions/post.c:1.92 Fri Apr 24 12:05:24 1998
--- php3/functions/post.c Fri Apr 24 13:32:20 1998
***************
*** 70,78 ****
          if (!strncasecmp(buf, "multipart/form-data", 19)) {
                  file_upload = 1;
                  mb = strchr(buf, '=');
! if (mb)
                          strncpy(boundary, mb + 1, sizeof(boundary));
! else {
                          php3_error(E_WARNING, "File Upload Error: No MIME boundary found");
                          php3_error(E_WARNING, "There should have been a \"boundary=something\" in the Content-Type string");
                          php3_error(E_WARNING, "The Content-Type string was: \"%s\"", buf);
--- 70,78 ----
          if (!strncasecmp(buf, "multipart/form-data", 19)) {
                  file_upload = 1;
                  mb = strchr(buf, '=');
! if (mb) {
                          strncpy(boundary, mb + 1, sizeof(boundary));
! } else {
                          php3_error(E_WARNING, "File Upload Error: No MIME boundary found");
                          php3_error(E_WARNING, "There should have been a \"boundary=something\" in the Content-Type string");
                          php3_error(E_WARNING, "The Content-Type string was: \"%s\"", buf);