From a20fe3f54b2ea6e99d2fbce755e8cf18a601b104 Mon Sep 17 00:00:00 2001 From: Bobi Jam Date: Fri, 10 Nov 2023 17:17:50 +0800 Subject: [PATCH] EX-7331 csdc: prohibit set compression upon encrypted file Setting compression layout component upon encrypted file is not allowed for now. This patch add this check on MDS in creating file with layout, adding/merging new mirror to existing file. Test-Parameters: testlist=sanity-sec env=ONLY=67,PTLDEBUG=-1 Signed-off-by: Bobi Jam Change-Id: I60d9f4bfce3a498f1eb3994c6276afb9d89c99a7 Reviewed-on: https://review.whamcloud.com/c/ex/lustre-release/+/53075 Tested-by: jenkins Tested-by: Maloo Tested-by: Sebastien Buisson Reviewed-by: Sebastien Buisson Reviewed-by: Andreas Dilger --- lustre/lod/lod_internal.h | 9 +-- lustre/lod/lod_lov.c | 45 ++++++++++++- lustre/lod/lod_object.c | 159 ++++++++++++++++++++++++++++++++++++++------- lustre/lod/lod_qos.c | 7 +- lustre/tests/sanity-sec.sh | 48 ++++++++++++++ 5 files changed, 236 insertions(+), 32 deletions(-) diff --git a/lustre/lod/lod_internal.h b/lustre/lod/lod_internal.h index 227771c..5636038 100644 --- a/lustre/lod/lod_internal.h +++ b/lustre/lod/lod_internal.h @@ -266,7 +266,8 @@ struct lod_object { struct lod_mirror_entry *ldo_mirrors; __u32 ldo_is_composite:1, ldo_flr_state:4, - ldo_comp_cached:1; + ldo_comp_cached:1, + ldo_parent_encrypted:1; }; /* directory stripe (LMV) */ struct { @@ -704,8 +705,8 @@ int lod_parse_dir_striping(const struct lu_env *env, struct lod_object *lo, int lod_initialize_objects(const struct lu_env *env, struct lod_object *mo, struct lov_ost_data_v1 *objs, int index); int lod_verify_striping(const struct lu_env *env, struct lod_device *d, - struct lod_object *lo, const struct lu_buf *buf, - bool is_from_disk); + struct lod_object *lo, struct lu_attr *attr, + const struct lu_buf *buf, bool is_from_disk); int lod_generate_lovea(const struct lu_env *env, struct lod_object *lo, struct lov_mds_md *lmm, int *lmm_size, bool is_dir); int lod_ea_store_resize(struct lod_thread_info *info, size_t size); @@ -762,7 +763,7 @@ int lod_prepare_create(const struct lu_env *env, struct lod_object *lo, int lod_use_defined_striping(const struct lu_env *, struct lod_object *, const struct lu_buf *); int lod_qos_parse_config(const struct lu_env *env, struct lod_object *lo, - const struct lu_buf *buf); + struct lu_attr *attr, const struct lu_buf *buf); int lod_qos_prep_create(const struct lu_env *env, struct lod_object *lo, struct lu_attr *attr, struct thandle *th, int comp_idx, __u64 reserve); diff --git a/lustre/lod/lod_lov.c b/lustre/lod/lod_lov.c index 22bc06c..eaf9ec4 100644 --- a/lustre/lod/lod_lov.c +++ b/lustre/lod/lod_lov.c @@ -2090,9 +2090,10 @@ int lod_dom_stripesize_choose(const struct lu_env *env, struct lod_device *d, * \retval -EINVAL if striping is invalid */ int lod_verify_striping(const struct lu_env *env, struct lod_device *d, - struct lod_object *lo, const struct lu_buf *buf, - bool is_from_disk) + struct lod_object *lo, struct lu_attr *attr, + const struct lu_buf *buf, bool is_from_disk) { + struct dt_object *next = dt_object_child(&lo->ldo_obj); struct lov_user_md_v1 *lum; struct lov_comp_md_v1 *comp_v1; struct lov_comp_md_entry_v1 *ent; @@ -2356,6 +2357,46 @@ recheck: } } + if (lov_pattern(le32_to_cpu(lum->lmm_pattern)) & + LOV_PATTERN_COMPRESS || + ent->lcme_compr_type != LL_COMPR_TYPE_NONE) { + bool encrypted = false; + + if (attr && attr->la_valid & LA_FLAGS && + attr->la_flags & LUSTRE_ENCRYPT_FL) { + CDEBUG(D_LAYOUT, + "%s: attr flags %x reveals encypted\n", + lod2obd(d)->obd_name, attr->la_flags); + encrypted = true; + } else if (dt_object_exists(next)){ + struct lustre_ost_attrs loa; + struct lu_buf loa_buf = { + .lb_buf = &loa, + .lb_len = sizeof(loa), + }; + + rc = dt_xattr_get(env, next, &loa_buf, + XATTR_NAME_LMA); + CDEBUG(D_LAYOUT, "%s: LMA incompat %x\n", + lod2obd(d)->obd_name, + loa.loa_lma.lma_incompat); + if (!rc && + loa.loa_lma.lma_incompat & LMAI_ENCRYPT) + encrypted = true; + } else if (lo->ldo_parent_encrypted) { + CDEBUG(D_LAYOUT, "%s: parent encypted\n", + lod2obd(d)->obd_name); + encrypted = true; + } + CDEBUG(D_LAYOUT, "%s: %sencrypted\n", + lod2obd(d)->obd_name, encrypted ? "" : "not "); + if (encrypted) { + CERROR("%s: cannot set compression layout in encrypted file.\n", + lod2obd(d)->obd_name); + RETURN(-EINVAL); + } + } + prev_end = le64_to_cpu(ext->e_end); rc = lod_verify_v1v3(d, &tmp, is_from_disk); diff --git a/lustre/lod/lod_object.c b/lustre/lod/lod_object.c index 16597b7..d9ab18f 100644 --- a/lustre/lod/lod_object.c +++ b/lustre/lod/lod_object.c @@ -1245,6 +1245,45 @@ lod_obj_stripe_attr_set_cb(const struct lu_env *env, struct lod_object *lo, } /** + * Check whether object contains compression component + * + * \retval 0 if it does not has compression component + * \retval 1 if it has compressoin component + * \retval negative on error + */ +static int lod_lovea_contains_compression(const struct lu_env *env, + struct lod_object *lo) +{ + struct lod_thread_info *info = lod_env_info(env); + struct lov_comp_md_v1 *lcm; + __u32 magic; + int i; + int rc; + + ENTRY; + + rc = lod_get_lov_ea(env, lo); + if (rc <= 0) + RETURN(rc); + + lcm = info->lti_ea_store; + magic = le32_to_cpu(lcm->lcm_magic); + if (magic != LOV_MAGIC_COMP_V1 && magic != LOV_MAGIC_SEL) + RETURN(0); + + for (i = 0; i < le16_to_cpu(lcm->lcm_entry_count); i++) { + struct lov_comp_md_entry_v1 *lcme; + + lcme = &lcm->lcm_entries[i]; + if (lcme->lcme_compr_type != LL_COMPR_TYPE_NONE) + RETURN(1); + continue; + } + + RETURN(0); +} + +/** * Implementation of dt_object_operations::do_declare_attr_set. * * If the object is striped, then apply the changes to all the stripes. @@ -1262,6 +1301,20 @@ static int lod_declare_attr_set(const struct lu_env *env, int rc, i; ENTRY; + /* prohibit encrypting object with compression component */ + if (attr->la_valid & LA_FLAGS && attr->la_flags & LUSTRE_ENCRYPT_FL) { + rc = lod_lovea_contains_compression(env, lo); + if (rc < 0) + RETURN(rc); + + if (rc > 0) { + CERROR("%s: cannot encrypt file with compression layout\n", + dt->do_lu.lo_dev->ld_obd->obd_name); + RETURN(-EINVAL); + } + + } + /* * declare setattr on the local object */ @@ -2470,6 +2523,7 @@ static int lod_dir_layout_set(const struct lu_env *env, */ static int lod_dir_declare_xattr_set(const struct lu_env *env, struct dt_object *dt, + struct lu_attr *attr, const struct lu_buf *buf, const char *name, int fl, struct thandle *th) @@ -2493,7 +2547,7 @@ static int lod_dir_declare_xattr_set(const struct lu_env *env, if (rc != 0) RETURN(rc); } else if (strcmp(name, XATTR_NAME_LOV) == 0) { - rc = lod_verify_striping(env, d, lo, buf, false); + rc = lod_verify_striping(env, d, lo, attr, buf, false); if (rc != 0) RETURN(rc); } @@ -2725,6 +2779,7 @@ static int lod_comp_md_size(struct lod_object *lo, bool is_dir) * * \param[in] env execution environment * \param[in] dt dt_object to add components on + * \param[in] attr attributes of the object * \param[in] buf buffer contains components to be added * \parem[in] th thandle * @@ -2733,6 +2788,7 @@ static int lod_comp_md_size(struct lod_object *lo, bool is_dir) */ static int lod_declare_layout_add(const struct lu_env *env, struct dt_object *dt, + struct lu_attr *attr, const struct lu_buf *buf, struct thandle *th) { @@ -2753,7 +2809,7 @@ static int lod_declare_layout_add(const struct lu_env *env, if (lo->ldo_flr_state != LCM_FL_NONE) RETURN(-EBUSY); - rc = lod_verify_striping(env, d, lo, buf, false); + rc = lod_verify_striping(env, d, lo, attr, buf, false); if (rc != 0) RETURN(rc); @@ -2819,6 +2875,7 @@ static int lod_declare_layout_add(const struct lu_env *env, lod_comp->llc_compr_type = comp_v1->lcm_entries[i].lcme_compr_type; + lod_comp->llc_compr_lvl = comp_v1->lcm_entries[i].lcme_compr_lvl; lod_comp->llc_compr_chunk_log_bits = @@ -3198,6 +3255,7 @@ static int lod_declare_layout_del(const struct lu_env *env, * * \param[in] env execution environment * \param[in] dt object + * \param[in] attr attributes of the object * \param[in] name name of xattr * \param[in] buf lu_buf contains xattr value * \param[in] th transaction handle @@ -3207,6 +3265,7 @@ static int lod_declare_layout_del(const struct lu_env *env, */ static int lod_declare_modify_layout(const struct lu_env *env, struct dt_object *dt, + struct lu_attr *attr, const char *name, const struct lu_buf *buf, struct thandle *th) @@ -3239,7 +3298,7 @@ static int lod_declare_modify_layout(const struct lu_env *env, op = (char *)name + len; if (strcmp(op, "add") == 0) { - rc = lod_declare_layout_add(env, dt, buf, th); + rc = lod_declare_layout_add(env, dt, attr, buf, th); } else if (strcmp(op, "del") == 0) { rc = lod_declare_layout_del(env, dt, buf, th); } else if (strncmp(op, "set", strlen("set")) == 0) { @@ -3322,6 +3381,7 @@ out: */ static int lod_declare_layout_merge(const struct lu_env *env, struct dt_object *dt, + struct lu_attr *attr, const struct lu_buf *mbuf, struct thandle *th) { @@ -3433,7 +3493,7 @@ static int lod_declare_layout_merge(const struct lu_env *env, /* check if first entry in new layout is DOM */ lmm = (struct lov_mds_md_v1 *)((char *)merge_lcm + - merge_lcm->lcm_entries[0].lcme_offset); + le32_to_cpu(merge_lcm->lcm_entries[0].lcme_offset)); merge_has_dom = lov_pattern(le32_to_cpu(lmm->lmm_pattern)) & LOV_PATTERN_MDT; @@ -3444,6 +3504,38 @@ static int lod_declare_layout_merge(const struct lu_env *env, lcme = &lcm->lcm_entries[cur_entry_count + i]; *lcme = *merge_lcme; + + lmm = (struct lov_mds_md_v1 *)((char *)merge_lcm + + le32_to_cpu(merge_lcme->lcme_offset)); + if (lov_pattern(le32_to_cpu(lmm->lmm_pattern)) & + LOV_PATTERN_COMPRESS || + merge_lcme->lcme_compr_type != LL_COMPR_TYPE_NONE) { + bool encrypted = false; + + if (attr->la_valid & LA_FLAGS && + attr->la_flags & LUSTRE_ENCRYPT_FL) { + encrypted = true; + } else { + struct lustre_ost_attrs loa; + struct lu_buf loa_buf = { + .lb_buf = &loa, + .lb_len = sizeof(loa), + }; + + rc = dt_xattr_get(env, + dt_object_child(&lo->ldo_obj), + &loa_buf, XATTR_NAME_LMA); + if (!rc && + loa.loa_lma.lma_incompat & LMAI_ENCRYPT) + encrypted = true; + } + if (encrypted) { + CERROR("%s: cannot merge compression layout in encrypted file.\n", + dt->do_lu.lo_dev->ld_obd->obd_name); + GOTO(out, rc = -EINVAL); + } + } + lcme->lcme_offset = cpu_to_le32(offset); if (merge_has_dom && i == 0) lcme->lcme_flags |= cpu_to_le32(LCME_FL_STALE); @@ -3527,6 +3619,13 @@ static int lod_declare_xattr_set(const struct lu_env *env, int rc; ENTRY; + if (dt_object_exists(dt)) { + rc = dt_attr_get(env, next, attr); + if (rc) + RETURN(rc); + } else { + memset(attr, 0, sizeof(*attr)); + } mode = dt->do_lu.lo_header->loh_attr & S_IFMT; if ((S_ISREG(mode) || mode == 0) && !(fl & (LU_XATTR_REPLACE | LU_XATTR_MERGE | LU_XATTR_SPLIT)) && @@ -3541,12 +3640,7 @@ static int lod_declare_xattr_set(const struct lu_env *env, * * LU_XATTR_REPLACE is set to indicate a layout swap */ - if (dt_object_exists(dt)) { - rc = dt_attr_get(env, next, attr); - if (rc) - RETURN(rc); - } else { - memset(attr, 0, sizeof(*attr)); + if (!dt_object_exists(dt)) { attr->la_valid = LA_TYPE | LA_MODE; attr->la_mode = S_IFREG; } @@ -3554,7 +3648,7 @@ static int lod_declare_xattr_set(const struct lu_env *env, } else if (fl & LU_XATTR_MERGE) { LASSERT(strcmp(name, XATTR_NAME_LOV) == 0 || strcmp(name, XATTR_LUSTRE_LOV) == 0); - rc = lod_declare_layout_merge(env, dt, buf, th); + rc = lod_declare_layout_merge(env, dt, attr, buf, th); } else if (fl & LU_XATTR_SPLIT) { LASSERT(strcmp(name, XATTR_NAME_LOV) == 0 || strcmp(name, XATTR_LUSTRE_LOV) == 0); @@ -3569,9 +3663,9 @@ static int lod_declare_xattr_set(const struct lu_env *env, if (!dt_object_exists(dt)) RETURN(-ENOENT); - rc = lod_declare_modify_layout(env, dt, name, buf, th); + rc = lod_declare_modify_layout(env, dt, attr, name, buf, th); } else if (S_ISDIR(mode)) { - rc = lod_dir_declare_xattr_set(env, dt, buf, name, fl, th); + rc = lod_dir_declare_xattr_set(env, dt, attr, buf, name, fl,th); } else if (strcmp(name, XATTR_NAME_FID) == 0) { rc = lod_replace_parent_fid(env, dt, buf, th, true); } else { @@ -4144,7 +4238,8 @@ static int lod_dir_striping_create_internal(const struct lu_env *env, info->lti_buf.lb_buf = v1; info->lti_buf.lb_len = sizeof(*v1); if (declare) - rc = lod_dir_declare_xattr_set(env, dt, &info->lti_buf, + rc = lod_dir_declare_xattr_set(env, dt, attr, + &info->lti_buf, XATTR_NAME_DEFAULT_LMV, 0, th); else @@ -4177,7 +4272,8 @@ static int lod_dir_striping_create_internal(const struct lu_env *env, info->lti_buf.lb_len = lmm_size; if (declare) - rc = lod_dir_declare_xattr_set(env, dt, &info->lti_buf, + rc = lod_dir_declare_xattr_set(env, dt, attr, + &info->lti_buf, XATTR_NAME_LOV, 0, th); else rc = lod_xattr_set_lov_on_dir(env, dt, &info->lti_buf, @@ -5133,7 +5229,8 @@ static int lod_get_default_striping(const struct lu_env *env, struct lod_thread_info *info = lod_env_info(env); struct lod_device *d = lu2lod_dev(lo->ldo_obj.do_lu.lo_dev); - rc = lod_verify_striping(env, d, lo, &info->lti_buf, false); + rc = lod_verify_striping(env, d, lo, NULL, &info->lti_buf, + false); if (rc) lds->lds_def_striping_set = 0; } @@ -5286,6 +5383,7 @@ static void lod_ah_init(const struct lu_env *env, { struct lod_device *d = lu2lod_dev(child->do_lu.lo_dev); struct lod_thread_info *info = lod_env_info(env); + struct lu_buf *lbuf = &lod_env_info(env)->lti_buf; struct lod_default_striping *lds = lod_lds_buf_get(env); struct dt_object *nextp = NULL; struct dt_object *nextc; @@ -5316,9 +5414,24 @@ static void lod_ah_init(const struct lu_env *env, if (S_ISREG(child_mode)) lod_free_comp_entries(lc); - if (!dt_object_exists(nextc)) + if (!dt_object_exists(nextc)) { nextc->do_ops->do_ah_init(env, ah, nextp, nextc, child_mode); + /** + * hint that the child object to be created would be encrypted + * if its parent directory has been encrypted. + */ + if (parent && parent->do_ops && parent->do_ops->do_xattr_get) { + struct lustre_ost_attrs loa; + + lbuf->lb_buf = &loa; + lbuf->lb_len = sizeof(loa); + rc = dt_xattr_get(env, nextp, lbuf, XATTR_NAME_LMA); + if (!rc && loa.loa_lma.lma_incompat & LMAI_ENCRYPT) + lc->ldo_parent_encrypted = 1; + } + } + if (S_ISDIR(child_mode)) { const struct lmv_user_md_v1 *lum1 = ah->dah_eadata; @@ -5460,8 +5573,8 @@ static void lod_ah_init(const struct lu_env *env, if (likely(lp != NULL)) { rc = lod_get_default_lov_striping(env, lp, lds, ah); if (rc == 0 && lds->lds_def_striping_set) { - rc = lod_verify_striping(env, d, lp, &info->lti_buf, - false); + rc = lod_verify_striping(env, d, lp, NULL, + &info->lti_buf, false); if (rc == 0) lod_striping_from_default(lc, lds, child_mode); } @@ -5497,8 +5610,8 @@ static void lod_ah_init(const struct lu_env *env, if (rc || !lds->lds_def_striping_set) goto out; - rc = lod_verify_striping(env, d, d->lod_md_root, &info->lti_buf, - false); + rc = lod_verify_striping(env, d, d->lod_md_root, NULL, + &info->lti_buf, false); if (rc) goto out; @@ -5655,8 +5768,8 @@ static int lod_declare_init_size(const struct lu_env *env, * \retval negative if failed */ int lod_declare_striped_create(const struct lu_env *env, struct dt_object *dt, - struct lu_attr *attr, - const struct lu_buf *lovea, struct thandle *th) + struct lu_attr *attr, const struct lu_buf *lovea, + struct thandle *th) { struct lod_thread_info *info = lod_env_info(env); struct dt_object *next = dt_object_child(dt); diff --git a/lustre/lod/lod_qos.c b/lustre/lod/lod_qos.c index b9f8e7f..3f1f477 100644 --- a/lustre/lod/lod_qos.c +++ b/lustre/lod/lod_qos.c @@ -2303,13 +2303,14 @@ unlock: * * \param[in] env execution environment for this thread * \param[in] lo LOD object + * \param[in] attr attributes of the object * \param[in] buf buffer containing the striping * * \retval 0 on success * \retval negative negated errno on error */ int lod_qos_parse_config(const struct lu_env *env, struct lod_object *lo, - const struct lu_buf *buf) + struct lu_attr *attr, const struct lu_buf *buf) { struct lod_layout_component *lod_comp; struct lod_device *d = lu2lod_dev(lod2lu_obj(lo)->lo_dev); @@ -2339,7 +2340,7 @@ int lod_qos_parse_config(const struct lu_env *env, struct lod_object *lo, else lod_free_comp_entries(lo); - rc = lod_verify_striping(env, d, lo, buf, false); + rc = lod_verify_striping(env, d, lo, attr, buf, false); if (rc) RETURN(-EINVAL); @@ -2896,7 +2897,7 @@ int lod_prepare_create(const struct lu_env *env, struct lod_object *lo, * in case the caller is passing lovea with new striping config, * we may need to parse lovea and apply new configuration */ - rc = lod_qos_parse_config(env, lo, buf); + rc = lod_qos_parse_config(env, lo, attr, buf); if (rc) RETURN(rc); diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index 96f06e2..0d0cf0d 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -6052,6 +6052,54 @@ test_66() { } run_test 66 "Encryption + compression" +test_67() { + local p="$TMP/$TESTSUITE-$TESTNAME.parameters" + local vaultdir=$DIR/$tdir/vault + local dir1=$vaultdir/compr + local dir2=$DIR/$tdir/compr2 + + (( MDS1_VERSION >= $(version_code 2.14.0.101) )) || + skip "Need MDS >= 2.14.0.101 for compression support" + + cli_enc=$($LCTL get_param mdc.*.import | grep client_encryption) + [ -n "$cli_enc" ] || skip "Need enc support" + which fscrypt || skip "Need fscrypt" + + mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed" + + fscrypt_setup $MOUNT 0 + stack_trap "rm -rf $MOUNT/.fscrypt" + + save_lustre_params client "llite.*.enable_compression" > $p + $LCTL set_param -n llite.*.enable_compression 1 + stack_trap "restore_lustre_params < $p; rm -f $p" EXIT + mkdir -p $vaultdir + stack_trap "rm -rf $vaultdir" + + echo -e 'mypass\nmypass' | fscrypt encrypt --verbose \ + --source=custom_passphrase --name=protector_67 $vaultdir || + error "fscrypt encrypt $vaultdir failed" + + # set compression layout upon encrypted dir + $LFS setstripe -E eof -Z lz4 --compress-chunk=64 $vaultdir && + error "should not be able to set $vaultdir compressed" + + mkdir -p $dir1 + $LFS setstripe -E eof -Z lz4 --compress-chunk=64 $dir1 && + error "should not be able to set $dir1 compressed" + + # encrypt dir with compression layout + mkdir -p $dir2 + $LFS setstripe -E eof -Z lz4 --compress-chunk=64 $dir2 || + error "setstripe $dir2 failed" + echo -e 'mypass\nmypass' | fscrypt encrypt --verbose \ + --source=custom_passphrase -name=protector_67_2 $dir2 && + error "should not be able to encrypt compressed $dir2" + + return 0 +} +run_test 67 "should not create compressed file on encrypted dir" + log "cleanup: ======================================================" sec_unsetup() { -- 1.8.3.1