Skip to content

Commit

Permalink
Check for closed sockets
Browse files Browse the repository at this point in the history
  • Loading branch information
nikic committed Aug 3, 2020
1 parent 6f1b8ca commit a0f43d9
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 43 deletions.
10 changes: 8 additions & 2 deletions ext/sockets/conversions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1341,10 +1341,16 @@ static void from_zval_write_fd_array_aux(zval *elem, unsigned i, void **args, se

if (Z_TYPE_P(elem) == IS_OBJECT && Z_OBJCE_P(elem) == socket_ce) {
php_socket *sock = Z_SOCKET_P(elem);
iarr[i] = sock->bsd_socket;
if (IS_INVALID_SOCKET(sock)) {
do_from_zval_err(ctx, "socket is already closed");
return;
}

iarr[i] = sock->bsd_socket;
return;
} else if (Z_TYPE_P(elem) == IS_RESOURCE) {
}

if (Z_TYPE_P(elem) == IS_RESOURCE) {
php_stream *stream;

stream = (php_stream *)zend_fetch_resource2_ex(elem, NULL, php_file_le_stream(), php_file_le_pstream());
Expand Down
8 changes: 8 additions & 0 deletions ext/sockets/php_sockets.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <php.h>
#ifdef PHP_WIN32
# include "windows_common.h"
#else
# define IS_INVALID_SOCKET(a) (a->bsd_socket < 0)
#endif

#define PHP_SOCKETS_VERSION PHP_VERSION
Expand Down Expand Up @@ -71,6 +73,12 @@ static inline php_socket *socket_from_obj(zend_object *obj) {

#define Z_SOCKET_P(zv) socket_from_obj(Z_OBJ_P(zv))

#define ENSURE_SOCKET_VALID(php_sock) do { \
if (IS_INVALID_SOCKET(php_sock)) { \
zend_argument_error(NULL, 1, "has already been closed"); \
RETURN_THROWS(); \
} \
} while (0)

#ifdef PHP_WIN32
struct sockaddr_un {
Expand Down
2 changes: 2 additions & 0 deletions ext/sockets/sendrecvmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ PHP_FUNCTION(socket_sendmsg)
LONG_CHECK_VALID_INT(flags, 3);

php_sock = Z_SOCKET_P(zsocket);
ENSURE_SOCKET_VALID(php_sock);

msghdr = from_zval_run_conversions(zmsg, php_sock, from_zval_write_msghdr_send,
sizeof(*msghdr), "msghdr", &allocations, &err);
Expand Down Expand Up @@ -220,6 +221,7 @@ PHP_FUNCTION(socket_recvmsg)
LONG_CHECK_VALID_INT(flags, 3);

php_sock = Z_SOCKET_P(zsocket);
ENSURE_SOCKET_VALID(php_sock);

msghdr = from_zval_run_conversions(zmsg, php_sock, from_zval_write_msghdr_recv,
sizeof(*msghdr), "msghdr", &allocations, &err);
Expand Down
38 changes: 33 additions & 5 deletions ext/sockets/sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
# include <fcntl.h>
# include <signal.h>
# include <sys/uio.h>
# define IS_INVALID_SOCKET(a) (a->bsd_socket < 0)
# define set_errno(a) (errno = a)
# include "php_sockets.h"
# if HAVE_IF_NAMETOINDEX
Expand Down Expand Up @@ -659,6 +658,10 @@ static int php_sock_array_to_fd_set(uint32_t arg_num, zval *sock_array, fd_set *
}

php_sock = Z_SOCKET_P(element);
if (IS_INVALID_SOCKET(php_sock)) {
zend_argument_type_error(arg_num, "contains a closed socket");
return -1;
}

PHP_SAFE_FD_SET(php_sock->bsd_socket, fds);
if (php_sock->bsd_socket > *max_fd) {
Expand Down Expand Up @@ -689,6 +692,7 @@ static int php_sock_array_from_fd_set(zval *sock_array, fd_set *fds) /* {{{ */

php_sock = Z_SOCKET_P(element);
ZEND_ASSERT(php_sock); /* element is supposed to be Socket object */
ZEND_ASSERT(!IS_INVALID_SOCKET(php_sock));

if (PHP_SAFE_FD_ISSET(php_sock->bsd_socket, fds)) {
/* Add fd to new array */
Expand Down Expand Up @@ -825,6 +829,7 @@ PHP_FUNCTION(socket_accept)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

object_init_ex(return_value, socket_ce);
new_sock = Z_SOCKET_P(return_value);
Expand All @@ -847,6 +852,7 @@ PHP_FUNCTION(socket_set_nonblock)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

if (!Z_ISUNDEF(php_sock->zstream)) {
php_stream *stream;
Expand Down Expand Up @@ -882,6 +888,7 @@ PHP_FUNCTION(socket_set_block)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

/* if socket was created from a stream, give the stream a chance to take
* care of the operation itself, thereby allowing it to update its internal
Expand Down Expand Up @@ -920,6 +927,7 @@ PHP_FUNCTION(socket_listen)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

if (listen(php_sock->bsd_socket, backlog) != 0) {
PHP_SOCKET_ERROR(php_sock, "unable to listen on socket", errno);
Expand All @@ -940,6 +948,7 @@ PHP_FUNCTION(socket_close)
}

php_socket = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_socket);

if (!Z_ISUNDEF(php_socket->zstream)) {
php_stream *stream = NULL;
Expand Down Expand Up @@ -978,6 +987,7 @@ PHP_FUNCTION(socket_write)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

if (length < 0) {
zend_argument_value_error(3, "must be greater than or equal to 0");
Expand Down Expand Up @@ -1017,6 +1027,7 @@ PHP_FUNCTION(socket_read)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

/* overflow check */
if ((length + 1) < 2) {
Expand Down Expand Up @@ -1081,6 +1092,7 @@ PHP_FUNCTION(socket_getsockname)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

sa = (struct sockaddr *) &sa_storage;

Expand Down Expand Up @@ -1152,6 +1164,7 @@ PHP_FUNCTION(socket_getpeername)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

sa = (struct sockaddr *) &sa_storage;

Expand Down Expand Up @@ -1264,6 +1277,7 @@ PHP_FUNCTION(socket_connect)
}

php_sock = Z_SOCKET_P(resource_socket);
ENSURE_SOCKET_VALID(php_sock);

switch(php_sock->type) {
#if HAVE_IPV6
Expand Down Expand Up @@ -1366,6 +1380,7 @@ PHP_FUNCTION(socket_bind)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

switch(php_sock->type) {
case AF_UNIX:
Expand Down Expand Up @@ -1443,6 +1458,7 @@ PHP_FUNCTION(socket_recv)
}

php_sock = Z_SOCKET_P(php_sock_res);
ENSURE_SOCKET_VALID(php_sock);

/* overflow check */
if ((len + 1) < 2) {
Expand Down Expand Up @@ -1482,13 +1498,14 @@ PHP_FUNCTION(socket_send)
RETURN_THROWS();
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

if (len < 0) {
zend_argument_value_error(3, "must be greater than or equal to 0");
RETURN_THROWS();
}

php_sock = Z_SOCKET_P(arg1);

retval = send(php_sock->bsd_socket, buf, (buf_len < (size_t)len ? buf_len : (size_t)len), flags);

if (retval == (size_t)-1) {
Expand Down Expand Up @@ -1522,6 +1539,7 @@ PHP_FUNCTION(socket_recvfrom)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

/* overflow check */
/* Shouldthrow ? */
Expand Down Expand Up @@ -1635,13 +1653,14 @@ PHP_FUNCTION(socket_sendto)
RETURN_THROWS();
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

if (len < 0) {
zend_argument_value_error(3, "must be greater than or equal to 0");
RETURN_THROWS();
}

php_sock = Z_SOCKET_P(arg1);

switch (php_sock->type) {
case AF_UNIX:
memset(&s_un, 0, sizeof(s_un));
Expand Down Expand Up @@ -1718,6 +1737,7 @@ PHP_FUNCTION(socket_get_option)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

if (level == IPPROTO_IP) {
switch (optname) {
Expand Down Expand Up @@ -1830,6 +1850,7 @@ PHP_FUNCTION(socket_set_option)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

set_errno(0);

Expand Down Expand Up @@ -2027,6 +2048,7 @@ PHP_FUNCTION(socket_shutdown)
}

php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

if (shutdown(php_sock->bsd_socket, how_shutdown) != 0) {
PHP_SOCKET_ERROR(php_sock, "Unable to shutdown socket", errno);
Expand All @@ -2050,6 +2072,8 @@ PHP_FUNCTION(socket_last_error)

if (arg1) {
php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

RETVAL_LONG(php_sock->error);
} else {
RETVAL_LONG(SOCKETS_G(last_error));
Expand All @@ -2069,6 +2093,8 @@ PHP_FUNCTION(socket_clear_error)

if (arg1) {
php_sock = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(php_sock);

php_sock->error = 0;
} else {
SOCKETS_G(last_error) = 0;
Expand Down Expand Up @@ -2179,6 +2205,7 @@ PHP_FUNCTION(socket_export_stream)
}

socket = Z_SOCKET_P(zsocket);
ENSURE_SOCKET_VALID(socket);

/* Either we already exported a stream or the socket came from an import,
* just return the existing stream */
Expand Down Expand Up @@ -2520,6 +2547,7 @@ PHP_FUNCTION(socket_wsaprotocol_info_export)
}

socket = Z_SOCKET_P(arg1);
ENSURE_SOCKET_VALID(socket);

if (SOCKET_ERROR == WSADuplicateSocket(socket->bsd_socket, (DWORD)target_pid, &wi)) {
DWORD err = WSAGetLastError();
Expand Down
8 changes: 6 additions & 2 deletions ext/sockets/tests/socket_export_stream-2.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ $s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
var_dump($s);
socket_close($s);

var_dump(socket_export_stream($s));
try {
var_dump(socket_export_stream($s));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

echo "Done.";
?>
Expand All @@ -31,5 +35,5 @@ socket_export_stream(): Argument #1 ($socket) must be of type Socket, resource g
socket_export_stream(): Argument #1 ($socket) must be of type Socket, resource given
object(Socket)#%d (0) {
}
resource(7) of type (stream)
socket_export_stream(): Argument #1 ($socket) has already been closed
Done.
22 changes: 10 additions & 12 deletions ext/sockets/tests/socket_export_stream-4.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@ function test($stream, $sock) {
echo "stream_set_blocking ";
try {
print_r(stream_set_blocking($stream, 0));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
} catch (Error $e) {
echo get_class($e), ": ", $e->getMessage(), "\n";
}
echo "\n";
}
if ($sock !== null) {
echo "socket_set_block ";
try {
print_r(socket_set_block($sock));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
} catch (Error $e) {
echo get_class($e), ": ", $e->getMessage(), "\n";
}
echo "\n";
echo "socket_get_option ";
try {
print_r(socket_get_option($sock, SOL_SOCKET, SO_TYPE));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
} catch (Error $e) {
echo get_class($e), ": ", $e->getMessage(), "\n";
}
echo "\n";
}
Expand Down Expand Up @@ -92,7 +92,7 @@ stream_set_blocking 1


close stream
stream_set_blocking stream_set_blocking(): supplied resource is not a valid stream resource
stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource

socket_set_block
Warning: socket_set_block(): unable to set blocking mode [%d]: %s in %s on line %d
Expand All @@ -103,13 +103,11 @@ Warning: socket_get_option(): Unable to retrieve socket option [%d]: %s in %s on


close socket
stream_set_blocking stream_set_blocking(): supplied resource is not a valid stream resource
stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource

socket_set_block
Warning: socket_set_block(): unable to set blocking mode [9]: Bad file descriptor in %s on line %d
socket_set_block Error: socket_set_block(): Argument #1 ($socket) has already been closed

socket_get_option
Warning: socket_get_option(): Unable to retrieve socket option [9]: Bad file descriptor in %s on line %d
socket_get_option Error: socket_get_option(): Argument #1 ($socket) has already been closed


Done.
Loading

0 comments on commit a0f43d9

Please sign in to comment.