Interfaces for Raspberry Pi imager

I have moved the snap to be rpi-imager built from the same git repo as before, as suggested. (they seemed to change the name of the app about an hour after I made mine, and at least once prior to that :slight_smile: - naming things is hard).

Ok, without udisks2 and block-devices, when selecting an SD card, I get this in a loop and the application fails to find an SD card.

Error executing lsblk
Error executing lsblk
Error executing lsblk

Screenshot%20from%202020-03-06%2009-22-53

This appears to originate here

If I connect block-devices the application operates the same, up until selecting an SD card. Now it’s found, but fails to write. So I added the udisks2 interface. At the point of writing, it asks for the “sudo” password. Not sure how it does that.

I believe that’s using policykit.

Edit: I’ve just looked at their source. They are doing all interaction with the devices through the udisks dbus api, so it is actually udisks that requests the password to authorise access to the raw device (outside confinement) when told by imager to do things to the device.

1 Like

Weirdly, this worked yesterday, but I can’t get it working today. Perhaps I connected something yesterday during my debugging which I haven’t connected today. Now it fails after the policykit prompt to access /dev/mmcblk0, which I suspect is when it’s trying to unmount the card. As this appears in the security log.

= Seccomp =
Time: Mar  6 14:13:28
Log: auid=1000 uid=1000 gid=1000 ses=3 pid=719483 comm="DownloadExtract" exe="/snap/imager/x1/bin/rpi-imager" sig=0 arch=c000003e 166(umount2) compat=0 ip=0x7f65aad768c7 code=0x50000
Syscall: umount2
Suggestion:
* add one of 'cifs-mount, network-control' to 'plugs'

So doing some more debugging.

Ok, now I’m baffled. I have udisks2 and others connected, but…

Screenshot%20from%202020-03-06%2014-23-47

= AppArmor =
Time: Mar  6 14:22:34
Log: apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/UDisks2/Manager" interface="org.freedesktop.DBus.Introspectable" member="Introspect" mask="send" name="org.freedesktop.UDisks2" pid=736410 label="snap.rpi-imager.rpi-imager" peer_pid=2805 peer_label="unconfined"
DBus access
Suggestion:
* try adding 'udisks2' to 'plugs'

= AppArmor =
Time: Mar  6 14:22:34
Log: apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/UDisks2/block_devices/mmcblk0" interface="org.freedesktop.DBus.Introspectable" member="Introspect" mask="send" name="org.freedesktop.UDisks2" pid=736410 label="snap.rpi-imager.rpi-imager" peer_pid=2805 peer_label="unconfined"
DBus access
Suggestion:
* try adding 'udisks2' to 'plugs'
$ snap connections rpi-imager 
Interface        Plug                        Slot              Notes
block-devices    rpi-imager:block-devices    :block-devices    manual
cifs-mount       rpi-imager:cifs-mount       :cifs-mount       manual
desktop          rpi-imager:desktop          :desktop          -
desktop-legacy   rpi-imager:desktop-legacy   :desktop-legacy   -
home             rpi-imager:home             :home             -
mount-observe    rpi-imager:mount-observe    -                 -
network          rpi-imager:network          :network          -
network-control  rpi-imager:network-control  :network-control  manual
network-manager  rpi-imager:network-manager  -                 -
opengl           rpi-imager:opengl           :opengl           -
raw-usb          rpi-imager:raw-usb          -                 -
removable-media  rpi-imager:removable-media  -                 -
udisks2          rpi-imager:udisks2          :udisks2          manual
x11              rpi-imager:x11              :x11              -

I’m getting plug blindness. What am I missing? :smiley:

Here’s the script I’m using for testing…

#!/bin/bash
set -eu
sudo snap remove rpi-imager
#snapcraft --use-lxd
#snapcraft remote-build --launchpad-user popey --launchpad-accept-public-upload
snapcraft
sudo snap install rpi-imager_*amd64.snap --dangerous
#sudo snap connect rpi-imager:mount-observe
#sudo snap connect rpi-imager:removable-media
sudo snap connect rpi-imager:udisks2
sudo snap connect rpi-imager:block-devices
sudo snap connect rpi-imager:cifs-mount
#sudo snap connect rpi-imager:network-control
snap run rpi-imager

Using the source at https://github.com/popey/imager-snap

