mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Fix GHSA-3cr5-j632-f35r: Null byte in hostnames
This fixes stream_socket_client() and fsockopen(). Specifically it adds a check to parse_ip_address_ex and it also makes sure that the \0 is not ignored in fsockopen() hostname formatting.
This commit is contained in:
parent
c5f1ae38a2
commit
27e67cc371
4 changed files with 78 additions and 5 deletions
|
@ -23,6 +23,28 @@
|
|||
#include "php_network.h"
|
||||
#include "file.h"
|
||||
|
||||
static size_t php_fsockopen_format_host_port(char **message, const char *prefix, size_t prefix_len,
|
||||
const char *host, size_t host_len, zend_long port)
|
||||
{
|
||||
char portbuf[32];
|
||||
int portlen = snprintf(portbuf, sizeof(portbuf), ":" ZEND_LONG_FMT, port);
|
||||
size_t total_len = prefix_len + host_len + portlen;
|
||||
|
||||
char *result = emalloc(total_len + 1);
|
||||
|
||||
if (prefix_len > 0) {
|
||||
memcpy(result, prefix, prefix_len);
|
||||
}
|
||||
memcpy(result + prefix_len, host, host_len);
|
||||
memcpy(result + prefix_len + host_len, portbuf, portlen);
|
||||
|
||||
result[total_len] = '\0';
|
||||
|
||||
*message = result;
|
||||
|
||||
return total_len;
|
||||
}
|
||||
|
||||
/* {{{ php_fsockopen() */
|
||||
|
||||
static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
|
||||
|
@ -62,11 +84,12 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
|
|||
}
|
||||
|
||||
if (persistent) {
|
||||
spprintf(&hashkey, 0, "pfsockopen__%s:" ZEND_LONG_FMT, host, port);
|
||||
php_fsockopen_format_host_port(&hashkey, "pfsockopen__", strlen("pfsockopen__"), host,
|
||||
host_len, port);
|
||||
}
|
||||
|
||||
if (port > 0) {
|
||||
hostname_len = spprintf(&hostname, 0, "%s:" ZEND_LONG_FMT, host, port);
|
||||
hostname_len = php_fsockopen_format_host_port(&hostname, "", 0, host, host_len, port);
|
||||
} else {
|
||||
hostname_len = host_len;
|
||||
hostname = host;
|
||||
|
|
21
ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt
Normal file
21
ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt
Normal file
|
@ -0,0 +1,21 @@
|
|||
--TEST--
|
||||
GHSA-3cr5-j632-f35r: Null byte termination in fsockopen()
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$server = stream_socket_server("tcp://localhost:0");
|
||||
|
||||
if (preg_match('/:(\d+)$/', stream_socket_get_name($server, false), $m)) {
|
||||
$client = fsockopen("localhost\0.example.com", intval($m[1]));
|
||||
var_dump($client);
|
||||
if ($client) {
|
||||
fclose($client);
|
||||
}
|
||||
}
|
||||
fclose($server);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
|
||||
Warning: fsockopen(): Unable to connect to localhost:%d (The hostname must not contain null bytes) in %s
|
||||
bool(false)
|
26
ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt
Normal file
26
ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt
Normal file
|
@ -0,0 +1,26 @@
|
|||
--TEST--
|
||||
GHSA-3cr5-j632-f35r: Null byte termination in stream_socket_client()
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$server = stream_socket_server("tcp://localhost:0");
|
||||
$socket_name = stream_socket_get_name($server, false);
|
||||
|
||||
if (preg_match('/:(\d+)$/', $socket_name, $m)) {
|
||||
$port = $m[1];
|
||||
$client = stream_socket_client("tcp://localhost\0.example.com:$port");
|
||||
var_dump($client);
|
||||
if ($client) {
|
||||
fclose($client);
|
||||
}
|
||||
} else {
|
||||
echo "Could not extract port from socket name: $socket_name\n";
|
||||
}
|
||||
|
||||
fclose($server);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
|
||||
Warning: stream_socket_client(): Unable to connect to tcp://localhost\0.example.com:%d (The hostname must not contain null bytes) in %s
|
||||
bool(false)
|
|
@ -594,12 +594,15 @@ static inline char *parse_ip_address_ex(const char *str, size_t str_len, int *po
|
|||
char *colon;
|
||||
char *host = NULL;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
char *p;
|
||||
if (memchr(str, '\0', str_len)) {
|
||||
*err = ZSTR_INIT_LITERAL("The hostname must not contain null bytes", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (*(str) == '[' && str_len > 1) {
|
||||
/* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
|
||||
p = memchr(str + 1, ']', str_len - 2);
|
||||
char *p = memchr(str + 1, ']', str_len - 2);
|
||||
if (!p || *(p + 1) != ':') {
|
||||
if (get_err) {
|
||||
*err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue