Skip to content

input/keyboard: Send keymaps as read-only fds - #2217

Open
cprussin wants to merge 1 commit into
Smithay:masterfrom
cprussin:keymap-read-only-fd
Open

cprussin wants to merge 1 commit into
Smithay:masterfrom
cprussin:keymap-read-only-fd

Conversation

@cprussin

Copy link
Copy Markdown

Description

I'm working on a project around smithay; I have a user of that project who runs it within SELinux. They recently reported that within the SELinux context, the fd is refused, even though it is write-sealed.

It seems that wlroots avoids this by sending a read-only fd.

This PR changes smithay to do the same thing. Specifically:

  • SealedFile::with_data (Linux, Android): after sealing, reopen /proc/self/fd/<n> with O_RDONLY and keep that fd. FreeBSD is unchanged, since it has no /proc/self/fd.
  • KeymapFile::with_fd (wl_keyboard < 7): write a named tempfile, open it read-only and send that. The file is removed on drop.

DISCLAIMER: This PR was generated by an LLM. However, I reviewed it and the code seems reasonable to me. I am no expert in this domain, so I sincerely apologize if this is not a valuable contribution.

Checklist

@ids1024

ids1024 commented Oct 15, 2026

Copy link
Copy Markdown
Member

Using /proc/self/fd/* is a little ugly, though I suppose there's nothing unsafe or racy about it (I wish there was a syscall to drop write permission on an fd...).

I don't really understand why this would break under SELinux, but to be fair I don't have that much experience with it and SELinux is pretty complicated.

...But cosmic-comp and niri are both packaged by Fedora, which uses SELinux, so it doesn't appear to be broken in general? Is there some particular SELinux configuration that causes issues with this? Or specific clients?

@ids1024

ids1024 commented Oct 15, 2026

Copy link
Copy Markdown
Member

https://wayland.app/protocols/wayland#wl_keyboard:event:keymap only requires that the FD can be read-only mmapped (with MAP_PRIVATE in version 7 or later), so a client failing for an fd meeting that requirement seems to be an incorrect implementation.

If that behavior is reasonable, it should be documented in the protocol specification.

@cprussin

Copy link
Copy Markdown
Author

hey @ids1024 thanks for looking!

It's not stock Fedora... the dude who reported this to me runs a custom policy that confines wezterm-gui in its own domain, and that domain has read/map but not write on the compositor's memfd. Fedora's targeted policy leaves desktop apps unconfined, so cosmic-comp and niri users won't hit this.

It's also not something the guy can work around. When an fd is passed over SCM_RIGHTS, SELinux (selinux_file_receive) checks the receiver's permissions against the fd's open mode, so an O_RDWR fd needs write even though it's write-sealed. The kernel drops the fd before the client ever sees it, so wezterm just gets no keymap and exits.

wlroots already sends an O_RDONLY fd for this reason (allocate_shm_file_pair), so the same policy works there. Sending read-only seems like the least-privilege choice regardless, since clients only need to read and mmap it. I'm happy to also propose a note in the protocol docs if you think that's worthwhile.

I'm happy to get an AVC denial log from the reporter if it will help.

@ids1024

ids1024 commented Oct 15, 2026

Copy link
Copy Markdown
Member

Sending read-only seems like the least-privilege choice regardless

With write sealing I think it's effectively the same permissions?

But if wlroots finds it useful to do this, and has no issues, it's probably reasonable for Smithay to as well.

I'm happy to get an AVC denial log from the reporter if it will help.

It might be nice to see an SELinux configuration file that has the minimum change to see this behavior.

cprussin added a commit to cprussin/smithay that referenced this pull request Oct 15, 2026
Clients confined by SELinux can be refused a writable fd they have no
write permission for, even a write-sealed memfd. wezterm, for one, then
exits. wlroots sends a read-only fd.

- SealedFile: reopen the sealed memfd O_RDONLY via /proc/self/fd on
  Linux and Android.
- KeymapFile::with_fd: for wl_keyboard < 7, reopen the temporary file
  O_RDONLY and send that.

Backport of Smithay#2217 onto v0.7.0.

Co-Authored-By: Connor Prussin <connor@prussin.net>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VcHGGcqy12FjbuwoZ6NfRz
@cprussin
cprussin force-pushed the keymap-read-only-fd branch from 5b200c7 to 35e0246 Compare October 15, 2026 22:27
cprussin added a commit to cprussin/domicile that referenced this pull request Oct 15, 2026
- Patch Smithay 0.7.0 with Smithay/smithay#2217, backported on the
  fork's `domicile-0.7` branch. Smithay sends `wl_keyboard.keymap` as
  an O_RDWR fd, which SELinux refuses confined clients such as wezterm.
- `flake.nix`: `outputHashes` for the git dependency.
- domicile-test-client: `--wl-seat-v7`, and the `keymap` trace names
  the fd's access mode.
- New `a_client_is_handed_a_read_only_keymap` checks both of Smithay's
  keymap paths (`wl_seat` 7 and 5).
- ROADMAP: drop the patch once a Smithay release contains #2217.



Claude-Session: https://claude.ai/code/session_01VcHGGcqy12FjbuwoZ6NfRz

Co-authored-by: Claude <noreply@anthropic.com>
@Ploug

Ploug commented Oct 16, 2026

Copy link
Copy Markdown

Hi there, I’m the reporter of this.
We run terminal clients under a restricted SELinux policy and we need each client to receive the compositor’s keyboard keymap without granting unnecessary write permission to it, as the client only needs to read and map the data.

Disclaimer the rest of this comment is made entirely by my AI agent under my review, as I personally do not have deep enough understanding of Smithay to understand the consequences for your project - only my specific requirements within my setup. I have attached a zip with the full reproduction scripts and guide - this too is created by the AI agent and reviewed by me.

smithay-2217-review-20261016.zip

Here is a reduced SCM_RIGHTS reproducer.
Keep the two attached scripts together; on an enforcing Fedora 44 test system, run as root: python3 run-repro.py.
The receiver uses SELinuxContext=system_u:system_r:container_t:s0; the sender is unconfined_t.

Both sends reference the same memfd with seals 15 (SEAL|SHRINK|GROW|WRITE). O_RDWR: bytes arrive, no fd, MSG_CTRUNC, write AVC. O_RDONLY: one fd arrives, matching inode/seals, no truncation.

SELinux’s receive hook uses file_to_av(), which requests write for FMODE_WRITE without consulting seals. The seal protects content; opening read-only avoids that extra receipt permission.

There is a correction to the earlier read/map statement: this tested policy denies map too; the received read-only fd’s PROT_READ|MAP_PRIVATE mmap fails with EACCES and a separate map AVC. That remains our policy work.

Tested: kernel 7.2.10-200.fc44, selinux-policy-targeted 44.11-1.fc44, container-selinux 2.251.0-1.fc44. No policy changes were made; the guest already contained local service modules. Pristine Fedora and patched-Smithay/client success remain untested.

We can supply more information if you like.

@cprussin

Copy link
Copy Markdown
Author

hey @ids1024 just checking in here -- is @Ploug 's repro sufficient? Thanks!

Clients confined by SELinux can be refused a writable fd they have no
write permission for, even a write-sealed memfd. wezterm, for one, then
exits. wlroots sends a read-only fd.

- SealedFile: reopen the sealed memfd O_RDONLY via /proc/self/fd on
  Linux and Android.
- KeymapFile::with_fd: for wl_keyboard < 7, reopen the temporary file
  O_RDONLY and send that.

This change was written with the help of an AI assistant (Claude Code).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtB9sCPmmMWHULi75nv7qG
@cprussin
cprussin force-pushed the keymap-read-only-fd branch from 35e0246 to ca089d9 Compare October 27, 2026 19:40
@cprussin

cprussin commented Nov 1, 2026

Copy link
Copy Markdown
Author

hey @ids1024 just a friendly nudge here, any chance we can move this forward? I'd love to remove my local patch for this.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants