public inbox for linux-fscrypt@vger.kernel.org
 help / color / mirror / Atom feed
From: Jeff Layton <jlayton@kernel.org>
To: ceph-devel@vger.kernel.org
Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org
Subject: [PATCH 22/36] ceph: add support to readdir for encrypted filenames
Date: Thu,  9 Dec 2021 10:36:33 -0500	[thread overview]
Message-ID: <20211209153647.58953-23-jlayton@kernel.org> (raw)
In-Reply-To: <20211209153647.58953-1-jlayton@kernel.org>

Add helper functions for buffer management and for decrypting filenames
returned by the MDS. Wire those into the readdir codepaths.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/ceph/dir.c   | 62 +++++++++++++++++++++++++++++++++++++++----------
 fs/ceph/inode.c | 38 +++++++++++++++++++++++++++---
 2 files changed, 85 insertions(+), 15 deletions(-)

diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 7977484d0317..f8812c976ba0 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -9,6 +9,7 @@
 
 #include "super.h"
 #include "mds_client.h"
+#include "crypto.h"
 
 /*
  * Directory operations: readdir, lookup, create, link, unlink,
@@ -241,7 +242,9 @@ static int __dcache_readdir(struct file *file,  struct dir_context *ctx,
 		di = ceph_dentry(dentry);
 		if (d_unhashed(dentry) ||
 		    d_really_is_negative(dentry) ||
-		    di->lease_shared_gen != shared_gen) {
+		    di->lease_shared_gen != shared_gen ||
+		    ((dentry->d_flags & DCACHE_NOKEY_NAME) &&
+		     fscrypt_has_encryption_key(dir))) {
 			spin_unlock(&dentry->d_lock);
 			dput(dentry);
 			err = -EAGAIN;
@@ -313,6 +316,8 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
 	int err;
 	unsigned frag = -1;
 	struct ceph_mds_reply_info_parsed *rinfo;
+	struct fscrypt_str tname = FSTR_INIT(NULL, 0);
+	struct fscrypt_str oname = FSTR_INIT(NULL, 0);
 
 	dout("readdir %p file %p pos %llx\n", inode, file, ctx->pos);
 	if (dfi->file_info.flags & CEPH_F_ATEND)
@@ -340,6 +345,10 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
 		ctx->pos = 2;
 	}
 
+	err = fscrypt_prepare_readdir(inode);
+	if (err)
+		goto out;
+
 	spin_lock(&ci->i_ceph_lock);
 	/* request Fx cap. if have Fx, we don't need to release Fs cap
 	 * for later create/unlink. */
@@ -360,6 +369,14 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
 		spin_unlock(&ci->i_ceph_lock);
 	}
 
+	err = ceph_fname_alloc_buffer(inode, &tname);
+	if (err < 0)
+		goto out;
+
+	err = ceph_fname_alloc_buffer(inode, &oname);
+	if (err < 0)
+		goto out;
+
 	/* proceed with a normal readdir */
 more:
 	/* do we have the correct frag content buffered? */
@@ -387,12 +404,14 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
 		dout("readdir fetching %llx.%llx frag %x offset '%s'\n",
 		     ceph_vinop(inode), frag, dfi->last_name);
 		req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
-		if (IS_ERR(req))
-			return PTR_ERR(req);
+		if (IS_ERR(req)) {
+			err = PTR_ERR(req);
+			goto out;
+		}
 		err = ceph_alloc_readdir_reply_buffer(req, inode);
 		if (err) {
 			ceph_mdsc_put_request(req);
-			return err;
+			goto out;
 		}
 		/* hints to request -> mds selection code */
 		req->r_direct_mode = USE_AUTH_MDS;
