Skip to content

Commit 94af047

Browse files
jtlaytonidryomov
authored andcommitted
ceph: add some fscrypt guardrails
Add the appropriate calls into fscrypt for various actions, including link, rename, setattr, and the open codepaths. Disable fallocate for encrypted inodes -- hopefully, just for now. If we have an encrypted inode, then the client will need to re-encrypt the contents of the new object. Disable copy offload to or from encrypted inodes. Set i_blkbits to crypto block size for encrypted inodes -- some of the underlying infrastructure for fscrypt relies on i_blkbits being aligned to crypto blocksize. Report STATX_ATTR_ENCRYPTED on encrypted inodes. [ lhenriques: forbid encryption with striped layouts ] Signed-off-by: Jeff Layton <jlayton@kernel.org> Reviewed-by: Xiubo Li <xiubli@redhat.com> Reviewed-and-tested-by: Luís Henriques <lhenriques@suse.de> Reviewed-by: Milind Changire <mchangir@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
1 parent 79f2f6a commit 94af047

5 files changed

Lines changed: 55 additions & 9 deletions

File tree

fs/ceph/crypto.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
#include <crypto/sha2.h>
1010
#include <linux/fscrypt.h>
1111

12+
#define CEPH_FSCRYPT_BLOCK_SHIFT 12
13+
#define CEPH_FSCRYPT_BLOCK_SIZE (_AC(1, UL) << CEPH_FSCRYPT_BLOCK_SHIFT)
14+
#define CEPH_FSCRYPT_BLOCK_MASK (~(CEPH_FSCRYPT_BLOCK_SIZE-1))
15+
1216
struct ceph_fs_client;
1317
struct ceph_acl_sec_ctx;
1418
struct ceph_mds_request;

fs/ceph/dir.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,10 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
11481148
if (ceph_snap(dir) != CEPH_NOSNAP)
11491149
return -EROFS;
11501150

1151+
err = fscrypt_prepare_link(old_dentry, dir, dentry);
1152+
if (err)
1153+
return err;
1154+
11511155
dout("link in dir %p %llx.%llx old_dentry %p:'%pd' dentry %p:'%pd'\n",
11521156
dir, ceph_vinop(dir), old_dentry, old_dentry, dentry, dentry);
11531157
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LINK, USE_AUTH_MDS);
@@ -1395,6 +1399,11 @@ static int ceph_rename(struct mnt_idmap *idmap, struct inode *old_dir,
13951399
if (err)
13961400
return err;
13971401

1402+
err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry,
1403+
flags);
1404+
if (err)
1405+
return err;
1406+
13981407
dout("rename dir %p dentry %p to dir %p dentry %p\n",
13991408
old_dir, old_dentry, new_dir, new_dentry);
14001409
req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);

fs/ceph/file.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,13 @@ int ceph_open(struct inode *inode, struct file *file)
366366

367367
/* filter out O_CREAT|O_EXCL; vfs did that already. yuck. */
368368
flags = file->f_flags & ~(O_CREAT|O_EXCL);
369-
if (S_ISDIR(inode->i_mode))
369+
if (S_ISDIR(inode->i_mode)) {
370370
flags = O_DIRECTORY; /* mds likes to know */
371+
} else if (S_ISREG(inode->i_mode)) {
372+
err = fscrypt_file_open(inode, file);
373+
if (err)
374+
return err;
375+
}
371376

