On Thu, Aug 01, 2019 at 01:31:08AM -0400, Theodore Y. Ts'o wrote: > On Wed, Jul 31, 2019 at 06:11:40PM -0700, Eric Biggers wrote: > > > > Well, it's either > > > > 1a. Remove the user's handle. > > OR > > 1b. Remove all users' handles. (FSCRYPT_REMOVE_KEY_FLAG_ALL_USERS) > > > > Then > > > > 2. If no handles remain, try to evict all inodes that use the key. > > > > By "purge all keys" do you mean step (2)? Note that it doesn't require root by > > itself; root is only required to remove other users' handles (1b). > > No, I was talking about 1b. I'd argue that 1a and 1b should be > different ioctl. 1b requires root, and 1a doesn't. > [...] > > > > Do you mean use a positive return value, or do you mean add an output field to > > the struct passed to the ioctl? > > I meant adding an output field. I see EBUSY and EUSERS as status bits > which *some* use cases might find useful. Ted, would you be happy with the following API? Removing keys ------------- Two ioctls are available for removing a key that was added by FS_IOC_ADD_ENCRYPTION_KEY: FS_IOC_REMOVE_ENCRYPTION_KEY and FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS. They differ only in cases where v2 policy keys are added or removed by non-root users. These ioctls don't work on keys that were added via the legacy process-subscribed keyrings mechanism. Before using these ioctls, read the `Kernel memory compromise`_ section for a discussion of the security goals and limitations of these ioctls. FS_IOC_REMOVE_ENCRYPTION_KEY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The FS_IOC_REMOVE_ENCRYPTION_KEY ioctl removes a claim to an fscrypt master encryption key from the filesystem, and possibly removes the key itself. It can be executed on any file or directory on the target filesystem, but using the filesystem's root directory is recommended. It takes in a pointer to a :c:type:`struct fscrypt_remove_key_arg`, defined as follows:: struct fscrypt_remove_key_arg { struct fscrypt_key_specifier key_spec; #define FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS 0x00000001 #define FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY 0x00000002 __u32 removal_status_flags; /* output */ __u32 __reserved[5]; }; This structure must be zeroed, then initialized as follows: - The key to remove is specified by ``key_spec``: - To remove a key used by v1 encryption policies, set ``key_spec.type`` to FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR and fill in ``key_spec.u.descriptor``. To remove this type of key, the calling process must have the CAP_SYS_ADMIN capability in the initial user namespace. - To remove a key used by v2 encryption policies, set ``key_spec.type`` to FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER and fill in ``key_spec.u.identifier``. To remove this type of key, no privileges are needed. However, users can only remove keys that they added themselves, subject to privileged override with FSCRYPT_REMOVE_KEY_FLAG_ALL_USERS. For v2 policy keys, this ioctl is usable by non-root users. However, to make this possible, it actually just removes the current user's claim to the key, undoing a single call to FS_IOC_ADD_ENCRYPTION_KEY. Only after all claims are removed is the key really removed. For example, if FS_IOC_ADD_ENCRYPTION_KEY was called with uid 1000, then the key will be "claimed" by uid 1000, and FS_IOC_REMOVE_ENCRYPTION_KEY will only succeed as uid 1000. Or, if both uids 1000 and 2000 added the key, then for each uid FS_IOC_REMOVE_ENCRYPTION_KEY will only remove their own claim. Only once *both* are removed is the key really removed. (Think of it like unlinking a file that may have hard links.) If FS_IOC_REMOVE_ENCRYPTION_KEY really removes the key, it will also try to "lock" all files that had been unlocked with the key. It won't lock files that are still in-use. If necessary, the ioctl can be executed again later to retry locking any remaining files. FS_IOC_REMOVE_ENCRYPTION_KEY returns 0 if either the key was removed (but may still have files remaining to be locked), the user's claim to the key was removed, or the key was already removed but had files remaining to be the locked so the ioctl retried locking them. In any of these cases, ``removal_status_flags`` is filled in with the following informational status flags: - ``FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS``: set if only the user's claim to the key was removed, not the key itself - ``FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY``: set if some file(s) are still in-use. Not guaranteed to be set in the case where only the user's claim to the key was removed. FS_IOC_REMOVE_ENCRYPTION_KEY can fail with the following errors: - ``EACCES``: The FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR key specifier type was specified, but the caller does not have the CAP_SYS_ADMIN capability in the initial user namespace - ``EINVAL``: invalid flags or key specifier type, or reserved bits were set - ``ENOKEY``: the key object was not found at all, i.e. it was never added in the first place or was already fully removed including all files locked; or, the user does not have a claim to the key. - ``ENOTTY``: this type of filesystem does not implement encryption - ``EOPNOTSUPP``: the kernel was not configured with encryption support for this filesystem, or the filesystem superblock has not had encryption enabled on it FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS is exactly the same as FS_IOC_REMOVE_ENCRYPTION_KEY, except that for v2 policy keys, the ALL_USERS version of the ioctl will remove all users' claims to the key, not just the current user's. I.e., the key itself will always be removed, no matter how many users have added it. This difference is only meaningful if non-root users are adding and removing keys. Because of this, FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS also requires "root", namely the CAP_SYS_ADMIN capability in the initial user namespace. Otherwise it will fail with ``EACCES``. ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/