Sec Bug->Bug #78819 [Opn]: Heap Overflow in msg_send
| From: | stas@php.net | 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