Skip to content

Commit de6e36a

Browse files
committed
Check for closed sockets
1 parent 6f1b8ca commit de6e36a

8 files changed

+81
-41
lines changed

ext/sockets/php_sockets.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include <php.h>
3030
#ifdef PHP_WIN32
3131
# include "windows_common.h"
32+
#else
33+
# define IS_INVALID_SOCKET(a) (a->bsd_socket < 0)
3234
#endif
3335

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

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

76+
#define ENSURE_SOCKET_VALID(php_sock) do { \
77+
if (IS_INVALID_SOCKET(php_sock)) { \
78+
zend_argument_error(NULL, 1, "has already been closed"); \
79+
RETURN_THROWS(); \
80+
} \
81+
} while (0)
7482

7583
#ifdef PHP_WIN32
7684
struct sockaddr_un {

ext/sockets/sendrecvmsg.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ PHP_FUNCTION(socket_sendmsg)
179179
LONG_CHECK_VALID_INT(flags, 3);
180180

181181
php_sock = Z_SOCKET_P(zsocket);
182+
ENSURE_SOCKET_VALID(php_sock);
182183

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

222223
php_sock = Z_SOCKET_P(zsocket);
224+
ENSURE_SOCKET_VALID(php_sock);
223225

224226
msghdr = from_zval_run_conversions(zmsg, php_sock, from_zval_write_msghdr_recv,
225227
sizeof(*msghdr), "msghdr", &allocations, &err);

ext/sockets/sockets.c

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
# include <fcntl.h>
5252
# include <signal.h>
5353
# include <sys/uio.h>
54-
# define IS_INVALID_SOCKET(a) (a->bsd_socket < 0)
5554
# define set_errno(a) (errno = a)
5655
# include "php_sockets.h"
5756
# if HAVE_IF_NAMETOINDEX
@@ -659,6 +658,10 @@ static int php_sock_array_to_fd_set(uint32_t arg_num, zval *sock_array, fd_set *
659658
}
660659

661660
php_sock = Z_SOCKET_P(element);
661+
if (IS_INVALID_SOCKET(php_sock)) {
662+
zend_argument_type_error(arg_num, "contains a closed socket");
663+
return -1;
664+
}
662665

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

690693
php_sock = Z_SOCKET_P(element);
691694
ZEND_ASSERT(php_sock); /* element is supposed to be Socket object */
695+
ZEND_ASSERT(!IS_INVALID_SOCKET(php_sock));
692696

693697
if (PHP_SAFE_FD_ISSET(php_sock->bsd_socket, fds)) {
694698
/* Add fd to new array */
@@ -825,6 +829,7 @@ PHP_FUNCTION(socket_accept)
825829
}
826830

827831
php_sock = Z_SOCKET_P(arg1);
832+
ENSURE_SOCKET_VALID(php_sock);
828833

829834
object_init_ex(return_value, socket_ce);
830835
new_sock = Z_SOCKET_P(return_value);
@@ -847,6 +852,7 @@ PHP_FUNCTION(socket_set_nonblock)
847852
}
848853

849854
php_sock = Z_SOCKET_P(arg1);
855+
ENSURE_SOCKET_VALID(php_sock);
850856

851857
if (!Z_ISUNDEF(php_sock->zstream)) {
852858
php_stream *stream;
@@ -882,6 +888,7 @@ PHP_FUNCTION(socket_set_block)
882888
}
883889

884890
php_sock = Z_SOCKET_P(arg1);
891+
ENSURE_SOCKET_VALID(php_sock);
885892

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

922929
php_sock = Z_SOCKET_P(arg1);
930+
ENSURE_SOCKET_VALID(php_sock);
923931

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

942950
php_socket = Z_SOCKET_P(arg1);
951+
ENSURE_SOCKET_VALID(php_socket);
943952

944953
if (!Z_ISUNDEF(php_socket->zstream)) {
945954
php_stream *stream = NULL;
@@ -978,6 +987,7 @@ PHP_FUNCTION(socket_write)
978987
}
979988

980989
php_sock = Z_SOCKET_P(arg1);
990+
ENSURE_SOCKET_VALID(php_sock);
981991

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

10191029
php_sock = Z_SOCKET_P(arg1);
1030+
ENSURE_SOCKET_VALID(php_sock);
10201031

10211032
/* overflow check */
10221033
if ((length + 1) < 2) {
@@ -1081,6 +1092,7 @@ PHP_FUNCTION(socket_getsockname)
10811092
}
10821093

10831094
php_sock = Z_SOCKET_P(arg1);
1095+
ENSURE_SOCKET_VALID(php_sock);
10841096

10851097
sa = (struct sockaddr *) &sa_storage;
10861098

@@ -1152,6 +1164,7 @@ PHP_FUNCTION(socket_getpeername)
11521164
}
11531165

11541166
php_sock = Z_SOCKET_P(arg1);
1167+
ENSURE_SOCKET_VALID(php_sock);
11551168

11561169
sa = (struct sockaddr *) &sa_storage;
11571170

@@ -1264,6 +1277,7 @@ PHP_FUNCTION(socket_connect)
12641277
}
12651278

12661279
php_sock = Z_SOCKET_P(resource_socket);
1280+
ENSURE_SOCKET_VALID(php_sock);
12671281

12681282
switch(php_sock->type) {
12691283
#if HAVE_IPV6
@@ -1366,6 +1380,7 @@ PHP_FUNCTION(socket_bind)
13661380
}
13671381

13681382
php_sock = Z_SOCKET_P(arg1);
1383+
ENSURE_SOCKET_VALID(php_sock);
13691384

13701385
switch(php_sock->type) {
13711386
case AF_UNIX:
@@ -1443,6 +1458,7 @@ PHP_FUNCTION(socket_recv)
14431458
}
14441459

14451460
php_sock = Z_SOCKET_P(php_sock_res);
1461+
ENSURE_SOCKET_VALID(php_sock);
14461462

14471463
/* overflow check */
14481464
if ((len + 1) < 2) {
@@ -1482,13 +1498,14 @@ PHP_FUNCTION(socket_send)
14821498
RETURN_THROWS();
14831499
}
14841500

1501+
php_sock = Z_SOCKET_P(arg1);
1502+
ENSURE_SOCKET_VALID(php_sock);
1503+
14851504
if (len < 0) {
14861505
zend_argument_value_error(3, "must be greater than or equal to 0");
14871506
RETURN_THROWS();
14881507
}
14891508

1490-
php_sock = Z_SOCKET_P(arg1);
1491-
14921509
retval = send(php_sock->bsd_socket, buf, (buf_len < (size_t)len ? buf_len : (size_t)len), flags);
14931510

14941511
if (retval == (size_t)-1) {
@@ -1522,6 +1539,7 @@ PHP_FUNCTION(socket_recvfrom)
15221539
}
15231540

15241541
php_sock = Z_SOCKET_P(arg1);
1542+
ENSURE_SOCKET_VALID(php_sock);
15251543

15261544
/* overflow check */
15271545
/* Shouldthrow ? */
@@ -1635,13 +1653,14 @@ PHP_FUNCTION(socket_sendto)
16351653
RETURN_THROWS();
16361654
}
16371655

1656+
php_sock = Z_SOCKET_P(arg1);
1657+
ENSURE_SOCKET_VALID(php_sock);
1658+
16381659
if (len < 0) {
16391660
zend_argument_value_error(3, "must be greater than or equal to 0");
16401661
RETURN_THROWS();
16411662
}
16421663

1643-
php_sock = Z_SOCKET_P(arg1);
1644-
16451664
switch (php_sock->type) {
16461665
case AF_UNIX:
16471666
memset(&s_un, 0, sizeof(s_un));
@@ -1718,6 +1737,7 @@ PHP_FUNCTION(socket_get_option)
17181737
}
17191738

17201739
php_sock = Z_SOCKET_P(arg1);
1740+
ENSURE_SOCKET_VALID(php_sock);
17211741

17221742
if (level == IPPROTO_IP) {
17231743
switch (optname) {
@@ -1830,6 +1850,7 @@ PHP_FUNCTION(socket_set_option)
18301850
}
18311851

18321852
php_sock = Z_SOCKET_P(arg1);
1853+
ENSURE_SOCKET_VALID(php_sock);
18331854

18341855
set_errno(0);
18351856

@@ -2027,6 +2048,7 @@ PHP_FUNCTION(socket_shutdown)
20272048
}
20282049

20292050
php_sock = Z_SOCKET_P(arg1);
2051+
ENSURE_SOCKET_VALID(php_sock);
20302052

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