@@ -405,7 +424,8 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
 			req->r_path2 = kstrdup(dfi->last_name, GFP_KERNEL);
 			if (!req->r_path2) {
 				ceph_mdsc_put_request(req);
-				return -ENOMEM;
+				err = -ENOMEM;
+				goto out;
 			}
 		} else if (is_hash_order(ctx->pos)) {
 			req->r_args.readdir.offset_hash =
@@ -426,7 +446,7 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
 		err = ceph_mdsc_do_request(mdsc, NULL, req);
 		if (err < 0) {
 			ceph_mdsc_put_request(req);
-			return err;
+			goto out;
 		}
 		dout("readdir got and parsed readdir result=%d on "
 		     "frag %x, end=%d, complete=%d, hash_order=%d\n",
@@ -479,7 +499,7 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
 			err = note_last_dentry(dfi, rde->name, rde->name_len,
 					       next_offset);
 			if (err)
-				return err;
+				goto out;
 		} else if (req->r_reply_info.dir_end) {
 			dfi->next_offset = 2;
 			/* keep last name */
@@ -507,22 +527,37 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
 	}
 	for (; i < rinfo->dir_nr; i++) {
 		struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i;
+		struct ceph_fname fname = { .dir	= inode,
+					    .name	= rde->name,
+					    .name_len	= rde->name_len,
+					    .ctext	= rde->altname,
+					    .ctext_len	= rde->altname_len };
+		u32 olen = oname.len;
 
 		BUG_ON(rde->offset < ctx->pos);
+		BUG_ON(!rde->inode.in);
 
 		ctx->pos = rde->offset;
 		dout("readdir (%d/%d) -> %llx '%.*s' %p\n",
 		     i, rinfo->dir_nr, ctx->pos,
 		     rde->name_len, rde->name, &rde->inode.in);
 
-		BUG_ON(!rde->inode.in);
+		err = ceph_fname_to_usr(&fname, &tname, &oname, NULL);
+		if (err) {
+			dout("Unable to decode %.*s. Skipping it.\n", rde->name_len, rde->name);
+			continue;
+		}
 
-		if (!dir_emit(ctx, rde->name, rde->name_len,
+		if (!dir_emit(ctx, oname.name, oname.len,
 			      ceph_present_ino(inode->i_sb, le64_to_cpu(rde->inode.in->ino)),
 			      le32_to_cpu(rde->inode.in->mode) >> 12)) {
 			dout("filldir stopping us...\n");
-			return 0;
+			err = 0;
+			goto out;
 		}
+
+		/* Reset the lengths to their original allocated vals */
+		oname.len = olen;
 		ctx->pos++;
 	}
 
@@ -577,9 +612,12 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
 					dfi->dir_ordered_count);
 		spin_unlock(&ci->i_ceph_lock);
 	}
-
+	err = 0;
 	dout("readdir %p file %p done.\n", inode, file);
-	return 0;
+out:
+	ceph_fname_free_buffer(inode, &tname);
+	ceph_fname_free_buffer(inode, &oname);
+	return err;
 }
 
 static void reset_readdir(struct ceph_dir_file_info *dfi)
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 6b2e639827ef..37cb0d334cf2 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1735,7 +1735,8 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
 			     struct ceph_mds_session *session)
 {
 	struct dentry *parent = req->r_dentry;
-	struct ceph_inode_info *ci = ceph_inode(d_inode(parent));
+	struct inode *inode = d_inode(parent);
+	struct ceph_inode_info *ci = ceph_inode(inode);
 	struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
 	struct qstr dname;
 	struct dentry *dn;
@@ -1745,6 +1746,8 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
 	u32 last_hash = 0;
 	u32 fpos_offset;
 	struct ceph_readdir_cache_control cache_ctl = {};
+	struct fscrypt_str tname = FSTR_INIT(NULL, 0);
+	struct fscrypt_str oname = FSTR_INIT(NULL, 0);
 
 	if (test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags))
 		return readdir_prepopulate_inodes_only(req, session);
@@ -1796,14 +1799,36 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
 	cache_ctl.index = req->r_readdir_cache_idx;
 	fpos_offset = req->r_readdir_offset;
 
