Help needed - Wrapping btrfs-tools into snap

I have a system that runs ubuntu core. On that system i have a btrfs filesystem mounted. Working with the btrfs-filesystem (e.g. creating snapshots, listing snapshots, …) requires btrfs-tools which are available on a classic system like ubuntu server or desktop through apt. As apt is not available on ubuntu core (outside of the classic snap) and searching the store and this forum turned up nothing i wrote a wrapper snap around the btrfs-tools.
This is what the snapcraft.yaml currently looks like:

name: btrfs-snap
version: '0.1.0'
summary: NotYetDone
description: |
  NotYetDone

confinement: devmode
grade: devel

architectures:
  - build-on: armhf
    run-on: armhf

apps:
  btrfs:
    command: btrfs
    plugs:
      - removable-media
      - mount-observe
parts:
  btrfs-tools:
    plugin: nil
    stage-packages:
      - btrfs-tools

Installing the snap using --devmode everything works fine.
Installing the snap using --jailmode i get an error when trying to list existing subvolumes.

ERROR: can't perform the search - Operation not permitted

I have used dmesg to try to find out what is missing but i have no clue what plug i need besides mount-observe. Following is the excerpt that is written to dmesg (dmesg -w) when i execute
sudo btrfs-snap.btrfs subvolume list /media/root/BTRFS_RAID/

[16127.040471] audit: type=1400 audit(1544106958.971:68): apparmor="DENIED" operation="open" profile="snap-update-ns.btrfs-snap" name="/proc/sys/net/core/somaxconn" pid=19426 comm="4" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
[16127.041741] audit: type=1400 audit(1544106958.971:69): apparmor="DENIED" operation="create" profile="snap-update-ns.btrfs-snap" pid=19426 comm="4" family="inet" sock_type="stream" protocol=6 requested_mask="create" denied_mask="create"
[16127.042461] audit: type=1400 audit(1544106958.971:70): apparmor="DENIED" operation="create" profile="snap-update-ns.btrfs-snap" pid=19426 comm="4" family="inet6" sock_type="stream" protocol=6 requested_mask="create" denied_mask="create"
[16127.042945] audit: type=1400 audit(1544106958.971:71): apparmor="DENIED" operation="create" profile="snap-update-ns.btrfs-snap" pid=19426 comm="4" family="inet6" sock_type="stream" protocol=6 requested_mask="create" denied_mask="create"
[16127.258847] audit: type=1400 audit(1544106959.187:72): apparmor="DENIED" operation="capable" profile="snap.btrfs-snap.btrfs" pid=19419 comm="btrfs" capability=21  capname="sys_admin"

Any hint in the right direction would be appreciated.

AFAICS this is not possible via snaps as this requires classic confinement and classic confinement snaps are not allowed to be installed outside the classic snap on a Ubuntu Core device.

You are right, classic confinement is not an option. I wonder what crazy interface is used as communication channel between the user space ‘btrfs-tool’ and the kernel space implementation of btrfs.
Is it dbus or something like that?
Can’t imagine that it is ‘hand-made’.

This will probably necessitate a specific btrfs-mount interface. Probably similar to the recently added cifs-mount interface: https://github.com/snapcore/snapd/pull/5340

Well currently I have no problem mounting an already existing btrfs filesystem.
I use systemd mounts for that. It took me some time to find out how to do that but it works pretty well for me now.
Creating btrfs filesystem is also not a problem udisks is the tool to use here. Udisks can also be used to mount and unmount btrfs filesystem on demand.
Udisks already exists as a snap.
I think but have not tested that it is also possible to mount cifs filesystem as long as the underlying kernel is available.

these apparmor lines should go away if you add network and network-bind to your plugs for the app … they are about socket creation which network-bind allows…

(well, perhaps not the last line though … )

As Oliver mentioned, the first 3 denials you have actually should be covered if you plug network and/or network-bind for the btrfs app too, and the last one you can get if you also plug hardware-observe.

I imagine however there are likely other denials you will run into with using btrfs that won’t be available via currently implemented snapd interfaces, and as such you won’t be able to do all these things from a strictly confined snap (not running in devmode) without an interface that allows access to these things (hence my example of cifs-mount).

Thanks for the tip with network and network-bind. I’ll add them an test if it helps.
Edit: network-bind did the trick for the first dmesg lines

Thanks for the hint using hardware-observe. I’ll add that and test if it helps.
Regarding the btrfs-mount interface I think this might go in the wrong direction.
Having looked into the code of btrfs-progs (the repo name for btrfs-tools) the communication between userspace and kernel is done mostly via ioctl’s. Wouldn’t it be better to have some kind of configurable interface where one can add ioctl codes called by the snap to access kernel functions required?
What do you think about that? Is it possible to create/have such an interface in the current snapd implementation?

Edit: hardware-observe did the trick. No additional problems found so far

1 Like

I haven’t thought about that enough really to say whether that’s a good idea or not for a snap. I would lean towards no simply because historically as many details as possible about snap confinement have been required to be implemented inside snapd interfaces (residing in snapd), rather than inside the snap. Additionally, snap interface updates are an easy thing to do and are often done, so it’s not out of the ordinary to have to add things to a snap interface in snapd and then wait until that snapd release hits stable before releasing anything using that.
If you want to propose such an interface, a better place than here to ask would be in the “snapd” category and a good person to ping on that topic would be @jdstrand

1 Like