Skip to content

Commit

Permalink
fscrypt: add FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS ioctl
Browse files Browse the repository at this point in the history
Add a root-only variant of the FS_IOC_REMOVE_ENCRYPTION_KEY ioctl which
removes all users' claims of the key, not just the current user's claim.
I.e., it always removes the key itself, no matter how many users have
added it.

This is useful for forcing a directory to be locked, without having to
figure out which user ID(s) the key was added under.  This is planned to
be used by a command like 'sudo fscrypt lock DIR --all-users' in the
fscrypt userspace tool (http://github.com/google/fscrypt).

Reviewed-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Eric Biggers <ebiggers@google.com>
  • Loading branch information
Eric Biggers committed Aug 13, 2019
1 parent 23c688b commit 78a1b96
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 5 deletions.
29 changes: 24 additions & 5 deletions fs/crypto/keyring.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*
* - FS_IOC_ADD_ENCRYPTION_KEY
* - FS_IOC_REMOVE_ENCRYPTION_KEY
* - FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS
* - FS_IOC_GET_ENCRYPTION_KEY_STATUS
*
* See the "User API" section of Documentation/filesystems/fscrypt.rst for more
Expand Down Expand Up @@ -699,8 +700,10 @@ static int try_to_lock_encrypted_files(struct super_block *sb,
/*
* Try to remove an fscrypt master encryption key.
*
* This removes the current user's claim to the key, then removes the key itself
* if no other users have claims.
* FS_IOC_REMOVE_ENCRYPTION_KEY (all_users=false) removes the current user's
* claim to the key, then removes the key itself if no other users have claims.
* FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS (all_users=true) always removes the
* key itself.
*
* To "remove the key itself", first we wipe the actual master key secret, so
* that no more inodes can be unlocked with it. Then we try to evict all cached
Expand All @@ -715,7 +718,7 @@ static int try_to_lock_encrypted_files(struct super_block *sb,
* For more details, see the "Removing keys" section of
* Documentation/filesystems/fscrypt.rst.
*/
int fscrypt_ioctl_remove_key(struct file *filp, void __user *_uarg)
static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
{
struct super_block *sb = file_inode(filp)->i_sb;
struct fscrypt_remove_key_arg __user *uarg = _uarg;
Expand Down Expand Up @@ -751,9 +754,12 @@ int fscrypt_ioctl_remove_key(struct file *filp, void __user *_uarg)

down_write(&key->sem);

/* If relevant, remove current user's claim to the key */
/* If relevant, remove current user's (or all users) claim to the key */
if (mk->mk_users && mk->mk_users->keys.nr_leaves_on_tree != 0) {
err = remove_master_key_user(mk);
if (all_users)
err = keyring_clear(mk->mk_users);
else
err = remove_master_key_user(mk);
if (err) {
up_write(&key->sem);
goto out_put_key;
Expand Down Expand Up @@ -809,8 +815,21 @@ int fscrypt_ioctl_remove_key(struct file *filp, void __user *_uarg)
err = put_user(status_flags, &uarg->removal_status_flags);
return err;
}

int fscrypt_ioctl_remove_key(struct file *filp, void __user *uarg)
{
return do_remove_key(filp, uarg, false);
}
EXPORT_SYMBOL_GPL(fscrypt_ioctl_remove_key);

int fscrypt_ioctl_remove_key_all_users(struct file *filp, void __user *uarg)
{
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
return do_remove_key(filp, uarg, true);
}
EXPORT_SYMBOL_GPL(fscrypt_ioctl_remove_key_all_users);

/*
* Retrieve the status of an fscrypt master encryption key.
*
Expand Down
8 changes: 8 additions & 0 deletions include/linux/fscrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *,
extern void fscrypt_sb_free(struct super_block *sb);
extern int fscrypt_ioctl_add_key(struct file *filp, void __user *arg);
extern int fscrypt_ioctl_remove_key(struct file *filp, void __user *arg);
extern int fscrypt_ioctl_remove_key_all_users(struct file *filp,
void __user *arg);
extern int fscrypt_ioctl_get_key_status(struct file *filp, void __user *arg);

/* keysetup.c */
Expand Down Expand Up @@ -396,6 +398,12 @@ static inline int fscrypt_ioctl_remove_key(struct file *filp, void __user *arg)
return -EOPNOTSUPP;
}

static inline int fscrypt_ioctl_remove_key_all_users(struct file *filp,
void __user *arg)
{
return -EOPNOTSUPP;
}

static inline int fscrypt_ioctl_get_key_status(struct file *filp,
void __user *arg)
{
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/fscrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ struct fscrypt_get_key_status_arg {
#define FS_IOC_GET_ENCRYPTION_POLICY_EX _IOWR('f', 22, __u8[9]) /* size + version */
#define FS_IOC_ADD_ENCRYPTION_KEY _IOWR('f', 23, struct fscrypt_add_key_arg)
#define FS_IOC_REMOVE_ENCRYPTION_KEY _IOWR('f', 24, struct fscrypt_remove_key_arg)
#define FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS _IOWR('f', 25, struct fscrypt_remove_key_arg)
#define FS_IOC_GET_ENCRYPTION_KEY_STATUS _IOWR('f', 26, struct fscrypt_get_key_status_arg)

/**********************************************************************/
Expand Down

0 comments on commit 78a1b96

Please sign in to comment.