Pipewire/wireplumber#1171
Conversation
WirePlumber is the session manager for the PipeWire multimedia framework. On standard Linux desktops it runs as a user service (systemd --user). On embedded/headless platforms such as Qualcomm QLI 2.0 it runs as a system-wide service (User=pipewire under system systemd). Without a dedicated policy WirePlumber falls back to the generic initrc_t domain. In initrc_t, SELinux blocks D-Bus method replies from modemmanager_t and bluetooth_t which are required for telephony and Bluetooth audio routing. The blocked replies cause WirePlumber to crash with SIGSEGV every ~25 seconds resulting in wpctl set-default and pw-play --target failures. The policy uses a compile-time ifdef(`wireplumber_system_service') switch following the same pattern as pipewire.te to select between system-service and user-service mode at m4 build time. The policy module is placed in apps/ consistent with pipewire. The policy confines the wireplumber_t domain with: - Domain transition via wireplumber_exec_t - PipeWire socket communication via pipewire_stream_connect(), pipewire_use_fds() and pipewire_rw_tmpfs_files() for zero-copy memfd buffer sharing (depends on pipewire policy PR SELinuxProject#1109) - Runtime directory management (system: /run/wireplumber, user: XDG_RUNTIME_DIR/wireplumber) - tmpfs/memfd shared memory for zero-copy audio buffers - Config file mmap via files_map_usr_files() - D-Bus system bus; dbus_system_domain when system service - D-Bus communication with ModemManager, BlueZ and oFono - udev runtime access for device monitoring including netlink_kobject_uevent_socket and xattr filesystem getattr - systemd sessions and logind session directory watch - /etc/machine-id, procfs, sysfs - /dev/snd inotify watch for device monitoring - Bluetooth socket with listen permission for BlueZ audio routing - RTKit realtime scheduling support - systemd journal logging Also adds ofono_dbus_chat() interface to ofono.if to allow bidirectional D-Bus communication between a domain and oFono. Also adds wireplumber_role() interface to wireplumber.if to wire up role access for user-service mode, following the same pattern as pipewire_role() in pipewire.if. Also extends pipewire.fc to label /usr/bin/wpctl as pipewire_exec_t so that wpctl transitions into pipewire_t and operates without AVC denials. Note: This patch depends on the pipewire policy (PR SELinuxProject#1109). Please merge PR SELinuxProject#1109 before this patch, as wireplumber.te uses pipewire_stream_connect(), pipewire_use_fds() and pipewire_rw_tmpfs_files() defined in pipewire.if. Signed-off-by: Tejas Vijay Kanfade <tkanfade@qti.qualcomm.com>
This extra `#` character causes a compilation error when any interfaces are added to `ofono.if`. Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
Many programs interact with pulseaudio through an interface, and the pulseaudio module allows pulseaudio_t to expose that interface. Other programs (in particualr, pipewire acting as pipewire-pulseaudio) also expose this interface. Here, that interface is exposed via a new `pulseaudio_provide_server` interface, and pipewire uses it. Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
pipewire makes (at least) pipewire-*{,-manager}{,.lock} files under the
user runtime directory. This allows pipewire to properly label them.
Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
Many programs will talk with the pipewire server over dbus. Allow such activity via a new pipewire_dbus_chat interface. Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
Many programs will interact with pipewire through an interface. Define that interface, and expose it via the new pipewire_client_domain. Additionally, use it for the pipewire_client_t domain. Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
Pipewire manages its resource limits. As a relatively trusted service, this should be allowed. Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
Pipewire goes beyond serving audio, and needs access to video devices. Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
Pipewire will load modules to handle "hotplugged" audio and/or audio codec changes. Allow these module loads. Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
Command line utilities write to the terminal; allow such access. Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
These changes got wireplumber working on a Debian trixie desktop. Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
|
|
||
| pipewire_stream_connect(pipewire_client) | ||
| pipewire_rw_stream_sockets(pipewire_client) | ||
| pipewire_mmap_rw_tmpfs_files(pipewire_client) |
There was a problem hiding this comment.
Should probably ideally be pipewire_mmap_rw_inherited_tmpfs_files(pipewire_client)
With these memfd/shm aspects excluding open can be a real win.
Here are my pipewire_client direct rules (in case youre interested)
root@nimbus:~# sesearch -A -s pipewire.client.typeattr -ds
allow pipewire.client.typeattr pipewire.conf.file:dir { getattr ioctl lock open read search };
allow pipewire.client.typeattr pipewire.conf.file:file { getattr ioctl lock map open read };
allow pipewire.client.typeattr pipewire.data.file:dir { getattr ioctl lock open read search };
allow pipewire.client.typeattr pipewire.data.file:file { getattr ioctl lock map open read };
allow pipewire.client.typeattr pipewire.home.conf.file:dir { getattr ioctl lock open read search };
allow pipewire.client.typeattr pipewire.home.conf.file:file { getattr ioctl lock map open read };
allow pipewire.client.typeattr pipewire.memfd_file:memfd_file { append getattr ioctl lock map read write };
allow pipewire.client.typeattr pipewire.run.file:sock_file { append getattr ioctl lock open write };
allow pipewire.client.typeattr pipewire.subj:fd use;
allow pipewire.client.typeattr pipewire.subj:unix_stream_socket connectto;
allow pipewire.client.typeattr pipewire.tmpfs.file:file { append getattr ioctl lock map read write };
root@nimbus:~# sesearch -A -t pipewire.client.typeattr -dt
allow pipewire.subj pipewire.client.typeattr:dir { getattr ioctl lock open read search };
allow pipewire.subj pipewire.client.typeattr:fd use;
allow pipewire.subj pipewire.client.typeattr:file { getattr ioctl lock open read };
allow pipewire.subj pipewire.client.typeattr:lnk_file { getattr lock read };
root@nimbus:~# sesearch -A -t pipewire.client.memfd.typeattr -dt
allow pipewire.subj pipewire.client.memfd.typeattr:memfd_file { append getattr ioctl lock read write };
root@nimbus:~# sesearch -A -t pipewire.client.tmpfs.typeattr -dt
allow pipewire.subj pipewire.client.tmpfs.typeattr:file { append getattr ioctl lock read write };
The pipewire.client.tmpfs.typeattr is for compatibility with pre-mem_fd.
| # | ||
|
|
||
| pipewire_stream_connect(pipewire_client) | ||
| pipewire_rw_stream_sockets(pipewire_client) |
There was a problem hiding this comment.
This is questionable. AVC denial of the event that prompted you to add this would be interesting to interpret. Could just be a leak unrelated to pipewire_client.
There was a problem hiding this comment.
I also noticed that you allow pw clients to dbus chat with pw. I actually don't have these rules (and see these accesses) in my policy but pw indeed maintains a name on the user dbus ... I wonder whether that pipewire_rw_stream_sockets(pipewire_client) might be due to that socket being passed through dbus in your scenario. I am just comparing your rules to what I have as per my sesearch analysis.
There was a problem hiding this comment.
o wait ...
root@nimbus:~# sesearch --dontaudit -t pipewire.subj -dt
dontaudit pautils.subj pipewire.subj:unix_stream_socket { append bind connect getattr getopt ioctl read setopt shutdown write };
dontaudit pipewire.subj pipewire.subj:capability net_admin;
So yes I am pretty sure this is related to pipewire-pulse one way or another. Should probably be dontaudited.
| allow pipewire_t pipewire_client:fd use; | ||
|
|
||
| optional_policy(` | ||
| pipewire_dbus_chat(pipewire_client) |
There was a problem hiding this comment.
I guess this is pipewire-pulse/org.pulseaudio.Server. Maybe I am overlooking something. Would be nice if there is a way to separate the pulseaudio compat rules because pulseaudio is on its way out. I have a sepearate module for pulseaudio compat specific rules. So that I can just delete that when I decide to get rid of my pipewire-pulse support.
| @@ -1,5 +1,6 @@ | |||
| # PipeWire daemon executable. | |||
| /usr/bin/pipewire -- gen_context(system_u:object_r:pipewire_exec_t,s0) | |||
| /usr/bin/wpctl -- gen_context(system_u:object_r:pipewire_exec_t,s0) | |||
There was a problem hiding this comment.
This does not belong here as its part of wireplumber and even if then pipewire_client_exec_t would probably be much more appropriate than pipewire_exec_t.
| allow wireplumber_t self:unix_dgram_socket create_socket_perms; | ||
|
|
||
| # Bluetooth socket (for BlueZ audio routing) | ||
| allow wireplumber_t self:bluetooth_socket { create bind setopt listen }; |
| allow wireplumber_t self:bluetooth_socket { create bind setopt listen }; | ||
|
|
||
| # netlink kobject uevent socket (for udev device monitoring) | ||
| allow wireplumber_t self:netlink_kobject_uevent_socket { create bind setopt getattr getopt }; |
| # netlink kobject uevent socket (for udev device monitoring) | ||
| allow wireplumber_t self:netlink_kobject_uevent_socket { create bind setopt getattr getopt }; | ||
|
|
||
| dev_read_sysfs(wireplumber_t) |
There was a problem hiding this comment.
Eventually would be nice if we could create some order in /sys and then it would be useful to know what exactly wireplumber_t is accessing below /sys. Then again it access a lot there so maybe best to not go there yet.
| fs_getattr_xattr_fs(wireplumber_t) | ||
|
|
||
| # v4l device getattr (video device enumeration) | ||
| dev_dontaudit_getattr_video_dev(wireplumber_t) |
There was a problem hiding this comment.
Probably best to just let it do its thing?
There was a problem hiding this comment.
root@nimbus:~# sesearch -A -s wireplumber.subj -t v4l.nodedev -ds
allow wireplumber.subj v4l.nodedev:chr_file { append getattr ioctl lock open read watch write };
|
|
||
| # Access PipeWire tmpfs shared memory (memfd zero-copy buffers) | ||
| optional_policy(` | ||
| pipewire_rw_tmpfs_files(wireplumber_t) |
There was a problem hiding this comment.
I would argue that wireplumber_t should probably be associated with pipewire_client instead.
wireplumber_tmpfs_t would then ideally also be associated with pipewire_client_tmpfs_type
Also again. These accesses are inherited. Open permission should not be needed. I believe that if one just consistently omits open when its not needed that this is worth the trouble in the longer run.
There was a problem hiding this comment.
So one could have a macro like:
pipewire_client(wireplumber_t, wireplumber_tmpfs_t)
Something like (untested):
interface pipewire_client(`,'
gen_require(` attribute pipewire_client_type, pipewire_client_tmpfs_type; ')
typeattribute $1 pipewire_client_type;
typeattribute $2 pipewire_client_tmpfs_type;
')
| ') | ||
|
|
||
| optional_policy(` | ||
| systemd_read_journal_files(wireplumber_t) |
There was a problem hiding this comment.
questionable. Have AVC denials?
| HOME_DIR/\.local/share/wireplumber(/.*)? gen_context(system_u:object_r:wireplumber_home_t,s0) | ||
|
|
||
| /run/wireplumber(/.*)? gen_context(system_u:object_r:wireplumber_runtime_t,s0) | ||
| /run/user/%{USERID}/wireplumber(/.*)? gen_context(system_u:object_r:wireplumber_runtime_t,s0) |
There was a problem hiding this comment.
Why did you add support for wireplumber_runtime_t sockets? Who calls wireplumber_stream_connect() and why?
| files_runtime_filetrans(wireplumber_t, wireplumber_runtime_t, { dir file sock_file }) | ||
| ',` | ||
| userdom_user_runtime_filetrans(wireplumber_t, wireplumber_runtime_t, dir) | ||
| userdom_user_home_dir_filetrans(wireplumber_t, wireplumber_home_t, dir) |
There was a problem hiding this comment.
There are no wireplumber_home_t dirs directly under user_home_dir_t dirs. This rule does not correspond to the wireplumber_home_t fc specs above.
| role wireplumber_roles types wireplumber_t; | ||
| ') | ||
|
|
||
| type wireplumber_home_t alias wireplumber_var_lib_t; |
There was a problem hiding this comment.
what is the point of that typealias? wireplumber_var_lib_t is not referenced anywhere?
|
@kcinimod-defensec Thank you for the review! I don't have time right now to respond to all of this (in particular, I'll want to demonstrate specific actions that break if I remove anything and/or figure out what wasn't actually necessary). This will take a minute, but I will work on it. |
The new pipewire module needs some changes to work on the desktop. I've also included @tkanfade's new wireplumber module, and changes atop it that I needed to get everything working.
I'm happy to divide these changes however makes everyone happy, but the current state of refpolicy main is nonfunctional.
There are also some comments about consolidating al of pulseaudio, pipewire, alsa, et. al. I take no position on that issue beyond also including wireplumber in that discussion.