Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cryptsetup: handle parallel activation of volumes with another tool gracefully #32903

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

kszczek
Copy link
Contributor

@kszczek kszczek commented May 17, 2024

This commit makes systemd-cryptsetup exit with a successful status when the volume gets unlocked outside of the current systemd-cryptsetup process while it was executing. This can be easily reproduced by calling systemd-cryptsetup, and while it waits for user to input a password/PIN, unlock the volume in a second terminal. Then after entering the password systemd-cryptsetup will exit with a non-zero status code.

This commit makes systemd-cryptsetup exit with a successful status when
the volume gets unlocked outside of the current systemd-cryptsetup
process while it was executing. This can be easily reproduced by calling
systemd-cryptsetup, and while it waits for user to input a password/PIN,
unlock the volume in a second terminal. Then after entering the password
systemd-cryptsetup will exit with a non-zero status code.
@github-actions github-actions bot added the please-review PR is ready for (re-)review by a maintainer label May 17, 2024
Copy link

Important

An -rc1 tag has been created and a release is being prepared, so please note that PRs introducing new features and APIs will be held back until the new version has been released.

@poettering
Copy link
Member

hmm, this is a really weird usecase. I am not really sure we should hide this kind of error, it seems really really specific to me, in particular as it's not clear if the activated volume really matches our expecations if we see EEXIST. could very well be some other device, no?

@poettering poettering changed the title cryptsetup: handle activation race conditions cryptsetup: handle parallel activation of volumes with another tool gracefully May 22, 2024
@kszczek
Copy link
Contributor Author

kszczek commented May 22, 2024

The situation I described is somewhat simplified, just an easy way to reproduce the issue. My actual use-case is a little bit more complex. I have a socket unit, which when triggered, assembles the key via a combination of TPM2 + FIDO2 devices. But the problem is, when TPM2 unseal fails or some other issue happens, I want to be able to use another "recovery" token. The problem is that systemd-cryptsetup falls back to a password prompt if the key acquired from the socket doesn't check out, so I can't use the recovery token on the second attempt, only passwords. I worked around this issue by calling another instance of systemd-cryptsetup in my aformentioned "keyscript", but this causes the issue described to arise. But the issue is mostly cosmetical, the system continues to boot, but the systemd-cryptsetup@ units show up as failed, even though the volumes are unlocked.

But yes, I agree with you that we can't guarantee that the device that was unlocked by the other tool is the same we are trying to unlock. But then maybe we could exit with a dedicated status code which would inform the caller of systemd-cryptsetup that the volume was already unlocked? This would allow me to solve the problem in my use-case by writing a drop-in unit for systemd-cryptsetup@ to treat this status code as success.

Also, currently systemd-cryptsetup exits with status code 1 in the situation described above, but also exits with status code 0 on subsequent invocations, doesn't this behavior also break expectations?

status = crypt_status(cd, volume);
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
log_info("Volume %s already active.", volume);
return 0;
}

🔐 Please enter passphrase for disk Linux LUKS (test): ••••••••                
Set cipher aes, mode xts-plain64, key size 512 bits for device /dev/vda3.
Device test already exists.
Failed to activate with specified passphrase: File exists
test@legion:~$ echo $?
1
test@legion:~$ sudo systemd-cryptsetup attach test /dev/vda3
Volume test already active.
test@legion:~$ echo $?
0
test@legion:~$ 

@kszczek
Copy link
Contributor Author

kszczek commented May 22, 2024

Okay, I've just learned that systemd-cryptsetup will always exit with EXIT_FAILURE no matter what the underlying error is, but it will send a notification using sd_notify with the actual errno, guess I didn't RTFM 😄

You have to add a drop-in for the systemd-cryptsetup@ unit though, because it uses Type=oneshot which will ignore these notifications by default. The drop-in unit has to set NotifyAccess=main in the [Service] section.

But the inconsistency I've mentioned in the comment above still stands. There are race conditions which will sometimes make systemd-cryptsetup exit with status code 1 and errno 17 (File exists), and in some other cases it will exit with status code 0 (the code snippet mentioned above). Are we concerned about this inconsistency?

Also off-topic: I'm struggling to find a way to make systemd treat errno 17 (File exists) as a successful exit of systemd-cryptsetup. I've tried SuccessExitStatus=, but it seems to apply only to the actual exit status code and not the errno. Have I missed anything in the docs which might help me here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cryptsetup needs-discussion 🤔 please-review PR is ready for (re-)review by a maintainer
Development

Successfully merging this pull request may close these issues.

None yet

3 participants