Skip to content

Pipewire/wireplumber#1171

Open
aerusso wants to merge 13 commits into
SELinuxProject:mainfrom
aerusso:mrs/pipewire2
Open

Pipewire/wireplumber#1171
aerusso wants to merge 13 commits into
SELinuxProject:mainfrom
aerusso:mrs/pipewire2

Conversation

@aerusso

@aerusso aerusso commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

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.

tkanfade and others added 13 commits June 29, 2026 04:23
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)

@kcinimod-defensec kcinimod-defensec Jun 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

@kcinimod-defensec kcinimod-defensec Jun 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread policy/modules/apps/wireplumber.te Outdated
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 };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_stream_socket_perms

Comment thread policy/modules/apps/wireplumber.te Outdated
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 };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_socket_perms

# 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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably best to just let it do its thing?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 };

Comment thread policy/modules/apps/wireplumber.te Outdated

# Access PipeWire tmpfs shared memory (memfd zero-copy buffers)
optional_policy(`
pipewire_rw_tmpfs_files(wireplumber_t)

@kcinimod-defensec kcinimod-defensec Jun 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the point of that typealias? wireplumber_var_lib_t is not referenced anywhere?

@aerusso

aerusso commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

@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.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants