Skip to content

Commit

Permalink
ceph: add fscrypt ioctls and ceph.fscrypt.auth vxattr
Browse files Browse the repository at this point in the history
We gate most of the ioctls on MDS feature support. The exception is the
key removal and status functions that we still want to work if the MDS's
were to (inexplicably) lose the feature.

For the set_policy ioctl, we take Fs caps to ensure that nothing can
create files in the directory while the ioctl is running. That should
be enough to ensure that the "empty_dir" check is reliable.

The vxattr is read-only, added mostly for future debugging purposes.

Signed-off-by: Jeff Layton <[email protected]>
Reviewed-by: Xiubo Li <[email protected]>
Reviewed-and-tested-by: Luís Henriques <[email protected]>
Reviewed-by: Milind Changire <[email protected]>
Signed-off-by: Ilya Dryomov <[email protected]>
  • Loading branch information
jtlayton authored and idryomov committed Aug 22, 2023
1 parent 6b5717b commit f061fed
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
84 changes: 84 additions & 0 deletions fs/ceph/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "mds_client.h"
#include "ioctl.h"
#include <linux/ceph/striper.h>
#include <linux/fscrypt.h>

/*
* ioctls
Expand Down Expand Up @@ -268,8 +269,54 @@ static long ceph_ioctl_syncio(struct file *file)
return 0;
}

static int vet_mds_for_fscrypt(struct file *file)
{
int i, ret = -EOPNOTSUPP;
struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(file_inode(file)->i_sb);

mutex_lock(&mdsc->mutex);
for (i = 0; i < mdsc->max_sessions; i++) {
struct ceph_mds_session *s = mdsc->sessions[i];

if (!s)
continue;
if (test_bit(CEPHFS_FEATURE_ALTERNATE_NAME, &s->s_features))
ret = 0;
break;
}
mutex_unlock(&mdsc->mutex);
return ret;
}

static long ceph_set_encryption_policy(struct file *file, unsigned long arg)
{
int ret, got = 0;
struct inode *inode = file_inode(file);
struct ceph_inode_info *ci = ceph_inode(inode);

ret = vet_mds_for_fscrypt(file);
if (ret)
return ret;

/*
* Ensure we hold these caps so that we _know_ that the rstats check
* in the empty_dir check is reliable.
*/
ret = ceph_get_caps(file, CEPH_CAP_FILE_SHARED, 0, -1, &got);
if (ret)
return ret;

ret = fscrypt_ioctl_set_policy(file, (const void __user *)arg);
if (got)
ceph_put_cap_refs(ci, got);

return ret;
}

long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;

dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg);
switch (cmd) {
case CEPH_IOC_GET_LAYOUT:
Expand All @@ -289,6 +336,43 @@ long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

case CEPH_IOC_SYNCIO:
return ceph_ioctl_syncio(file);

case FS_IOC_SET_ENCRYPTION_POLICY:
return ceph_set_encryption_policy(file, arg);

case FS_IOC_GET_ENCRYPTION_POLICY:
ret = vet_mds_for_fscrypt(file);
if (ret)
return ret;
return fscrypt_ioctl_get_policy(file, (void __user *)arg);

case FS_IOC_GET_ENCRYPTION_POLICY_EX:
ret = vet_mds_for_fscrypt(file);
if (ret)
return ret;
return fscrypt_ioctl_get_policy_ex(file, (void __user *)arg);

case FS_IOC_ADD_ENCRYPTION_KEY:
ret = vet_mds_for_fscrypt(file);
if (ret)
return ret;
return fscrypt_ioctl_add_key(file, (void __user *)arg);

case FS_IOC_REMOVE_ENCRYPTION_KEY:
return fscrypt_ioctl_remove_key(file, (void __user *)arg);

case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
return fscrypt_ioctl_remove_key_all_users(file,
(void __user *)arg);

case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
return fscrypt_ioctl_get_key_status(file, (void __user *)arg);

case FS_IOC_GET_ENCRYPTION_NONCE:
ret = vet_mds_for_fscrypt(file);
if (ret)
return ret;
return fscrypt_ioctl_get_nonce(file, (void __user *)arg);
}

return -ENOTTY;
Expand Down
27 changes: 27 additions & 0 deletions fs/ceph/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,24 @@ static ssize_t ceph_vxattrcb_auth_mds(struct ceph_inode_info *ci,
return ret;
}

#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
static bool ceph_vxattrcb_fscrypt_auth_exists(struct ceph_inode_info *ci)
{
return ci->fscrypt_auth_len;
}

static ssize_t ceph_vxattrcb_fscrypt_auth(struct ceph_inode_info *ci,
char *val, size_t size)
{
if (size) {
if (size < ci->fscrypt_auth_len)
return -ERANGE;
memcpy(val, ci->fscrypt_auth, ci->fscrypt_auth_len);
}
return ci->fscrypt_auth_len;
}
#endif /* CONFIG_FS_ENCRYPTION */

#define CEPH_XATTR_NAME(_type, _name) XATTR_CEPH_PREFIX #_type "." #_name
#define CEPH_XATTR_NAME2(_type, _name, _name2) \
XATTR_CEPH_PREFIX #_type "." #_name "." #_name2
Expand Down Expand Up @@ -500,6 +518,15 @@ static struct ceph_vxattr ceph_common_vxattrs[] = {
.exists_cb = NULL,
.flags = VXATTR_FLAG_READONLY,
},
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
{
.name = "ceph.fscrypt.auth",
.name_size = sizeof("ceph.fscrypt.auth"),
.getxattr_cb = ceph_vxattrcb_fscrypt_auth,
.exists_cb = ceph_vxattrcb_fscrypt_auth_exists,
.flags = VXATTR_FLAG_READONLY,
},
#endif /* CONFIG_FS_ENCRYPTION */
{ .name = NULL, 0 } /* Required table terminator */
};

Expand Down

0 comments on commit f061fed

Please sign in to comment.