Accessing hidraw devices inside a snapped application

Hi,

After attending Till’s snap packaging workshop recently, I am trying to create a snap package for the glucometerutils application that I use regularly. The application supports interacting with glucometer devices from various manufacturers and as a result, each device is likely accessed in a different way.

For example, my One Touch Verio Flex glucometer can be accessed via a device like /dev/sdb when connected to the computer using a micro-USB to USB cable. My FreeStyle Libre reader can be accessed via a device like /dev/hidraw11.

While the application supports many other devices which could be using many other device and connection types, I do not have access to test with those devices and hence would like the snap to support at least the two devices that I own and use daily.

For the OneTouch Verio Flex glucometer, I was able to get it working with the block-devices plug and manually connecting the snap to it after the installation. But for the FreeStyle Libre device, access to hidraw devices is not working even after declaring a hidraw plug. Based on the search results that I found in this forum, it looks like a gadget snap might be required for this to work. There were also a few replies that mentioned requesting hotplug support for this. But as a third-party application packager, I do not know whether any of this is appropriate for this snap and which one to choose.

Since the raw-usb interface appeared to be promising, I tried adding that plug to snapcraft.yaml but that didn’t work.

Here is my WIP snapcraft.yaml file.

name: glucometerutils
summary: |
  This snap provides a command line tool to interact with glucometer models.
description: |
  This snap provides a `glucometer` utility, which allows interacting with a number of glucometer models from various
  manufacturers. While support varies by device, the actions that may be available are as follows:

    * `info` shows the model, serial number, data and time, and configured glucose unit of the device.
    * `dump` exports the recorded blood sugar or β-ketone readings from the device in comma-separated values format.
    * `datetime` reads or updates the date and time of the device clock.
    * `zero` deletes all the recorded readings (only implemented for few devices).
base: core22
confinement: strict
grade: devel
adopt-info: glucometerutils

parts:
  glucometerutils:
    plugin: python
    source: https://github.com/glucometers-tech/glucometerutils.git
    override-pull: |
      craftctl default
      craftctl set version="$(git rev-parse HEAD | cut -c -10)"
    python-packages:
      - attrs
      - construct
      - freestyle-hid[encryption]>=1.1.0
      - hidapi
      - PYSCSI[sgio]>=2.0.1
      - pyserial[cp2110]>=3.5b0

apps:
  glucometer:
    command: bin/glucometer
    plugs:
      - block-devices
      - hidraw
      - raw-usb

I had attempted to create a snap package for this application a while ago and posted ModuleNotFoundError exception for a snap built in classic confinement mode and Classic confinement request for the 'glucometerutils' snap for the questions that I had at that time.

But this time, I am going with a fresh, from-the-scratch approach, trying to make this application work with strict confinement instead of the classic confinement that I attempted last time.

Here are the logs showing the output of various relevant commands that I ran while trying to investigate this issue.

# Connected the `block-devices` interface to the snap manually.
$ sudo snap connect glucometerutils:block-devices
# `dmesg` output on connecting my `OneTouch Verio Flex` glucometer using USB cable.
$ sudo dmesg -Hw
Nov14 14:48] usb 1-5.2.4: new full-speed USB device number 20 using xhci_hcd
[  +0.128974] usb 1-5.2.4: New USB device found, idVendor=2766, idProduct=0004, bcdDevice= 0.01
[  +0.000021] usb 1-5.2.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  +0.000006] usb 1-5.2.4: Product: Verio Flex
[  +0.000005] usb 1-5.2.4: Manufacturer: LifeScan
[  +0.000005] usb 1-5.2.4: SerialNumber: ZGQGM58H
[  +0.008201] usb-storage 1-5.2.4:1.0: USB Mass Storage device detected
[  +0.000869] scsi host4: usb-storage 1-5.2.4:1.0
[  +1.030817] scsi 4:0:0:0: Direct-Access     LifeScan                       PQ: 0 ANSI: 2
[  +0.000338] sd 4:0:0:0: Attached scsi generic sg1 type 0
[  +0.000584] sd 4:0:0:0: [sdb] 261738 512-byte logical blocks: (134 MB/128 MiB)
[  +0.000271] sd 4:0:0:0: [sdb] Write Protect is off
[  +0.000002] sd 4:0:0:0: [sdb] Mode Sense: 03 00 00 00
[  +0.000337] sd 4:0:0:0: [sdb] No Caching mode page found
[  +0.000002] sd 4:0:0:0: [sdb] Assuming drive cache: write through
[  +0.008925]  sdb:
[  +0.000289] sd 4:0:0:0: [sdb] Attached SCSI removable disk

# `lsusb` output after connecting it.
$ lsusb
Bus 004 Device 005: ID 05e3:0626 Genesys Logic, Inc. Hub
Bus 004 Device 006: ID 04e8:4001 Samsung Electronics Co., Ltd PSSD T7
Bus 004 Device 004: ID 05e3:0620 Genesys Logic, Inc. GL3523 Hub
Bus 004 Device 003: ID 17e9:6006 DisplayLink Dell Universal Dock D6000
Bus 004 Device 002: ID 05e3:0620 Genesys Logic, Inc. GL3523 Hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 012: ID 046d:c548 Logitech, Inc. Logi Bolt Receiver
Bus 001 Device 011: ID 3434:0280 Keychron Keychron K8 Pro
Bus 001 Device 009: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 001 Device 010: ID 06c4:c411 Bizlink International Corp. D6000 Controller
Bus 001 Device 007: ID 05e3:0608 Genesys Logic, Inc. Hub
Bus 001 Device 020: ID 2766:0004 LifeScan Verio Flex
Bus 001 Device 006: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 001 Device 004: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 001 Device 005: ID 0c45:671d Microdia Integrated_Webcam_HD
Bus 001 Device 002: ID 1050:0407 Yubico.com Yubikey 4/5 OTP+U2F+CCID
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

# Using the command provided by snap to connect to the glucometer
$ sudo glucometerutils.glucometer --driver otverio2015 --device /dev/sdb info
OneTouch Verio Flex glucometer
Serial Number: <redacted>
Version Information:
    Software version: RI_01.08.00
Native Unit: mg/dL
Time: 2023-11-14 14:46:27

# Attempt to connect the `hidraw` plug manually
$ sudo snap connect glucometerutils:hidraw
error: snap "snapd" has no "hidraw" interface slots

# Connected the `raw-usb` plug manually
$ sudo snap connect glucometerutils:raw-usb

# Get the connections of my snap
$ snap connections glucometerutils
Interface      Plug                           Slot            Notes
block-devices  glucometerutils:block-devices  :block-devices  manual
hidraw         glucometerutils:hidraw         -               -
raw-usb        glucometerutils:raw-usb        :raw-usb        manual

# `dmesg` output on connecting my `FreeStyle Libre` glucometer using a USB cable
$ sudo dmesg -Hw
[Nov14 14:59] usb 1-5.2.4: new full-speed USB device number 21 using xhci_hcd
[  +0.125481] usb 1-5.2.4: New USB device found, idVendor=1a61, idProduct=3650, bcdDevice= 1.00
[  +0.000007] usb 1-5.2.4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[  +0.000003] usb 1-5.2.4: Product: ADC Reader
[  +0.000002] usb 1-5.2.4: Manufacturer: Abbott Diabetes Care
[  +0.005142] hid-generic 0003:1A61:3650.0014: hiddev4,hidraw11: USB HID v10.10 Device [Abbott Diabetes Care ADC Reader] on usb-0000:00:14.0-5.2.4/input0

# `lsusb` output
$ lsusb
Bus 004 Device 005: ID 05e3:0626 Genesys Logic, Inc. Hub
Bus 004 Device 006: ID 04e8:4001 Samsung Electronics Co., Ltd PSSD T7
Bus 004 Device 004: ID 05e3:0620 Genesys Logic, Inc. GL3523 Hub
Bus 004 Device 003: ID 17e9:6006 DisplayLink Dell Universal Dock D6000
Bus 004 Device 002: ID 05e3:0620 Genesys Logic, Inc. GL3523 Hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 012: ID 046d:c548 Logitech, Inc. Logi Bolt Receiver
Bus 001 Device 011: ID 3434:0280 Keychron Keychron K8 Pro
Bus 001 Device 009: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 001 Device 010: ID 06c4:c411 Bizlink International Corp. D6000 Controller
Bus 001 Device 007: ID 05e3:0608 Genesys Logic, Inc. Hub
Bus 001 Device 021: ID 1a61:3650 Abbott Diabetes Care FreeStyle Libre
Bus 001 Device 006: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 001 Device 004: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 001 Device 005: ID 0c45:671d Microdia Integrated_Webcam_HD
Bus 001 Device 002: ID 1050:0407 Yubico.com Yubikey 4/5 OTP+U2F+CCID
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root 

