Whamcloud - gitweb
LU-15176 sec: allow subdir mount of encrypted dir
authorSebastien Buisson <sbuisson@ddn.com>
Fri, 29 Oct 2021 11:29:25 +0000 (13:29 +0200)
committerAndreas Dilger <adilger@whamcloud.com>
Mon, 21 Mar 2022 18:48:18 +0000 (18:48 +0000)
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.

Lustre-change: https://review.whamcloud.com/45407
Lustre-commit: faf057b46bc770a1a69cacd59e65a40a4b18b9fd

Fixes: 40d91eafe2 ("LU-12275 sec: atomicity of encryption context getting/setting")
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: Ic7a273813533f2904225011b247cdfe995ce9be8
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/45909
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/llite/llite_lib.c
lustre/mdc/mdc_dev.c
lustre/mdc/mdc_request.c
lustre/mdt/mdt_handler.c
lustre/mdt/mdt_io.c
lustre/ptlrpc/layout.c
lustre/target/tgt_handler.c
lustre/tests/sanity-sec.sh

index 734e6c5..26065ad 100644 (file)
@@ -230,6 +230,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
        struct lustre_md lmd;
        u64 valid;
        int size, err, checksum;
+       void *encctx;
+       int encctxlen;
 
        ENTRY;
        sbi->ll_md_obd = class_name2obd(md);
@@ -603,7 +605,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 (sbi->ll_flags & LL_SBI_ACL)
                valid |= OBD_MD_FLACL;
 
@@ -617,6 +620,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",
@@ -637,7 +647,6 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
                                            sbi->ll_flags & LL_SBI_32BIT_API),
                       &lmd);
        md_free_lustre_md(sbi->ll_md_exp, &lmd);
-       ptlrpc_req_finished(request);
 
        if (IS_ERR(root)) {
                lmd_clear_acl(&lmd);
@@ -645,9 +654,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 = sbi->ll_flags & LL_SBI_CHECKSUM;
        if (sbi->ll_checksum_set) {
                err = obd_set_info_async(NULL, sbi->ll_dt_exp,
@@ -3166,9 +3188,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 && i2 == i2->i_sb->s_root->d_inode) ||
+           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;
index 1acea0a..d18238d 100644 (file)
@@ -1274,6 +1274,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;
index 382b464..54cabe1 100644 (file)
@@ -162,7 +162,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;
@@ -190,6 +191,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);
 }
 
@@ -208,6 +221,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;
@@ -239,9 +253,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,
@@ -295,6 +316,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,
@@ -306,7 +328,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,
index a18f9a0..5f99963 100644 (file)
@@ -1312,6 +1312,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)
 {
@@ -1632,6 +1646,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))
@@ -1649,6 +1664,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);
@@ -2830,18 +2849,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)
index 9a92114..1589016 100644 (file)
@@ -1398,6 +1398,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));
index 6864cdd..414f046 100644 (file)
@@ -567,12 +567,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[] = {
index e275029..db02f00 100644 (file)
@@ -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);
        }
index d234b19..e096f72 100755 (executable)
@@ -2711,6 +2711,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
@@ -4508,18 +4521,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
@@ -4570,7 +4571,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"
@@ -4618,7 +4619,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"
@@ -4633,7 +4634,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
@@ -4659,7 +4660,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
@@ -4698,7 +4699,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
@@ -4711,6 +4712,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() {