From fb99b37a05696db4ceabb793e5f16727ec854ed1 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 9 May 2020 14:17:17 -0700 Subject: keyring/user_keyring: switch to KEYCTL_UNLINK KEYCTL_INVALIDATE has complicated semantics: it doesn't remove the key from the keyring right away but rather marks it as being invalidated, and then removes it asynchronously. This nondeterministically breaks the heuristic I'm implementing to detect v1-encrypted directories being incompletely locked. Instead, switch to KEYCTL_UNLINK, which has simpler semantics. Note that Android uses KEYCTL_UNLINK too. --- keyring/keyring.go | 2 +- keyring/user_keyring.go | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) (limited to 'keyring') diff --git a/keyring/keyring.go b/keyring/keyring.go index 6623943..fb9cc0e 100644 --- a/keyring/keyring.go +++ b/keyring/keyring.go @@ -173,7 +173,7 @@ func GetEncryptionKeyStatus(descriptor string, options *Options) (KeyStatus, err if useFsKeyring { return fsGetEncryptionKeyStatus(descriptor, options.Mount, options.User) } - _, err = userFindKey(buildKeyDescription(options, descriptor), options.User) + _, _, err = userFindKey(buildKeyDescription(options, descriptor), options.User) if err != nil { return KeyAbsent, nil } diff --git a/keyring/user_keyring.go b/keyring/user_keyring.go index 71f519d..beeb36d 100644 --- a/keyring/user_keyring.go +++ b/keyring/user_keyring.go @@ -78,39 +78,37 @@ func userRemoveKey(description string, targetUser *user.User) error { runtime.LockOSThread() // ensure target user keyring remains possessed in thread keyring defer runtime.UnlockOSThread() - keyID, err := userFindKey(description, targetUser) + keyID, keyringID, err := userFindKey(description, targetUser) if err != nil { return ErrKeyNotPresent } - // We use KEYCTL_INVALIDATE instead of KEYCTL_REVOKE because - // invalidating a key immediately removes it. - _, err = unix.KeyctlInt(unix.KEYCTL_INVALIDATE, keyID, 0, 0, 0) - log.Printf("KeyctlInvalidate(%d) = %v", keyID, err) + _, err = unix.KeyctlInt(unix.KEYCTL_UNLINK, keyID, keyringID, 0, 0) + log.Printf("KeyctlUnlink(%d, %d) = %v", keyID, keyringID, err) if err != nil { return errors.Wrap(ErrKeyRemove, err.Error()) } return nil } -// userFindKey tries to locate a key in the user keyring with the provided -// description. The key ID is returned if we can find the key. An error is -// returned if the key does not exist. -func userFindKey(description string, targetUser *user.User) (int, error) { +// userFindKey tries to locate a key with the provided description in the user +// keyring for the target user. The key ID and keyring ID are returned if we can +// find the key. An error is returned if the key does not exist. +func userFindKey(description string, targetUser *user.User) (int, int, error) { runtime.LockOSThread() // ensure target user keyring remains possessed in thread keyring defer runtime.UnlockOSThread() keyringID, err := UserKeyringID(targetUser, false) if err != nil { - return 0, err + return 0, 0, err } keyID, err := unix.KeyctlSearch(keyringID, KeyType, description, 0) log.Printf("KeyctlSearch(%d, %s, %s) = %d, %v", keyringID, KeyType, description, keyID, err) if err != nil { - return 0, errors.Wrap(ErrKeySearch, err.Error()) + return 0, 0, errors.Wrap(ErrKeySearch, err.Error()) } - return keyID, err + return keyID, keyringID, err } // UserKeyringID returns the key id of the target user's user keyring. We also -- cgit v1.2.3