Systemd integration - arkq/bluez-alsa GitHub Wiki

Using BlueALSA with systemd

Introduction

Systemd (systemd) is now the most common system and service manager on mainstream linux distributions. The bluez-alsa project now includes systemd service unit files for the bluealsa daemon and the bluealsa-aplay utility.

There are many different scenarios in which BlueALSA may be used, and the flexibility of systemd's configuration files means that there are equally many ways that the BlueALSA service units can be configured. The unit files provided by the project are intended to give a flexible and secure basis that can be used out-of-the box in the most common scenarios but can also be easily customized for any specialized use-case.

Installation

The BlueALSA systemd unit files are not installed by default, they must be explicitly enabled when configuring the build by including the configure option --enable-systemd. See Installation from source for more information on build and install procedure for BlueALSA.

There are also some configure options that can modify the unit files, setting the command-line arguments and setting the user id under which each service should be started. By default both services are run as user root. bluealsa is started with bluealsa -p a2dp-source -p a2dp-sink and bluealsa-aplay is started with no arguments. See the respective manual pages for full details of all available command-line arguments bluealsa manual page, bluealsa-aplay manual page.

It is generally considered best practice not to run services as root unless absolutely necessary. Neither of the BlueALSA services need root privileges, so long as the accounts they use have the required group memberships, and for bluealsa D-Bus permission is correctly granted to the chosen user. For maximum security, the chosen user accounts should be "system" accounts, which means each should:

  • have its own group
  • have no home directory
  • have no shell
  • have logins disabled

Distributions vary in the way that user and group accounts are created, so you should consult your distribution's documentation for instructions. As an example, on Debian and derivatives you can create suitable accounts called bluealsa and bluealsa-aplay with

sudo adduser --system --group --no-create-home bluealsa
sudo adduser --system --group --no-create-home bluealsa-aplay
sudo adduser bluealsa-aplay audio

If you are using bluez 5.50 or older you will also need to add the bluealsa user to the bluetooth group:

sudo adduser bluealsa bluetooth

(Note that adduser is a Debian utility; other distributions will likely have alternative utilities, each with its own command-line syntax).

For more details on the BlueALSA configure options for systemd, see the "Installation Options" section of the Installation from source wiki page.

Once the installation is complete, systemd needs to be informed of the new services by running (as root)

systemctl daemon-reload

Earlier BlueALSA releases

If using BlueALSA v3.1.0 or earlier, systemd unit files are not included in the sources. The file templates can be obtained from the latest sources: bluealsa service file template and bluealsa-aplay service file template. It is necessary to modify the User= and ExecStart= directives in both templates then save them without the .in suffix to create usable systemd service files. For example, the bluealsa.service file may be edited to contain the lines

User=root
ExecStart=/usr/bin/bluealsa -S -p a2dp-source -p a2dp-sink

Security Sandbox

The BlueALSA service unit files include comprehensive security sandbox directives aimed at providing the most complete lock-down possible and thereby reducing the security risk exposure to an absolute minimum.

bluealsa service

A default install, with user root for the bluealsa service, results in the following security analysis report for bluealsa.service from systemd-analyze security bluealsa.service (showing only those items identified as security risks):

✗ PrivateNetwork=                    Service has access to the host's network                            0.5
✗ User=/DynamicUser=                 Service runs as root user                                           0.4
✗ RestrictAddressFamilies=~…         Service may allocate exotic sockets                                 0.3
✗ DeviceAllow=                       Service has a device ACL with some special devices                  0.1
✗ PrivateUsers=                                               Service has access to other users               0.2
✗ AmbientCapabilities=                                        Service process receives ambient capabilities   0.1
✗ CapabilityBoundingSet=~CAP_NET_(BIND_SERVICE|BROADCAST|RAW) Service has elevated networking privileges      0.1
✗ RootDirectory=/RootImage=          Service runs within the host's root directory                       0.1
✗ RestrictAddressFamilies=~AF_UNIX   Service may allocate local sockets                                  0.1
✗ ProcSubset=                        Service has full access to non-process /proc files (/proc subset=)  0.1

Overall exposure level for bluealsa.service: 1.6 OK 🙂

The exposure level can be further reduced by running the service as a non-root user as described in Installation above. This removes the User=/DynamicUser= score resulting in an overall rating of:

Overall exposure level for bluealsa.service: 1.2 OK 🙂

The directives PrivateUsers=false, AmbientCapabilities=CAP_NET_RAW, and CapabilityBoundingSet=CAP_NET_RAW are required only to permit the bluealsa daemon to modify SCO routing for Broadcom bluetooth adapters. If your system does not use Broadcom adapters, or if the system has its own means of setting the SCO routing, then these directives can be tightened. Change them to:

CapabilityBoundingSet=
AmbientCapabilities=
PrivateUsers=true

and the overall exposure level is further reduced:

Overall exposure level for bluealsa.service: 0.8 SAFE 😀

The remaining directives cannot be further tightened because they are required for the function of the bluealsa service. Each of the exposure report scoring items is discussed here:

  • PrivateNetwork=
    Permits creation of Unix Domain sockets, which is required for HFP/HSP RFCOMM function. If a system does not require SCO support, then PrivateNetwork can be enabled. Note that the client PCM control sockets are actually created by D-Bus, so bluealsa does not need this permission for those; however see also RestrictAddressFamilies=~AF_UNIX below.
  • RestrictAddressFamilies=~…
    The "exotic" sockets referenced here are in fact Bluetooth sockets which are required for access to the HCI through which all bluetooth data flows.
  • DeviceAllow=
    This is actually a consequence of the ProtectClock=true directive, and is therefore not avoidable.
  • RootDirectory=/RootImage=
    The purpose of this directive is to run the service in a chroot() jail. Since that would require a full set of the dependency libraries within the chroot, it is not possible for the BlueALSA installer to set this up in a generic way. In general, use of User= in combination with the other directives here gives equivalent protection.
  • RestrictAddressFamilies=~AF_UNIX
    Use of Unix domain sockets is required so that clients can connect to the bluealsa service.
  • ProcSubset=
    Although bluealsa does not need access to other processes' data, it does require access to certain kernel APIs, which would be denied by setting this directive.

