Merge pull request #115823 from deralmas/what-the-fd

Wayland Embedder: Fix FD leak with inert objects
This commit is contained in:
Thaddeus Crews
2026-02-05 09:32:34 -06:00
2 changed files with 22 additions and 25 deletions

View File

@@ -2351,13 +2351,10 @@ void WaylandEmbedder::shutdown() {
}
}
Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, int *fds_requested) {
Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, LocalVector<int> &r_sent_fds) {
ERR_FAIL_NULL_V(info, ERR_BUG);
ERR_FAIL_NULL_V(fds_requested, ERR_BUG);
ERR_FAIL_NULL_V_MSG(info->direction == ProxyDirection::COMPOSITOR && client, ERR_BUG, "Wait, where did this message come from?");
*fds_requested = 0;
WaylandObject *object = nullptr;
uint32_t global_id = INVALID_ID;
@@ -2410,17 +2407,15 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
}
ERR_FAIL_NULL_V(message, ERR_BUG);
*fds_requested = String(message->signature).count("h");
LocalVector<int> sent_fds;
if (*fds_requested > 0) {
DEBUG_LOG_WAYLAND_EMBED(vformat("Requested %d FDs.", *fds_requested));
int fds_requested = String(message->signature).count("h");
if (fds_requested > 0) {
DEBUG_LOG_WAYLAND_EMBED(vformat("Requested %d FDs.", fds_requested));
List<int> &fd_queue = info->direction == ProxyDirection::COMPOSITOR ? client->fds : compositor_fds;
for (int i = 0; i < *fds_requested; ++i) {
for (int i = 0; i < fds_requested; ++i) {
ERR_FAIL_COND_V_MSG(fd_queue.is_empty(), ERR_BUG, "Out of FDs.");
DEBUG_LOG_WAYLAND_EMBED(vformat("Fetching FD %d.", fd_queue.front()->get()));
sent_fds.push_back(fd_queue.front()->get());
r_sent_fds.push_back(fd_queue.front()->get());
fd_queue.pop_front();
}
@@ -2429,6 +2424,7 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
if (object->destroyed) {
DEBUG_LOG_WAYLAND_EMBED("Ignoring message for inert object.");
// Inert object.
return OK;
}
@@ -2451,7 +2447,7 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
DEBUG_LOG_WAYLAND_EMBED("Falling back to generic handler.");
if (handle_generic_msg(client, object, message, info, buf)) {
send_raw_message(compositor_socket, { { buf, info->size } }, sent_fds);
send_raw_message(compositor_socket, { { buf, info->size } }, r_sent_fds);
}
} else {
uint32_t global_name = 0;
@@ -2522,7 +2518,7 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
buf[0] = instance_id;
if (handle_generic_msg(&c, local_obj.get(), message, info, buf, instance_id)) {
send_raw_message(c.socket, { { buf, info->size } }, sent_fds);
send_raw_message(c.socket, { { buf, info->size } }, r_sent_fds);
}
handled = true;
@@ -2558,7 +2554,7 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
DEBUG_LOG_WAYLAND_EMBED("Falling back to generic handler.");
if (handle_generic_msg(&c, local_obj.get(), message, info, buf)) {
send_raw_message(c.socket, { { buf, info->size } }, sent_fds);
send_raw_message(c.socket, { { buf, info->size } }, r_sent_fds);
}
handled = true;
@@ -2594,7 +2590,7 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
buf[0] = local_id;
if (handle_generic_msg(client, local_obj.get(), message, info, buf)) {
send_raw_message(client->socket, { { buf, info->size } }, sent_fds);
send_raw_message(client->socket, { { buf, info->size } }, r_sent_fds);
}
} else {
WARN_PRINT_ONCE(vformat("[Wayland Embedder] Unexpected client-less event from %s#g0x%x. Object has probably leaked.", object->interface->name, global_id));
@@ -2603,11 +2599,6 @@ Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *in
}
}
for (int fd : sent_fds) {
DEBUG_LOG_WAYLAND_EMBED(vformat("Closing fd %d.", fd));
close(fd);
}
return OK;
}
@@ -2730,8 +2721,6 @@ Error WaylandEmbedder::handle_sock(int p_fd) {
full_msg.msg_control = nullptr;
full_msg.msg_controllen = 0;
int fds_requested = 0;
Client *client = nullptr;
if (p_fd == compositor_socket) {
// Let's figure out the recipient of the message.
@@ -2747,12 +2736,20 @@ Error WaylandEmbedder::handle_sock(int p_fd) {
client = &clients[p_fd];
}
if (handle_msg_info(client, &info, msg_buf.ptr(), &fds_requested) != OK) {
return ERR_BUG;
LocalVector<int> sent_fds;
Error err = handle_msg_info(client, &info, msg_buf.ptr(), sent_fds);
for (int fd : sent_fds) {
DEBUG_LOG_WAYLAND_EMBED(vformat("Closing fd %d.", fd));
close(fd);
}
DEBUG_LOG_WAYLAND_EMBED(" === END PACKET === ");
if (err != OK) {
return ERR_BUG;
}
return OK;
}

View File

@@ -610,7 +610,7 @@ class WaylandEmbedder {
void shutdown();
bool handle_generic_msg(Client *client, const WaylandObject *p_object, const struct wl_message *message, const struct msg_info *info, uint32_t *buf, uint32_t instance_id = INVALID_ID);
Error handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, int *fds_requested);
Error handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, LocalVector<int> &r_fds_requested);
Error handle_sock(int p_fd);
void handle_fd(int p_fd, int p_revents);