diff options
29 files changed, 400 insertions, 84 deletions
diff --git a/ext/bz2/bz2.c b/ext/bz2/bz2.c index baa65b3878..6678876c96 100644 --- a/ext/bz2/bz2.c +++ b/ext/bz2/bz2.c @@ -148,7 +148,11 @@ static size_t php_bz2iop_read(php_stream *stream, char *buf, size_t count) just_read = BZ2_bzread(self->bz_file, buf, to_read); if (just_read < 1) { - stream->eof = 0 == just_read; + /* it is not safe to keep reading after an error, see #72613 */ + stream->eof = 1; + if (just_read < 0) { + return -1; + } break; } diff --git a/ext/bz2/tests/72613.bz2 b/ext/bz2/tests/72613.bz2 Binary files differnew file mode 100644 index 0000000000..0b932f8d91 --- /dev/null +++ b/ext/bz2/tests/72613.bz2 diff --git a/ext/bz2/tests/bug72613.phpt b/ext/bz2/tests/bug72613.phpt new file mode 100644 index 0000000000..82547e6ae0 --- /dev/null +++ b/ext/bz2/tests/bug72613.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #72613 (Inadequate error handling in bzread()) +--SKIPIF-- +<?php if (!extension_loaded("bz2")) print "skip"; ?> +--FILE-- +<?php +$fp = bzopen(__DIR__.'/72613.bz2', 'r'); +if ($fp === FALSE) { + exit("ERROR: bzopen()"); +} +$data = ""; +while (!feof($fp)) { + $res = bzread($fp); + if ($res === FALSE) { + exit("ERROR: bzread()"); + } + $data .= $res; +} +bzclose($fp); +?> +DONE +--EXPECT-- +DONE
\ No newline at end of file diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 9449022119..6335b7ae8e 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -3608,6 +3608,10 @@ PHP_FUNCTION(curl_unescape) RETURN_FALSE; } + if (str_len > INT_MAX) { + RETURN_FALSE; + } + if ((out = curl_easy_unescape(ch->cp, str, str_len, &out_len))) { RETVAL_STRINGL(out, out_len); curl_free(out); diff --git a/ext/exif/exif.c b/ext/exif/exif.c index e8c622418a..9f951d78a3 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; @@ -2724,6 +2727,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 @@ -2752,10 +2761,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: @@ -2764,7 +2782,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; } @@ -3050,7 +3068,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 Binary files differnew file mode 100644 index 0000000000..1764c805fb --- /dev/null +++ b/ext/exif/tests/bug72603.jpeg 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 Binary files differnew file mode 100644 index 0000000000..0a61ae2e02 --- /dev/null +++ b/ext/exif/tests/bug72618.jpg 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 bd60a3480c..c91287cc7b 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/mcrypt/mcrypt.c b/ext/mcrypt/mcrypt.c index 68528d30f2..cf9c2ccdf1 100644 --- a/ext/mcrypt/mcrypt.c +++ b/ext/mcrypt/mcrypt.c @@ -645,6 +645,10 @@ PHP_FUNCTION(mcrypt_generic) memset(ZSTR_VAL(data_str), 0, data_size); memcpy(ZSTR_VAL(data_str), data, data_len); } else { /* It's not a block algorithm */ + if (data_len > INT_MAX) { + php_error_docref(NULL, E_WARNING, "Data size too large, %d maximum", INT_MAX); + RETURN_FALSE; + } data_size = (int)data_len; data_str = zend_string_alloc(data_size, 0); memset(ZSTR_VAL(data_str), 0, data_size); @@ -695,6 +699,10 @@ PHP_FUNCTION(mdecrypt_generic) memset(data_s, 0, data_size); memcpy(data_s, data, data_len); } else { /* It's not a block algorithm */ + if (data_len > INT_MAX) { + php_error_docref(NULL, E_WARNING, "Data size too large, %d maximum", INT_MAX); + RETURN_FALSE; + } data_size = (int)data_len; data_s = emalloc(data_size + 1); memset(data_s, 0, data_size); diff --git a/ext/pdo_pgsql/tests/bug72570.phpt b/ext/pdo_pgsql/tests/bug72570.phpt index 1ac68a3892..e52efd93bb 100644 --- a/ext/pdo_pgsql/tests/bug72570.phpt +++ b/ext/pdo_pgsql/tests/bug72570.phpt @@ -18,11 +18,11 @@ $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $stmt = $db->prepare("SELECT 1"); try { - $stmt->execute([1]); + var_dump($stmt->execute([1])); } catch (PDOException $e) { var_dump($e->getCode()); } ?> --EXPECT-- -string(5) "08P01" +bool(false) diff --git a/ext/session/session.c b/ext/session/session.c index d85d72b2a6..bbf5b0fb94 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -985,6 +985,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 cb48a0da22..b32b845c73 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -2068,6 +2068,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) @@ -2357,6 +2365,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 fd1596e5cd..1cef26c3ae 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -4019,15 +4019,16 @@ 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 or every available environment variable if no varname is present */ PHP_FUNCTION(getenv) { char *ptr, *str = NULL; 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(), "|sb", &str, &str_len, &local_only) == FAILURE) { RETURN_FALSE; } @@ -4037,13 +4038,15 @@ PHP_FUNCTION(getenv) return; } - /* 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 3d5b002086..1362e4d5ec 100644 --- a/ext/zip/zip_stream.c +++ b/ext/zip/zip_stream.c @@ -263,7 +263,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]; @@ -271,7 +271,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 da76e00b92..e1c22bd182 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -1019,6 +1019,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 f93b4e851b..7f0823af5a 100644 --- a/main/php_variables.c +++ b/main/php_variables.c @@ -749,6 +749,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'))) { @@ -774,6 +790,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]); @@ -789,6 +806,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]); |