ceph: make ceph_fill_trace and ceph_get_name decrypt names
authorJeff Layton <jlayton@kernel.org>
Mon, 10 Aug 2020 19:13:29 +0000 (15:13 -0400)
committerIlya Dryomov <idryomov@gmail.com>
Thu, 24 Aug 2023 09:24:34 +0000 (11:24 +0200)
When we get a dentry in a trace, decrypt the name so we can properly
instantiate the dentry or fill out ceph_get_name() buffer.

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>
fs/ceph/export.c
fs/ceph/inode.c

index f780e4e..8559990 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "super.h"
 #include "mds_client.h"
+#include "crypto.h"
 
 /*
  * Basic fh
@@ -535,7 +536,9 @@ static int ceph_get_name(struct dentry *parent, char *name,
 {
        struct ceph_mds_client *mdsc;
        struct ceph_mds_request *req;
+       struct inode *dir = d_inode(parent);
        struct inode *inode = d_inode(child);
+       struct ceph_mds_reply_info_parsed *rinfo;
        int err;
 
        if (ceph_snap(inode) != CEPH_NOSNAP)
@@ -547,30 +550,47 @@ static int ceph_get_name(struct dentry *parent, char *name,
        if (IS_ERR(req))
                return PTR_ERR(req);
 
-       inode_lock(d_inode(parent));
-
+       inode_lock(dir);
        req->r_inode = inode;
        ihold(inode);
        req->r_ino2 = ceph_vino(d_inode(parent));
-       req->r_parent = d_inode(parent);
-       ihold(req->r_parent);
+       req->r_parent = dir;
+       ihold(dir);
        set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
        req->r_num_caps = 2;
        err = ceph_mdsc_do_request(mdsc, NULL, req);
+       inode_unlock(dir);
 
-       inode_unlock(d_inode(parent));
+       if (err)
+               goto out;
 
-       if (!err) {
-               struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
+       rinfo = &req->r_reply_info;
+       if (!IS_ENCRYPTED(dir)) {
                memcpy(name, rinfo->dname, rinfo->dname_len);
                name[rinfo->dname_len] = 0;
-               dout("get_name %p ino %llx.%llx name %s\n",
-                    child, ceph_vinop(inode), name);
        } else {
-               dout("get_name %p ino %llx.%llx err %d\n",
-                    child, ceph_vinop(inode), err);
-       }
+               struct fscrypt_str oname = FSTR_INIT(NULL, 0);
+               struct ceph_fname fname = { .dir        = dir,
+                                           .name       = rinfo->dname,
+                                           .ctext      = rinfo->altname,
+                                           .name_len   = rinfo->dname_len,
+                                           .ctext_len  = rinfo->altname_len };
+
+               err = ceph_fname_alloc_buffer(dir, &oname);
+               if (err < 0)
+                       goto out;
 
+               err = ceph_fname_to_usr(&fname, NULL, &oname, NULL);
+               if (!err) {
+                       memcpy(name, oname.name, oname.len);
+                       name[oname.len] = 0;
+               }
+               ceph_fname_free_buffer(dir, &oname);
+       }
+out:
+       dout("get_name %p ino %llx.%llx err %d %s%s\n",
+                    child, ceph_vinop(inode), err,
+                    err ? "" : "name ", err ? "" : name);
        ceph_mdsc_put_request(req);
        return err;
 }
index 50ff641..a6e9a41 100644 (file)
@@ -1406,8 +1406,15 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
                if (dir && req->r_op == CEPH_MDS_OP_LOOKUPNAME &&
                    test_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags) &&
                    !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) {
+                       bool is_nokey = false;
                        struct qstr dname;
                        struct dentry *dn, *parent;
+                       struct fscrypt_str oname = FSTR_INIT(NULL, 0);
+                       struct ceph_fname fname = { .dir        = dir,
+                                                   .name       = rinfo->dname,
+                                                   .ctext      = rinfo->altname,
+                                                   .name_len   = rinfo->dname_len,
+                                                   .ctext_len  = rinfo->altname_len };
 
                        BUG_ON(!rinfo->head->is_target);
                        BUG_ON(req->r_dentry);
@@ -1415,8 +1422,20 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
                        parent = d_find_any_alias(dir);
                        BUG_ON(!parent);
 
-                       dname.name = rinfo->dname;
-                       dname.len = rinfo->dname_len;
+                       err = ceph_fname_alloc_buffer(dir, &oname);
+                       if (err < 0) {
+                               dput(parent);
+                               goto done;
+                       }
+
+                       err = ceph_fname_to_usr(&fname, NULL, &oname, &is_nokey);
+                       if (err < 0) {
+                               dput(parent);
+                               ceph_fname_free_buffer(dir, &oname);
+                               goto done;
+                       }
+                       dname.name = oname.name;
+                       dname.len = oname.len;
                        dname.hash = full_name_hash(parent, dname.name, dname.len);
                        tvino.ino = le64_to_cpu(rinfo->targeti.in->ino);
                        tvino.snap = le64_to_cpu(rinfo->targeti.in->snapid);
@@ -1431,9 +1450,15 @@ retry_lookup:
                                     dname.len, dname.name, dn);
                                if (!dn) {
                                        dput(parent);
+                                       ceph_fname_free_buffer(dir, &oname);
                                        err = -ENOMEM;
                                        goto done;
                                }
+                               if (is_nokey) {
+                                       spin_lock(&dn->d_lock);
+                                       dn->d_flags |= DCACHE_NOKEY_NAME;
+                                       spin_unlock(&dn->d_lock);
+                               }
                                err = 0;
                        } else if (d_really_is_positive(dn) &&
                                   (ceph_ino(d_inode(dn)) != tvino.ino ||
@@ -1445,6 +1470,7 @@ retry_lookup:
                                dput(dn);
                                goto retry_lookup;
                        }
+                       ceph_fname_free_buffer(dir, &oname);
 
                        req->r_dentry = dn;
                        dput(parent);