+	err = ceph_fname_alloc_buffer(inode, &tname);
+	if (err < 0)
+		goto out;
+
+	err = ceph_fname_alloc_buffer(inode, &oname);
+	if (err < 0)
+		goto out;
+
 	/* FIXME: release caps/leases if error occurs */
 	for (i = 0; i < rinfo->dir_nr; i++) {
+		bool is_nokey = false;
 		struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i;
 		struct ceph_vino tvino;
+		u32 olen = oname.len;
+		struct ceph_fname fname = { .dir	= inode,
+					    .name	= rde->name,
+					    .name_len	= rde->name_len,
+					    .ctext	= rde->altname,
+					    .ctext_len	= rde->altname_len };
+
+		err = ceph_fname_to_usr(&fname, &tname, &oname, &is_nokey);
+		if (err) {
+			dout("Unable to decode %.*s. Skipping it.", rde->name_len, rde->name);
+			continue;
+		}
 
-		dname.name = rde->name;
-		dname.len = rde->name_len;
+		dname.name = oname.name;
+		dname.len = oname.len;
 		dname.hash = full_name_hash(parent, dname.name, dname.len);
+		oname.len = olen;
 
 		tvino.ino = le64_to_cpu(rde->inode.in->ino);
 		tvino.snap = le64_to_cpu(rde->inode.in->snapid);
@@ -1834,6 +1859,11 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
 				err = -ENOMEM;
 				goto out;
 			}
+			if (is_nokey) {
+				spin_lock(&dn->d_lock);
+				dn->d_flags |= DCACHE_NOKEY_NAME;
+				spin_unlock(&dn->d_lock);
+			}
 		} else if (d_really_is_positive(dn) &&
 			   (ceph_ino(d_inode(dn)) != tvino.ino ||
 			    ceph_snap(d_inode(dn)) != tvino.snap)) {
@@ -1922,6 +1952,8 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
 		req->r_readdir_cache_idx = cache_ctl.index;
 	}
 	ceph_readdir_cache_release(&cache_ctl);
+	ceph_fname_free_buffer(inode, &tname);
+	ceph_fname_free_buffer(inode, &oname);
 	dout("readdir_prepopulate done\n");
 	return err;
 }