# Error when trying to access the glucometer using glucometerutils.glucometer
$ sudo glucometerutils.glucometer --driver fslibre --device /dev/hidraw11 info
Traceback (most recent call last):
  File "/snap/glucometerutils/x1/lib/python3.10/site-packages/glucometerutils/support/freestyle.py", line 59, in __init__
    self._session = freestyle_hid.Session(
  File "/snap/glucometerutils/x1/lib/python3.10/site-packages/freestyle_hid/_session.py", line 165, in __init__
    self._handle = HidWrapper.open(device_path, ABBOTT_VENDOR_ID, product_id)
  File "/snap/glucometerutils/x1/lib/python3.10/site-packages/freestyle_hid/_hidwrapper.py", line 37, in open
    return HidRaw(device_path)
  File "/snap/glucometerutils/x1/lib/python3.10/site-packages/freestyle_hid/_hidwrapper.py", line 48, in __init__
    self._handle = device_path.open("w+b")
  File "/usr/lib/python3.10/pathlib.py", line 1119, in open
    return self._accessor.open(self, mode, buffering, encoding, errors,
PermissionError: [Errno 1] Operation not permitted: '/dev/hidraw11'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/snap/glucometerutils/x1/bin/glucometer", line 8, in <module>
    sys.exit(main())
  File "/snap/glucometerutils/x1/lib/python3.10/site-packages/glucometerutils/glucometer.py", line 118, in main
    device = requested_driver.device(args.device)
  File "/snap/glucometerutils/x1/lib/python3.10/site-packages/glucometerutils/drivers/fslibre.py", line 32, in __init__
    super().__init__(0x3650, device_path, encoding="utf-8")
  File "/snap/glucometerutils/x1/lib/python3.10/site-packages/glucometerutils/support/freestyle.py", line 68, in __init__
    raise exceptions.ConnectionFailed(str(e)) from e
glucometerutils.exceptions.ConnectionFailed: [Errno 1] Operation not permitted: '/dev/hidraw11'

# snappy-debug output
$ sudo journalctl --output=short --follow --all | sudo snappy-debug
= Seccomp =
Time: Nov 14 15:02:09
Log: auid=1000 uid=0 gid=0 ses=4 subj=snap.glucometerutils.glucometer pid=323134 comm="python3" exe="/usr/bin/python3.10" sig=0 arch=c000003e 41(socket) compat=0 ip=0x7fd855abbceb code=0x50000
Syscall: socket
Suggestions:
* add account-control (if using NETLINK_AUDIT)
* add audio-playback (if using NETLINK_KOBJECT_UEVENT)
* add bluetooth-control (if using AF_{ALG,BLUETOOTH})
* add firewall-control (if using NETLINK_{FIREWALL,IP6_FW,NETFILTER,NF_LOG,ROUTE})
* add hardware-observe (if using NETLINK_{GENERIC,KOBJECT_UEVENT})
* add netlink-audit (if using NETLINK_AUDIT)
* add netlink-connector (if using NETLINK_CONNECTOR)
* add network (if using AF_INET{,6}, AF_CONN, NETLINK_ROUTE)
* add network-bind (if using AF_INET{,6}, NETLINK_ROUTE)
* add network-control (if using AF_{APPLETALK,BRIDGE,INET,INET6,IPX,PACKET,PPPOX,SNA}, NETLINK_{DNRTMSG,FIB_LOOKUP,GENERIC,INET_DIAG,ISCSI,KOBJECT_UEVENT,RDMA,ROUTE,XFRM})
* add network-observe (if using SOCK_RAW, AF_INET{,6}), NETLINK_{GENERIC,INET_DIAG,KOBJECT_UEVENT,ROUTE})
* add raw-usb (if using NETLINK_KOBJECT_UEVENT)
* add time-control (if using NETLINK_AUDIT)
* add unity7 (if using NETLINK_KOBJECT_UEVENT)
* add x11 (if using NETLINK_KOBJECT_UEVENT)

# Successful access when using the non-snapped version of this application
$ sudo ./venv/bin/glucometer --driver fslibre --device /dev/hidraw11 info
FreeStyle Libre
Serial Number: <redacted>
Version Information:
    Software version: 2.6.0
Native Unit: mg/dL
Time: 2023-11-14 14:56:00

Edit: I see that the output of the snappy-debug command indicates that a socket system call is getting blocked. I will try to investigate why this is happening. If you have any ideas, please let me know.

I am not sure what the next steps here are and if my previous request for classic confinement is still the way to go here. I reviewed Process for reviewing classic confinement snaps but it is not clear to me if this application qualifies or not. Please advise on what my next steps should be.

If there is any additional information needed to investigate this further, please let me know and I will collect and share it in this thread.

I have created this post under the snapd category but please re-categorize it if this thread belongs elsewhere.

Thank you!

I am still stuck with this issue and here is what the Permissions dialog for this snap (installed locally) on the Snap Store application looks like.

The dropdown for the hidraw permission is empty and I am unable to select anything as a result.