Sec Bug->Bug #78819 [Opn]: Heap Overflow in msg_send

From: Date: Tue, 19 Nov 2019 06:09:37 +0000
Subject: Sec Bug->Bug #78819 [Opn]: Heap Overflow in msg_send
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-223792@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=78819&edit=1 ID: 78819 Updated by: stas@php.net Reported by: jr at coredu dot mp Summary: Heap Overflow in msg_send Status: Open -Type: Security +Type: Bug Package: Semaphore related Operating System: 64 bit Posix Systems PHP Version: 7.3.11 Block user comment: N Private report: Y Previous Comments: ------------------------------------------------------------------------ [2019-11-17 11:37:41] cmb@php.net ext/sysvmsg/sysvmsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/sysvmsg/sysvmsg.c b/ext/sysvmsg/sysvmsg.c index 6384ace349..a0e188d980 100644 --- a/ext/sysvmsg/sysvmsg.c +++ b/ext/sysvmsg/sysvmsg.c @@ -391,7 +391,7 @@ PHP_FUNCTION(msg_send) sysvmsg_queue_t * mq = NULL; struct php_msgbuf * messagebuffer = NULL; /* buffer to transmit */ int result; - int message_len = 0; + size_t message_len = 0; RETVAL_FALSE; ------------------------------------------------------------------------ [2019-11-15 13:47:28] jr at coredu dot mp Description: ------------ When sending a message that is 0x7FFFFFFF bytes large (maximum positive 32 bit integer), an integer overflow in msg_send causes a subsequent memcpy to overflow the messagebuffer. ext/sysvmsg/sysvmsg.c: PHP_FUNCTION(msg_send) { ... int message_len = 0; if (do_serialize) { ... } else { char *p; switch (Z_TYPE_P(message)) { case IS_STRING: p = Z_STRVAL_P(message); message_len = Z_STRLEN_P(message); break; case IS_LONG: message_len = spprintf(&p, 0, ZEND_LONG_FMT, Z_LVAL_P(message)); break; case IS_FALSE: message_len = spprintf(&p, 0, "0"); break; case IS_TRUE: message_len = spprintf(&p, 0, "1"); break; case IS_DOUBLE: message_len = spprintf(&p, 0, "%F", Z_DVAL_P(message)); break; default: php_error_docref(NULL, E_WARNING, "Message parameter must be either a string or a number."); RETURN_FALSE; } messagebuffer = safe_emalloc(message_len, 1, sizeof(struct php_msgbuf)); memcpy(messagebuffer->mtext, p, message_len + 1); if (Z_TYPE_P(message) != IS_STRING) { efree(p); } } ... } Since message_len is a signed 32 bit integer, the maximum positive value that it can hold is 0x7FFFFFFF. When memcpy is called, 1 additional byte is added to message_len, this will overflow the integer and set the value to "-1". Memcpy actually expects an argument of type size_t which is an unsigned 64 bit integer. This means the 32 bit -1 will be implicitly converted to a 64 bit -1 and then interpreted as an unsigned value which is much larger than the allocated buffer. This causes a heap overflow. Test script: --------------- <?php ini_set("memory_limit", -1); $a = msg_get_queue(234); $a = msg_send($a, 1, str_repeat("a", 0x7FFFFFFF), false); echo "$a\n" ?> Expected result: ---------------- No Segmentation Fault Actual result: -------------- Segmentation Fault ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=78819&edit=1

« previous php.bugs (#223792) next »