mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-04-09 08:21:08 -04:00
test: add unit test for fds mismatch
This commit is contained in:
parent
c9ecbf9fab
commit
337801717e
1 changed files with 100 additions and 0 deletions
|
|
@ -3,6 +3,7 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <spa/pod/builder.h>
|
||||
#include <spa/pod/parser.h>
|
||||
|
|
@ -165,6 +166,85 @@ static void test_reentering(struct pw_protocol_native_connection *in,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a packet claiming more FDs in its header than were actually
|
||||
* sent via SCM_RIGHTS is rejected. Without the n_fds validation this
|
||||
* would cause the receiver to read uninitialised / stale FD values.
|
||||
*/
|
||||
static void test_spoofed_fds(struct pw_protocol_native_connection *in,
|
||||
struct pw_protocol_native_connection *out)
|
||||
{
|
||||
const struct pw_protocol_native_message *msg;
|
||||
int res;
|
||||
|
||||
/*
|
||||
* First, send a valid message through the normal API so that the
|
||||
* receiver's version handshake happens (it switches to HDR_SIZE=16
|
||||
* on the first message). Use a message with 0 FDs.
|
||||
*/
|
||||
{
|
||||
struct spa_pod_builder *b;
|
||||
struct pw_protocol_native_message *wmsg;
|
||||
|
||||
b = pw_protocol_native_connection_begin(out, 0, 1, &wmsg);
|
||||
spa_assert_se(b != NULL);
|
||||
spa_pod_builder_add_struct(b, SPA_POD_Int(0));
|
||||
pw_protocol_native_connection_end(out, b);
|
||||
pw_protocol_native_connection_flush(out);
|
||||
|
||||
/* Consume it on the reading side */
|
||||
res = pw_protocol_native_connection_get_next(in, &msg);
|
||||
spa_assert_se(res == 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now craft a raw packet on the wire that claims n_fds=5 in the
|
||||
* header but send 0 actual FDs via SCM_RIGHTS.
|
||||
*
|
||||
* v3 header layout (16 bytes / 4 uint32s):
|
||||
* p[0] = id
|
||||
* p[1] = (opcode << 24) | (payload_size & 0xffffff)
|
||||
* p[2] = seq
|
||||
* p[3] = n_fds
|
||||
*
|
||||
* We need a minimal valid SPA pod as payload.
|
||||
*/
|
||||
{
|
||||
/* Build a tiny SPA pod: struct { Int(0) } */
|
||||
uint8_t payload[16];
|
||||
struct spa_pod_builder pb;
|
||||
|
||||
spa_pod_builder_init(&pb, payload, sizeof(payload));
|
||||
spa_pod_builder_add_struct(&pb, SPA_POD_Int(0));
|
||||
|
||||
uint32_t payload_size = pb.state.offset;
|
||||
uint32_t header[4];
|
||||
|
||||
header[0] = 1; /* id */
|
||||
header[1] = (5u << 24) | (payload_size & 0xffffff); /* opcode=5, size */
|
||||
header[2] = 0; /* seq */
|
||||
header[3] = 5; /* SPOOFED: claim 5 fds, send 0 */
|
||||
|
||||
struct iovec iov[2];
|
||||
struct msghdr mh = { 0 };
|
||||
|
||||
iov[0].iov_base = header;
|
||||
iov[0].iov_len = sizeof(header);
|
||||
iov[1].iov_base = payload;
|
||||
iov[1].iov_len = payload_size;
|
||||
mh.msg_iov = iov;
|
||||
mh.msg_iovlen = 2;
|
||||
/* No msg_control — 0 FDs via SCM_RIGHTS */
|
||||
|
||||
ssize_t sent = sendmsg(out->fd, &mh, MSG_NOSIGNAL);
|
||||
spa_assert_se(sent == (ssize_t)(sizeof(header) + payload_size));
|
||||
}
|
||||
|
||||
/* The receiver must reject this packet */
|
||||
res = pw_protocol_native_connection_get_next(in, &msg);
|
||||
spa_assert_se(res == -EPROTO);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct pw_main_loop *loop;
|
||||
|
|
@ -198,6 +278,26 @@ int main(int argc, char *argv[])
|
|||
|
||||
pw_protocol_native_connection_destroy(in);
|
||||
pw_protocol_native_connection_destroy(out);
|
||||
|
||||
/* test_spoofed_fds needs its own connection pair */
|
||||
{
|
||||
int fds2[2];
|
||||
struct pw_protocol_native_connection *in2, *out2;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds2) < 0)
|
||||
spa_assert_not_reached();
|
||||
|
||||
in2 = pw_protocol_native_connection_new(context, fds2[0]);
|
||||
spa_assert_se(in2 != NULL);
|
||||
out2 = pw_protocol_native_connection_new(context, fds2[1]);
|
||||
spa_assert_se(out2 != NULL);
|
||||
|
||||
test_spoofed_fds(in2, out2);
|
||||
|
||||
pw_protocol_native_connection_destroy(in2);
|
||||
pw_protocol_native_connection_destroy(out2);
|
||||
}
|
||||
|
||||
pw_context_destroy(context);
|
||||
pw_main_loop_destroy(loop);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue