# ------------------------------------------------------------------
#
# Copyright 2018 Canonical Ltd.
# This file is Copyright 2020 by the GPSD project
# SPDX-License-Identifier: BSD-2-clause
#
# This software is distributed under a BSD-style license. See the
# file "COPYING" in the top-level directory of the distribution for details.
#
# WARNING: using gps with apparmor will drive you crazy and is not recommended.
# gpsd depends on system libraries that change frequently.  They use
# system calls that change frequently for many reasons.  Thus no whitelist
# will ever be correct.  You will be playing whack-a-mole.
#
# Apparmor profiles are meant to cover and allow for the most common use
# cases and that is what this profile tries to cover. Due to the nature of
# the program there are various different use-cases and if you trigger
# apparmor denies (see dmesg and journal) it is recommended to add matching
# local overrides for your use-case. See:
# gitlab.com/apparmor/apparmor/-/blob/master/profiles/apparmor.d/local/README
# This way your changes do not conflict with further updates of the program.
#
# If you consider this use case common please report a bug upstream so that
# the rule can be added to the default profile.
#
# If instead you are just frustrated and want to get it silenced it is
# recommended to set it to complain mode:
#  $ sudo aa-complain usr.sbin.gpsd
# That way nothing will be blocked anymore, but you will be able to see and
# report the denials of your use case. That way there is a chance to update
# the default profile for it.

# ------------------------------------------------------------------

#include <tunables/global>

/usr/sbin/gpsd flags=(attach_disconnected) {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  # For shmctl()
  capability ipc_lock,
  capability net_bind_service,
  capability sys_nice,
  capability fsetid,
  capability setgid,
  capability setuid,
  capability sys_resource,

  # for all the remote connection options
  network dgram,
  network stream,
  network bluetooth,
  network can raw,

  # own binary
  /usr/sbin/gpsd rmix,

  # common serial paths to GPS devices
  /dev/tty{,S,USB,AMA,ACM}[0-9]*    rw,
  /sys/dev/char     r,
  /sys/dev/char/**  r,

  # Bluetooth devices, for Bluetooth GNSS receivers
  /dev/rfcomm* rw,
  owner /dev/rfcomm* w,

  # pps related devices
  /dev/pps[0-9]*              rw,
  /sys/devices/virtual/pps    r,
  /sys/devices/virtual/pps/** r,

  # gpsd device to share, no idea who uses these
  /dev/gpsd[0-9] rw,
  # default receiver to use, a symbolic link to a tty
  /dev/gps0 rw,

  # libusb device access to GPS devices
  /proc/      r,
  /dev/       r,
  /sys/class/ r,
  /sys/bus/   r,
  /dev/bus/usb/ r,
  /sys/bus/usb/devices/ r,
  /sys/devices/pci[0-9]*/**/{uevent,busnum,devnum,speed,descriptors} r,
  /run/udev/data/+usb* r,
  /run/udev/data/c189* r,

  # common config path (by default unused)
  /etc/gpsd/* r,
  # gpsd will call this on device attach/detach allowing for custom handlers
  /etc/gpsd/device-hook ix,
  # which may in turn shebang one of these
  # handle merged and non-merged user cases
  /{,usr/}bin/dash rix,
  /{,usr/}bin/bash rix,

  # control socket e.g. for gpsdctl
  /{,var/}run/gpsd.sock rw,

  # enumerate own FDs
  @{PROC}/@{pid}/fd/ r,

  # default paths feeding GPS data into chrony
  /{,var/}run/chrony.tty{,S,USB,AMA}[0-9]*.sock rw,
  /tmp/chrony.tty{,S,USB,AMA}[0-9]*.sock rw,

  # for gpsfake:
  /tmp/gpsfake-*.sock rw,

  # logging
  /{,var/}run/systemd/journal/dev-log w,

  # required for pps initialization
  capability sys_time,
  /sys/devices/virtual/pps/ r,

  # to submit data to chrony
  ptrace read peer=/usr/sbin/chronyd,

  # for libusb in case USB based GPS devices are used
  /sys/devices/**/usb[0-9]*/** r,

  # triggered on fusercount, not strictly required and unsafe to allow
  # adding an explicit denial rule silences the warnings
  deny ptrace read peer=unconfined,
  deny capability sys_ptrace,
  deny capability dac_read_search,
  deny capability dac_override,

  # gpsd tries to load pps_ldisc directly, but gpsd doesn't need
  # the general power of cap 'sys_module', pps_ldisc is auto-loaded
  # by the kernel when gpsd is creating the pps device
  deny capability sys_module,

  # Site-specific additions and overrides. See local/README for details.
  #include <local/usr.sbin.gpsd>
}
# vim:syntax=apparmor
