lustre-devel-lustre.org archive mirror
 help / color / mirror / Atom feed
From: James Simmons <jsimmons@infradead.org>
To: Andreas Dilger <adilger@whamcloud.com>,
	Oleg Drokin <green@whamcloud.com>, NeilBrown <neilb@suse.de>
Cc: Lustre Development List <lustre-devel@lists.lustre.org>
Subject: [lustre-devel] [PATCH 12/40] lustre: sec: fid2path for encrypted files
Date: Sun,  9 Apr 2023 08:12:52 -0400	[thread overview]
Message-ID: <1681042400-15491-13-git-send-email-jsimmons@infradead.org> (raw)
In-Reply-To: <1681042400-15491-1-git-send-email-jsimmons@infradead.org>

From: Sebastien Buisson <sbuisson@ddn.com>

Add support of fid2path for encrypted files. Server side returns raw
encrypted path name to client, which needs to process the returned
string. This is done from top to bottom, by iteratively decrypting
parent name and then doing a lookup on it, so that child can in turn
be decrypted.

For encrypted files that do not have their names encrypted, lookups
can be skipped. Indeed, name decryption is a no-op in this case, which
means it is not necessary to fetch the encryption key associated with
the parent inode.

Without the encryption key, lookups are skipped for the same reason.
But names have to be encoded and/or digested. So server needs to
insert FIDs of individual path components in the returned string.
These FIDs are interpreted by the client to build encoded/digested
names.

WC-bug-id: https://jira.whamcloud.com/browse/LU-16205
Lustre-commit: fa9da556ad22b1485 ("LU-16205 sec: fid2path for encrypted files")
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/48930
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: jsimmons <jsimmons@infradead.org>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Signed-off-by: James Simmons <jsimmons@infradead.org>
---
 fs/lustre/include/lustre_export.h |   5 ++
 fs/lustre/llite/file.c            | 160 +++++++++++++++++++++++++++++++++++++-
 fs/lustre/llite/llite_internal.h  |  17 ++++
 fs/lustre/llite/llite_lib.c       |   1 +
 fs/lustre/lmv/lmv_obd.c           |  38 +++++++--
 fs/lustre/mdc/mdc_request.c       |  10 +--
 6 files changed, 214 insertions(+), 17 deletions(-)

diff --git a/fs/lustre/include/lustre_export.h b/fs/lustre/include/lustre_export.h
index 6a59e6c..59f1dea 100644
--- a/fs/lustre/include/lustre_export.h
+++ b/fs/lustre/include/lustre_export.h
@@ -284,6 +284,11 @@ static inline int exp_connect_encrypt(struct obd_export *exp)
 	return !!(exp_connect_flags2(exp) & OBD_CONNECT2_ENCRYPT);
 }
 
+static inline int exp_connect_encrypt_fid2path(struct obd_export *exp)
+{
+	return !!(exp_connect_flags2(exp) & OBD_CONNECT2_ENCRYPT_FID2PATH);
+}
+
 static inline int exp_connect_lseek(struct obd_export *exp)
 {
 	return !!(exp_connect_flags2(exp) & OBD_CONNECT2_LSEEK);
diff --git a/fs/lustre/llite/file.c b/fs/lustre/llite/file.c
index aa9c5da..668d544 100644
--- a/fs/lustre/llite/file.c
+++ b/fs/lustre/llite/file.c
@@ -2744,12 +2744,146 @@ static int ll_do_fiemap(struct inode *inode, struct fiemap *fiemap,
 	return rc;
 }
 
+static int fid2path_for_enc_file(struct inode *parent, char *gfpath,
+				 u32 gfpathlen)
+{
+	struct dentry *de = NULL, *de_parent = d_find_any_alias(parent);
+	struct fscrypt_str lltr = FSTR_INIT(NULL, 0);
+	struct fscrypt_str de_name;
+	char *p, *ptr = gfpath;
+	size_t len = 0, len_orig = 0;
+	int enckey = -1, nameenc = -1;
+	int rc = 0;
+
+	gfpath++;
+	while ((p = strsep(&gfpath, "/")) != NULL) {
+		struct lu_fid fid;
+
+		de = NULL;
+		if (!*p) {
+			dput(de_parent);
+			break;
+		}
+		len_orig = strlen(p);
+
+		rc = sscanf(p, "["SFID"]", RFID(&fid));
+		if (rc == 3)
+			p = strchr(p, ']') + 1;
+		else
+			fid_zero(&fid);
+		rc = 0;
+		len = strlen(p);
+
+		if (!IS_ENCRYPTED(parent)) {
+			if (gfpathlen < len + 1) {
+				dput(de_parent);
+				rc = -EOVERFLOW;
+				break;
+			}
+			memmove(ptr, p, len);
+			p = ptr;
+			ptr += len;
+			*(ptr++) = '/';
+			gfpathlen -= len + 1;
+			goto lookup;
+		}
+
+		/* From here, we know parent is encrypted */
+		if (enckey != 0) {
+			rc = fscrypt_get_encryption_info(parent);
+			if (rc && rc != -ENOKEY) {
+				dput(de_parent);
+				break;
+			}
+		}
+
+		if (enckey == -1) {
+			if (fscrypt_has_encryption_key(parent))
+				enckey = 1;
+			else
+				enckey = 0;
+			if (enckey == 1)
+				nameenc = true;
+		}
+
+		/* Even if names are not encrypted, we still need to call
+		 * ll_fname_disk_to_usr in order to decode names as they are
+		 * coming from the wire.
+		 */
+		rc = fscrypt_fname_alloc_buffer(parent, NAME_MAX + 1, &lltr);
+		if (rc < 0) {
+			dput(de_parent);
+			break;
+		}
+
+		de_name.name = p;
+		de_name.len = len;
+		rc = ll_fname_disk_to_usr(parent, 0, 0, &de_name,
+					  &lltr, &fid);
+		if (rc) {
+			fscrypt_fname_free_buffer(&lltr);
+			dput(de_parent);
+			break;
+		}
+		lltr.name[lltr.len] = '\0';
+
+		if (lltr.len <= len_orig && gfpathlen >= lltr.len + 1) {
+			memcpy(ptr, lltr.name, lltr.len);
+			p = ptr;
+			len = lltr.len;
+			ptr += lltr.len;
+			*(ptr++) = '/';
+			gfpathlen -= lltr.len + 1;
+		} else {
+			rc = -EOVERFLOW;
+		}
+		fscrypt_fname_free_buffer(&lltr);
+
+		if (rc == -EOVERFLOW) {
+			dput(de_parent);
+			break;
+		}
+
+lookup:
+		if (!gfpath) {
+			/* We reached the end of the string, which means
+			 * we are dealing with the last component in the path.
+			 * So save a useless lookup and exit.
+			 */
+			dput(de_parent);
+			break;
+		}
+
+		if (enckey == 0 || nameenc == 0)
+			continue;
+
+		inode_lock(parent);
+		de = lookup_one_len(p, de_parent, len);
+		inode_unlock(parent);
+		if (IS_ERR_OR_NULL(de) || !de->d_inode) {
+			dput(de_parent);
+			rc = -ENODATA;
+			break;
+		}
+
+		parent = de->d_inode;
+		dput(de_parent);
+		de_parent = de;
+	}
+
+	if (len)
+		*(ptr - 1) = '\0';
+	if (!IS_ERR_OR_NULL(de))
+		dput(de);
+	return rc;
+}
+
 int ll_fid2path(struct inode *inode, void __user *arg)
 {
 	struct obd_export *exp = ll_i2mdexp(inode);
 	const struct getinfo_fid2path __user *gfin = arg;
 	struct getinfo_fid2path *gfout;
-	u32 pathlen;
+	u32 pathlen, pathlen_orig;
 	size_t outsize;
 	int rc;
 
@@ -2763,7 +2897,9 @@ int ll_fid2path(struct inode *inode, void __user *arg)
 
 	if (pathlen > PATH_MAX)
 		return -EINVAL;
+	pathlen_orig = pathlen;
 
+gf_alloc:
 	outsize = sizeof(*gfout) + pathlen;
 
 	gfout = kzalloc(outsize, GFP_KERNEL);
@@ -2781,17 +2917,37 @@ int ll_fid2path(struct inode *inode, void __user *arg)
 	 * old server without fileset mount support will ignore this.
 	 */
 	*gfout->gf_root_fid = *ll_inode2fid(inode);
+	gfout->gf_pathlen = pathlen;
 
 	/* Call mdc_iocontrol */
 	rc = obd_iocontrol(OBD_IOC_FID2PATH, exp, outsize, gfout, NULL);
 	if (rc != 0)
 		goto gf_free;
 
-	if (copy_to_user(arg, gfout, outsize))
+	if (gfout->gf_pathlen && gfout->gf_path[0] == '/') {
+		/* by convention, server side (mdt_path_current()) puts
+		 * a leading '/' to tell client that we are dealing with
+		 * an encrypted file
+		 */
+		rc = fid2path_for_enc_file(inode, gfout->gf_path,
+					   gfout->gf_pathlen);
+		if (rc)
+			goto gf_free;
+		if (strlen(gfout->gf_path) > gfin->gf_pathlen) {
+			rc = -EOVERFLOW;
+			goto gf_free;
+		}
+	}
+
+	if (copy_to_user(arg, gfout, sizeof(*gfout) + pathlen_orig))
 		rc = -EFAULT;
 
 gf_free:
 	kfree(gfout);
+	if (rc == -ENAMETOOLONG) {
+		pathlen += PATH_MAX;
+		goto gf_alloc;
+	}
 	return rc;
 }
 
diff --git a/fs/lustre/llite/llite_internal.h b/fs/lustre/llite/llite_internal.h
index 1d85d0b..2223dbb 100644
--- a/fs/lustre/llite/llite_internal.h
+++ b/fs/lustre/llite/llite_internal.h
@@ -523,6 +523,23 @@ static inline void obd_connect_set_name_enc(struct obd_connect_data *data)
 #endif
 }
 
+static inline bool obd_connect_has_enc_fid2path(struct obd_connect_data *data)
+{
+#ifdef HAVE_LUSTRE_CRYPTO
+	return data->ocd_connect_flags & OBD_CONNECT_FLAGS2 &&
+		data->ocd_connect_flags2 & OBD_CONNECT2_ENCRYPT_FID2PATH;
+#else
+	return false;
+#endif
+}
+
+static inline void obd_connect_set_enc_fid2path(struct obd_connect_data *data)
+{
+#ifdef HAVE_LUSTRE_CRYPTO
+	data->ocd_connect_flags2 |= OBD_CONNECT2_ENCRYPT_FID2PATH;
+#endif
+}
+
 /*
  * Locking to guarantee consistency of non-atomic updates to long long i_size,
  * consistency between file size and KMS.
diff --git a/fs/lustre/llite/llite_lib.c b/fs/lustre/llite/llite_lib.c
index e48bb6c..3774ca8 100644
--- a/fs/lustre/llite/llite_lib.c
+++ b/fs/lustre/llite/llite_lib.c
@@ -358,6 +358,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
 
 	obd_connect_set_secctx(data);
 	if (ll_sbi_has_encrypt(sbi)) {
+		obd_connect_set_enc_fid2path(data);
 		obd_connect_set_name_enc(data);
 		obd_connect_set_enc(data);
 	}
diff --git a/fs/lustre/lmv/lmv_obd.c b/fs/lustre/lmv/lmv_obd.c
index 64d16d8..99604e8 100644
--- a/fs/lustre/lmv/lmv_obd.c
+++ b/fs/lustre/lmv/lmv_obd.c
@@ -551,6 +551,8 @@ static int lmv_fid2path(struct obd_export *exp, int len, void *karg,
 	struct getinfo_fid2path *remote_gf = NULL;
 	struct lu_fid root_fid;
 	int remote_gf_size = 0;
+	int currentisenc = 0;
+	int globalisenc = 0;
 	int rc;
 
 	tgt = lmv_fid2tgt(lmv, &gf->gf_fid);
@@ -565,11 +567,23 @@ static int lmv_fid2path(struct obd_export *exp, int len, void *karg,
 	if (rc != 0 && rc != -EREMOTE)
 		goto out_fid2path;
 
+	if (gf->gf_path[0] == '/') {
+		/* by convention, server side (mdt_path_current()) puts
+		 * a leading '/' to tell client that we are dealing with
+		 * an encrypted file
+		 */
+		currentisenc = 1;
+		globalisenc = 1;
+	} else {
+		currentisenc = 0;
+	}
+
 	/* If remote_gf != NULL, it means just building the
 	 * path on the remote MDT, copy this path segment to gf
 	 */
 	if (remote_gf) {
 		struct getinfo_fid2path *ori_gf;
+		int oldisenc = 0;
 		char *ptr;
 		int len;
 
@@ -581,14 +595,22 @@ static int lmv_fid2path(struct obd_export *exp, int len, void *karg,
 		}
 
 		ptr = ori_gf->gf_path;
+		oldisenc = ptr[0] == '/';
 
 		len = strlen(gf->gf_path);
-		/* move the current path to the right to release space
-		 * for closer-to-root part
-		 */
-		memmove(ptr + len + 1, ptr, strlen(ori_gf->gf_path));
-		memcpy(ptr, gf->gf_path, len);
-		ptr[len] = '/';
+		if (len) {
+			/* move the current path to the right to release space
+			 * for closer-to-root part
+			 */
+			memmove(ptr + len - currentisenc + 1 + globalisenc,
+				ptr + oldisenc,
+				strlen(ori_gf->gf_path) - oldisenc + 1);
+			if (globalisenc)
+				*(ptr++) = '/';
+			memcpy(ptr, gf->gf_path + currentisenc,
+			       len - currentisenc);
+			ptr[len - currentisenc] = '/';
+		}
 	}
 
 	CDEBUG(D_INFO, "%s: get path %s " DFID " rec: %llu ln: %u\n",
@@ -601,13 +623,13 @@ static int lmv_fid2path(struct obd_export *exp, int len, void *karg,
 
 	/* sigh, has to go to another MDT to do path building further */
 	if (!remote_gf) {
-		remote_gf_size = sizeof(*remote_gf) + PATH_MAX;
+		remote_gf_size = sizeof(*remote_gf) + len - sizeof(*gf);
 		remote_gf = kzalloc(remote_gf_size, GFP_NOFS);
 		if (!remote_gf) {
 			rc = -ENOMEM;
 			goto out_fid2path;
 		}
-		remote_gf->gf_pathlen = PATH_MAX;
+		remote_gf->gf_pathlen = len - sizeof(*gf);
 	}
 
 	if (!fid_is_sane(&gf->gf_fid)) {
diff --git a/fs/lustre/mdc/mdc_request.c b/fs/lustre/mdc/mdc_request.c
index 643b6ee..58ea982 100644
--- a/fs/lustre/mdc/mdc_request.c
+++ b/fs/lustre/mdc/mdc_request.c
@@ -1707,8 +1707,6 @@ static int mdc_ioc_fid2path(struct obd_export *exp, struct getinfo_fid2path *gf)
 	void *key;
 	int rc;
 
-	if (gf->gf_pathlen > PATH_MAX)
-		return -ENAMETOOLONG;
 	if (gf->gf_pathlen < 2)
 		return -EOVERFLOW;
 
@@ -1746,12 +1744,10 @@ static int mdc_ioc_fid2path(struct obd_export *exp, struct getinfo_fid2path *gf)
 		goto out;
 	}
 
-	CDEBUG(D_IOCTL, "path got " DFID " from %llu #%d: %s\n",
+	CDEBUG(D_IOCTL, "path got " DFID " from %llu #%d: %.*s\n",
 	       PFID(&gf->gf_fid), gf->gf_recno, gf->gf_linkno,
-	       gf->gf_pathlen < 512 ? gf->gf_path :
-	       /* only log the last 512 characters of the path */
-	       gf->gf_path + gf->gf_pathlen - 512);
-
+	       /* only log the first 512 characters of the path */
+	       512, gf->gf_path);
 out:
 	kfree(key);
 	return rc;
-- 
1.8.3.1

_______________________________________________
lustre-devel mailing list
lustre-devel@lists.lustre.org
http://lists.lustre.org/listinfo.cgi/lustre-devel-lustre.org

  parent reply	other threads:[~2023-04-09 12:24 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-09 12:12 [lustre-devel] [PATCH 00/40] lustre: backport OpenSFS changes from March XX, 2023 James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 01/40] lustre: protocol: basic batching processing framework James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 02/40] lustre: lov: fiemap improperly handles fm_extent_count=0 James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 03/40] lustre: llite: SIGBUS is possible on a race with page reclaim James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 04/40] lustre: osc: page fault in osc_release_bounce_pages() James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 05/40] lustre: readahead: add stats for read-ahead page count James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 06/40] lustre: quota: enforce project quota for root James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 07/40] lustre: ldlm: send the cancel RPC asap James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 08/40] lustre: enc: align Base64 encoding with RFC 4648 base64url James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 09/40] lustre: quota: fix insane grant quota James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 10/40] lustre: llite: check truncated page in ->readpage() James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 11/40] lnet: o2iblnd: Fix key mismatch issue James Simmons
2023-04-09 12:12 ` James Simmons [this message]
2023-04-09 12:12 ` [lustre-devel] [PATCH 13/40] lustre: sec: Lustre/HSM on enc file with enc key James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 14/40] lustre: llite: check read page past requested James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 15/40] lustre: llite: fix relatime support James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 16/40] lustre: ptlrpc: clarify AT error message James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 17/40] lustre: update version to 2.15.54 James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 18/40] lustre: tgt: skip free inodes in OST weights James Simmons
2023-04-09 12:12 ` [lustre-devel] [PATCH 19/40] lustre: fileset: check fileset for operations by fid James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 20/40] lustre: clio: Remove cl_page_size() James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 21/40] lustre: fid: clean up OBIF_MAX_OID and IDIF_MAX_OID James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 22/40] lustre: llog: fix processing of a wrapped catalog James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 23/40] lustre: llite: replace lld_nfs_dentry flag with opencache handling James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 24/40] lustre: llite: match lock in corresponding namespace James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 25/40] lnet: libcfs: remove unused hash code James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 26/40] lustre: client: -o network needs add_conn processing James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 27/40] lnet: Lock primary NID logic James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 28/40] lnet: Peers added via kernel API should be permanent James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 29/40] lnet: don't delete peer created by Lustre James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 30/40] lnet: memory leak in copy_ioc_udsp_descr James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 31/40] lnet: remove crash with UDSP James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 32/40] lustre: ptlrpc: fix clang build errors James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 33/40] lustre: ldlm: remove client_import_find_conn() James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 34/40] lnet: add 'force' option to lnetctl peer del James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 35/40] lustre: ldlm: BL_AST lock cancel still can be batched James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 36/40] lnet: lnet_parse_route uses wrong loop var James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 37/40] lustre: tgt: add qos debug James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 38/40] lustre: enc: file names encryption when using secure boot James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 39/40] lustre: uapi: add DMV_IMP_INHERIT connect flag James Simmons
2023-04-09 12:13 ` [lustre-devel] [PATCH 40/40] lustre: llite: dir layout inheritance fixes James Simmons

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=1681042400-15491-13-git-send-email-jsimmons@infradead.org \
    --to=jsimmons@infradead.org \
    --cc=adilger@whamcloud.com \
    --cc=green@whamcloud.com \
    --cc=lustre-devel@lists.lustre.org \
    --cc=neilb@suse.de \
    /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;
as well as URLs for NNTP newsgroup(s).