Slightly less baffled now. i think it’s all down to not being able to unmount the SD card. It works sometimes, because sometimes the SD card happens to not be mounted, which works fine. The moment the SD card is already mounted, that’s what causes the above failure. So we need to perhaps tweak one of the existing interfaces to allow unmounting.

To be clear. I see no way to make this snap work without an interface which allows unmounting.

With the udisks2 interface connected, if you add this to /var/lib/snapd/apparmor/profiles/snap.rpi-imager.rpi-imager:

dbus (send)
    bus=system
    path=/org/freedesktop/UDisks2/**
    interface=org.freedesktop.DBus.Introspectable
    peer=(label=unconfined),

and you reload the policy with sudo apparmor_policy -r /var/lib/snapd/apparmor/profiles/snap.rpi-imager.rpi-imager do the application work correctly?

I suspect that the application is falling back to umount/etc itself since udisks2 isn’t working correctly. If we can fix udisks2, my hope is that your application will not need the extra accesses.

This should be fixed in https://github.com/snapcore/snapd/pull/8262

I assume you mean sudo apparmor_parser and yes, that works!

Thank you.

Thanks for confirming. I’ve now submitted a PR for 2.44 that will hopefully make it in: https://github.com/snapcore/snapd/pull/8263

@popey - now that udisks2 works, is block-devices still needed?

It still fails without block-devices. Failing to run lsblk

beyond using lsblk it will also need to directly write to the device node at some point in the process to actually write the image to disk (like dd and friends do)

There’s a further issue here. A user on Solus alerted me to a problem with another snap (sosumi) where I use snapctl is-connected (interface) to prompt the user to connect a disconnected interface before continuing.

They get:

error: error running snapctl: Unknown command `is-connected'. Please specify one command of: get, restart, services, set, start or stop

Which is likely because they’re on 2.39.3 as Solus is outdated.

So do we also need to add an assumes: 2.43 to the snapcraft.yaml as an extra guard, to prevent people installing the snap when on <2.43? If so, this will be needed on all snaps which use snapctl is-connected?

Yes this is the right thing to do here

assumes is a list of strings. Also the snapd assumption is snapd2.43, not 2.43:

assumes:
  - snapd2.43
3 Likes

To be clear, udisks2 has polkit integration so on classic it is what will prompt for access for mounting/umounting/etc.

@popey - I agree with @alexmurray that block-devices grants device ownership to the snap since it grants raw access to devices. Is your snap intended to not run under sudo? If sudo must be used for this snap to function, then +1 to auto-connect block-devices provided services aren’t added to the snap to bypass this restriction.

If sudo isn’t required:

  • how is the snap elevating permissions to provide the access? Are there root-running daemons running to provide the non-root frontend access?
  • if there is a client/server split, what access controls is the server performing to make sure a connecting client doesn’t have instant root? (keep in mind, if it is listening on a socket, any non-root, unconfined processes would be able to use the socket)
  • what are security policy denials you see when block-devices isn’t connected?

I am not using sudo when launching the application.

@lucyllewy suggested they’re using udisks2 to elevate, in an earlier comment.
There is no client/server split.

When block-devices is not connected I get:

= AppArmor =            
Time: Mar 25 16:46:32
Log: apparmor="DENIED" operation="open" profile="snap.rpi-imager.rpi-imager" name="/sys/block/" pid=149531 comm="lsblk" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
File: /sys/block/ (read)        
Suggestions:
* adjust program to not access '/sys/block/'
* add 'block-devices' to 'plugs'  

It fails to find the SD card slot so I can’t proceed at that point.

The application outputs:

Error executing lsblk
Error executing lsblk
Error executing lsblk
Error executing lsblk
Error executing lsblk
Error executing lsblk
Error executing lsblk

.

Looking at the upstream source code, lsblk appears to be used to get the list of block devices on the system and udisks2 is used to open the device on behalf of the user (https://github.com/raspberrypi/rpi-imager/blob/qml/downloadthread.cpp#L184) if it can’t be opened directly - so it might be interesting to see if upstream would be interested in using udisks2 to enumerate the block devices as well as a fallback for lsblk failing - then block-devices would not be required…

@jdstrand - thoughts on adding read/write attributes on the block-devices interface so that we can grant just read-only access - this would allow cases like this to use it and not have to grant such privileged access?

Note that lsblk is supposed to be supported by hardware-observe and allows /sys/{block,bus,class,devices,firmware}/{,**} r,.

Can you try with just plugging udisk2 and hardware-observe, skipping block-devices?