Sophie

Sophie

distrib > Mandriva > 10.0 > i586 > by-pkgid > 980f5b0a0cb06ae4486a72dcc0241bbc > files > 18

php-4.3.4-4.6.100mdk.src.rpm

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)

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)

o XXX-XXXX-XXXX:
  magic_quotes_gpc could lead to one level directory traversal with
  file uploads.
  (main/rfc1867.c)

Index: ext/exif/exif.c
--- ext/exif/exif.c.bigsec	2003-09-22 17:28:07.000000000 -0600
+++ ext/exif/exif.c	2004-12-16 18:26:39.000000000 -0700
@@ -2713,7 +2713,7 @@
 			// JPEG does not use absolute pointers instead its pointers are relative to the start
 			// of the TIFF header in APP1 section.
 			*/
-			if (offset_val<0 || offset_val+byte_count>ImageInfo->FileSize || (ImageInfo->FileType!=IMAGE_FILETYPE_TIFF_II && ImageInfo->FileType!=IMAGE_FILETYPE_TIFF_MM)) {
+			if (offset_val<0 || offset_val+byte_count>ImageInfo->FileSize || (ImageInfo->FileType!=IMAGE_FILETYPE_TIFF_II && ImageInfo->FileType!=IMAGE_FILETYPE_TIFF_MM && ImageInfo->FileType!=IMAGE_FILETYPE_JPEG)) {
 				if (value_ptr < dir_entry) {
 					/* we can read this if offset_val > 0 */
 					/* some files have their values in other parts of the file */
@@ -3751,7 +3751,7 @@
 			}
 		}
 		for (i=0; i<SECTION_COUNT; i++) {
-			sprintf(tmp, ",%s,", exif_get_sectionname(i));
+			snprintf(tmp, sizeof(tmp), ",%s,", exif_get_sectionname(i));
 			if (strstr(sections_str, tmp)) {
 				sections_needed |= 1<<i;
 			}

Index: ext/shmop/shmop.c
--- ext/shmop/shmop.c.orig	2002-12-31 17:35:20 +0100
+++ ext/shmop/shmop.c	2004-12-16 17:20:05 +0100
@@ -316,7 +316,7 @@
 		RETURN_FALSE;
 	}
 
-	if (offset > shmop->size) {
+	if (offset < 0 || offset > shmop->size) {
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset out of range");
 		RETURN_FALSE;
 	}
Index: ext/standard/link.c
--- ext/standard/link.c.orig	2002-12-31 17:35:31 +0100
+++ ext/standard/link.c	2004-12-16 17:20:05 +0100
@@ -65,6 +65,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(Z_STRVAL_PP(filename), buff, MAXPATHLEN-1);
 
 	if (ret == -1) {
Index: ext/standard/pack.c
--- ext/standard/pack.c.orig	2004-02-25 13:36:24 +0100
+++ ext/standard/pack.c	2004-12-16 17:20:05 +0100
@@ -63,6 +63,13 @@
 #include <netinet/in.h>
 #endif
 
+#define INC_OUTPUTPOS(a,b) \
+	if ((a) < 0 || ((INT_MAX - outputpos)/(b)) < (a)) { \
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow in format string", code); \
+		RETURN_FALSE; \
+	} \
+	outputpos += (a)*(b);
+
 /* Whether machine is little endian */
 char machine_little_endian;
 
@@ -246,7 +253,7 @@
 		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': 
@@ -254,34 +261,34 @@
 			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;
 
 			case 'X':
@@ -650,6 +657,11 @@
 				sprintf(n, "%.*s", namelen, name);
 			}
 
+			if (size != 0 && size != -1 && INT_MAX - size + 1 < inputpos) {
+				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow", type);
+				inputpos = 0;
+			}
+
 			if ((inputpos + size) <= inputlen) {
 				switch ((int) type) {
 					case 'a': 
@@ -820,6 +832,10 @@
 				}
 
 				inputpos += size;
+				if (inputpos < 0) {
+					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type);
+					inputpos = 0;
+				}
 			} else if (arg < 0) {
 				/* Reached end of input for '*' repeater */
 				break;
Index: ext/standard/var_unserializer.re
--- ext/standard/var_unserializer.re.orig	2004-03-27 02:17:06 +0100
+++ ext/standard/var_unserializer.re	2004-12-16 21:09:57 +0100
@@ -62,7 +62,7 @@
 
 	if (!var_hash) return !SUCCESS;
 
-	if (id >= var_hash->used_slots) return !SUCCESS;
+	if (id < 0 || id >= var_hash->used_slots) return !SUCCESS;
 
 	*store = &var_hash->data[id];
 
@@ -139,7 +139,7 @@
 static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements)
 {
 	while (elements-- > 0) {
-		zval *key, *data;
+		zval *key, *data, *old_data;
 
 		ALLOC_INIT_ZVAL(key);
 
@@ -161,9 +161,15 @@
 
 		switch (Z_TYPE_P(key)) {
 			case IS_LONG:
+				if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)) {
+					var_replace(var_hash, old_data, rval);
+				}
 				zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
 				break;
 			case IS_STRING:
+				if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)) {
+					var_replace(var_hash, old_data, rval);
+				}
 				zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
 				break;
 
@@ -398,7 +404,6 @@
 #ifdef ZEND_ENGINE_2
 					ce = *(zend_class_entry **)ce; /* Bad hack, TBF! */
 #endif	
-					efree(class_name);
 				}
 			}
 		}
@@ -406,7 +411,6 @@
 #ifdef ZEND_ENGINE_2
 		ce = *(zend_class_entry **)ce; /* Bad hack, TBF! */
 #endif	
-		efree(class_name);
 	}
 
 	*p = YYCURSOR;
@@ -414,8 +418,8 @@
 
 	if (incomplete_class) {
 		php_store_class_name(*rval, class_name, len2 TSRMLS_CC);
-		efree(class_name);
 	}
+	efree(class_name);
 
 	return object_common2(UNSERIALIZE_PASSTHRU, elements);
 }
Index: ext/standard/var_unserializer.c
--- ext/standard/var_unserializer.c.orig	2004-07-13 16:53:12 +0200
+++ ext/standard/var_unserializer.c	2004-12-16 21:10:16 +0100
@@ -63,7 +63,7 @@
 
 	if (!var_hash) return !SUCCESS;
 
-	if (id >= var_hash->used_slots) return !SUCCESS;
+	if (id < 0 || id >= var_hash->used_slots) return !SUCCESS;
 
 	*store = &var_hash->data[id];
 
@@ -134,7 +134,7 @@
 static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements)
 {
 	while (elements-- > 0) {
-		zval *key, *data;
+		zval *key, *data, *old_data;
 
 		ALLOC_INIT_ZVAL(key);
 
@@ -156,9 +156,15 @@
 
 		switch (Z_TYPE_P(key)) {
 			case IS_LONG:
+				if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)) {
+					var_replace(var_hash, old_data, rval);
+				}
 				zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
 				break;
 			case IS_STRING:
+				if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)) {
+					var_replace(var_hash, old_data, rval);
+				}
 				zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
 				break;
 
@@ -435,7 +441,6 @@
 #ifdef ZEND_ENGINE_2
 					ce = *(zend_class_entry **)ce; /* Bad hack, TBF! */
 #endif	
-					efree(class_name);
 				}
 			}
 		}
@@ -443,7 +448,6 @@
 #ifdef ZEND_ENGINE_2
 		ce = *(zend_class_entry **)ce; /* Bad hack, TBF! */
 #endif	
-		efree(class_name);
 	}
 
 	*p = YYCURSOR;
@@ -451,8 +455,8 @@
 
 	if (incomplete_class) {
 		php_store_class_name(*rval, class_name, len2 TSRMLS_CC);
-		efree(class_name);
 	}
+	efree(class_name);
 
 	return object_common2(UNSERIALIZE_PASSTHRU, elements);
 }
Index: main/php.h
--- main/php.h.orig	2003-09-25 01:22:32 +0200
+++ main/php.h	2004-12-16 17:20:05 +0100
@@ -226,6 +226,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
+
 #define PHP_GCC_VERSION ZEND_GCC_VERSION
 #define PHP_ATTRIBUTE_MALLOC ZEND_ATTRIBUTE_MALLOC
 #define PHP_ATTRIBUTE_FORMAT ZEND_ATTRIBUTE_FORMAT
Index: main/safe_mode.c
--- main/safe_mode.c.orig	2003-03-17 14:50:23 +0100
+++ main/safe_mode.c	2004-12-16 17:20:05 +0100
@@ -54,13 +54,16 @@
 	php_stream_wrapper *wrapper = NULL;
 	TSRMLS_FETCH();
 
-	strlcpy(filenamecopy, filename, MAXPATHLEN);
-	filename=(char *)&filenamecopy;
-
 	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') {
 			mode = CHECKUID_DISALLOW_FILE_NOT_EXISTS;
Index: main/rfc1867.c
--- main/rfc1867.c.bigsec	2004-12-16 18:30:00.000000000 -0700
+++ main/rfc1867.c	2004-12-16 18:36:39.000000000 -0700
@@ -60,6 +60,7 @@
 #define UPLOAD_ERROR_B    2  /* Uploaded file exceeded MAX_FILE_SIZE */
 #define UPLOAD_ERROR_C    3  /* Partially uploaded */
 #define UPLOAD_ERROR_D    4  /* No file uploaded */
+#define UPLOAD_ERROR_E    6  /* Missing /tmp or similar directory */
 
 void php_rfc1867_register_constants(TSRMLS_D)
 {
@@ -68,6 +69,7 @@
 	REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FORM_SIZE",  UPLOAD_ERROR_B,  CONST_CS | CONST_PERSISTENT);
 	REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL",    UPLOAD_ERROR_C,  CONST_CS | CONST_PERSISTENT);
 	REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE",    UPLOAD_ERROR_D,  CONST_CS | CONST_PERSISTENT);
+	REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E,  CONST_CS | CONST_PERSISTENT);
 }
 
 static void normalize_protected_variable(char *varname TSRMLS_DC)
@@ -757,7 +759,7 @@
 	while (!multipart_buffer_eof(mbuff TSRMLS_CC))
 	{
 		char buff[FILLUNIT];
-		char *cd=NULL,*param=NULL,*filename=NULL;
+		char *cd=NULL,*param=NULL,*filename=NULL,*tmp=NULL;
 		int blen=0, wlen=0;
 
 		zend_llist_clean(&header);
@@ -849,12 +851,14 @@
 				SAFE_RETURN;
 			}
 
+			total_bytes = cancel_upload = 0;
+
 			if (!skip_upload) {
 				/* Handle file */
 				fp = php_open_temporary_file(PG(upload_tmp_dir), "php", &temp_filename TSRMLS_CC);
 				if (!fp) {
 					sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file");
-					skip_upload = 1;
+					cancel_upload = UPLOAD_ERROR_E;
 				}
 			}
 			if (skip_upload) {
@@ -863,9 +867,6 @@
 				continue;
 			}	
 
-			total_bytes = 0;
-			cancel_upload = 0;
-
 			if(strlen(filename) == 0) {
 #ifdef DEBUG_FILE_UPLOAD
 				sapi_module.sapi_error(E_NOTICE, "No file uploaded");
@@ -892,10 +893,12 @@
 					}
 				} 
 			} 
-			fclose(fp);
+			if (fp) {
+				fclose(fp);
+			}
 
 #ifdef DEBUG_FILE_UPLOAD
-			if(strlen(filename) > 0 && total_bytes == 0) {
+			if(strlen(filename) > 0 && total_bytes == 0 && !cancel_upload) {
 				sapi_module.sapi_error(E_WARNING, "Uploaded file size 0 - file [%s=%s] not saved", param, filename);
 				cancel_upload = 5;
 			}
@@ -903,7 +906,9 @@
 
 			if (cancel_upload) {
 				if (temp_filename) {
-					unlink(temp_filename);
+					if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
+						unlink(temp_filename);
+					}
 					efree(temp_filename);
 				}
 				temp_filename="";
@@ -956,6 +961,14 @@
 #else
 			s = strrchr(filename, '\\');
 #endif
+			if (PG(magic_quotes_gpc)) {
+				s = s ? s : filename;
+				tmp = strrchr(s, '\'');
+				s = tmp > s ? tmp : s;
+				tmp = strrchr(s, '"');
+				s = tmp > s ? tmp : s;
+			}
+
 			if (s && s > filename) {
 				safe_php_register_variable(lbuf, s+1, NULL, 0 TSRMLS_CC);
 			} else {

Index: TSRM/tsrm_virtual_cwd.c
--- TSRM/tsrm_virtual_cwd.c.orig	2003-07-28 20:35:34 +0200
+++ TSRM/tsrm_virtual_cwd.c	2004-12-16 21:15:08 +0100
@@ -301,15 +301,22 @@
 
 	if (path_length == 0) 
 		return (0);
+	if (path_length >= MAXPATHLEN)
+		return (1);
 
 #if !defined(TSRM_WIN32) && !defined(NETWARE)
 	/* cwd_length can be 0 when getcwd() fails.
 	 * This can happen under solaris when a dir does not have read permissions
 	 * but *does* have execute permissions */
 	if (IS_ABSOLUTE_PATH(path, path_length) || (state->cwd_length < 1)) {
-		if (use_realpath && realpath(path, resolved_path)) {
-			path = resolved_path;
-			path_length = strlen(path);
+		if (use_realpath) {
+			if (realpath(path, resolved_path)) {
+				path = resolved_path;
+				path_length = strlen(path);
+			} else {
+				/* disable for now
+				return 1; */
+			}
 		}
 	} else { /* Concat current directory with relative path and then run realpath() on it */
 		char *tmp;
@@ -325,9 +332,19 @@
 		memcpy(ptr, path, path_length);
 		ptr += path_length;
 		*ptr = '\0';
-		if (use_realpath && realpath(tmp, resolved_path)) {
-			path = resolved_path;
-			path_length = strlen(path);
+		if (strlen(tmp) >= MAXPATHLEN) {
+			free(tmp);
+			return 1;
+		}
+		if (use_realpath) {
+			if (realpath(tmp, resolved_path)) {
+				path = resolved_path;
+				path_length = strlen(path);
+			} else {
+				/* disable for now
+				free(tmp);
+				return 1; */
+			}
 		}
 		free(tmp);
 	}
@@ -818,13 +835,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;
 	}
@@ -834,8 +862,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++ = ' ';