Permission error with usb unix-hotplug passthrough to container on Debian 13

Goal

I’m trying to get a usb device (PicoTech PicoScope 2204A) to work inside a container.

What works

On my personal PC, running Arch Linux, this works without issue:

sudo incus config device add informed-cardinal pico unix-hotplug vendorid=0ce9 productid=1007 mode=0666
# Now I have to physically re-plug the device in order for the /dev/bus node to show, but that's ok for now.
sudo incus shell informed-cardinal
$ dd if=/dev/bus/usb/008/032 bs=1 count=1  # inside container
1+0 records in
1+0 records out
1 byte copied, 2.4716e-05 s, 40.5 kB/s

The container has no further configuration. It is unprivileged.

The problem

But, when I do the same on my (pretty vanilla) Debian 13 machine, I get: dd: failed to open '/dev/bus/usb/002/016': Permission denied.

What I tried

I tried to add this raw lxc option, which is mentioned here and there on the web:

incus config set sound-katydid raw.lxc="lxc.cgroup2.devices.allow = c 189:* rwm"

The only observation is that, with that option in place, I get this error upon opening the container shell: -bash: /dev/null: Operation not permitted. Presumably the option overrides/messes up some important implicit lxc configuration.

Another thing I tried was to set lxc.apparmor.profile=unconfined, I don’t see any difference.

I also tried to make the container privileged, but this didn’t help either.
On the Debian host, the dd command does succeed.

Question

What is the difference between the Arch and Debian systems, that leads to a permission error on Debian? What do I change to get this to work?

Thanks!

Maybe AppArmor as that would be available on Debian but not on Arch?
If that’s the case, there may be something useful in dmesg.

With unprivileged container, with or without the raw.lxc lxc.apparmor.profile=unconfined option in place, when I restart the container:

[Wed Apr 22 17:59:02 2026] audit: type=1400 audit(1776873542.636:385): apparmor="STATUS" operation="profile_remove" profile="unconfined" name="incus-sound-katydid_</var/lib/incus>" pid=330389 comm="apparmor_parser"
[Wed Apr 22 17:59:03 2026] audit: type=1400 audit(1776873542.972:386): apparmor="STATUS" operation="profile_load" profile="unconfined" name="incus-sound-katydid_</var/lib/incus>" pid=330679 comm="apparmor_parser"

No further messages when I try to attempt to dd, or when I replug the device.

Starting a privileged container results in these messages in dmesg:

[Wed Apr 22 18:00:01 2026] audit: type=1400 audit(1776873601.244:387): apparmor="STATUS" operation="profile_remove" profile="unconfined" name="incus-sound-katydid_</var/lib/incus>" pid=331343 comm="apparmor_parser"
[Wed Apr 22 18:00:01 2026] audit: type=1400 audit(1776873601.628:388): apparmor="STATUS" operation="profile_load" profile="unconfined" name="incus-sound-katydid_</var/lib/incus>" pid=331623 comm="apparmor_parser"
[Wed Apr 22 18:00:02 2026] audit: type=1400 audit(1776873601.992:389): apparmor="DENIED" operation="mount" class="mount" info="failed type match" error=-13 profile="incus-sound-katydid_</var/lib/incus>" name="/dev/.incus-systemd-credentials/" pid=331651 comm="(sd-gens)" flags="ro, remount, bind"
[Wed Apr 22 18:00:02 2026] audit: type=1400 audit(1776873601.992:390): apparmor="DENIED" operation="mount" class="mount" info="failed type match" error=-13 profile="incus-sound-katydid_</var/lib/incus>" name="/dev/pts/" pid=331651 comm="(sd-gens)" flags="ro, nosuid, noexec, remount, bind"
[Wed Apr 22 18:00:02 2026] audit: type=1400 audit(1776873601.992:391): apparmor="DENIED" operation="mount" class="mount" info="failed type match" error=-13 profile="incus-sound-katydid_</var/lib/incus>" name="/dev/" pid=331651 comm="(sd-gens)" flags="ro, remount, bind"
[Wed Apr 22 18:00:02 2026] audit: type=1400 audit(1776873601.992:392): apparmor="DENIED" operation="mount" class="mount" info="failed flags match" error=-13 profile="incus-sound-katydid_</var/lib/incus>" name="/" pid=331651 comm="(sd-gens)" flags="ro, remount, bind"
[Wed Apr 22 18:00:02 2026] audit: type=1400 audit(1776873602.284:393): apparmor="DENIED" operation="mount" class="mount" info="failed type match" error=-13 profile="incus-sound-katydid_</var/lib/incus>" name="/tmp/" pid=331734 comm="mount" flags="rw, move"

When I create a new container: sudo incus launch images:debian/trixie, without any customization (the default profile is not modified either), I also get the same: apparmor="STATUS" operation="profile_load" profile="unconfined" name="incus-moving-ibex_</var/lib/incus>" pid=332684 comm="apparmor_parser".

So, only when starting a privileged container does anything get DENIED. But, I get the permission denied with both priv and unpriv.
Is there any further AppArmor configuration I could change or test with?

Thank you!

NB.
I’m using your zabbly-incus-stable.sources repo, so version 6.23 now.

I noticed that on my Arch system /var/lib/incus/devices was mounted as tmpfs, while on Debian it was simply a directory on my (ZFS) root filesystem, which has the nodev mount option.

I then mounted it as tmpfs on Debian too: mount -t tmpfs -o rw,relatime,size=51200k,mode=711 tmpfs /var/lib/incus/devices, and this actually solved the issue. I can now dd inside the container.

But, I’m confused about this. The reason I actually started using the Zabbly repository was to obtain a newer version that included this fix: Make /var/lib/incus/devices a tmpfs #2668 .
I did that because of another issue with a different container, which needed a PCIe NIC passed through. With the stock Debian version of Incus, the container wouldn’t start with the NIC device attached. After upgrading Incus with the Zabbly repo, that issue was fixed.
However, apparently the devices node is still not tmpfs.

@stgraber Does this seem to you like it could be the core underlying issue that was giving me this problem? How would you suggest solving this persistently?

Thank you.

root@castiana:~# grep /devices /proc/mounts 
tmpfs /var/lib/incus/devices tmpfs rw,relatime,size=51200k,mode=711,inode64 0 0

Did you ever reboot the machine since moving to the Zabbly packages?
Mounting devices as a tmpfs can only be done when no instances are running at all, so just upgrading to a newer version will not immediately apply it.

After I upgraded the packages, I stopped all instances and restarted the Incus systemd service.
I may indeed not have restarted the server, not entirely sure anymore.
Either way, I did reboot now and devices is now indeed mounted as tmpfs.
Thank you!