Security Fixes (OpenPKG-2004.053-php): o CAN-2004-1018: shmop_write() out of bounds memory write access. (ext/shmop/shmop.c) o CAN-2004-1018: integer overflow/underflow in pack() and unpack() functions. (main/php.h, ext/standard/pack.c) o CAN-2004-1019: possible information disclosure, double free and negative reference index array underflow in deserialization code. (ext/standard/var_unserializer.re, ext/standard/var_unserializer.c) **** NOT APPLICABLE IN 4.1.2!! **** o CAN-2004-1020: addslashes() not escaping \0 correctly. (ext/standard/string.c) **** NOT NECCESSARY IN PHP 4.3.8!! **** o CAN-2004-1063: safe_mode execution directory bypass. (ext/standard/link.c, TSRM/tsrm_virtual_cwd.c) o CAN-2004-1064: arbitrary file access through path truncation. (main/safe_mode.c) o CAN-2004-1065: exif_read_data() overflow on long sectionname. (ext/exif/exif.c) **** NOT APPLICABLE IN 4.1.2!! **** o XXX-XXXX-XXXX: magic_quotes_gpc could lead to one level directory traversal with file uploads. (main/rfc1867.c) **** PARTS OF THE PATCH NOT APPLICABLE IN 4.1.2!! **** diff -aur php-4.1.2-orig/ext/shmop/shmop.c php-4.1.2/ext/shmop/shmop.c --- php-4.1.2-orig/ext/shmop/shmop.c 2002-01-09 10:40:13.000000000 +0200 +++ php-4.1.2/ext/shmop/shmop.c 2005-01-05 21:24:38.000000000 +0200 @@ -325,7 +325,7 @@ RETURN_FALSE; } - if ( (*offset)->value.lval > shmop->size ) { + if (offset < 0 || (*offset)->value.lval > shmop->size ) { php_error(E_WARNING, "shmop_write: offset out of range"); RETURN_FALSE; } diff -aur php-4.1.2-orig/ext/standard/link.c php-4.1.2/ext/standard/link.c --- php-4.1.2-orig/ext/standard/link.c 2001-08-11 20:03:37.000000000 +0300 +++ php-4.1.2/ext/standard/link.c 2005-01-05 21:24:38.000000000 +0200 @@ -63,6 +63,14 @@ } convert_to_string_ex(filename); + if (PG(safe_mode) && !php_checkuid(Z_STRVAL_PP(filename), NULL, CHECKUID_CHECK_FILE_AND_DIR)) { + RETURN_FALSE; + } + + if (php_check_open_basedir(Z_STRVAL_PP(filename) TSRMLS_CC)) { + RETURN_FALSE; + } + ret = readlink((*filename)->value.str.val, buff, 255); if (ret == -1) { php_error(E_WARNING, "readlink failed (%s)", strerror(errno)); diff -aur php-4.1.2-orig/ext/standard/pack.c php-4.1.2/ext/standard/pack.c --- php-4.1.2-orig/ext/standard/pack.c 2001-08-11 20:03:37.000000000 +0300 +++ php-4.1.2/ext/standard/pack.c 2005-01-05 21:24:38.000000000 +0200 @@ -49,6 +49,13 @@ #include #endif +#define INC_OUTPUTPOS(a,b) \ + if ((a) < 0 || ((INT_MAX - outputpos)/(b)) < (a)) { \ + php_error(E_WARNING, "Type %c: integer overflow in format string", code); \ + RETURN_FALSE; \ + } \ + outputpos += (a)*(b); + /* Whether machine is little endian */ char machine_little_endian; @@ -216,39 +223,39 @@ switch ((int)code) { case 'h': case 'H': { - outputpos += (arg + 1) / 2; /* 4 bit per arg */ + INC_OUTPUTPOS((arg + 1) / 2,1) /* 4 bit per arg */ break; } case 'a': case 'A': case 'c': case 'C': case 'x': { - outputpos += arg; /* 8 bit per arg */ + INC_OUTPUTPOS(arg,1) /* 8 bit per arg */ break; } case 's': case 'S': case 'n': case 'v': { - outputpos += arg * 2; /* 16 bit per arg */ + INC_OUTPUTPOS(arg,2) /* 16 bit per arg */ break; } case 'i': case 'I': { - outputpos += arg * sizeof(int); + INC_OUTPUTPOS(arg,sizeof(int)) break; } case 'l': case 'L': case 'N': case 'V': { - outputpos += arg * 4; /* 32 bit per arg */ + INC_OUTPUTPOS(arg,4) /* 32 bit per arg */ break; } case 'f': { - outputpos += arg * sizeof(float); + INC_OUTPUTPOS(arg,sizeof(float)) break; } case 'd': { - outputpos += arg * sizeof(double); + INC_OUTPUTPOS(arg,sizeof(double)) break; } @@ -615,6 +622,11 @@ sprintf(n, "%.*s", namelen, name); } + if (size != 0 && size != -1 && INT_MAX - size + 1 < inputpos) { + php_error(E_WARNING, "Type %c: integer overflow", type); + inputpos = 0; + } + if ((inputpos + size) <= inputlen) { switch ((int)type) { case 'a': case 'A': { @@ -778,6 +790,10 @@ } inputpos += size; + if (inputpos < 0) { + php_error(E_WARNING, "Type %c: outside of string", type); + inputpos = 0; + } } else if (arg < 0) { /* Reached end of input for '*' repeater */ break; diff -aur php-4.1.2-orig/main/php.h php-4.1.2/main/php.h --- php-4.1.2-orig/main/php.h 2005-01-05 21:23:38.000000000 +0200 +++ php-4.1.2/main/php.h 2005-01-05 21:24:38.000000000 +0200 @@ -188,6 +188,14 @@ #define LONG_MIN (- LONG_MAX - 1) #endif +#ifndef INT_MAX +#define INT_MAX 2147483647 +#endif + +#ifndef INT_MIN +#define INT_MIN (- INT_MAX - 1) +#endif + #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) || defined(BROKEN_SPRINTF) || defined(BROKEN_SNPRINTF) || defined(BROKEN_VSNPRINTF) #include "snprintf.h" #endif diff -aur php-4.1.2-orig/main/rfc1867.c php-4.1.2/main/rfc1867.c --- php-4.1.2-orig/main/rfc1867.c 2005-01-05 21:23:38.000000000 +0200 +++ php-4.1.2/main/rfc1867.c 2005-01-05 21:24:38.000000000 +0200 @@ -276,6 +276,15 @@ sprintf(lbuf, "%s_name", namebuf); } s = strrchr(filenamebuf, '\\'); + if (PG(magic_quotes_gpc)) { + char *tmp; + s = s ? s : filename; + tmp = strrchr(s, '\''); + s = tmp > s ? tmp : s; + tmp = strrchr(s, '"'); + s = tmp > s ? tmp : s; + } + if (s && s > filenamebuf) { safe_php_register_variable(lbuf, s+1, NULL, 0 TSRMLS_CC); } else { diff -aur php-4.1.2-orig/main/safe_mode.c php-4.1.2/main/safe_mode.c --- php-4.1.2-orig/main/safe_mode.c 2001-08-05 04:42:44.000000000 +0300 +++ php-4.1.2/main/safe_mode.c 2005-01-05 21:24:38.000000000 +0200 @@ -49,12 +49,17 @@ int ret; long uid=0L, gid=0L, duid=0L, dgid=0L; char path[MAXPATHLEN]; - char *s; + char *s, *filenamecopy; TSRMLS_FETCH(); if (!filename) { return 0; /* path must be provided */ } + + if (strlcpy(filenamecopy, filename, MAXPATHLEN)>=MAXPATHLEN) { + return 0; + } + filename=(char *)&filenamecopy; if (fopen_mode) { if (fopen_mode[0] == 'r') { diff -aur php-4.1.2-orig/TSRM/tsrm_virtual_cwd.c php-4.1.2/TSRM/tsrm_virtual_cwd.c --- php-4.1.2-orig/TSRM/tsrm_virtual_cwd.c 2001-11-17 23:15:57.000000000 +0200 +++ php-4.1.2/TSRM/tsrm_virtual_cwd.c 2005-01-05 21:24:38.000000000 +0200 @@ -272,9 +272,12 @@ if (path_length == 0) return (0); + if (path_length >= MAXPATHLEN) + return (1); #if !defined(TSRM_WIN32) && !defined(__BEOS__) if (IS_ABSOLUTE_PATH(path, path_length)) { + /* use_realpath always on in this version..? */ if (realpath(path, resolved_path)) { path = resolved_path; path_length = strlen(path); @@ -293,6 +296,11 @@ memcpy(ptr, path, path_length); ptr += path_length; *ptr = '\0'; + if (strlen(tmp) >= MAXPATHLEN) { + free(tmp); + return 1; + } + /* realpath always used in this version ..? */ if (realpath(tmp, resolved_path)) { path = resolved_path; path_length = strlen(path); @@ -700,13 +708,24 @@ CWD_API FILE *virtual_popen(const char *command, const char *type TSRMLS_DC) { int command_length; + int dir_length, extra = 0; char *command_line; - char *ptr; + char *ptr, *dir; FILE *retval; command_length = strlen(command); - ptr = command_line = (char *) malloc(command_length + sizeof("cd ; ") + CWDG(cwd).cwd_length+1); + dir_length = CWDG(cwd).cwd_length; + dir = CWDG(cwd).cwd; + while (dir_length > 0) { + if (*dir == '\'') extra+=3; + dir++; + dir_length--; + } + dir_length = CWDG(cwd).cwd_length; + dir = CWDG(cwd).cwd; + + ptr = command_line = (char *) malloc(command_length + sizeof("cd '' ; ") + dir_length +1+1); if (!command_line) { return NULL; } @@ -716,8 +735,21 @@ if (CWDG(cwd).cwd_length == 0) { *ptr++ = DEFAULT_SLASH; } else { - memcpy(ptr, CWDG(cwd).cwd, CWDG(cwd).cwd_length); - ptr += CWDG(cwd).cwd_length; + *ptr++ = '\''; + while (dir_length > 0) { + switch (*dir) { + case '\'': + *ptr++ = '\''; + *ptr++ = '\\'; + *ptr++ = '\''; + /* fall-through */ + default: + *ptr++ = *dir; + } + dir++; + dir_length--; + } + *ptr++ = '\''; } *ptr++ = ' ';