Wayland clients changing pid can create uncloseable windows
Affected version
OS: Debian Sid
Mutter version: 40.1
GNOME Shell version: 40.1
Mutter backend: Wayland
Bug summary
When a wayland client uses fork()
to get itself a new pid, the logic for killing windows in meta_window_kill
seems to fail.
Steps to reproduce
- Compile and run this gtk4 program: https://gitlab.gnome.org/-/snippets/2068
- Press "Fork"
- Try to close the window
- Alternatively, run the program again and repeat from step 2, pressing "Fork and sleep" this time
What happened
The window can't be closed, the force quit dialog has no effect and can't kill the window either. It can only be killed by using system monitor, or by opening terminal and running pkill, killall, etc.
What did you expect to happen
Force quit should be able to kill the client, or at least detect that the pid has already gone away.
Relevant logs, screenshots, screencasts etc.
Technically the case of just "Fork" without doing a sleep afterwards hangs because of a deadlock in GDBusConnection, the use of threading there is not safe to use with fork
. This is not a bug in Gio, but it does demonstrate the problem. The "Fork and sleep" case makes it clearer what is going on.
In both test cases, meta_window_kill
is sending signals to the wrong pid, because meta_window_get_pid
(and in turn wl_client_get_credentials
) only gets the pid once, and then caches it.
From the X11 side, running it as an X11 client with GDK_BACKEND=x11
will allow the force quit dialog to close the window, but the process continues to live in the background because the signal is still going to the old pid. This seems to not be fixable in Mutter alone because a similar type of pid caching also seems to happen in the X server: os/client.c#L287
As far as I know there isn't really a totally race-free way to handle this at the moment because that would require pidfds. but for wayland clients, getting SO_PEERCRED also uses the cached value in the kernel so the only real solution here seems to be to get a call to retrieve a pidfd for the current connected process...SO_PEERCRED
each time meta_window_get_pid
is called should at least improve the experience for a user with a stuck window.