Skip to content

Commit fca8166

Browse files
committed
Fix socket_sendmsg() sending wrong fd for Socket objects in SCM_RIGHTS
from_array_iterate() yields a 1-based index. The Socket-object branch of from_zval_write_fd_array_aux() wrote iarr[i] while the resource branch correctly used iarr[i - 1], so the first descriptor slot was left zeroed and every object descriptor was shifted up by one, with the last truncated by cmsg_len. socket_sendmsg() therefore transmitted the wrong descriptors (the first always fd 0) whenever a Socket object was passed in an SCM_RIGHTS control message. Closes GH-22338
1 parent a480965 commit fca8166

3 files changed

Lines changed: 67 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: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
socket_sendmsg(): SCM_RIGHTS transfers a Socket object with the correct fd
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+
$ppath = $dir . "/socket_sendmsg_scm_rights_object_p.sock";
22+
@unlink($rpath);
23+
@unlink($ppath);
24+
25+
$recv = socket_create(AF_UNIX, SOCK_DGRAM, 0);
26+
socket_bind($recv, $rpath);
27+
28+
$send = socket_create(AF_UNIX, SOCK_DGRAM, 0);
29+
socket_connect($send, $rpath);
30+
31+
// Pass a single Socket object, bound to a known path so the received fd
32+
// can be identified via getsockname().
33+
$payload = socket_create(AF_UNIX, SOCK_DGRAM, 0);
34+
socket_bind($payload, $ppath);
35+
36+
socket_sendmsg($send, [
37+
'iov' => ['x'],
38+
'control' => [[
39+
'level' => SOL_SOCKET,
40+
'type' => SCM_RIGHTS,
41+
'data' => [$payload],
42+
]],
43+
], 0);
44+
45+
$data = [
46+
'name' => [],
47+
'buffer_size' => 64,
48+
'controllen' => socket_cmsg_space(SOL_SOCKET, SCM_RIGHTS, 1),
49+
];
50+
socket_recvmsg($recv, $data, 0);
51+
52+
$got = $data['control'][0]['data'][0];
53+
var_dump($got instanceof Socket);
54+
socket_getsockname($got, $addr);
55+
var_dump($addr === $ppath);
56+
?>
57+
--CLEAN--
58+
<?php
59+
$dir = sys_get_temp_dir();
60+
@unlink($dir . "/socket_sendmsg_scm_rights_object_r.sock");
61+
@unlink($dir . "/socket_sendmsg_scm_rights_object_p.sock");
62+
?>
63+
--EXPECT--
64+
bool(true)
65+
bool(true)

0 commit comments

Comments
 (0)