[RFC PATCH v11 29/51] ceph: add some fscrypt guardrails

Jeff Layton
2022-03-22T14:15:53Z

Add the appropriate calls into fscrypt for various actions, including
link, rename, setattr, and the open codepaths.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
fs/ceph/dir.c | 8 ++++++++
fs/ceph/file.c | 14 +++++++++++++-
fs/ceph/inode.c | 4 ++++
3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 82a5f37e9d4a..8a9f916bfc6c 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1121,6 +1121,10 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
if (ceph_snap(dir) != CEPH_NOSNAP)
return -EROFS;

+ err = fscrypt_prepare_link(old_dentry, dir, dentry);
+ if (err)
+ return err;
+
dout("link in dir %p old_dentry %p dentry %p\n", dir,
old_dentry, dentry);
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LINK, USE_AUTH_MDS);
@@ -1318,6 +1322,10 @@ static int ceph_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
(!ceph_quota_is_same_realm(old_dir, new_dir)))
return -EXDEV;

+ err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
+ if (err)
+ return err;
+
dout("rename dir %p dentry %p to dir %p dentry %p\n",
old_dir, old_dentry, new_dir, new_dentry);
req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 5832dcea2d8c..8a222ce5f8ce 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -372,8 +372,13 @@ int ceph_open(struct inode *inode, struct file *file)

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

dout("open inode %p ino %llx.%llx file %p flags %d (%d)\n", inode,
ceph_vinop(inode), file, flags, file->f_flags);
@@ -842,6 +847,13 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
dout("atomic_open finish_no_open on dn %p\n", dn);
err = finish_no_open(file, dn);
} else {
+ if (IS_ENCRYPTED(dir) &&
+ !fscrypt_has_permitted_context(dir, d_inode(dentry))) {
+ pr_warn("Inconsistent encryption context (parent %llx:%llx child %llx:%llx)\n",
+ ceph_vinop(dir), ceph_vinop(d_inode(dentry)));
+ goto out_req;
+ }
+
dout("atomic_open finish_open on dn %p\n", dn);
if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) {
struct inode *newino = d_inode(dentry);
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index fe006f189c0f..35e7ef462136 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -2483,6 +2483,10 @@ int ceph_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
if (ceph_inode_is_shutdown(inode))
return -ESTALE;

+ err = fscrypt_prepare_setattr(dentry, attr);
+ if (err)
+ return err;
+
err = setattr_prepare(&init_user_ns, dentry, attr);
if (err != 0)
return err;
--
2.35.1