Commit 85529096 authored by Jeff Layton's avatar Jeff Layton Committed by Ilya Dryomov
Browse files

ceph: make ceph_fill_trace and ceph_get_name decrypt names



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: default avatarJeff Layton <jlayton@kernel.org>
Reviewed-by: default avatarXiubo Li <xiubli@redhat.com>
Reviewed-and-tested-by: default avatarLuís Henriques <lhenriques@suse.de>
Reviewed-by: default avatarMilind Changire <mchangir@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent 457117f0
Loading
Loading
Loading
Loading
+32 −12
Original line number Diff line number Diff line
@@ -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;
}
+28 −2
Original line number Diff line number Diff line
@@ -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 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
				     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 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
				dput(dn);
				goto retry_lookup;
			}
			ceph_fname_free_buffer(dir, &oname);

			req->r_dentry = dn;
			dput(parent);