-- 
2.33.1


  parent reply	other threads:[~2021-12-09 15:37 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-09 15:36 [PATCH 00/36] ceph+fscrypt: context, filename, symlink and size handling support Jeff Layton
2021-12-09 15:36 ` [PATCH 01/36] vfs: export new_inode_pseudo Jeff Layton
2021-12-09 15:36 ` [PATCH 02/36] fscrypt: export fscrypt_base64url_encode and fscrypt_base64url_decode Jeff Layton
2021-12-10 19:10   ` Eric Biggers
2021-12-13  8:17   ` Christoph Hellwig
2021-12-09 15:36 ` [PATCH 03/36] fscrypt: export fscrypt_fname_encrypt and fscrypt_fname_encrypted_size Jeff Layton
2021-12-10 19:32   ` Eric Biggers
2021-12-09 15:36 ` [PATCH 04/36] fscrypt: add fscrypt_context_for_new_inode Jeff Layton
2021-12-10 19:40   ` Eric Biggers
2021-12-09 15:36 ` [PATCH 05/36] fscrypt: uninline and export fscrypt_require_key Jeff Layton
2021-12-10 19:46   ` Eric Biggers
2021-12-10 20:40     ` Jeff Layton
2021-12-12 19:56       ` Eric Biggers
2021-12-12 20:38         ` Jeff Layton
2021-12-12 21:03           ` Eric Biggers
2021-12-15 12:10             ` Jeff Layton
2021-12-09 15:36 ` [PATCH 06/36] ceph: preallocate inode for ops that may create one Jeff Layton
2021-12-09 15:36 ` [PATCH 07/36] ceph: crypto context handling for ceph Jeff Layton
2021-12-09 15:36 ` [PATCH 08/36] ceph: parse new fscrypt_auth and fscrypt_file fields in inode traces Jeff Layton
2021-12-09 15:36 ` [PATCH 09/36] ceph: add fscrypt_* handling to caps.c Jeff Layton
2021-12-09 15:36 ` [PATCH 10/36] ceph: add ability to set fscrypt_auth via setattr Jeff Layton
2021-12-09 15:36 ` [PATCH 11/36] ceph: implement -o test_dummy_encryption mount option Jeff Layton
2021-12-09 15:36 ` [PATCH 12/36] ceph: decode alternate_name in lease info Jeff Layton
2021-12-09 15:36 ` [PATCH 13/36] ceph: add fscrypt ioctls Jeff Layton
2021-12-09 15:36 ` [PATCH 14/36] ceph: make ceph_msdc_build_path use ref-walk Jeff Layton
2021-12-09 15:36 ` [PATCH 15/36] ceph: add encrypted fname handling to ceph_mdsc_build_path Jeff Layton
2021-12-09 15:36 ` [PATCH 16/36] ceph: send altname in MClientRequest Jeff Layton
2021-12-09 15:36 ` [PATCH 17/36] ceph: encode encrypted name in dentry release Jeff Layton
2021-12-09 15:36 ` [PATCH 18/36] ceph: properly set DCACHE_NOKEY_NAME flag in lookup Jeff Layton
2021-12-09 15:36 ` [PATCH 19/36] ceph: make d_revalidate call fscrypt revalidator for encrypted dentries Jeff Layton
2021-12-09 15:36 ` [PATCH 20/36] ceph: add helpers for converting names for userland presentation Jeff Layton
2021-12-09 15:36 ` [PATCH 21/36] ceph: add fscrypt support to ceph_fill_trace Jeff Layton
2021-12-09 15:36 ` Jeff Layton [this message]
2021-12-09 15:36 ` [PATCH 23/36] ceph: create symlinks with encrypted and base64-encoded targets Jeff Layton
2021-12-09 15:36 ` [PATCH 24/36] ceph: make ceph_get_name decrypt filenames Jeff Layton
2021-12-09 15:36 ` [PATCH 25/36] ceph: add a new ceph.fscrypt.auth vxattr Jeff Layton
2021-12-09 15:36 ` [PATCH 26/36] ceph: add some fscrypt guardrails Jeff Layton
2021-12-09 15:36 ` [PATCH 27/36] ceph: don't allow changing layout on encrypted files/directories Jeff Layton
2021-12-09 15:36 ` [PATCH 28/36] libceph: add CEPH_OSD_OP_ASSERT_VER support Jeff Layton
2021-12-09 15:36 ` [PATCH 29/36] ceph: size handling for encrypted inodes in cap updates Jeff Layton
2021-12-09 15:36 ` [PATCH 30/36] ceph: fscrypt_file field handling in MClientRequest messages Jeff Layton
2021-12-09 15:36 ` [PATCH 31/36] ceph: get file size from fscrypt_file when present in inode traces Jeff Layton
2021-12-09 15:36 ` [PATCH 32/36] ceph: handle fscrypt fields in cap messages from MDS Jeff Layton
2021-12-09 15:36 ` [PATCH 33/36] ceph: add __ceph_get_caps helper support Jeff Layton
2021-12-09 15:36 ` [PATCH 34/36] ceph: add __ceph_sync_read " Jeff Layton
2021-12-09 15:36 ` [PATCH 35/36] ceph: add object version support for sync read Jeff Layton
2021-12-09 15:36 ` [PATCH 36/36] ceph: add truncate size handling support for fscrypt Jeff Layton
2021-12-10  2:47 ` [PATCH 00/36] ceph+fscrypt: context, filename, symlink and size handling support Xiubo Li
2021-12-10 19:33 ` Eric Biggers
2021-12-10 20:09   ` Jeff Layton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211209153647.58953-23-jlayton@kernel.org \
    --to=jlayton@kernel.org \
    --cc=ceph-devel@vger.kernel.org \
    --cc=linux-fscrypt@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox