summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2016-07-19 01:35:58 -0700
committerStanislav Malyshev <stas@php.net>2016-07-19 01:39:28 -0700
commitb00f8f2a5bae651d6375ca34c676963f1f25ee5a (patch)
treeaeffcdefca1269348c8b42e200b380044154ecad
parente9a58bee24a4004e50a59d0d01927e6632d6da27 (diff)
parent4d0565b5bad444b0652379668c5116b74ee13747 (diff)
downloadphp-git-b00f8f2a5bae651d6375ca34c676963f1f25ee5a.tar.gz
Merge branch 'PHP-5.6' into PHP-7.0
* PHP-5.6: fix #72519, possible OOB using imagegif fix #72512, invalid read or write for palette image when invalid transparent index is used Apparently some envs miss SIZE_MAX Fix tests Fix bug #72618: NULL Pointer Dereference in exif_process_user_comment Partial fix for bug #72613 - do not treat negative returns from bz2 as size_t Fix bug #72606: heap-buffer-overflow (write) simplestring_addn simplestring.c Fix for bug #72558, Integer overflow error within _gdContributionsAlloc() Fix bug #72603: Out of bound read in exif_process_IFD_in_MAKERNOTE Fix bug #72562 - destroy var_hash properly Fix bug #72533 (locale_accept_from_http out-of-bounds access) Fix fir bug #72520 Fix for bug #72513 Fix for bug #72513 CS fix and comments with bug ID Fix for HTTP_PROXY issue. 5.6.24RC1 add tests for bug #72512 Fixed bug #72512 gdImageTrueColorToPaletteBody allows arbitrary write/read access Fixed bug #72479 - same as #72434 Conflicts: Zend/zend_virtual_cwd.c ext/bz2/bz2.c ext/exif/exif.c ext/session/session.c ext/snmp/snmp.c ext/standard/basic_functions.c main/SAPI.c main/php_variables.c
-rw-r--r--ext/exif/exif.c41
-rw-r--r--ext/exif/tests/bug54002.phpt6
-rw-r--r--ext/exif/tests/bug62523_2.phpt6
-rw-r--r--ext/exif/tests/bug72603.jpegbin0 -> 3711 bytes
-rw-r--r--ext/exif/tests/bug72603.phpt11
-rw-r--r--ext/exif/tests/bug72618.jpgbin0 -> 3711 bytes
-rw-r--r--ext/exif/tests/bug72618.phpt11
-rw-r--r--ext/gd/libgd/gd.c2
-rw-r--r--ext/gd/libgd/gd_interpolation.c116
-rw-r--r--ext/gd/tests/bug72512_0.phpt18
-rw-r--r--ext/gd/tests/bug72512_1.phpt18
-rw-r--r--ext/intl/locale/locale_methods.c18
-rw-r--r--ext/intl/tests/bug72533.phpt30
-rw-r--r--ext/session/session.c1
-rw-r--r--ext/session/tests/bug72562.phpt44
-rw-r--r--ext/snmp/snmp.c9
-rw-r--r--ext/snmp/tests/bug72479.phpt35
-rw-r--r--ext/standard/basic_functions.c21
-rw-r--r--ext/xmlrpc/libxmlrpc/simplestring.c24
-rw-r--r--ext/xmlrpc/libxmlrpc/simplestring.h2
-rw-r--r--ext/zip/zip_stream.c4
-rw-r--r--main/SAPI.c4
-rw-r--r--main/php_variables.c18
23 files changed, 358 insertions, 81 deletions
diff --git a/ext/exif/exif.c b/ext/exif/exif.c
index 777694538b..cf221419d5 100644
--- a/ext/exif/exif.c
+++ b/ext/exif/exif.c
@@ -2604,6 +2604,7 @@ static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoP
*pszEncoding = NULL;
/* Copy the comment */
if (ByteCount>=8) {
+ const zend_encoding *from, *to;
if (!memcmp(szValuePtr, "UNICODE\0", 8)) {
*pszEncoding = estrdup((const char*)szValuePtr);
szValuePtr = szValuePtr+8;
@@ -2624,15 +2625,16 @@ static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoP
} else {
decode = ImageInfo->decode_unicode_le;
}
+ to = zend_multibyte_fetch_encoding(ImageInfo->encode_unicode);
+ from = zend_multibyte_fetch_encoding(decode);
/* XXX this will fail again if encoding_converter returns on error something different than SIZE_MAX */
- if (zend_multibyte_encoding_converter(
+ if (!to || !from || zend_multibyte_encoding_converter(
(unsigned char**)pszInfoPtr,
&len,
(unsigned char*)szValuePtr,
ByteCount,
- zend_multibyte_fetch_encoding(ImageInfo->encode_unicode),
- zend_multibyte_fetch_encoding(decode)
- ) == (size_t)-1) {
+ to,
+ from) == (size_t)-1) {
len = exif_process_string_raw(pszInfoPtr, szValuePtr, ByteCount);
}
return len;
@@ -2646,14 +2648,15 @@ static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoP
szValuePtr = szValuePtr+8;
ByteCount -= 8;
/* XXX this will fail again if encoding_converter returns on error something different than SIZE_MAX */
- if (zend_multibyte_encoding_converter(
+ to = zend_multibyte_fetch_encoding(ImageInfo->encode_jis);
+ from = zend_multibyte_fetch_encoding(ImageInfo->motorola_intel ? ImageInfo->decode_jis_be : ImageInfo->decode_jis_le);
+ if (!to || !from || zend_multibyte_encoding_converter(
(unsigned char**)pszInfoPtr,
&len,
(unsigned char*)szValuePtr,
ByteCount,
- zend_multibyte_fetch_encoding(ImageInfo->encode_jis),
- zend_multibyte_fetch_encoding(ImageInfo->motorola_intel ? ImageInfo->decode_jis_be : ImageInfo->decode_jis_le)
- ) == (size_t)-1) {
+ to,
+ from) == (size_t)-1) {
len = exif_process_string_raw(pszInfoPtr, szValuePtr, ByteCount);
}
return len;
@@ -2723,6 +2726,12 @@ static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * valu
break;
}
+ if (maker_note->offset >= value_len) {
+ /* Do not go past the value end */
+ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "IFD data too short: 0x%04X offset 0x%04X", value_len, maker_note->offset);
+ return FALSE;
+ }
+
dir_start = value_ptr + maker_note->offset;
#ifdef EXIF_DEBUG
@@ -2751,10 +2760,19 @@ static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * valu
offset_base = value_ptr;
break;
case MN_OFFSET_GUESS:
+ if (maker_note->offset + 10 + 4 >= value_len) {
+ /* Can not read dir_start+10 since it's beyond value end */
+ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "IFD data too short: 0x%04X", value_len);
+ return FALSE;
+ }
offset_diff = 2 + NumDirEntries*12 + 4 - php_ifd_get32u(dir_start+10, ImageInfo->motorola_intel);
#ifdef EXIF_DEBUG
exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Using automatic offset correction: 0x%04X", ((int)dir_start-(int)offset_base+maker_note->offset+displacement) + offset_diff);
#endif
+ if (offset_diff < 0 || offset_diff >= value_len ) {
+ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "IFD data bad offset: 0x%04X length 0x%04X", offset_diff, value_len);
+ return FALSE;
+ }
offset_base = value_ptr + offset_diff;
break;
default:
@@ -2763,7 +2781,7 @@ static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * valu
}
if ((2+NumDirEntries*12) > value_len) {
- exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Illegal IFD size: 2 + x%04X*12 = x%04X > x%04X", NumDirEntries, 2+NumDirEntries*12, value_len);
+ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Illegal IFD size: 2 + 0x%04X*12 = 0x%04X > 0x%04X", NumDirEntries, 2+NumDirEntries*12, value_len);
return FALSE;
}
@@ -3049,7 +3067,10 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha
break;
case TAG_MAKER_NOTE:
- exif_process_IFD_in_MAKERNOTE(ImageInfo, value_ptr, byte_count, offset_base, IFDlength, displacement);
+ if (!exif_process_IFD_in_MAKERNOTE(ImageInfo, value_ptr, byte_count, offset_base, IFDlength, displacement)) {
+ EFREE_IF(outside);
+ return FALSE;
+ }
break;
case TAG_EXIF_IFD_POINTER:
diff --git a/ext/exif/tests/bug54002.phpt b/ext/exif/tests/bug54002.phpt
index c51fa58897..8f85339190 100644
--- a/ext/exif/tests/bug54002.phpt
+++ b/ext/exif/tests/bug54002.phpt
@@ -13,8 +13,4 @@ exif_read_data(__DIR__ . '/bug54002_2.jpeg');
--EXPECTF--
Warning: exif_read_data(bug54002_1.jpeg): Process tag(x0205=UndefinedTa): Illegal byte_count in %sbug54002.php on line %d
-Warning: exif_read_data(bug54002_1.jpeg): Process tag(xA000=FlashPixVer): Illegal pointer offset(%s) in %sbug54002.php on line %d
-
-Warning: exif_read_data(bug54002_2.jpeg): Process tag(x0205=UndefinedTa): Illegal byte_count in %sbug54002.php on line %d
-
-Warning: exif_read_data(bug54002_2.jpeg): Process tag(xA000=FlashPixVer): Illegal pointer offset(%s) in %sbug54002.php on line %d
+Warning: exif_read_data(bug54002_2.jpeg): Process tag(x0205=UndefinedTa): Illegal byte_count in %sbug54002.php on line %d \ No newline at end of file
diff --git a/ext/exif/tests/bug62523_2.phpt b/ext/exif/tests/bug62523_2.phpt
index ddc8ae824e..c533d42652 100644
--- a/ext/exif/tests/bug62523_2.phpt
+++ b/ext/exif/tests/bug62523_2.phpt
@@ -10,7 +10,9 @@ echo "Test\n";
var_dump(count(exif_read_data(__DIR__."/bug62523_2.jpg")));
?>
Done
---EXPECT--
+--EXPECTF--
Test
-int(76)
+
+Warning: exif_read_data(bug62523_2.jpg): IFD data bad offset: 0xADB23672 length 0x0D94 in %s/bug62523_2.php on line %d
+int(30)
Done
diff --git a/ext/exif/tests/bug72603.jpeg b/ext/exif/tests/bug72603.jpeg
new file mode 100644
index 0000000000..1764c805fb
--- /dev/null
+++ b/ext/exif/tests/bug72603.jpeg
Binary files differ
diff --git a/ext/exif/tests/bug72603.phpt b/ext/exif/tests/bug72603.phpt
new file mode 100644
index 0000000000..a4295f9848
--- /dev/null
+++ b/ext/exif/tests/bug72603.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Bug #72603 (Out of bound read in exif_process_IFD_in_MAKERNOTE)
+--SKIPIF--
+<?php if (!extension_loaded('exif')) print 'skip exif extension not available';?>
+--FILE--
+<?php
+var_dump(count(exif_read_data(dirname(__FILE__) . "/bug72603.jpeg")));
+?>
+--EXPECTF--
+Warning: exif_read_data(bug72603.jpeg): IFD data bad offset: 0x058C length 0x001C in %s/bug72603.php on line %d
+int(13) \ No newline at end of file
diff --git a/ext/exif/tests/bug72618.jpg b/ext/exif/tests/bug72618.jpg
new file mode 100644
index 0000000000..0a61ae2e02
--- /dev/null
+++ b/ext/exif/tests/bug72618.jpg
Binary files differ
diff --git a/ext/exif/tests/bug72618.phpt b/ext/exif/tests/bug72618.phpt
new file mode 100644
index 0000000000..424c0ec402
--- /dev/null
+++ b/ext/exif/tests/bug72618.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Bug 72618 (NULL Pointer Dereference in exif_process_user_comment)
+--SKIPIF--
+<?php if (!extension_loaded('exif')) print 'skip exif extension not available';?>
+--FILE--
+<?php
+var_dump(count(exif_read_data(dirname(__FILE__) . "/bug72618.jpg")));
+?>
+--EXPECTF--
+Warning: exif_read_data(bug72618.jpg): IFD data bad offset: 0x058E length 0x0030 in %s/bug72618.php on line %d
+int(13) \ No newline at end of file
diff --git a/ext/gd/libgd/gd.c b/ext/gd/libgd/gd.c
index 73548062bb..4292671417 100644
--- a/ext/gd/libgd/gd.c
+++ b/ext/gd/libgd/gd.c
@@ -188,7 +188,7 @@ gdImagePtr gdImageCreateTrueColor (int sx, int sy)
return NULL;
}
- if (overflow2(sizeof(int), sx)) {
+ if (overflow2(sizeof(int *), sx)) {
return NULL;
}
diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c
index fb34982582..b9c4c2878e 100644
--- a/ext/gd/libgd/gd_interpolation.c
+++ b/ext/gd/libgd/gd_interpolation.c
@@ -879,20 +879,39 @@ int getPixelInterpolated(gdImagePtr im, const double x, const double y, const in
static inline LineContribType * _gdContributionsAlloc(unsigned int line_length, unsigned int windows_size)
{
unsigned int u = 0;
- LineContribType *res;
+ LineContribType *res;
+ int overflow_error = 0;
res = (LineContribType *) gdMalloc(sizeof(LineContribType));
if (!res) {
return NULL;
}
- res->WindowSize = windows_size;
- res->LineLength = line_length;
- res->ContribRow = (ContributionType *) gdMalloc(line_length * sizeof(ContributionType));
-
- for (u = 0 ; u < line_length ; u++) {
- res->ContribRow[u].Weights = (double *) gdMalloc(windows_size * sizeof(double));
- }
- return res;
+ res->WindowSize = windows_size;
+ res->LineLength = line_length;
+ if (overflow2(line_length, sizeof(ContributionType))) {
+ return NULL;
+ }
+ res->ContribRow = (ContributionType *) gdMalloc(line_length * sizeof(ContributionType));
+ if (res->ContribRow == NULL) {
+ gdFree(res);
+ return NULL;
+ }
+ for (u = 0 ; u < line_length ; u++) {
+ if (overflow2(windows_size, sizeof(double))) {
+ overflow_error = 1;
+ } else {
+ res->ContribRow[u].Weights = (double *) gdMalloc(windows_size * sizeof(double));
+ }
+ if (overflow_error == 1 || res->ContribRow[u].Weights == NULL) {
+ u--;
+ while (u >= 0) {
+ gdFree(res->ContribRow[u].Weights);
+ u--;
+ }
+ return NULL;
+ }
+ }
+ return res;
}
static inline void _gdContributionsFree(LineContribType * p)
@@ -907,59 +926,62 @@ static inline void _gdContributionsFree(LineContribType * p)
static inline LineContribType *_gdContributionsCalc(unsigned int line_size, unsigned int src_size, double scale_d, const interpolation_method pFilter)
{
- double width_d;
- double scale_f_d = 1.0;
- const double filter_width_d = DEFAULT_BOX_RADIUS;
+ double width_d;
+ double scale_f_d = 1.0;
+ const double filter_width_d = DEFAULT_BOX_RADIUS;
int windows_size;
unsigned int u;
LineContribType *res;
+ int overflow_error = 0;
- if (scale_d < 1.0) {
- width_d = filter_width_d / scale_d;
- scale_f_d = scale_d;
- } else {
- width_d= filter_width_d;
- }
-
- windows_size = 2 * (int)ceil(width_d) + 1;
- res = _gdContributionsAlloc(line_size, windows_size);
+ if (scale_d < 1.0) {
+ width_d = filter_width_d / scale_d;
+ scale_f_d = scale_d;
+ } else {
+ width_d= filter_width_d;
+ }
- for (u = 0; u < line_size; u++) {
- const double dCenter = (double)u / scale_d;
- /* get the significant edge points affecting the pixel */
- register int iLeft = MAX(0, (int)floor (dCenter - width_d));
- int iRight = MIN((int)ceil(dCenter + width_d), (int)src_size - 1);
- double dTotalWeight = 0.0;
+ windows_size = 2 * (int)ceil(width_d) + 1;
+ res = _gdContributionsAlloc(line_size, windows_size);
+ if (res == NULL) {
+ return NULL;
+ }
+ for (u = 0; u < line_size; u++) {
+ const double dCenter = (double)u / scale_d;
+ /* get the significant edge points affecting the pixel */
+ register int iLeft = MAX(0, (int)floor (dCenter - width_d));
+ int iRight = MIN((int)ceil(dCenter + width_d), (int)src_size - 1);
+ double dTotalWeight = 0.0;
int iSrc;
- /* Cut edge points to fit in filter window in case of spill-off */
- if (iRight - iLeft + 1 > windows_size) {
- if (iLeft < ((int)src_size - 1 / 2)) {
- iLeft++;
- } else {
- iRight--;
- }
- }
+ /* Cut edge points to fit in filter window in case of spill-off */
+ if (iRight - iLeft + 1 > windows_size) {
+ if (iLeft < ((int)src_size - 1 / 2)) {
+ iLeft++;
+ } else {
+ iRight--;
+ }
+ }
- res->ContribRow[u].Left = iLeft;
- res->ContribRow[u].Right = iRight;
+ res->ContribRow[u].Left = iLeft;
+ res->ContribRow[u].Right = iRight;
- for (iSrc = iLeft; iSrc <= iRight; iSrc++) {
- dTotalWeight += (res->ContribRow[u].Weights[iSrc-iLeft] = scale_f_d * (*pFilter)(scale_f_d * (dCenter - (double)iSrc)));
- }
+ for (iSrc = iLeft; iSrc <= iRight; iSrc++) {
+ dTotalWeight += (res->ContribRow[u].Weights[iSrc-iLeft] = scale_f_d * (*pFilter)(scale_f_d * (dCenter - (double)iSrc)));
+ }
if (dTotalWeight < 0.0) {
_gdContributionsFree(res);
return NULL;
}
- if (dTotalWeight > 0.0) {
- for (iSrc = iLeft; iSrc <= iRight; iSrc++) {
- res->ContribRow[u].Weights[iSrc-iLeft] /= dTotalWeight;
- }
- }
- }
- return res;
+ if (dTotalWeight > 0.0) {
+ for (iSrc = iLeft; iSrc <= iRight; iSrc++) {
+ res->ContribRow[u].Weights[iSrc-iLeft] /= dTotalWeight;
+ }
+ }
+ }
+ return res;
}
static inline void _gdScaleRow(gdImagePtr pSrc, unsigned int src_width, gdImagePtr dst, unsigned int dst_width, unsigned int row, LineContribType *contrib)
diff --git a/ext/gd/tests/bug72512_0.phpt b/ext/gd/tests/bug72512_0.phpt
new file mode 100644
index 0000000000..5f98662d45
--- /dev/null
+++ b/ext/gd/tests/bug72512_0.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #72512 gdImageTrueColorToPaletteBody allows arbitrary write/read access, var 0
+--SKIPIF--
+<?php
+ if (!extension_loaded('gd')) die("skip gd extension not available\n");
+?>
+--FILE--
+<?php
+
+$img = imagecreatetruecolor(13, 1007);
+
+imagecolortransparent($img, -10066304);
+imagetruecolortopalette($img, TRUE, 3);
+imagescale($img, 1, 65535);
+?>
+==DONE==
+--EXPECT--
+==DONE==
diff --git a/ext/gd/tests/bug72512_1.phpt b/ext/gd/tests/bug72512_1.phpt
new file mode 100644
index 0000000000..bba01a7118
--- /dev/null
+++ b/ext/gd/tests/bug72512_1.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #72512 gdImageTrueColorToPaletteBody allows arbitrary write/read access, var 1
+--SKIPIF--
+<?php
+ if (!extension_loaded('gd')) die("skip gd extension not available\n");
+?>
+--FILE--
+<?php
+
+$img = imagecreatetruecolor(100, 100);
+imagecolortransparent($img, -1000000);
+imagetruecolortopalette($img, TRUE, 3);
+imagecolortransparent($img, 9);
+
+?>
+==DONE==
+--EXPECT--
+==DONE==
diff --git a/ext/intl/locale/locale_methods.c b/ext/intl/locale/locale_methods.c
index 857c14a005..32a70d2f7f 100644
--- a/ext/intl/locale/locale_methods.c
+++ b/ext/intl/locale/locale_methods.c
@@ -1598,6 +1598,24 @@ PHP_FUNCTION(locale_accept_from_http)
"locale_accept_from_http: unable to parse input parameters", 0 );
RETURN_FALSE;
}
+ if(http_accept_len > ULOC_FULLNAME_CAPACITY) {
+ /* check each fragment, if any bigger than capacity, can't do it due to bug #72533 */
+ char *start = http_accept;
+ char *end;
+ size_t len;
+ do {
+ end = strchr(start, ',');
+ len = end ? end-start : http_accept_len-(start-http_accept);
+ if(len > ULOC_FULLNAME_CAPACITY) {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "locale_accept_from_http: locale string too long", 0 TSRMLS_CC );
+ RETURN_FALSE;
+ }
+ if(end) {
+ start = end+1;
+ }
+ } while(end != NULL);
+ }
available = ures_openAvailableLocales(NULL, &status);
INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to retrieve locale list");
diff --git a/ext/intl/tests/bug72533.phpt b/ext/intl/tests/bug72533.phpt
new file mode 100644
index 0000000000..c7fcba39d0
--- /dev/null
+++ b/ext/intl/tests/bug72533.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Bug #72533 (locale_accept_from_http out-of-bounds access)
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+
+function ut_main()
+{
+ $ret = var_export(ut_loc_accept_http(str_repeat('x', 256)), true);
+ $ret .= "\n";
+ if(intl_is_failure(intl_get_error_code())) {
+ $ret .= var_export(intl_get_error_message(), true);
+ }
+ $ret .= "\n";
+ $ret .= var_export(ut_loc_accept_http(str_repeat('en,', 256)), true);
+ $ret .= "\n";
+ if(intl_is_failure(intl_get_error_code())) {
+ $ret .= var_export(intl_get_error_message(), true);
+ }
+ return $ret;
+}
+
+include_once( 'ut_common.inc' );
+ut_run();
+?>
+--EXPECTF--
+false
+'locale_accept_from_http: locale string too long: U_ILLEGAL_ARGUMENT_ERROR'
+'en' \ No newline at end of file
diff --git a/ext/session/session.c b/ext/session/session.c
index 5b7841de5c..380cad5b58 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -971,6 +971,7 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
namelen = ((unsigned char)(*p)) & (~PS_BIN_UNDEF);
if (namelen < 0 || namelen > PS_BIN_MAX || (p + namelen) >= endptr) {
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
return FAILURE;
}
diff --git a/ext/session/tests/bug72562.phpt b/ext/session/tests/bug72562.phpt
new file mode 100644
index 0000000000..d85e48b069
--- /dev/null
+++ b/ext/session/tests/bug72562.phpt
@@ -0,0 +1,44 @@
+--TEST--
+Bug #72562: Use After Free in unserialize() with Unexpected Session Deserialization
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--FILE--
+<?php
+
+ini_set('session.serialize_handler', 'php_binary');
+session_start();
+$sess = "\x1xi:1;\x2y";
+session_decode($sess);
+$uns_1 = '{';
+$out_1[] = unserialize($uns_1);
+unset($out_1);
+$fakezval = ptr2str(1122334455);
+$fakezval .= ptr2str(0);
+$fakezval .= "\x00\x00\x00\x00";
+$fakezval .= "\x01";
+$fakezval .= "\x00";
+$fakezval .= "\x00\x00";
+for ($i = 0; $i < 5; $i++) {
+ $v[$i] = $fakezval.$i;
+}
+$uns_2 = 'R:2;';
+$out_2 = unserialize($uns_2);
+var_dump($out_2);
+
+function ptr2str($ptr)
+{
+ $out = '';
+ for ($i = 0; $i < 8; $i++) {
+ $out .= chr($ptr & 0xff);
+ $ptr >>= 8;
+ }
+ return $out;
+}
+?>
+--EXPECTF--
+Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/bug72562.php on line %d
+
+Notice: unserialize(): Error at offset 0 of 1 bytes in %s/bug72562.php on line %d
+
+Notice: unserialize(): Error at offset 4 of 4 bytes in %s/bug72562.php on line %d
+bool(false)
diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c
index 67e39f1645..7b685ff5dc 100644
--- a/ext/snmp/snmp.c
+++ b/ext/snmp/snmp.c
@@ -2071,6 +2071,14 @@ static int php_snmp_has_property(zval *object, zval *member, int has_set_exists,
}
/* }}} */
+static HashTable *php_snmp_get_gc(zval *object, zval ***gc_data, int *gc_data_count TSRMLS_DC) /* {{{ */
+{
+ *gc_data = NULL;
+ *gc_data_count = 0;
+ return zend_std_get_properties(object TSRMLS_CC);
+}
+/* }}} */
+
/* {{{ php_snmp_get_properties(zval *object)
Returns all object properties. Injects SNMP properties into object on first call */
static HashTable *php_snmp_get_properties(zval *object)
@@ -2361,6 +2369,7 @@ PHP_MINIT_FUNCTION(snmp)
php_snmp_object_handlers.write_property = php_snmp_write_property;
php_snmp_object_handlers.has_property = php_snmp_has_property;
php_snmp_object_handlers.get_properties = php_snmp_get_properties;
+ php_snmp_object_handlers.get_gc = php_snmp_get_gc;
/* Register SNMP Class */
INIT_CLASS_ENTRY(ce, "SNMP", php_snmp_class_methods);
diff --git a/ext/snmp/tests/bug72479.phpt b/ext/snmp/tests/bug72479.phpt
new file mode 100644
index 0000000000..0308754360
--- /dev/null
+++ b/ext/snmp/tests/bug72479.phpt
@@ -0,0 +1,35 @@
+--TEST--
+Bug #72479: Use After Free Vulnerability in SNMP with GC and unserialize()
+--SKIPIF--
+<?php
+require_once(dirname(__FILE__).'/skipif.inc');
+?>
+--FILE--
+<?php
+$arr = [1, [1, 2, 3, 4, 5], 3, 4, 5];
+$poc = 'a:3:{i:1;N;i:2;O:4:"snmp":1:{s:11:"quick_print";'.serialize($arr).'}i:1;R:7;}';
+$out = unserialize($poc);
+gc_collect_cycles();
+$fakezval = ptr2str(1122334455);
+$fakezval .= ptr2str(0);
+$fakezval .= "\x00\x00\x00\x00";
+$fakezval .= "\x01";
+$fakezval .= "\x00";
+$fakezval .= "\x00\x00";
+for ($i = 0; $i < 5; $i++) {
+ $v[$i] = $fakezval.$i;
+}
+var_dump($out[1]);
+
+function ptr2str($ptr)
+{
+ $out = '';
+ for ($i = 0; $i < 8; $i++) {
+ $out .= chr($ptr & 0xff);
+ $ptr >>= 8;
+ }
+ return $out;
+}
+?>
+--EXPECT--
+int(1) \ No newline at end of file
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c
index 1eb8e1c02c..c4505886d6 100644
--- a/ext/standard/basic_functions.c
+++ b/ext/standard/basic_functions.c
@@ -4009,24 +4009,27 @@ PHP_FUNCTION(long2ip)
* System Functions *
********************/
-/* {{{ proto string getenv(string varname)
+/* {{{ proto string getenv(string varname[, bool local_only])
Get the value of an environment variable */
PHP_FUNCTION(getenv)
{
char *ptr, *str;
size_t str_len;
+ zend_bool local_only = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &str, &str_len, &local_only) == FAILURE) {
RETURN_FALSE;
}
- /* SAPI method returns an emalloc()'d string */
- ptr = sapi_getenv(str, str_len);
- if (ptr) {
- // TODO: avoid realocation ???
- RETVAL_STRING(ptr);
- efree(ptr);
- return;
+ if (!local_only) {
+ /* SAPI method returns an emalloc()'d string */
+ ptr = sapi_getenv(str, str_len);
+ if (ptr) {
+ // TODO: avoid realocation ???
+ RETVAL_STRING(ptr);
+ efree(ptr);
+ return;
+ }
}
#ifdef PHP_WIN32
{
diff --git a/ext/xmlrpc/libxmlrpc/simplestring.c b/ext/xmlrpc/libxmlrpc/simplestring.c
index 026567e5f5..c88754fb9a 100644
--- a/ext/xmlrpc/libxmlrpc/simplestring.c
+++ b/ext/xmlrpc/libxmlrpc/simplestring.c
@@ -172,6 +172,9 @@ void simplestring_free(simplestring* string) {
}
/******/
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t)-1)
+#endif
/****f* FUNC/simplestring_addn
* NAME
* simplestring_addn
@@ -190,18 +193,31 @@ void simplestring_free(simplestring* string) {
* simplestring_add ()
* SOURCE
*/
-void simplestring_addn(simplestring* target, const char* source, int add_len) {
+void simplestring_addn(simplestring* target, const char* source, size_t add_len) {
+ size_t newsize = target->size, incr = 0;
if(target && source) {
if(!target->str) {
simplestring_init_str(target);
}
+
+ if((SIZE_MAX - add_len) < target->len || (SIZE_MAX - add_len - 1) < target->len) {
+ /* check for overflows, if there's a potential overflow do nothing */
+ return;
+ }
+
if(target->len + add_len + 1 > target->size) {
/* newsize is current length + new length */
- int newsize = target->len + add_len + 1;
- int incr = target->size * 2;
+ newsize = target->len + add_len + 1;
+ incr = target->size * 2;
/* align to SIMPLESTRING_INCR increments */
- newsize = newsize - (newsize % incr) + incr;
+ if (incr) {
+ newsize = newsize - (newsize % incr) + incr;
+ }
+ if(newsize < (target->len + add_len + 1)) {
+ /* some kind of overflow happened */
+ return;
+ }
target->str = (char*)realloc(target->str, newsize);
target->size = target->str ? newsize : 0;
diff --git a/ext/xmlrpc/libxmlrpc/simplestring.h b/ext/xmlrpc/libxmlrpc/simplestring.h
index 59186a7764..b46b0d779a 100644
--- a/ext/xmlrpc/libxmlrpc/simplestring.h
+++ b/ext/xmlrpc/libxmlrpc/simplestring.h
@@ -63,7 +63,7 @@ void simplestring_init(simplestring* string);
void simplestring_clear(simplestring* string);
void simplestring_free(simplestring* string);
void simplestring_add(simplestring* string, const char* add);
-void simplestring_addn(simplestring* string, const char* add, int add_len);
+void simplestring_addn(simplestring* string, const char* add, size_t add_len);
#ifdef __cplusplus
}
diff --git a/ext/zip/zip_stream.c b/ext/zip/zip_stream.c
index a1f620182c..d586233dee 100644
--- a/ext/zip/zip_stream.c
+++ b/ext/zip/zip_stream.c
@@ -264,7 +264,7 @@ php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper,
zend_string **opened_path,
php_stream_context *context STREAMS_DC)
{
- int path_len;
+ size_t path_len;
zend_string *file_basename;
char file_dirname[MAXPATHLEN];
@@ -272,7 +272,7 @@ php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper,
struct zip *za;
struct zip_file *zf = NULL;
char *fragment;
- int fragment_len;
+ size_t fragment_len;
int err;
php_stream *stream = NULL;
diff --git a/main/SAPI.c b/main/SAPI.c
index 496bbfbd12..9029e2e570 100644
--- a/main/SAPI.c
+++ b/main/SAPI.c
@@ -1020,6 +1020,10 @@ SAPI_API zend_stat_t *sapi_get_stat(void)
SAPI_API char *sapi_getenv(char *name, size_t name_len)
{
+ if (!strncasecmp(name, "HTTP_PROXY", name_len)) {
+ /* Ugly fix for HTTP_PROXY issue, see bug #72573 */
+ return NULL;
+ }
if (sapi_module.getenv) {
char *value, *tmp = sapi_module.getenv(name, name_len);
if (tmp) {
diff --git a/main/php_variables.c b/main/php_variables.c
index 73274d7695..5791990038 100644
--- a/main/php_variables.c
+++ b/main/php_variables.c
@@ -730,6 +730,22 @@ static zend_bool php_auto_globals_create_files(zend_string *name)
return 0; /* don't rearm */
}
+/* Upgly hack to fix HTTP_PROXY issue, see bug #72573 */
+static void check_http_proxy(HashTable *var_table)
+{
+ if (zend_hash_str_exists(var_table, "HTTP_PROXY", sizeof("HTTP_PROXY")-1)) {
+ char *local_proxy = getenv("HTTP_PROXY");
+
+ if (!local_proxy) {
+ zend_hash_str_del(var_table, "HTTP_PROXY", sizeof("HTTP_PROXY")-1);
+ } else {
+ zval local_zval;
+ ZVAL_STRING(&local_zval, local_proxy);
+ zend_hash_str_update(var_table, "HTTP_PROXY", sizeof("HTTP_PROXY")-1, &local_zval);
+ }
+ }
+}
+
static zend_bool php_auto_globals_create_server(zend_string *name)
{
if (PG(variables_order) && (strchr(PG(variables_order),'S') || strchr(PG(variables_order),'s'))) {
@@ -755,6 +771,7 @@ static zend_bool php_auto_globals_create_server(zend_string *name)
array_init(&PG(http_globals)[TRACK_VARS_SERVER]);
}
+ check_http_proxy(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]));
zend_hash_update(&EG(symbol_table), name, &PG(http_globals)[TRACK_VARS_SERVER]);
Z_ADDREF(PG(http_globals)[TRACK_VARS_SERVER]);
@@ -770,6 +787,7 @@ static zend_bool php_auto_globals_create_env(zend_string *name)
php_import_environment_variables(&PG(http_globals)[TRACK_VARS_ENV]);
}
+ check_http_proxy(Z_ARRVAL(PG(http_globals)[TRACK_VARS_ENV]));
zend_hash_update(&EG(symbol_table), name, &PG(http_globals)[TRACK_VARS_ENV]);
Z_ADDREF(PG(http_globals)[TRACK_VARS_ENV]);