github.com/rigado/snapd@v2.42.5-go-mod+incompatible/interfaces/builtin/pulseaudio.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-2017 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package builtin
    21  
    22  import (
    23  	"github.com/snapcore/snapd/interfaces"
    24  	"github.com/snapcore/snapd/interfaces/apparmor"
    25  	"github.com/snapcore/snapd/interfaces/seccomp"
    26  	"github.com/snapcore/snapd/interfaces/udev"
    27  	"github.com/snapcore/snapd/release"
    28  	"github.com/snapcore/snapd/snap"
    29  )
    30  
    31  const pulseaudioSummary = `allows operating as or interacting with the pulseaudio service`
    32  
    33  const pulseaudioBaseDeclarationSlots = `
    34    pulseaudio:
    35      allow-installation:
    36        slot-snap-type:
    37          - app
    38          - core
    39      deny-connection:
    40        on-classic: false
    41  `
    42  
    43  const pulseaudioConnectedPlugAppArmor = `
    44  # Allow communicating with pulseaudio service for playback and, on some
    45  # distributions, recording.
    46  /{run,dev}/shm/pulse-shm-* mrwk,
    47  
    48  owner /{,var/}run/pulse/ r,
    49  owner /{,var/}run/pulse/native rwk,
    50  owner /run/user/[0-9]*/ r,
    51  owner /run/user/[0-9]*/pulse/ rw,
    52  
    53  /run/udev/data/c116:[0-9]* r,
    54  /run/udev/data/+sound:card[0-9]* r,
    55  `
    56  
    57  const pulseaudioConnectedPlugAppArmorDesktop = `
    58  # Only on desktop do we need access to /etc/pulse for any PulseAudio client
    59  # to read available client side configuration settings. On an Ubuntu Core
    60  # device those things will be stored inside the snap directory.
    61  /etc/pulse/ r,
    62  /etc/pulse/** r,
    63  owner @{HOME}/.pulse-cookie rk,
    64  owner @{HOME}/.config/pulse/cookie rk,
    65  owner /{,var/}run/user/*/pulse/ rwk,
    66  owner /{,var/}run/user/*/pulse/native rwk,
    67  `
    68  
    69  const pulseaudioConnectedPlugSecComp = `
    70  shmctl
    71  `
    72  
    73  const pulseaudioPermanentSlotAppArmor = `
    74  # When running PulseAudio in system mode it will switch to the at
    75  # build time configured user/group on startup.
    76  capability setuid,
    77  capability setgid,
    78  
    79  capability sys_nice,
    80  capability sys_resource,
    81  
    82  owner @{PROC}/@{pid}/exe r,
    83  /etc/machine-id r,
    84  
    85  # Audio related
    86  @{PROC}/asound/devices r,
    87  @{PROC}/asound/card** r,
    88  
    89  # Should use the alsa interface instead
    90  /dev/snd/pcm* rw,
    91  /dev/snd/control* rw,
    92  /dev/snd/timer r,
    93  
    94  /sys/**/sound/** r,
    95  
    96  # For udev
    97  network netlink raw,
    98  /sys/devices/virtual/dmi/id/sys_vendor r,
    99  /sys/devices/virtual/dmi/id/bios_vendor r,
   100  # FIXME: use udev queries to make this more specific
   101  /run/udev/data/** r,
   102  
   103  owner /{,var/}run/pulse/ rw,
   104  owner /{,var/}run/pulse/** rwk,
   105  
   106  # Shared memory based communication with clients
   107  /{run,dev}/shm/pulse-shm-* mrwk,
   108  
   109  /usr/share/applications/ r,
   110  
   111  owner /run/pulse/native/ rwk,
   112  owner /run/user/[0-9]*/ r,
   113  owner /run/user/[0-9]*/pulse/ rw,
   114  `
   115  
   116  const pulseaudioPermanentSlotSecComp = `
   117  # The following are needed for UNIX sockets
   118  personality
   119  setpriority
   120  bind
   121  listen
   122  accept
   123  accept4
   124  shmctl
   125  # Needed to set root as group for different state dirs
   126  # pulseaudio creates on startup.
   127  setgroups
   128  setgroups32
   129  # libudev
   130  socket AF_NETLINK - NETLINK_KOBJECT_UEVENT
   131  `
   132  
   133  type pulseAudioInterface struct{}
   134  
   135  func (iface *pulseAudioInterface) Name() string {
   136  	return "pulseaudio"
   137  }
   138  
   139  func (iface *pulseAudioInterface) StaticInfo() interfaces.StaticInfo {
   140  	return interfaces.StaticInfo{
   141  		Summary:              pulseaudioSummary,
   142  		ImplicitOnClassic:    true,
   143  		BaseDeclarationSlots: pulseaudioBaseDeclarationSlots,
   144  	}
   145  }
   146  
   147  func (iface *pulseAudioInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   148  	spec.AddSnippet(pulseaudioConnectedPlugAppArmor)
   149  	if release.OnClassic {
   150  		spec.AddSnippet(pulseaudioConnectedPlugAppArmorDesktop)
   151  	}
   152  	return nil
   153  }
   154  
   155  func (iface *pulseAudioInterface) UDevPermanentSlot(spec *udev.Specification, slot *snap.SlotInfo) error {
   156  	spec.TagDevice(`KERNEL=="controlC[0-9]*"`)
   157  	spec.TagDevice(`KERNEL=="pcmC[0-9]*D[0-9]*[cp]"`)
   158  	spec.TagDevice(`KERNEL=="timer"`)
   159  	return nil
   160  }
   161  
   162  func (iface *pulseAudioInterface) AppArmorPermanentSlot(spec *apparmor.Specification, slot *snap.SlotInfo) error {
   163  	spec.AddSnippet(pulseaudioPermanentSlotAppArmor)
   164  	return nil
   165  }
   166  
   167  func (iface *pulseAudioInterface) SecCompConnectedPlug(spec *seccomp.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   168  	spec.AddSnippet(pulseaudioConnectedPlugSecComp)
   169  	return nil
   170  }
   171  
   172  func (iface *pulseAudioInterface) SecCompPermanentSlot(spec *seccomp.Specification, slot *snap.SlotInfo) error {
   173  	spec.AddSnippet(pulseaudioPermanentSlotSecComp)
   174  	return nil
   175  }
   176  
   177  func (iface *pulseAudioInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool {
   178  	return true
   179  }
   180  
   181  func init() {
   182  	registerIface(&pulseAudioInterface{})
   183  }