Merge branch 'PHP-7.3'

* PHP-7.3:
  Fix #77367: Negative size parameter in mb_split
  Fix #77369 - memcpy with negative length via crafted DNS response
  Fix more issues with encodilng length
  Fix #77270: imagecolormatch Out Of Bounds Write on Heap
  Fix bug #77380  (Global out of bounds read in xmlrpc base64 code)
  Fix bug #77371 (heap buffer overflow in mb regex functions - compile_string_node)
  Fix bug #77370 - check that we do not read past buffer end when parsing multibytes
  Fix #77269: Potential unsigned underflow in gdImageScale
  Fix bug #77247 (heap buffer overflow in phar_detect_phar_fname_ext)
  Fix bug #77242 (heap out of bounds read in xmlrpc_decode())
  Regenerate certs for openssl tests
This commit is contained in:
Stanislav Malyshev 2019-01-06 12:50:10 -08:00
commit 0f148839b5
19 changed files with 190 additions and 23 deletions

View File

@ -33,8 +33,8 @@ int gdImageColorMatch (gdImagePtr im1, gdImagePtr im2)
return -4; /* At least 1 color must be allocated */ return -4; /* At least 1 color must be allocated */
} }
buf = (unsigned long *)safe_emalloc(sizeof(unsigned long), 5 * im2->colorsTotal, 0); buf = (unsigned long *)safe_emalloc(sizeof(unsigned long), 5 * gdMaxColors, 0);
memset( buf, 0, sizeof(unsigned long) * 5 * im2->colorsTotal ); memset( buf, 0, sizeof(unsigned long) * 5 * gdMaxColors );
for (x=0; x<im1->sx; x++) { for (x=0; x<im1->sx; x++) {
for( y=0; y<im1->sy; y++ ) { for( y=0; y<im1->sy; y++ ) {

View File

@ -890,8 +890,13 @@ static inline LineContribType * _gdContributionsAlloc(unsigned int line_length,
{ {
unsigned int u = 0; unsigned int u = 0;
LineContribType *res; LineContribType *res;
int overflow_error = 0; size_t weights_size;
if (overflow2(windows_size, sizeof(double))) {
return NULL;
} else {
weights_size = windows_size * sizeof(double);
}
res = (LineContribType *) gdMalloc(sizeof(LineContribType)); res = (LineContribType *) gdMalloc(sizeof(LineContribType));
if (!res) { if (!res) {
return NULL; return NULL;
@ -908,15 +913,10 @@ static inline LineContribType * _gdContributionsAlloc(unsigned int line_length,
return NULL; return NULL;
} }
for (u = 0 ; u < line_length ; u++) { for (u = 0 ; u < line_length ; u++) {
if (overflow2(windows_size, sizeof(double))) { res->ContribRow[u].Weights = (double *) gdMalloc(weights_size);
overflow_error = 1; if (res->ContribRow[u].Weights == NULL) {
} else {
res->ContribRow[u].Weights = (double *) gdMalloc(windows_size * sizeof(double));
}
if (overflow_error == 1 || res->ContribRow[u].Weights == NULL) {
unsigned int i; unsigned int i;
u--; for (i=0;i<u;i++) {
for (i=0;i<=u;i++) {
gdFree(res->ContribRow[i].Weights); gdFree(res->ContribRow[i].Weights);
} }
gdFree(res->ContribRow); gdFree(res->ContribRow);

View File

@ -0,0 +1,21 @@
--TEST--
Bug #77269 (Potential unsigned underflow in gdImageScale)
--SKIPIF--
<?php
if (!extension_loaded('gd')) die('skip gd extension not available');
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
?>
--INI--
memory_limit=2G
--FILE--
<?php
$im = imagecreate(2**28, 1);
if(is_resource($im)) {
imagescale($im, 1, 1, IMG_TRIANGLE);
}
?>
===DONE===
--EXPECTF--
Warning: imagescale():%S product of memory allocation multiplication would exceed INT_MAX, failing operation gracefully
in %s on line %d
===DONE===

View File

@ -0,0 +1,18 @@
--TEST--
Bug #77270 (imagecolormatch Out Of Bounds Write on Heap)
--SKIPIF--
<?php
if (!extension_loaded('gd')) die('skip gd extension not available');
if (!GD_BUNDLED && version_compare(GD_VERSION, '2.2.5', '<=')) die('skip upstream bugfix has not been released');
?>
--FILE--
<?php
$img1 = imagecreatetruecolor(0xfff, 0xfff);
$img2 = imagecreate(0xfff, 0xfff);
imagecolorallocate($img2, 0, 0, 0);
imagesetpixel($img2, 0, 0, 255);
imagecolormatch($img1, $img2);
?>
===DONE===
--EXPECT--
===DONE===

View File

@ -540,13 +540,13 @@ compile_length_string_node(Node* node, regex_t* reg)
ambig = NODE_STRING_IS_AMBIG(node); ambig = NODE_STRING_IS_AMBIG(node);
p = prev = sn->s; p = prev = sn->s;
prev_len = enclen(enc, p); SAFE_ENC_LEN(enc, p, sn->end, prev_len);
p += prev_len; p += prev_len;
slen = 1; slen = 1;
rlen = 0; rlen = 0;
for (; p < sn->end; ) { for (; p < sn->end; ) {
len = enclen(enc, p); SAFE_ENC_LEN(enc, p, sn->end, len);
if (len == prev_len) { if (len == prev_len) {
slen++; slen++;
} }
@ -591,12 +591,12 @@ compile_string_node(Node* node, regex_t* reg)
ambig = NODE_STRING_IS_AMBIG(node); ambig = NODE_STRING_IS_AMBIG(node);
p = prev = sn->s; p = prev = sn->s;
prev_len = enclen(enc, p); SAFE_ENC_LEN(enc, p, end, prev_len);
p += prev_len; p += prev_len;
slen = 1; slen = 1;
for (; p < end; ) { for (; p < end; ) {
len = enclen(enc, p); SAFE_ENC_LEN(enc, p, end, len);
if (len == prev_len) { if (len == prev_len) {
slen++; slen++;
} }
@ -3624,7 +3624,7 @@ expand_case_fold_string(Node* node, regex_t* reg)
goto err; goto err;
} }
len = enclen(reg->enc, p); SAFE_ENC_LEN(reg->enc, p, end, len);
if (n == 0) { if (n == 0) {
if (IS_NULL(snode)) { if (IS_NULL(snode)) {

View File

@ -393,14 +393,17 @@ save_entry(ScanEnv* env, enum SaveType type, int* id)
c = ONIGENC_MBC_TO_CODE(enc, p, end); \ c = ONIGENC_MBC_TO_CODE(enc, p, end); \
pfetch_prev = p; \ pfetch_prev = p; \
p += ONIGENC_MBC_ENC_LEN(enc, p); \ p += ONIGENC_MBC_ENC_LEN(enc, p); \
if(UNEXPECTED(p > end)) p = end; \
} while (0) } while (0)
#define PINC_S do { \ #define PINC_S do { \
p += ONIGENC_MBC_ENC_LEN(enc, p); \ p += ONIGENC_MBC_ENC_LEN(enc, p); \
if(UNEXPECTED(p > end)) p = end; \
} while (0) } while (0)
#define PFETCH_S(c) do { \ #define PFETCH_S(c) do { \
c = ONIGENC_MBC_TO_CODE(enc, p, end); \ c = ONIGENC_MBC_TO_CODE(enc, p, end); \
p += ONIGENC_MBC_ENC_LEN(enc, p); \ p += ONIGENC_MBC_ENC_LEN(enc, p); \
if(UNEXPECTED(p > end)) p = end; \
} while (0) } while (0)
#define PPEEK (p < end ? ONIGENC_MBC_TO_CODE(enc, p, end) : PEND_VALUE) #define PPEEK (p < end ? ONIGENC_MBC_TO_CODE(enc, p, end) : PEND_VALUE)
@ -5410,6 +5413,9 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
} }
else { /* string */ else { /* string */
p = tok->backp + enclen(enc, tok->backp); p = tok->backp + enclen(enc, tok->backp);
int len;
SAFE_ENC_LEN(enc, tok->backp, end, len);
p = tok->backp + len;
} }
} }
break; break;

View File

@ -455,4 +455,16 @@ extern int onig_global_callout_names_free(void);
extern int onig_print_names(FILE*, regex_t*); extern int onig_print_names(FILE*, regex_t*);
#endif #endif
#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
# define UNEXPECTED(condition) __builtin_expect(condition, 0)
#else
# define UNEXPECTED(condition) (condition)
#endif
#define SAFE_ENC_LEN(enc, p, end, res) do { \
int __res = enclen(enc, p); \
if (UNEXPECTED(p + __res > end)) __res = end - p; \
res = __res; \
} while(0);
#endif /* REGPARSE_H */ #endif /* REGPARSE_H */

View File

@ -1238,7 +1238,6 @@ PHP_FUNCTION(mb_split)
size_t string_len; size_t string_len;
int err; int err;
size_t n;
zend_long count = -1; zend_long count = -1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|l", &arg_pattern, &arg_pattern_len, &string, &string_len, &count) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|l", &arg_pattern, &arg_pattern_len, &string, &string_len, &count) == FAILURE) {
@ -1296,8 +1295,8 @@ PHP_FUNCTION(mb_split)
} }
/* otherwise we just have one last element to add to the array */ /* otherwise we just have one last element to add to the array */
n = ((OnigUChar *)(string + string_len) - chunk_pos); if ((OnigUChar *)(string + string_len) > chunk_pos) {
if (n > 0) { size_t n = ((OnigUChar *)(string + string_len) - chunk_pos);
add_next_index_stringl(return_value, (char *)chunk_pos, n); add_next_index_stringl(return_value, (char *)chunk_pos, n);
} else { } else {
add_next_index_stringl(return_value, "", 0); add_next_index_stringl(return_value, "", 0);

View File

@ -0,0 +1,21 @@
--TEST--
Bug #77367 (Negative size parameter in mb_split)
--SKIPIF--
<?php
if (!extension_loaded('mbstring')) die('mbstring extension not available');
if (!function_exists('mb_split')) die('mb_split() not available');
?>
--FILE--
<?php
mb_regex_encoding('UTF-8');
var_dump(mb_split("\\w", "\xfc"));
?>
===DONE===
--EXPECT--
array(2) {
[0]=>
string(0) ""
[1]=>
string(0) ""
}
===DONE===

View File

@ -0,0 +1,13 @@
--TEST--
Bug #77370 (Buffer overflow on mb regex functions - fetch_token)
--SKIPIF--
<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?>
--FILE--
<?php
var_dump(mb_split(" \xfd",""));
?>
--EXPECT--
array(1) {
[0]=>
string(0) ""
}

View File

@ -0,0 +1,10 @@
--TEST--
Bug #77371 (heap buffer overflow in mb regex functions - compile_string_node)
--SKIPIF--
<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?>
--FILE--
<?php
var_dump(mb_ereg("()0\xfc00000\xfc00000\xfc00000\xfc",""));
?>
--EXPECT--
bool(false)

View File

@ -0,0 +1,16 @@
--TEST--
Bug #77381 (heap buffer overflow in multibyte match_at)
--SKIPIF--
<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?>
--FILE--
<?php
var_dump(mb_ereg("000||0\xfa","0"));
var_dump(mb_ereg("(?i)000000000000000000000\xf0",""));
var_dump(mb_ereg("0000\\"."\xf5","0"));
var_dump(mb_ereg("(?i)FFF00000000000000000\xfd",""));
?>
--EXPECT--
int(1)
bool(false)
bool(false)
bool(false)

View File

@ -2026,7 +2026,7 @@ next_extension:
} }
while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) { while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) {
pos = memchr(pos + 1, '.', filename_len - (pos - filename) + 1); pos = memchr(pos + 1, '.', filename_len - (pos - filename) - 1);
if (!pos) { if (!pos) {
return FAILURE; return FAILURE;
} }

View File

@ -0,0 +1,14 @@
--TEST--
PHP bug #77247 (heap buffer overflow in phar_detect_phar_fname_ext)
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
--FILE--
<?php
try {
var_dump(new Phar('a/.b', 0,'test.phar'));
} catch(UnexpectedValueException $e) {
echo "OK";
}
?>
--EXPECT--
OK

View File

@ -454,6 +454,10 @@ static u_char *php_parserr(u_char *cp, u_char *end, querybuf *answer, int type_t
GETLONG(ttl, cp); GETLONG(ttl, cp);
GETSHORT(dlen, cp); GETSHORT(dlen, cp);
CHECKCP(dlen); CHECKCP(dlen);
if (dlen == 0) {
/* No data in the response - nothing to do */
return NULL;
}
if (type_to_fetch != DNS_T_ANY && type != type_to_fetch) { if (type_to_fetch != DNS_T_ANY && type != type_to_fetch) {
cp += dlen; cp += dlen;
return cp; return cp;
@ -544,6 +548,9 @@ static u_char *php_parserr(u_char *cp, u_char *end, querybuf *answer, int type_t
CHECKCP(n); CHECKCP(n);
add_assoc_stringl(subarray, "tag", (char*)cp, n); add_assoc_stringl(subarray, "tag", (char*)cp, n);
cp += n; cp += n;
if ( (size_t) dlen < ((size_t)n) + 2 ) {
return NULL;
}
n = dlen - n - 2; n = dlen - n - 2;
CHECKCP(n); CHECKCP(n);
add_assoc_stringl(subarray, "value", (char*)cp, n); add_assoc_stringl(subarray, "value", (char*)cp, n);

View File

@ -166,7 +166,7 @@ void base64_decode_xmlrpc(struct buffer_st *bfr, const char *source, int length)
return; return;
} }
if (dtable[c] & 0x80) { if (dtable[(unsigned char)c] & 0x80) {
/* /*
fprintf(stderr, "Offset %i length %i\n", offset, length); fprintf(stderr, "Offset %i length %i\n", offset, length);
fprintf(stderr, "character '%c:%x:%c' in input file.\n", c, c, dtable[c]); fprintf(stderr, "character '%c:%x:%c' in input file.\n", c, c, dtable[c]);

View File

@ -720,6 +720,9 @@ xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTI
long byte_idx = XML_GetCurrentByteIndex(parser); long byte_idx = XML_GetCurrentByteIndex(parser);
/* int byte_total = XML_GetCurrentByteCount(parser); */ /* int byte_total = XML_GetCurrentByteCount(parser); */
const char * error_str = XML_ErrorString(err_code); const char * error_str = XML_ErrorString(err_code);
if(byte_idx > len) {
byte_idx = len;
}
if(byte_idx >= 0) { if(byte_idx >= 0) {
snprintf(buf, snprintf(buf,
sizeof(buf), sizeof(buf),

View File

@ -0,0 +1,10 @@
--TEST--
Bug #77242 (heap out of bounds read in xmlrpc_decode())
--SKIPIF--
<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
--FILE--
<?php
var_dump(xmlrpc_decode(base64_decode("PD94bWwgdmVyc2lvbmVuY29kaW5nPSJJU084ODU5NyKkpKSkpKSkpKSkpKSkpKSkpKSkpKSk")));
?>
--EXPECT--
NULL

View File

@ -0,0 +1,17 @@
--TEST--
Bug #77380 (Global out of bounds read in xmlrpc base64 code)
--SKIPIF--
<?php
if (!extension_loaded("xmlrpc")) print "skip";
?>
--FILE--
<?php
var_dump(xmlrpc_decode(base64_decode("PGJhc2U2ND7CkzwvYmFzZTY0Pgo=")));
?>
--EXPECT--
object(stdClass)#1 (2) {
["scalar"]=>
string(0) ""
["xmlrpc_type"]=>
string(6) "base64"
}