Skip to content

Commit e463914

Browse files
committed
Fix socket_sendmsg() sending wrong fd for Socket objects in SCM_RIGHTS
The Socket-object branch of from_zval_write_fd_array_aux() indexed the fd array with the 1-based loop counter (iarr[i]) instead of iarr[i - 1] like the resource branch, leaving slot 0 zeroed so a single Socket delivered fd 0 (stdin) to the receiver. Broken since the 8.0 resource-to-object conversion. Closes GH-22338
1 parent 3704b9d commit e463914

3 files changed

Lines changed: 79 additions & 2 deletions

File tree

ext/sockets/conversions.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1385,7 +1385,7 @@ static void from_zval_write_fd_array_aux(zval *elem, unsigned i, void **args, se
13851385
return;
13861386
}
13871387

1388-
iarr[i] = sock->bsd_socket;
1388+
iarr[i - 1] = sock->bsd_socket;
13891389
return;
13901390
}
13911391

ext/sockets/tests/socket_cmsg_rights.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ if ($data["control"]) {
5858
if ($control["level"] == SOL_SOCKET &&
5959
$control["type"] == SCM_RIGHTS) {
6060
foreach ($control["data"] as $resource) {
61-
if (!is_resource($resource)) {
61+
if (!is_resource($resource) && !($resource instanceof Socket)) {
6262
echo "FAIL RES\n";
6363
var_dump($data);
6464
exit;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
--TEST--
2+
socket_sendmsg(): SCM_RIGHTS transfers Socket objects with the correct fds
3+
--EXTENSIONS--
4+
sockets
5+
--SKIPIF--
6+
<?php
7+
if (strtolower(substr(PHP_OS, 0, 3)) == 'win') {
8+
die('skip not for Microsoft Windows');
9+
}
10+
if (strtolower(substr(PHP_OS, 0, 3)) == 'aix') {
11+
die('skip not for AIX');
12+
}
13+
if (!defined('SCM_RIGHTS')) {
14+
die('skip SCM_RIGHTS not available');
15+
}
16+
?>
17+
--FILE--
18+
<?php
19+
$dir = sys_get_temp_dir();
20+
$rpath = $dir . "/socket_sendmsg_scm_rights_object_r.sock";
21+
$ppath1 = $dir . "/socket_sendmsg_scm_rights_object_p1.sock";
22+
$ppath2 = $dir . "/socket_sendmsg_scm_rights_object_p2.sock";
23+
@unlink($rpath);
24+
@unlink($ppath1);
25+
@unlink($ppath2);
26+
27+
$recv = socket_create(AF_UNIX, SOCK_DGRAM, 0);
28+
socket_bind($recv, $rpath);
29+
30+
$send = socket_create(AF_UNIX, SOCK_DGRAM, 0);
31+
socket_connect($send, $rpath);
32+
33+
// Two Socket objects in a single SCM_RIGHTS message, each bound to a known
34+
// path so the received fds can be identified and ordered via getsockname().
35+
$payload1 = socket_create(AF_UNIX, SOCK_DGRAM, 0);
36+
socket_bind($payload1, $ppath1);
37+
$payload2 = socket_create(AF_UNIX, SOCK_DGRAM, 0);
38+
socket_bind($payload2, $ppath2);
39+
40+
socket_sendmsg($send, [
41+
'iov' => ['x'],
42+
'control' => [[
43+
'level' => SOL_SOCKET,
44+
'type' => SCM_RIGHTS,
45+
'data' => [$payload1, $payload2],
46+
]],
47+
], 0);
48+
49+
$data = [
50+
'name' => [],
51+
'buffer_size' => 64,
52+
'controllen' => socket_cmsg_space(SOL_SOCKET, SCM_RIGHTS, 2),
53+
];
54+
socket_recvmsg($recv, $data, 0);
55+
56+
$got = $data['control'][0]['data'];
57+
var_dump(count($got));
58+
var_dump($got[0] instanceof Socket);
59+
var_dump($got[1] instanceof Socket);
60+
socket_getsockname($got[0], $addr0);
61+
socket_getsockname($got[1], $addr1);
62+
var_dump($addr0 === $ppath1);
63+
var_dump($addr1 === $ppath2);
64+
?>
65+
--CLEAN--
66+
<?php
67+
$dir = sys_get_temp_dir();
68+
@unlink($dir . "/socket_sendmsg_scm_rights_object_r.sock");
69+
@unlink($dir . "/socket_sendmsg_scm_rights_object_p1.sock");
70+
@unlink($dir . "/socket_sendmsg_scm_rights_object_p2.sock");
71+
?>
72+
--EXPECT--
73+
int(2)
74+
bool(true)
75+
bool(true)
76+
bool(true)
77+
bool(true)

0 commit comments

Comments
 (0)