Summary
I came across what seemed like a very strange issue when building an image on a Debian Buster system. The system is admittedly a bit out of date- the kernel package and most of the system/userland is from ~June of 2020. It's possible this issue has been fixed in the most recent release of Debian Buster. This is the environment I encountered the issue on:
8:49:34 › lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 10 (buster)
Release: 10
Codename: buster
8:49:36 › uname -a
Linux host 5.6.0-0.bpo.2-amd64 #1 SMP Debian 5.6.14-2~bpo10+1 (2020-06-09) x86_64 GNU/Linux
8:49:38 › /sbin/losetup -V
losetup from util-linux 2.33.1
Symptoms / Reproduce
When using make
to build an image as an unprivileged user on a freshly booted system, the losetup
command used to create a loopback device fails, causing a build failure
$ make V=mark-two IMX=imx6ulz BOOT=uSD
...
sudo /sbin/losetup usbarmory-mark-two-usd-debian_buster-base_image-20210424.raw -o 5242880 --sizelimit 3500MiB
losetup: usbarmory-mark-two-usd-debian_buster-base_image-20210424.raw: failed to use device: No such device
make: *** [Makefile:83: usbarmory-mark-two-usd-debian_buster-base_image-20210424.raw] Error 1
This command in the Makefile
looks like this:
sudo /sbin/losetup $(LOSETUP_DEV) usbarmory-${IMG_VERSION}.raw -o 5242880 --sizelimit 3500MiB
Clearly the LOSETUP_DEV
variable is not set. This confused me, because on line 24, it is very clearly set:
LOSETUP_DEV=$(shell /sbin/losetup -f)
Cause
The root cause is that the loop
module is not loaded until losetup
is invoked as a privileged user (explicitly or via sudo
) or until modprobe loop
is explicitly invoked. It's arguable whether this is a bug or not, but because the losetup -f
command fails silently, I think it is a bug
One could also say that the cause is that losetup -f
is not invoked with sudo
. I say that because of the following behavior, and the fact that adding sudo
fixes the problem. Here's the behavior that initially baffled me. Note this is an unprivileged user (authorized for sudo
)
Unprivileged:
9:37:56 › /sbin/losetup -f
losetup: cannot find an unused loop device: Permission denied
Via sudo
:
9:38:00 › sudo /sbin/losetup -f
/dev/loop0
Again, unprivileged:
9:38:04 › /sbin/losetup -f
/dev/loop0
- The first command fails as the
loop
module is not loaded by default and is not autoloaded
- The second command, presumably because it is running with root privileges, causes the
loop
module to load implicitly/automatically.
- Retrying
losetup -f
as an unprivileged user after that works
The permission denied message is a result of access("/dev/loop-control", W_OK)
, which returns EACCES when the loop
module isn't loaded. Very deceiving behavior, but probably documented somewhere
Fix
Invoke sudo losetup -f
instead of losetup -f
in the Makefile
. This fixes the issue and makes the losetup
invocation consistent with the others in the Makefile
Another option is failing the build when the losetup -f
fails, but I think it's better to just avoid the issue entirely by adding sudo
Notes
I am guessing that this is not "broken" in all distributions and probably worked on older versions of Debian, and still works on other distributions. My guess is this was caused by one or more of the following:
- The module auto-loading behavior was changed
- The way
losetup
behaves was changed
- Previous versions of Debian explicitly loaded
loop
on boot
- Previous versions of Debian did not build
loop
support as a module
I will send a PR for this as it's a very simple fix- assuming this is considered a bug. I think it's a better solution then letting users figure out the silent failure of losetup -f
is what caused the failure in losetup
later on- it took me a good 10-15 minutes to track this down, despite being very simple. It's not intuitive at all and the Permission Denied error from losetup
contributes to the confusion