#------------------------------------------------------------------
#    Copyright (C) 2024 Canonical Ltd.
#
#    Author: Federico Quattrin <federico.quattrin@canonical.com>
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of version 2 of the GNU General Public
#    License published by the Free Software Foundation.
#------------------------------------------------------------------
# vim: ft=apparmor
#

abi <abi/5.0>,
include <tunables/global>

profile lsusb /usr/bin/lsusb {
  include <abstractions/base>

  /usr/bin/lsusb mr,

  network netlink raw,

  # CAP_NET_ADMIN is invoked as part of setsockopt(2) on a udev socket
  # using SO_RCVBUFFORCE to override rlimits:

  # libudev/libudev-monitor.c:udev_monitor_new_from_netlink
  # libsystemd/sd-device/device-monitor.c:device_monitor_new_full
  # libsystemd/sd-device/device-monitor.c:sd_device_monitor_set_receive_buffer_size
  # basic/socket-util.c:fd_set_rcvbuf

  # Because libudev can work just fine with a suboptimal buffer size,
  # the capability isn't actually necessary, and we can silence the denial.
  deny capability net_admin,

  # CAP_SYS_ADMIN is invoked to set a classic BPF filter on a udev socket,
  # using setsockopt(2) with SO_ATTACHFILTER:

  # libudev/libudev-monitor.c:udev_monitor_enable_receiving
  # libsystemd/sd-device/device-monitor.c:device_monitor_new_full
  # libsystemd/sd-device/device-monitor.c:sd_device_monitor_filter_update

  # libudev seems to work fine without the BPF filter in place, so we
  # can silence the denial.
  deny capability sys_admin,

  /dev/bus/usb/@{d}@{d}@{d}/@{d}@{d}@{d} rw,

  /dev/ r,
  /dev/bus/usb/ r,
  @{run}/udev/data/*usb:* r,
  @{run}/udev/data/c*:* r,

  @{sys}/bus/ r,
  @{sys}/bus/usb/devices/ r,
  @{sys}/class/ r,

  @{sys}/devices/**/usb[0-9]**/uevent r,
  @{sys}/devices/**/usb[0-9]**/busnum r,
  @{sys}/devices/**/usb[0-9]**/descriptors r,
  @{sys}/devices/**/usb[0-9]**/devnum r,
  @{sys}/devices/**/usb[0-9]**/speed r,
  @{sys}/devices/**/usb[0-9]**/manufacturer r,
  @{sys}/devices/**/usb[0-9]**/product r,
  @{sys}/devices/**/usb[0-9]**/serial r,
  # needed for --tree
  @{sys}/devices/**/usb[0-9]**/bAlternateSetting r,
  @{sys}/devices/**/usb[0-9]**/bInterfaceClass r,
  @{sys}/devices/**/usb[0-9]**/bInterfaceNumber r,
  @{sys}/devices/**/usb[0-9]**/bInterfaceProtocol r,
  @{sys}/devices/**/usb[0-9]**/bInterfaceSubClass r,
  @{sys}/devices/**/usb[0-9]**/bNumEndpoints r,
  @{sys}/devices/**/usb[0-9]**/bConfigurationValue r,
  @{sys}/devices/**/usb[0-9]**/bDeviceClass r,
  @{sys}/devices/**/usb[0-9]**/bDeviceProtocol r,
  @{sys}/devices/**/usb[0-9]**/bDeviceSubClass r,
  @{sys}/devices/**/usb[0-9]**/bMaxPacketSize0 r,
  @{sys}/devices/**/usb[0-9]**/bNumConfigurations r,
  @{sys}/devices/**/usb[0-9]**/bNumInterfaces r,
  @{sys}/devices/**/usb[0-9]**/bcdDevice r,
  @{sys}/devices/**/usb[0-9]**/bmAttributes r,
  @{sys}/devices/**/usb[0-9]**/configuration r,
  @{sys}/devices/**/usb[0-9]**/idProduct r,
  @{sys}/devices/**/usb[0-9]**/idVendor r,
  @{sys}/devices/**/usb[0-9]**/maxchild r,
  @{sys}/devices/**/usb[0-9]**/rx_lanes r,
  @{sys}/devices/**/usb[0-9]**/tx_lanes r,
  # Needed for --tree -v
  @{sys}/devices/**/usb[0-9]**/bMaxPower r,
  @{sys}/devices/**/usb[0-9]**/version r,

  include if exists <local/lsusb>
}
