From faf057b46bc770a1a69cacd59e65a40a4b18b9fd Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Fri, 29 Oct 2021 13:29:25 +0200 Subject: [PATCH] LU-15176 sec: allow subdir mount of encrypted dir In case of sub-directory mount of an encrypted directory, we need to retrieve the encryption context of the root inode of the filesystem. This is done by making the MDT return this upon getattr reply. Also add sanity-sec test_60 to exercise this capability. Fixes: 40d91eafe2 ("LU-12275 sec: atomicity of encryption context getting/setting") Signed-off-by: Sebastien Buisson Change-Id: Ic7a273813533f2904225011b247cdfe995ce9be8 Reviewed-on: https://review.whamcloud.com/45407 Reviewed-by: Andreas Dilger Tested-by: jenkins Reviewed-by: James Simmons Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/llite/llite_lib.c | 30 +++++++++++++++-- lustre/mdc/mdc_dev.c | 1 + lustre/mdc/mdc_request.c | 28 ++++++++++++++-- lustre/mdt/mdt_handler.c | 31 ++++++++++------- lustre/mdt/mdt_io.c | 1 + lustre/ptlrpc/layout.c | 13 +++---- lustre/target/tgt_handler.c | 4 +++ lustre/tests/sanity-sec.sh | 82 +++++++++++++++++++++++++++++++++++---------- 8 files changed, 149 insertions(+), 41 deletions(-) diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index 3872cd4..01783b1 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -274,6 +274,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) u64 valid; int size, err, checksum; bool api32; + void *encctx; + int encctxlen; ENTRY; sbi->ll_md_obd = class_name2obd(md); @@ -642,7 +644,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) /* make root inode * XXX: move this to after cbd setup? */ - valid = OBD_MD_FLGETATTR | OBD_MD_FLBLOCKS | OBD_MD_FLMODEASIZE; + valid = OBD_MD_FLGETATTR | OBD_MD_FLBLOCKS | OBD_MD_FLMODEASIZE | + OBD_MD_ENCCTX; if (test_bit(LL_SBI_ACL, sbi->ll_flags)) valid |= OBD_MD_FLACL; @@ -656,6 +659,13 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) err = md_getattr(sbi->ll_md_exp, op_data, &request); + /* We need enc ctx info, so reset it in op_data to + * prevent it from being freed. + */ + encctx = op_data->op_file_encctx; + encctxlen = op_data->op_file_encctx_size; + op_data->op_file_encctx = NULL; + op_data->op_file_encctx_size = 0; OBD_FREE_PTR(op_data); if (err) { CERROR("%s: md_getattr failed for root: rc = %d\n", @@ -675,7 +685,6 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) api32 = test_bit(LL_SBI_32BIT_API, sbi->ll_flags); root = ll_iget(sb, cl_fid_build_ino(&sbi->ll_root_fid, api32), &lmd); md_free_lustre_md(sbi->ll_md_exp, &lmd); - ptlrpc_req_finished(request); if (IS_ERR(root)) { lmd_clear_acl(&lmd); @@ -683,9 +692,22 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) root = NULL; CERROR("%s: bad ll_iget() for root: rc = %d\n", sbi->ll_fsname, err); + ptlrpc_req_finished(request); GOTO(out_root, err); } + if (encctxlen) { + CDEBUG(D_SEC, + "server returned encryption ctx for root inode "DFID"\n", + PFID(&sbi->ll_root_fid)); + err = ll_set_encflags(root, encctx, encctxlen, true); + if (err) + CWARN("%s: cannot set enc ctx for "DFID": rc = %d\n", + sbi->ll_fsname, + PFID(&sbi->ll_root_fid), err); + } + ptlrpc_req_finished(request); + checksum = test_bit(LL_SBI_CHECKSUM, sbi->ll_flags); if (sbi->ll_checksum_set) { err = obd_set_info_async(NULL, sbi->ll_dt_exp, @@ -3276,9 +3298,11 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, if (ll_need_32bit_api(ll_i2sbi(i1))) op_data->op_cli_flags |= CLI_API32; - if (opc == LUSTRE_OPC_LOOKUP || opc == LUSTRE_OPC_CREATE) { + if ((i2 && is_root_inode(i2)) || + opc == LUSTRE_OPC_LOOKUP || opc == LUSTRE_OPC_CREATE) { /* In case of lookup, ll_setup_filename() has already been * called in ll_lookup_it(), so just take provided name. + * Also take provided name if we are dealing with root inode. */ fname.disk_name.name = (unsigned char *)name; fname.disk_name.len = namelen; diff --git a/lustre/mdc/mdc_dev.c b/lustre/mdc/mdc_dev.c index bd67c30..2705461 100644 --- a/lustre/mdc/mdc_dev.c +++ b/lustre/mdc/mdc_dev.c @@ -1290,6 +1290,7 @@ static int mdc_io_data_version_start(const struct lu_env *env, req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, 0); req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, 0); + req_capsule_set_size(&req->rq_pill, &RMF_FILE_ENCCTX, RCL_SERVER, 0); ptlrpc_request_set_replen(req); req->rq_interpret_reply = mdc_data_version_interpret; diff --git a/lustre/mdc/mdc_request.c b/lustre/mdc/mdc_request.c index bc79122..980683e 100644 --- a/lustre/mdc/mdc_request.c +++ b/lustre/mdc/mdc_request.c @@ -161,7 +161,8 @@ out: * layouts. --umka */ static int mdc_getattr_common(struct obd_export *exp, - struct ptlrpc_request *req) + struct ptlrpc_request *req, + struct md_op_data *op_data) { struct req_capsule *pill = &req->rq_pill; struct mdt_body *body; @@ -189,6 +190,18 @@ static int mdc_getattr_common(struct obd_export *exp, RETURN(-EPROTO); } + /* If encryption context was returned by MDT, put it in op_data + * so that caller can set it on inode and save an extra getxattr. + */ + if (op_data && op_data->op_valid & OBD_MD_ENCCTX && + body->mbo_valid & OBD_MD_ENCCTX) { + op_data->op_file_encctx = + req_capsule_server_get(pill, &RMF_FILE_ENCCTX); + op_data->op_file_encctx_size = + req_capsule_get_size(pill, &RMF_FILE_ENCCTX, + RCL_SERVER); + } + RETURN(0); } @@ -207,6 +220,7 @@ static int mdc_getattr(struct obd_export *exp, struct md_op_data *op_data, struct ptlrpc_request **request) { struct ptlrpc_request *req; + struct obd_device *obd = class_exp2obd(exp); struct obd_import *imp = class_exp2cliimp(exp); __u32 acl_bufsize = LUSTRE_POSIX_ACL_MAX_SIZE_OLD; int rc; @@ -238,9 +252,16 @@ again: req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, acl_bufsize); req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, op_data->op_mode); + if (exp_connect_encrypt(exp) && op_data->op_valid & OBD_MD_ENCCTX) + req_capsule_set_size(&req->rq_pill, &RMF_FILE_ENCCTX, + RCL_SERVER, + obd->u.cli.cl_max_mds_easize); + else + req_capsule_set_size(&req->rq_pill, &RMF_FILE_ENCCTX, + RCL_SERVER, 0); ptlrpc_request_set_replen(req); - rc = mdc_getattr_common(exp, req); + rc = mdc_getattr_common(exp, req, op_data); if (rc) { if (rc == -ERANGE) { acl_bufsize = min_t(__u32, @@ -294,6 +315,7 @@ again: req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, op_data->op_mode); req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, acl_bufsize); + req_capsule_set_size(&req->rq_pill, &RMF_FILE_ENCCTX, RCL_SERVER, 0); ptlrpc_request_set_replen(req); if (op_data->op_bias & MDS_FID_OP) { struct mdt_body *b = req_capsule_client_get(&req->rq_pill, @@ -305,7 +327,7 @@ again: } } - rc = mdc_getattr_common(exp, req); + rc = mdc_getattr_common(exp, req, NULL); if (rc) { if (rc == -ERANGE) { acl_bufsize = min_t(__u32, diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index 50abf84..7f721b8 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -1321,6 +1321,20 @@ out: RETURN(rc); } +static void mdt_preset_encctx_size(struct mdt_thread_info *info) +{ + struct req_capsule *pill = info->mti_pill; + + ENTRY; + if (req_capsule_has_field(pill, &RMF_FILE_ENCCTX, + RCL_SERVER)) + /* pre-set size in server part with max size */ + req_capsule_set_size(pill, &RMF_FILE_ENCCTX, + RCL_SERVER, + info->mti_mdt->mdt_max_mdsize); + EXIT; +} + static int mdt_getattr_internal(struct mdt_thread_info *info, struct mdt_object *o, int ma_need) { @@ -1641,6 +1655,7 @@ static int mdt_getattr(struct tgt_session_info *tsi) * enlarge the buffer when necessary. */ req_capsule_set_size(pill, &RMF_ACL, RCL_SERVER, LUSTRE_POSIX_ACL_MAX_SIZE_OLD); + mdt_preset_encctx_size(info); rc = req_capsule_server_pack(pill); if (unlikely(rc != 0)) @@ -1658,6 +1673,10 @@ static int mdt_getattr(struct tgt_session_info *tsi) info->mti_cross_ref = !!(reqbody->mbo_valid & OBD_MD_FLCROSSREF); rc = mdt_getattr_internal(info, obj, 0); + if (unlikely(rc)) + GOTO(out_shrink, rc); + + rc = mdt_pack_encctx_in_reply(info, obj); EXIT; out_shrink: mdt_client_compatibility(info); @@ -2868,18 +2887,6 @@ static void mdt_preset_secctx_size(struct mdt_thread_info *info) } } -static void mdt_preset_encctx_size(struct mdt_thread_info *info) -{ - struct req_capsule *pill = info->mti_pill; - - if (req_capsule_has_field(pill, &RMF_FILE_ENCCTX, - RCL_SERVER)) - /* pre-set size in server part with max size */ - req_capsule_set_size(pill, &RMF_FILE_ENCCTX, - RCL_SERVER, - info->mti_mdt->mdt_max_mdsize); -} - static int mdt_reint_internal(struct mdt_thread_info *info, struct mdt_lock_handle *lhc, __u32 op) diff --git a/lustre/mdt/mdt_io.c b/lustre/mdt/mdt_io.c index bf80be4..4c8bff6 100644 --- a/lustre/mdt/mdt_io.c +++ b/lustre/mdt/mdt_io.c @@ -1586,6 +1586,7 @@ int mdt_data_version_get(struct tgt_session_info *tsi) req_capsule_set_size(tsi->tsi_pill, &RMF_MDT_MD, RCL_SERVER, 0); req_capsule_set_size(tsi->tsi_pill, &RMF_ACL, RCL_SERVER, 0); + req_capsule_set_size(tsi->tsi_pill, &RMF_FILE_ENCCTX, RCL_SERVER, 0); rc = req_capsule_server_pack(tsi->tsi_pill); if (unlikely(rc != 0)) RETURN(err_serious(rc)); diff --git a/lustre/ptlrpc/layout.c b/lustre/ptlrpc/layout.c index 2c68ea3..973c422 100644 --- a/lustre/ptlrpc/layout.c +++ b/lustre/ptlrpc/layout.c @@ -565,12 +565,13 @@ static const struct req_msg_field *mds_getxattr_server[] = { }; static const struct req_msg_field *mds_getattr_server[] = { - &RMF_PTLRPC_BODY, - &RMF_MDT_BODY, - &RMF_MDT_MD, - &RMF_ACL, - &RMF_CAPA1, - &RMF_CAPA2 + &RMF_PTLRPC_BODY, + &RMF_MDT_BODY, + &RMF_MDT_MD, + &RMF_ACL, + &RMF_CAPA1, + &RMF_CAPA2, + &RMF_FILE_ENCCTX, }; static const struct req_msg_field *mds_setattr_server[] = { diff --git a/lustre/target/tgt_handler.c b/lustre/target/tgt_handler.c index ce034a1..4123d47 100644 --- a/lustre/target/tgt_handler.c +++ b/lustre/target/tgt_handler.c @@ -458,6 +458,10 @@ static int tgt_handle_request0(struct tgt_session_info *tsi, body->oa.o_flags & OBD_FL_SHORT_IO) ? remote_nb[0].rnb_len : 0); } + if (req_capsule_has_field(tsi->tsi_pill, &RMF_FILE_ENCCTX, + RCL_SERVER)) + req_capsule_set_size(tsi->tsi_pill, &RMF_FILE_ENCCTX, + RCL_SERVER, 0); rc = req_capsule_server_pack(tsi->tsi_pill); } diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index ca9da83..ee4fd1a 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -2712,6 +2712,19 @@ setup_dummy_key() { echo -n -e "${key}" | keyctl padd logon fscrypt:4242424242424242 @s } +insert_enc_key() { + cancel_lru_locks + sync ; echo 3 > /proc/sys/vm/drop_caches + setup_dummy_key +} + +remove_enc_key() { + cancel_lru_locks + sync ; echo 3 > /proc/sys/vm/drop_caches + keyctl revoke $(keyctl show | awk '$7 ~ "^fscrypt:" {print $1}') + keyctl reap +} + setup_for_enc_tests() { # remount client with test_dummy_encryption option if is_mounted $MOUNT; then @@ -4535,18 +4548,6 @@ test_58() { } run_test 58 "access to enc file's xattrs" -insert_enc_key() { - sync ; echo 3 > /proc/sys/vm/drop_caches - setup_dummy_key -} - -remove_env_key() { - cancel_lru_locks - sync ; echo 3 > /proc/sys/vm/drop_caches - keyctl revoke $(keyctl show | awk '$7 ~ "^fscrypt:" {print $1}') - keyctl reap -} - verify_mirror() { local mirror1=$TMP/$tfile.mirror1 local mirror2=$TMP/$tfile.mirror2 @@ -4597,7 +4598,7 @@ test_59a() { $LFS getstripe $testfile # now, without the key - remove_env_key + remove_enc_key scrambledfile=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type f) $LFS mirror resync $scrambledfile || error "could not resync mirror" @@ -4645,7 +4646,7 @@ test_59b() { $LFS getstripe $testfile # now, without the key - remove_env_key + remove_enc_key scrambledfile=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type f) $LFS migrate -i1 $scrambledfile || error "migrate $scrambledfile failed" @@ -4660,7 +4661,7 @@ test_59b() { error "migrated file is corrupted" # now, without the key - remove_env_key + remove_enc_key $LFS mirror extend -N -i0 $scrambledfile || error "mirror extend $scrambledfile failed (1)" $LFS getstripe $scrambledfile @@ -4686,7 +4687,7 @@ test_59b() { verify_mirror $testfile $tmpfile # now, without the key - remove_env_key + remove_enc_key $LFS mirror split --mirror-id 1 -d $scrambledfile || error "mirror split file $scrambledfile failed (1)" $LFS getstripe $scrambledfile @@ -4725,7 +4726,7 @@ test_59c() { echo b > $dirname/subf # now, without the key - remove_env_key + remove_enc_key scrambleddir=$(find $DIR/$tdir/ -maxdepth 1 -mindepth 1 -type d) # migrate a non-empty encrypted dir @@ -4738,6 +4739,53 @@ test_59c() { } run_test 59c "MDT migrate of encrypted files without key" +test_60() { + local testdir=$DIR/$tdir/mytestdir + local testfile=$DIR/$tdir/$tfile + + (( $MDS1_VERSION > $(version_code 2.14.53) )) || + skip "Need MDS version at least 2.14.53" + + $LCTL get_param mdc.*.import | grep -q client_encryption || + skip "client encryption not supported" + + mount.lustre --help |& grep -q "test_dummy_encryption:" || + skip "need dummy encryption support" + + stack_trap cleanup_for_enc_tests EXIT + setup_for_enc_tests + + echo a > $DIR/$tdir/file1 + mkdir $DIR/$tdir/subdir + echo b > $DIR/$tdir/subdir/subfile1 + + remove_enc_key + # unmount client completely + umount_client $MOUNT || error "umount $MOUNT failed" + if is_mounted $MOUNT2; then + umount_client $MOUNT2 || error "umount $MOUNT2 failed" + fi + + # remount client with subdirectory mount + export FILESET=/$tdir + mount_client $MOUNT ${MOUNT_OPTS} || error "remount failed" + if [ "$MOUNT_2" ]; then + mount_client $MOUNT2 ${MOUNT_OPTS} || error "remount failed" + fi + export FILESET="" + + ls -Rl $DIR || error "ls -Rl $DIR failed (1)" + + # now, with the key + insert_enc_key + + ls -Rl $DIR || error "ls -Rl $DIR failed (2)" + cat $DIR/file1 || error "cat $DIR/$tdir/file1 failed" + cat $DIR/subdir/subfile1 || + error "cat $DIR/$tdir/subdir/subfile1 failed" +} +run_test 60 "Subdirmount of encrypted dir" + log "cleanup: ======================================================" sec_unsetup() { -- 1.8.3.1