#774647 can't a use key file stored on an encrypted rootfs to unlock the resume device at initramfs stage #774647
- Package:
- cryptsetup-initramfs
- Source:
- cryptsetup
- Submitter:
- Åukasz Stelmach
- Date:
- 2025-08-17 17:47:57 UTC
- Severity:
- wishlist
- Tags:
Dear Maintainer, I have the following setup (see below for the files) + /boot on /dev/sda1 + root filesystem on /dev/mapper/sda2_cryptblk + /home, /var and swap on LVM on /dev/mapper/sdb2_crypt --- blkid --- /dev/mapper/vg1-home: LABEL="HOME" UUID="3c300542" TYPE="ext4" /dev/mapper/vg1-var: LABEL="VAR" UUID="c4be931f" TYPE="ext4" /dev/mapper/vg1-swap: LABEL="swap" UUID="cb8020c2" TYPE="swap" ------------- sda2_crypt is protected by a password I enter upon boot-up, sdb2_crypt with a key file stored on the root filesystem. I added resume=UUID=... pointing to my swap to the kernel command line and ran update-initramfs and got the following message cryptsetup: WARNING: target sdb2_crypt uses a key file, skipped Apparently the cryptsetup initramfs scripts do not support my case where a key file for a partition is stored on another encrypted partition. A simmilar use case has been described here: https://bugs.launchpad.net/ubuntu/+source/cryptsetup/+bug/238163
Hi, The main reason reported this problem is that I want to enter a single password to decrypt all my partitions. In such case there is a way to work the problem around: a) set the same password for all the devices you want initrd to decrypt, b) use keyctl to cache the password. My /etc/crypttab now looks like this:-----8<----- sda2_crypt UUID=e499987ab017 root_key luks,keyscript=decrypt_keyctl sdb2_crypt UUID=c3b74b86b567 root_key luks,keyscript=decrypt_keyctl -----8<----- The procedure is described in the README.keyctl file. http://anonscm.debian.org/viewvc/pkg-cryptsetup/cryptsetup/trunk/debian/README.keyctl?revision=977&view=co
Control: merge 776409 -1 Hi, Yeah, it's because in the initramfs (before pivot_root) the key files are relative to the real rootfs's mountpoint (/root). Sergio Gelato has found another workaround [0] using a dummy keyscript. I'll see how to support this use case natively. As documented in crypttab(5), “the initramfs hook processes the root device, any resume devices and any devices with the initramfs option set”, so indeed we could safely include a keyfile if stored on an encrypted device that's processed earlier. AFAICT it's mostly a matter of getting the file's mountpoint and finding out whether the device was already included in conf.d/cryptroot. Cheers,
Here is a simple patch that adds keyfile support for non-root devices. Ideally we would also warn the user if the key file is stored on an unencrypted device, but that requires some code refactoring in the hook file so it'll come in a later patch.
Hi Guilhem, Am 12.12.2015 um 20:38 schrieb Guilhem Moulin: I like your idea to check whether the keyfile is on the rootfs for resume and other non-rootfs devices that are processed during initramfs. I've some comments and questions regarding your patch though. Have you tested the patch already? What's the reason for introducing the isrootdev variable? Why not use the "rootdev" option that's already there? Honestly, I don't get it. Probably I miss something, though ;) */ You set isrootdev=n at the beginning of add_device(). If the device is an underlying device for rootfs , then rootdev is added to $opts (old) and now, isrootdev=y is set additionally (new). The value of isrootdev is given to get_device_opts() as $3. */ At the start of get_device_opts(), isrootdev is set to the value of $3. If the opt "rootdev" is set, then isrootdev=y is set. */ Up to now, the variable $isrootdev is only set to 'y' in exactly the same situations as that the opt "rootdev" is set as well. If rootdev is not set in $opts, then $isroodev=n. So in my eyes, the opt "rootdev" and the variable $isrootdev are consistent. */ Later in get_device_opts() when the keyfiles are processed, you check for $isrootdev and warn if it $isrootdev!=n. Why not simply search for "rootdev" in $OPTIONS instead? See below for a suggestion. See above. See above. I think, that the following would be sufficient: if echo "$OPTIONS" | grep -q "\brootdev\b"; then Would need to stat against the canonical file (e.g. after readlink) here. Otherwise, the keyfile path can be a link on the rootfs that points to another partition. Should be as easy as adding: keylink=$(readlink -e "$dev") just before the case selection and running stat against $keylink. No need for the TODO in my eyes. We only get here, if the key is stored on the rootfs. In this case, we don't fiddle around with the keyfile at all. All we do, is change the path to the keyfile in cryptroot-script, so the keyfile itself is not touched by us at all. Sure, it would be nice to warn the user if she stores the keyfile on an unencrypted root fs, but then this is just one more corner case where a user implements an uncommon custom setup in an unsecure fashion, and we cannot check against all those corner cases anyway. Would be key="$keylink" then. See above. I like :) See above. See above. Cheers jonas
Hi,
Yes, but only on a resume device (and without LVM). (But I don't see
how the same wouldn't work for other devices and/or LVM.)
I only wanted to avoid parsing the $OPTIONS string :-P But indeed it's
easier to grep through $OPTIONS. And not more error prone if we assume
that crypttab fields don't contain blanks or commas.
As pointed out on IRC, word delimiters are error prone since
‘key=/path/to/rootdev.key’ would match, for instance. But
if echo "$OPTIONS" | grep -q "^(.*,)?rootdev(,.*)?$"; then
looks fine.
Oh, right, stat's -L flag deferences symlink, but doesn't take the
canonical path, indeed.
Makes sense, fixed and new patch enclosed.
Cheers,
Sorry, typo :-P
current init which requires all node devices to be present before the rootfs is being mounted, as found in initramfs-tools(8): local-top OR nfs-top After these scripts have been executed, the root device node is expected to be present (local) or the network interface is expected to be usable (NFS). local-block These scripts are called with the name of a local block device. After these scripts have been executed, that device node should be present. If the local-top or local-block scripts fail to create the wanted device node, the local-block scripts will be called periodically to try again. local-premount OR nfs-premount are run after the sanity of the root device has been verified (local) or the network interface has been brought up (NFS), but before the actual root fs has been mounted. local-bottom OR nfs-bottom are run after the rootfs has been mounted (local) or the NFS root share has been mounted. So I guess we'll have to mount the roofs read-only in a temporary directory, and unmount it afterwards.
I just added support for unlocking devices at initramfs stage using a key file stored on the encrypted root FS. However the resume device won't be unlocked this way since the resume boot script is currently run before mounting the root FS.
Hey.
I recently considered to do the same, i.e.:
- have a passphrase only for the dm-crypt encrypted rootfs
- have a separate dm-crypt encrypted swap device for hibernate only
- use a high-entropy key-file on the rootfs to decrypt the swap device
My understanding of the initramfs-tools boot is as follows:
init-top
...
local-top => here cryptroot opens ("decrypts") the root- and resume-
device as well as any with "initramfs"-option in crypttab
local-bottom => it retries the same here
local-premount => here, none of these devices has been mounted, yet
also here, the resume happens, at which point
the system is completely replaced, the initramfs used
just before for booting into the resume no longer
exists, no mounting of the devices will take place,
no pivot_root either
(none of this is anyway necessary, as the resumed
system has all that already done)
So the only way to get a key-file within the (not mounted) rootfs after
local-top/bottom but before the resume in local-premount would be to
actually mount the root fs before.
This is however pretty dangerous.
Even if the mounting is done read-only, filesystems may perform changes
(at least btrfs does, and I think ext4 may do so too).
There was recently [0], where someone mounted the root-fs in-between
suspend and resume and got corruptions.
While it was argued that the filesystem was frozen at suspend and that
btrfs would *try* to detect (since 6.2) whether it was mounted in-
between,... it was also argued that caching (in the resumed system) may
cause corruptions.
The blockdevice would need to be blockdev --setro first, but even that
may be more complex than one might think:
Consider e.g. multi-device filesystems (again e.g. btrfs), where the
other devices are auto-detected via UUID.
So IMO, this feature cannot be safely implemented.
Maybe the only way to do it safely was a hack:
- create a swapfile in the rootfs (this is anyway required to be not
moved)
- get it's physical offest into the device (beware: for btrfs special
commands are needed for that)
- let cryptroot read the key raw from that offest
But, again, quite ugly and hacky.
Cheers,
Chris.
[0] https://lore.kernel.org/linux-btrfs/ba9fb1c9-ccbc-4b93-92f9-a8c17ffab7f6@business-insulting.de/
Hey. I rather think now that even my hack with the swapfile isn't really save. The idea with that was that it's just the file, but not activated as swap of course. But who knows for sure that in this case the file is never moved. Anyway, @Guilhem, would you agree to close this as wontfix and add a README.x entry that describes why - with hibernation/resume - the key file cannot safely be loaded from a filesystem that is hibernated, too? Not sure whether to better put it in README.initramfs (yes it happens in that phase) or README.Debian (in principle a user could just hack something together on his own with the same issue and not even install cryptsetup-initramfs). Cheers, Chris.