20512073
if (arg1) {
20522074
php_sock = Z_SOCKET_P(arg1);
2075+
ENSURE_SOCKET_VALID(php_sock);
2076+
20532077
RETVAL_LONG(php_sock->error);
20542078
} else {
20552079
RETVAL_LONG(SOCKETS_G(last_error));
@@ -2069,6 +2093,8 @@ PHP_FUNCTION(socket_clear_error)
20692093

20702094
if (arg1) {
20712095
php_sock = Z_SOCKET_P(arg1);
2096+
ENSURE_SOCKET_VALID(php_sock);
2097+
20722098
php_sock->error = 0;
20732099
} else {
20742100
SOCKETS_G(last_error) = 0;
@@ -2179,6 +2205,7 @@ PHP_FUNCTION(socket_export_stream)
21792205
}
21802206

21812207
socket = Z_SOCKET_P(zsocket);
2208+
ENSURE_SOCKET_VALID(socket);
21822209

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

25222549
socket = Z_SOCKET_P(arg1);
2550+
ENSURE_SOCKET_VALID(socket);
25232551

25242552
if (SOCKET_ERROR == WSADuplicateSocket(socket->bsd_socket, (DWORD)target_pid, &wi)) {
25252553
DWORD err = WSAGetLastError();

ext/sockets/tests/socket_export_stream-2.phpt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ $s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
2222
var_dump($s);
2323
socket_close($s);
2424

25-
var_dump(socket_export_stream($s));
25+
try {
26+
var_dump(socket_export_stream($s));
27+
} catch (Error $e) {
28+
echo $e->getMessage(), "\n";
29+
}
2630

2731
echo "Done.";
2832
?>
@@ -31,5 +35,5 @@ socket_export_stream(): Argument #1 ($socket) must be of type Socket, resource g
3135
socket_export_stream(): Argument #1 ($socket) must be of type Socket, resource given
3236
object(Socket)#%d (0) {
3337
}
34-
resource(7) of type (stream)
38+
socket_export_stream(): Argument #1 ($socket) has already been closed
3539
Done.

ext/sockets/tests/socket_export_stream-4.phpt

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,24 @@ function test($stream, $sock) {
1616
echo "stream_set_blocking ";
1717
try {
1818
print_r(stream_set_blocking($stream, 0));
19-
} catch (TypeError $e) {
20-
echo $e->getMessage(), "\n";
19+
} catch (Error $e) {
20+
echo get_class($e), ": ", $e->getMessage(), "\n";
2121
}
2222
echo "\n";
2323
}
2424
if ($sock !== null) {
2525
echo "socket_set_block ";
2626
try {
2727
print_r(socket_set_block($sock));
28-
} catch (TypeError $e) {
29-
echo $e->getMessage(), "\n";
28+
} catch (Error $e) {
29+
echo get_class($e), ": ", $e->getMessage(), "\n";
3030
}
3131
echo "\n";
3232
echo "socket_get_option ";
3333
try {
3434
print_r(socket_get_option($sock, SOL_SOCKET, SO_TYPE));
35-
} catch (TypeError $e) {
36-
echo $e->getMessage(), "\n";
35+
} catch (Error $e) {
36+
echo get_class($e), ": ", $e->getMessage(), "\n";
3737
}
3838
echo "\n";
3939
}
@@ -92,7 +92,7 @@ stream_set_blocking 1
9292

9393

9494
close stream
95-
stream_set_blocking stream_set_blocking(): supplied resource is not a valid stream resource
95+
stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource
9696

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

104104

105105
close socket
106-
stream_set_blocking stream_set_blocking(): supplied resource is not a valid stream resource
106+
stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource
107107

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

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

114112

115113
Done.

ext/sockets/tests/socket_import_stream-4.phpt

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,24 @@ function test($stream, $sock) {
1616
echo "stream_set_blocking ";
1717
try {
1818
print_r(stream_set_blocking($stream, 0));
19-
} catch (TypeError $e) {
20-
echo $e->getMessage(), "\n";
19+
} catch (Error $e) {
20+
echo get_class($e), ": ", $e->getMessage(), "\n";
2121
}
2222
echo "\n";
2323
}
2424
if ($sock !== null) {
2525
echo "socket_set_block ";
2626
try {
2727
print_r(socket_set_block($sock));
28-
} catch (TypeError $e) {
29-
echo $e->getMessage(), "\n";
28+
} catch (Error $e) {
29+
echo get_class($e), ": ", $e->getMessage(), "\n";
3030
}
3131
echo "\n";
3232
echo "socket_get_option ";
3333
try {
3434
print_r(socket_get_option($sock, SOL_SOCKET, SO_TYPE));
35-
} catch (TypeError $e) {
36-
echo $e->getMessage(), "\n";
35+
} catch (Error $e) {
36+
echo get_class($e), ": ", $e->getMessage(), "\n";
3737
}
3838
echo "\n";
3939
}
@@ -87,7 +87,7 @@ stream_set_blocking 1
8787

8888

8989
close stream
90-
stream_set_blocking stream_set_blocking(): supplied resource is not a valid stream resource
90+
stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource
9191

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

9999

100100
close socket
101-
stream_set_blocking stream_set_blocking(): supplied resource is not a valid stream resource
101+
stream_set_blocking TypeError: stream_set_blocking(): supplied resource is not a valid stream resource
102102

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

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

109107

110108
Done.

0 commit comments

Comments
 (0)