372377
dout("open inode %p ino %llx.%llx file %p flags %d (%d)\n", inode,
373378
ceph_vinop(inode), file, flags, file->f_flags);
@@ -879,6 +884,13 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
879884
dout("atomic_open finish_no_open on dn %p\n", dn);
880885
err = finish_no_open(file, dn);
881886
} else {
887+
if (IS_ENCRYPTED(dir) &&
888+
!fscrypt_has_permitted_context(dir, d_inode(dentry))) {
889+
pr_warn("Inconsistent encryption context (parent %llx:%llx child %llx:%llx)\n",
890+
ceph_vinop(dir), ceph_vinop(d_inode(dentry)));
891+
goto out_req;
892+
}
893+
882894
dout("atomic_open finish_open on dn %p\n", dn);
883895
if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) {
884896
struct inode *newino = d_inode(dentry);
@@ -2222,6 +2234,9 @@ static long ceph_fallocate(struct file *file, int mode,
22222234
if (!S_ISREG(inode->i_mode))
22232235
return -EOPNOTSUPP;
22242236

2237+
if (IS_ENCRYPTED(inode))
2238+
return -EOPNOTSUPP;
2239+
22252240
prealloc_cf = ceph_alloc_cap_flush();
22262241
if (!prealloc_cf)
22272242
return -ENOMEM;
@@ -2543,6 +2558,10 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
25432558
return -EOPNOTSUPP;
25442559
}
25452560

2561+
/* Every encrypted inode gets its own key, so we can't offload them */
2562+
if (IS_ENCRYPTED(src_inode) || IS_ENCRYPTED(dst_inode))
2563+
return -EOPNOTSUPP;
2564+
25462565
if (len < src_ci->i_layout.object_size)
25472566
return -EOPNOTSUPP; /* no remote copy will be done */
25482567

fs/ceph/inode.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -972,13 +972,6 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
972972
issued |= __ceph_caps_dirty(ci);
973973
new_issued = ~issued & info_caps;
974974

975-
/* directories have fl_stripe_unit set to zero */
976-
if (le32_to_cpu(info->layout.fl_stripe_unit))
977-
inode->i_blkbits =
978-
fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
979-
else
980-
inode->i_blkbits = CEPH_BLOCK_SHIFT;
981-
982975
__ceph_update_quota(ci, iinfo->max_bytes, iinfo->max_files);
983976

984977
#ifdef CONFIG_FS_ENCRYPTION
@@ -1004,6 +997,15 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
1004997
ceph_decode_timespec64(&ci->i_snap_btime, &iinfo->snap_btime);
1005998
}
1006999

1000+
/* directories have fl_stripe_unit set to zero */
1001+
if (IS_ENCRYPTED(inode))
1002+
inode->i_blkbits = CEPH_FSCRYPT_BLOCK_SHIFT;
1003+
else if (le32_to_cpu(info->layout.fl_stripe_unit))
1004+
inode->i_blkbits =
1005+
fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
1006+
else
1007+
inode->i_blkbits = CEPH_BLOCK_SHIFT;
1008+
10071009
if ((new_version || (new_issued & CEPH_CAP_LINK_SHARED)) &&
10081010
(issued & CEPH_CAP_LINK_EXCL) == 0)
10091011
set_nlink(inode, le32_to_cpu(info->nlink));
@@ -2495,6 +2497,10 @@ int ceph_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
24952497
if (ceph_inode_is_shutdown(inode))
24962498
return -ESTALE;
24972499

2500+
err = fscrypt_prepare_setattr(dentry, attr);
2501+
if (err)
2502+
return err;
2503+
24982504
err = setattr_prepare(&nop_mnt_idmap, dentry, attr);
24992505
if (err != 0)
25002506
return err;
@@ -2778,8 +2784,12 @@ int ceph_getattr(struct mnt_idmap *idmap, const struct path *path,
27782784
stat->nlink = 1 + 1 + ci->i_subdirs;
27792785
}
27802786

2781-
stat->attributes_mask |= STATX_ATTR_CHANGE_MONOTONIC;
27822787
stat->attributes |= STATX_ATTR_CHANGE_MONOTONIC;
2788+
if (IS_ENCRYPTED(inode))
2789+
stat->attributes |= STATX_ATTR_ENCRYPTED;
2790+
stat->attributes_mask |= (STATX_ATTR_CHANGE_MONOTONIC |
2791+
STATX_ATTR_ENCRYPTED);
2792+
27832793
stat->result_mask = request_mask & valid_mask;
27842794
return err;
27852795
}

fs/ceph/ioctl.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ static long ceph_set_encryption_policy(struct file *file, unsigned long arg)
294294
struct inode *inode = file_inode(file);
295295
struct ceph_inode_info *ci = ceph_inode(inode);
296296

297+
/* encrypted directories can't have striped layout */
298+
if (ci->i_layout.stripe_count > 1)
299+
return -EINVAL;
300+
297301
ret = vet_mds_for_fscrypt(file);
298302
if (ret)
299303
return ret;

0 commit comments

Comments
 (0)