Possibly missing apparmor network permission

I’ve just made a snap of bandwhich which is a command line utility for monitoring things that use network bandwidth - a bit like nethogs.

I’ve specified network, network-observe and system-observe but it’s still unable to work. The application reports as follows (even when run with sudo which is typically required anyway).

$ sudo bandwhich -i wlp3s0
Error: 
    Insufficient permissions to listen on network interface(s). You can work around
    this issue like this:

    * Try running `bandwhich` with `sudo`

    * Build a `setcap(8)` wrapper for `bandwhich` with the following rules:
        `cap_net_raw,cap_net_admin+ep`

The syslog has the following:

[Tue Jan 14 20:45:14 2020] audit: type=1400 audit(1579093473.242:528491): apparmor="DENIED" operation="create" profile="snap.bandwhich.bandwhich" pid=2124841 comm="bandwhich" family="packet" sock_type="raw" protocol=768 requested_mask="create" denied_mask="create"
[Tue Jan 14 20:45:14 2020] audit: type=1400 audit(1579093473.242:528492): apparmor="DENIED" operation="create" profile="snap.bandwhich.bandwhich" pid=2124841 comm="bandwhich" family="packet" sock_type="raw" protocol=768 requested_mask="create" denied_mask="create"

snappy-debug gives this.

= AppArmor =
Time: Jan 15 13:04:33
Log: apparmor="DENIED" operation="create" profile="snap.bandwhich.bandwhich" pid=2124841 comm="bandwhich" family="packet" sock_type="raw" protocol=768 requested_mask="create" denied_mask="create"

The application works when installed in devmode. It’s in the edge channel if you want to test.

Is there a missing interface, or missing thing in an existing interface?

I think this probably needs an addition to the network interface to allow raw sockets. Similar to how I added write support to the optical-drive interface. It would then be an optional extra that the store can assert for snaps that absolutely require it, and opt-in for other snaps if the user decides to allow it.

IIUC, network-control has this rule:

network packet,

which absent other restrictions should allow all packet domain network sockets (raw or otherwise).

Could you try adding

network packet raw,

to the apparmor profile and re-load it to see if the denials go away and the application works?

1 Like

Oh well if I could read I would have noticed you didn’t try network-control, try using network-control too :smiley_cat:

1 Like

It’s almost there. Now errors with:

= AppArmor =
Time: Jan 15 15:39:17
Log: apparmor="DENIED" operation="capable" profile="snap.bandwhich.bandwhich" pid=2357930 comm="display_handler" capability=2  capname="dac_read_search"
Capability: dac_read_search
Suggestions:
* adjust program to not require 'CAP_DAC_READ_SEARCH' (see 'man 7 capabilities')
* do nothing if program otherwise works properly

When run confined it looks like this:-

When unconfined (running the binary directly) it looks like this:

So when confined it can’t identify processes owning traffic (even though it has process-control) and also seems to be failing to do dns lookups, as the remote address lookup fails too.

$ snap connections bandwhich 
Interface        Plug                       Slot              Notes
network          bandwhich:network          :network          -
network-control  bandwhich:network-control  :network-control  manual
network-observe  bandwhich:network-observe  :network-observe  manual
process-control  bandwhich:process-control  :process-control  manual
system-observe   bandwhich:system-observe   :system-observe   manual

Just as a test to see if dac_read_search is all you need to get it to work, you could try adding either greengrass-support or system-backup interfaces, though I don’t think either of these interfaces should really be used with your snap as your snap is neither greengrass nor does it seem to be backing anything up.

system-backup is unknown here on 2.42.
greengrass-support worked. What’s the next step, if that worked, do we need to find specifically what in that interface worked?

Ah yes, I think that’s a 2.43 thing. If you wanted you could try refresh to snapd/core beta channel.

You could try disconnecting the greengrass-support interface and adding the following snippet to your apparmor profile for your snap:

capability dac_read_search,

(putting it within the braces). The apparmor profile would be located at /var/lib/snapd/apparmor/profiles/snap.<snap-name>.<app-name>. After editing, reload it with:

sudo apparmor_parser -r /var/lib/snapd/apparmor/profiles/snap.<snap-name>.<app-name>

and then re-launch your application and see if it works.

I did just notice that another slightly weird interface that might be more acceptable for your application to use is the home interface with the read: all attribute specified. But first try just adding the above snippet to your profile, then if it does work with just that capability line added, try removing that line and connecting the home interface with the read: all attribute specified (IIRC the home interface won’t auto-connect with read: all specified and will need a store assertion to auto-connect).

It doesn’t work with that capability added to the apparmor profile.

What is the full list of interfaces you are using with this snap (minus greengrass-support)?

Currently…

$ snap connections bandwhich 
Interface           Plug                          Slot              Notes
greengrass-support  bandwhich:greengrass-support  -                 -
network             bandwhich:network             :network          -
network-control     bandwhich:network-control     :network-control  manual
network-observe     bandwhich:network-observe     :network-observe  manual
process-control     bandwhich:process-control     :process-control  manual
system-observe      bandwhich:system-observe      :system-observe   manual

What’s the output of cat /sys/fs/cgroup/devices/snap.<snap-name>.<snap-app>/devices.list ?

$ cat /sys/fs/cgroup/devices/snap.bandwhich.bandwhich/devices.list 
c 1:3 rwm
c 1:7 rwm
c 1:5 rwm
c 1:8 rwm
c 1:9 rwm
c 5:0 rwm
c 5:1 rwm
c 5:2 rwm
c 136:* rwm
c 137:* rwm
c 138:* rwm
c 139:* rwm
c 140:* rwm
c 141:* rwm
c 142:* rwm
c 143:* rwm
c 10:239 rwm
c 10:242 rwm
c 10:200 rwm

So try adding the capability snippet from before, re-load the apparmor profile, then run the program, and while the program is running, try doing this:

sudo rmdir /sys/fs/cgroup/devices/snap.bandwhich.bandwhich/devices.list

and see if the application starts working again.

rm: cannot remove '/sys/fs/cgroup/devices/snap.bandwhich.bandwhich/devices.list': Operation not permitted

Oh sorry typo on my part (leave out the device.list):

sudo rmdir /sys/fs/cgroup/devices/snap.bandwhich.bandwhich

It’s still not right.

I am seeing processes owned by root in the process list (like sshd) but not my own chrome browser (which is using bandwidth as I am on a call. Chrome (and other user processes) show up in the unconfined bandwhich. The dns lookups also don’t work.

Could you post your snapcraft.yaml link so I can debug a bit myself?

name: bandwhich
base: core18 # the base snap is the execution environment for this snap
adopt-info: bandwhich
summary: Single-line elevator pitch for your amazing snap # 79 char long summary
description: |
  Terminal bandwidth utilization tool (formerly known as "what")

architectures:
  - build-on: i386
  - build-on: amd64
  - build-on: s390x
  - build-on: arm64
  - build-on: ppc64el

grade: stable
confinement: strict

parts:
  bandwhich:
    plugin: rust
    source: https://github.com/imsnif/bandwhich.git
    source-tag: '0.9.0'
    build-packages:
      - build-essential
    override-pull: |
      snapcraftctl pull
      snapcraftctl set-version $(git describe --tags --abbrev=0)

apps:
  bandwhich:
    command: bandwhich
    plugs:
      - network
      - network-observe
      - system-observe
      - network-control
      - process-control
      - greengrass-support

I think creating a socket is a different operation from creating a raw socket. It feels like network should not allow you to create raw sockets. Perhaps a new interface or an option on the network interface.

CC @pedronis and @jdstrand for design ideas.