Control: retitle -1 `decrypt_keyctl` fails when the user-keyring(7) isn't attached to the calling process
Hi Sebastian, Thanks for the detailed report! I was able to reproduce this in a fresh Buster netinstall, taking SSH sessions and sudo(8)'s ā-iā flag out of the picture. This is what I get right after a reboot: user@kvm-31992:~$ sudo keyctl show @u Keyring 99804791 --alswrv 0 65534 keyring: _uid.0 user@kvm-31992:~$ sudo keyctl show @s Keyring 1021507217 --alswrv 1000 1000 keyring: _ses 872133423 ---lswrv 1000 65534 \_ keyring: _uid.1000 user@kvm-31992:~$ sudo keyctl show @us Keyring 133933438 --alswrv 0 65534 keyring: _uid_ses.0 99804791 --alswrv 0 65534 \_ keyring: _uid.0 Keys attached to root's user-keyring(7) can't be read. user@kvm-31992:~$ sudo keyctl add user "foo" "bar" @u 875128385 user@kvm-31992:~$ sudo keyctl show @us Keyring 133933438 --alswrv 0 65534 keyring: _uid_ses.0 99804791 --alswrv 0 65534 \_ keyring: _uid.0 875128385 --alswrv 0 0 \_ user: foo user@kvm-31992:~$ sudo keyctl print 875128385 keyctl_read_alloc: Permission denied So LUKS2 volumes can't be open using token keyrings: user@kvm-31992:~$ sudo dd if=/dev/zero of=/tmp/disk.img bs=1M count=64 status=none user@kvm-31992:~$ sudo cryptsetup luksFormat -q \ --pbkdf-force-iterations 4 --pbkdf-memory 32 /tmp/disk.img <<<bar user@kvm-31992:~$ sudo cryptsetup token add --key-description foo -S 0 /tmp/disk.img user@kvm-31992:~$ sudo cryptsetup luksOpen --test-passphrase --debug \ --token-only /tmp/disk.img [ā¦] # keyring_get_passphrase failed (error -126) # Token 0 (luks2-keyring) open failed with -22. And indeed decrypt_keyctl chokes as well: user@kvm-31992:~$ sudo CRYPTTAB_NAME=foo CRYPTTAB_KEY=bar CRYPTTAB_TRIED=0 \ /lib/cryptsetup/scripts/decrypt_keyctl Caching passphrase for foo: *** keyctl_set_timeout: Permission denied Error setting timeout on key (163348240), removing AFAICT this is because the caller doesn't possess %user:foo, cf. https://manpages.debian.org/buster/manpages/keyrings.7.en.html#Possession A workaround is to do these operations in a new session-keyring(7), and link root's user-keyring(7) to it. user@kvm-31992:~$ sudo keyctl session Joined session keyring: 777897511 root@kvm-31992:/home/user# keyctl link @u @s root@kvm-31992:/home/user# keyctl show Session Keyring 777897511 --alswrv 0 0 keyring: _ses 99804791 --alswrv 0 65534 \_ keyring: _uid.0 875128385 --alswrv 0 0 \_ user: foo root@kvm-31992:/home/user# keyctl print 875128385 bar root@kvm-31992:/home/user# cryptsetup luksOpen --test-passphrase -v \ --token-only /tmp/disk.img Key slot 0 unlocked. Command successful. root@kvm-31992:/home/user# CRYPTTAB_NAME=foo CRYPTTAB_KEY=bar CRYPTTAB_TRIED=0 \ /lib/cryptsetup/scripts/decrypt_keyctl >/dev/null Caching passphrase for foo: *** root@kvm-31992:/home/user# exit I suppose /etc/pam.d/sudo could use pam_keyinit(8) to initialize a new session instead of doing the above dance. Anyway cryptsetup calls request_key("user",,NULL,0) at the moment, so unlocking LUKS2 devices via keyring tokens will only works in sessions where the user-keyring(7) is linked to the session-keyring(7). On Wed, 04 Sep 2019 at 00:18:57 +0200, Sebastian Mohr wrote: > I don't know whether there are further security implications or > something like that, AFAICT blindly using session-keyring(7) as it might open a window during which any program in the user session is able to read the payload: user@kvm-31992:~$ sudo keyctl add user "foo" "foo" @s 137160032 user@kvm-31992:~$ keyctl show @s Keyring 461059914 --alswrv 1000 1000 keyring: _ses 641525861 --alswrv 1000 65534 \_ keyring: _uid.1000 137160032 --alswrv 0 0 \_ user: foo user@kvm-31992:~$ keyctl print 137160032 foo (While the key is owned by the privileged user, it's possessed by the caller. It might even be possible to poison the session-keyring(7) by creating %user:foo with non-root ownership.) I think the best place to solve that is in /etc/pam.d/sudo itself, but failing that I suppose it's acceptable to have the payload readable by root (perhaps only as fallback, when the caller doesn't have enough right on the key it's adding). Perhaps keyctl(1) could provide a wrapper using thread-keyring(7) as temporary keyring, like the attached PoC. Or we could even rewrite decrypt_keyctl in C, or merge it with askpass. In fact one of our goals for this release cycle is to better integrate crypttab(5) with LUKS2 native keyring support, and that probably goes via adding keyring support in askpass. Cheers, -- Guilhem.
signature.asc
Description: PGP signature