Real-time priority

The latest BlueALSA source code [not yet released] includes the ability to run the bluealsa service with real-time capabilities, and this is recommended when using the SCO profiles. See the bluealsa manual page for more information. This option requires some relaxing of the sandbox restrictions, which by default prevent the use of real-time priority. Note that misuse of this capability can cause a system-wide denial of service, and so should only be enabled for those services which genuinely require it and can be trusted. The additional service directives required are:

AmbientCapabilities=CAP_SYS_NICE
CapabilityBoundingSet=CAP_SYS_NICE
RestrictRealtime=false
SystemCallFilter=@resources

See the Usage section below for advice on editing the systemd configuration.

This naturally results in an increased security exposure risk:

✗ CapabilityBoundingSet=~CAP_SYS_(NICE|RESOURCE) Service has privileges to change resource use parameters        0.1
✗ RestrictRealtime=                              Service may acquire realtime scheduling                         0.1
✗ SystemCallFilter=~@resources                   System call allow list defined for service, and @resources is included (e.g. ioprio_set is allowed)      0.2

→ Overall exposure level for bluealsa.service: 1.9 OK 🙂

bluealsa-aplay service

A default install, with user root for the bluealsa-aplay service, produces the following report from systemd-analyze security bluealsa-aplay.service:

✗ PrivateNetwork=                     Service has access to the host's network                            0.5
✗ User=/DynamicUser=                  Service runs as root user                                           0.4
✗ DeviceAllow=                        Service has a device ACL with some special devices                  0.1
✗ RootDirectory=/RootImage=           Service runs within the host's root directory                       0.1
✗ RestrictAddressFamilies=~AF_UNIX    Service may allocate local sockets                                  0.1
✗ ProcSubset=                         Service has full access to non-process /proc files (/proc subset=)  0.1
✗ PrivateDevices=                     Service potentially has access to hardware devices                  0.2

Overall exposure level for bluealsa-aplay.service: 1.2 OK 🙂

... and again use of a non-root user gives the same improvement:

Overall exposure level for bluealsa-aplay.service: 0.8 SAFE 😀

The only difference from the bluealsa report is that bluealsa-aplay does not require bluetooth sockets, but that is balanced by the need for access to hardware sound devices (PrivateDevices=).

Usage

Please consult your distribution's documentation or the systemd documentation if you need help with using systemd services.

The service unit files can be used to start bluealsa and bluealsa-aplay when the bluetooth subsystem starts (typically at boot) by "enabling" them:

sudo systemctl enable bluealsa.service
sudo systemctl enable bluealsa-aplay.service

Note that if using bluealsa-aplay with HFP or HSP (bluealsa-aplay --profile-sco) then it should not be started at boot on a gateway host (HFP-AG or HSP-AG); this is because it will cause bluealsa to aquire the SCO transport as soon as a device connects, even though there may be no audio stream available in either direction at that time. This will waste bandwidth and battery power on the remote device. It is OK to start bluealsa-aplay at boot on a hands-free/headset host (HFP-HF or HSP-HS) because in that role bluealsa will not immediately acquire the transport.

It is also possible to start and stop either service manually, whether "enabled" or not, for example:

sudo systemctl start bluealsa.service
sudo systemctl stop bluealsa.service

If it becomes necessary to modify a systemd service unit after installation, it is best not to edit the original unit file. This is because such changes will be lost if BlueALSA is later re-installed or upgraded. Instead, the systemctl edit utility can be used.

To make small changes, for example to the bluealsa service file, create a drop-in override by using:

sudo systemctl edit bluealsa.service

In this file, just place the directives you wish to override, including the appropriate group header (e.g. [Service] etc). Note that although most directives allow only one value and are completely replaced by the override, some others permit multiple instances and so the override value is used in addition to the existing value.

A notable example of the multiple instance type is ExecStart. To completely replace a multiple instance directive it is necessary to first clear it by specifying an empty value. So, for example to enable the aptX codec, the override file should be:

[Service]
ExecStart=
ExecStart=/usr/bin/bluealsa -S -p a2dp-source -p a2dp-sink -c aptx

If you wish to make many changes, the whole file can be replaced with:

sudo systemctl edit --full bluealsa.service

This creates a complete copy of the installed file. The copy "hides" the installed file so that the copy is not overwritten if BlueALSA is re-installed or upgraded.

To undo the overrides and restore the original installed file, use:

sudo systemctl revert bluealsa.service

Drop-in override changes take effect the next time the service is started. So to apply the changes immediately:

sudo systemctl restart bluealsa.service

See the systemctl manual page for more information.

Debugging and Troubleshooting

When BlueALSA is built with the option --enable-debug the bluealsa daemon and bluealsa-aplay application both produce large amounts of debug output. This output is sent to stderr, which by default systemd redirects to its journal file. This makes such builds less suitable for use with systemd, especially on embedded and other small systems with limited file space. It is therefore recommended not to run debug builds using systemd.

If you do need to run debug builds from systemd for any reason, then the logs will be visible using the systemd journalctl utility. For example:

sudo journalctl -xeu bluealsa.service

sudo journalctl -xeu bluealsa-aplay.service