- chlg_ops, to allow access to Lustre Changelogs.
- dne_ops, to allow operations related to DNE (e.g. 'lfs mkdir').
- file_perms, to allow modifications of file permissions and owners.
+- fscrypt_admin, to allow fscrypt related admin tasks (create or modify
+protectors/policies). Note that even without this role, it is still possible
+to lock or unlock encrypted directories, as these operations only need read
+access to fscrypt metadata.
- quota_ops, to allow quota modifications.
Apart from all, any role not explicitly specified is forbidden. And to forbid
all roles, use 'none' value.
LOHA_EXISTS = BIT(0),
LOHA_REMOTE = BIT(1),
LOHA_HAS_AGENT_ENTRY = BIT(2),
+ LOHA_FSCRYPT_MD = BIT(3),
/**
* UNIX file type is stored in S_IFMT bits.
*/
enum nodemap_rbac_roles nrn_mode;
const char *nrn_name;
} nodemap_rbac_names[] = {
- { NODEMAP_RBAC_FILE_PERMS, "file_perms" },
- { NODEMAP_RBAC_DNE_OPS, "dne_ops" },
- { NODEMAP_RBAC_QUOTA_OPS, "quota_ops" },
- { NODEMAP_RBAC_BYFID_OPS, "byfid_ops" },
- { NODEMAP_RBAC_CHLG_OPS, "chlg_ops" },
+ { NODEMAP_RBAC_FILE_PERMS, "file_perms" },
+ { NODEMAP_RBAC_DNE_OPS, "dne_ops" },
+ { NODEMAP_RBAC_QUOTA_OPS, "quota_ops" },
+ { NODEMAP_RBAC_BYFID_OPS, "byfid_ops" },
+ { NODEMAP_RBAC_CHLG_OPS, "chlg_ops" },
+ { NODEMAP_RBAC_FSCRYPT_ADMIN, "fscrypt_admin" },
};
struct nodemap_pde {
int uc_rbac_quota_ops:1;
int uc_rbac_byfid_ops:1;
int uc_rbac_chlg_ops:1;
+ int uc_rbac_fscrypt_admin:1;
};
struct lu_ucred *lu_ucred(const struct lu_env *env);
};
enum nodemap_rbac_roles {
- NODEMAP_RBAC_FILE_PERMS = 0x00000001,
- NODEMAP_RBAC_DNE_OPS = 0x00000002,
- NODEMAP_RBAC_QUOTA_OPS = 0x00000004,
- NODEMAP_RBAC_BYFID_OPS = 0x00000008,
- NODEMAP_RBAC_CHLG_OPS = 0x00000010,
- NODEMAP_RBAC_NONE = (__u32)~(NODEMAP_RBAC_FILE_PERMS |
- NODEMAP_RBAC_DNE_OPS |
- NODEMAP_RBAC_QUOTA_OPS |
- NODEMAP_RBAC_BYFID_OPS |
- NODEMAP_RBAC_CHLG_OPS),
+ NODEMAP_RBAC_FILE_PERMS = 0x00000001,
+ NODEMAP_RBAC_DNE_OPS = 0x00000002,
+ NODEMAP_RBAC_QUOTA_OPS = 0x00000004,
+ NODEMAP_RBAC_BYFID_OPS = 0x00000008,
+ NODEMAP_RBAC_CHLG_OPS = 0x00000010,
+ NODEMAP_RBAC_FSCRYPT_ADMIN = 0x00000020,
+ NODEMAP_RBAC_NONE = (__u32)~(NODEMAP_RBAC_FILE_PERMS |
+ NODEMAP_RBAC_DNE_OPS |
+ NODEMAP_RBAC_QUOTA_OPS |
+ NODEMAP_RBAC_BYFID_OPS |
+ NODEMAP_RBAC_CHLG_OPS |
+ NODEMAP_RBAC_FSCRYPT_ADMIN),
NODEMAP_RBAC_ALL = 0xFFFFFFFF, /* future caps ON by default */
};
(lc->ldo_dir_hash_type & LMV_HASH_FLAG_KNOWN) |
d->lod_mdt_descs.ltd_lmv_desc.ld_pattern;
+ /* make sure all fscrypt metadata stays on same mdt */
+ if (child->do_lu.lo_header->loh_attr & LOHA_FSCRYPT_MD) {
+ lc->ldo_dir_stripe_count = 0;
+ lds->lds_dir_def_stripe_offset =
+ lod2lu_dev(d)->ld_site->ld_seq_site->ss_node_id;
+ lds->lds_dir_def_striping_set = 1;
+ lc->ldo_def_striping = lds;
+ }
+
CDEBUG(D_INFO, "final dir stripe_count=%hu offset=%d hash=%u\n",
lc->ldo_dir_stripe_count,
(int)lc->ldo_dir_stripe_offset, lc->ldo_dir_hash_type);
uc->uc_rbac_quota_ops = 1;
uc->uc_rbac_byfid_ops = 1;
uc->uc_rbac_chlg_ops = 1;
+ uc->uc_rbac_fscrypt_admin = 1;
RETURN(0);
}
RETURN(rc);
}
+ /* return immutable attr on fscrypt metadata files
+ * if fscrypt admin is not permitted
+ */
+ if (o->mot_obj.lo_header->loh_attr & LOHA_FSCRYPT_MD &&
+ !mdt_ucred(info)->uc_rbac_fscrypt_admin)
+ la->la_flags |= LUSTRE_IMMUTABLE_FL;
+
/* if file is released, check if a restore is running */
if (ma->ma_valid & MA_HSM) {
repbody->mbo_valid |= OBD_MD_TSTATE;
info->mti_cross_ref = !!(reqbody->mbo_valid & OBD_MD_FLCROSSREF);
+ rc = mdt_init_ucred(info, reqbody);
+ if (rc)
+ GOTO(out_shrink, rc);
+
rc = mdt_getattr_internal(info, obj, 0);
if (unlikely(rc))
- GOTO(out_shrink, rc);
+ GOTO(out_ucred, rc);
rc = mdt_pack_encctx_in_reply(info, obj);
EXIT;
+out_ucred:
+ mdt_exit_ucred(info);
out_shrink:
mdt_client_compatibility(info);
rc2 = mdt_fix_reply(info);
struct mdt_lock_handle *lhp = NULL;
struct ldlm_lock *lock;
struct req_capsule *pill = info->mti_pill;
+ bool fscrypt_md = false;
__u64 try_bits = 0;
bool is_resent;
int ma_need = 0;
CDEBUG(D_INODE, "getattr with lock for "DFID"/"DNAME", "
"ldlm_rep = %p\n", PFID(mdt_object_fid(parent)),
PNAME(lname), ldlm_rep);
+
+ if (parent->mot_obj.lo_header->loh_attr & LOHA_FSCRYPT_MD ||
+ (fid_is_root(mdt_object_fid(parent)) &&
+ lname->ln_namelen == strlen(dot_fscrypt_name) &&
+ strncmp(lname->ln_name, dot_fscrypt_name,
+ lname->ln_namelen) == 0))
+ fscrypt_md = true;
} else {
reqbody = req_capsule_client_get(pill, &RMF_MDT_BODY);
if (unlikely(reqbody == NULL))
GOTO(out_child, rc);
}
+ if (fscrypt_md)
+ child->mot_obj.lo_header->loh_attr |= LOHA_FSCRYPT_MD;
+
/* finally, we can get attr for child. */
rc = mdt_getattr_internal(info, child, ma_need);
if (unlikely(rc != 0)) {
mdt_ucred(info)->uc_rbac_quota_ops = 1;
mdt_ucred(info)->uc_rbac_byfid_ops = 1;
mdt_ucred(info)->uc_rbac_chlg_ops = 1;
+ mdt_ucred(info)->uc_rbac_fscrypt_admin = 1;
rc = mdt_add_dirty_flag(info, mfd->mfd_object, &info->mti_attr);
lu_context_exit(&ses);
uc->uc_rbac_quota_ops = !!(rbac & NODEMAP_RBAC_QUOTA_OPS);
uc->uc_rbac_byfid_ops = !!(rbac & NODEMAP_RBAC_BYFID_OPS);
uc->uc_rbac_chlg_ops = !!(rbac & NODEMAP_RBAC_CHLG_OPS);
+ uc->uc_rbac_fscrypt_admin = !!(rbac & NODEMAP_RBAC_FSCRYPT_ADMIN);
}
static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
GOTO(out, result);
}
+ if (!uc->uc_rbac_fscrypt_admin &&
+ parent->mot_obj.lo_header->loh_attr & LOHA_FSCRYPT_MD &&
+ open_flags & MDS_OPEN_CREAT)
+ GOTO(out_parent, result = -EPERM);
+
result = mdt_check_enc(info, parent);
if (result)
GOTO(out_parent, result);
struct md_attr *ma = &info->mti_attr;
struct mdt_reint_record *rr = &info->mti_rr;
struct md_op_spec *spec = &info->mti_spec;
+ struct lu_ucred *uc = mdt_ucred(info);
bool restripe = false;
int rc;
if (S_ISDIR(ma->ma_attr.la_mode) &&
spec->u.sp_ea.eadata != NULL && spec->u.sp_ea.eadatalen != 0) {
const struct lmv_user_md *lum = spec->u.sp_ea.eadata;
- struct lu_ucred *uc = mdt_ucred(info);
struct obd_export *exp = mdt_info_req(info)->rq_export;
/* Only new clients can create remote dir( >= 2.4) and
if (rc)
GOTO(put_parent, rc);
+ if (!uc->uc_rbac_fscrypt_admin &&
+ parent->mot_obj.lo_header->loh_attr & LOHA_FSCRYPT_MD)
+ GOTO(put_parent, rc = -EPERM);
+
/*
* LU-10235: check if name exists locklessly first to avoid massive
* lock recalls on existing directories.
if (rc)
GOTO(put_child, rc);
+ if (parent->mot_obj.lo_header->loh_attr & LOHA_FSCRYPT_MD ||
+ (rr->rr_name.ln_namelen == strlen(dot_fscrypt_name) &&
+ strncmp(rr->rr_name.ln_name, dot_fscrypt_name,
+ rr->rr_name.ln_namelen) == 0))
+ child->mot_obj.lo_header->loh_attr |= LOHA_FSCRYPT_MD;
+
/*
* Do not perform lookup sanity check. We know that name does
* not exist.
struct mdt_lock_handle *parent_lh;
struct mdt_lock_handle *child_lh;
struct ldlm_enqueue_info *einfo = &info->mti_einfo[0];
+ struct lu_ucred *uc = mdt_ucred(info);
__u64 lock_ibits;
bool cos_incompat = false;
int no_name = 0;
GOTO(put_parent, rc);
}
+ if (!uc->uc_rbac_fscrypt_admin &&
+ mp->mot_obj.lo_header->loh_attr & LOHA_FSCRYPT_MD)
+ GOTO(put_parent, rc = -EPERM);
+
OBD_RACE(OBD_FAIL_MDS_REINT_OPEN);
OBD_RACE(OBD_FAIL_MDS_REINT_OPEN2);
relock:
GOTO(put_parent, rc);
if (info->mti_spec.sp_rm_entry) {
- struct lu_ucred *uc = mdt_ucred(info);
-
if (!mdt_is_dne_client(req->rq_export))
/* Return -ENOTSUPP for old client */
GOTO(unlock_parent, rc = -ENOTSUPP);
struct mdt_lock_handle *lh_newp = NULL;
struct lu_fid *old_fid = &info->mti_tmp_fid1;
struct lu_fid *new_fid = &info->mti_tmp_fid2;
+ struct lu_ucred *uc = mdt_ucred(info);
__u64 lock_ibits;
bool reverse = false, discard = false;
bool cos_incompat;
if (rc)
GOTO(out_put_tgtdir, rc);
+ if (!uc->uc_rbac_fscrypt_admin &&
+ mtgtdir->mot_obj.lo_header->loh_attr & LOHA_FSCRYPT_MD)
+ GOTO(out_put_tgtdir, rc = -EPERM);
+
/*
* Note: do not enqueue rename lock for replay request, because
* if other MDT holds rename lock, but being blocked to wait for
uc->uc_rbac_quota_ops = 1;
uc->uc_rbac_byfid_ops = 1;
uc->uc_rbac_chlg_ops = 1;
+ uc->uc_rbac_fscrypt_admin = 1;
task = kthread_create(mdt_restriper_main, info, "mdt_restriper_%03d",
mdt_seq_site(mdt)->ss_node_id);
ucred->uc_rbac_quota_ops = 1;
ucred->uc_rbac_byfid_ops = 1;
ucred->uc_rbac_chlg_ops = 1;
+ ucred->uc_rbac_fscrypt_admin = 1;
}
static void echo_ucred_fini(struct lu_env *env)
(long long)NODEMAP_RBAC_BYFID_OPS);
LASSERTF(NODEMAP_RBAC_CHLG_OPS == 0x00000010UL, "found 0x%.8llxUL\n",
(long long)NODEMAP_RBAC_CHLG_OPS);
- LASSERTF(NODEMAP_RBAC_NONE == 0xFFFFFFE0UL, "found 0x%.8llxUL\n",
+ LASSERTF(NODEMAP_RBAC_FSCRYPT_ADMIN == 0x00000020UL, "found 0x%.8llxUL\n",
+ (long long)NODEMAP_RBAC_FSCRYPT_ADMIN);
+ LASSERTF(NODEMAP_RBAC_NONE == 0xFFFFFFC0UL, "found 0x%.8llxUL\n",
(long long)NODEMAP_RBAC_NONE);
LASSERTF(NODEMAP_RBAC_ALL == 0xFFFFFFFFUL, "found 0x%.8llxUL\n",
(long long)NODEMAP_RBAC_ALL);
quota_ops \
byfid_ops \
chlg_ops \
+ fscrypt_admin \
;
do
[[ "$rbac" =~ "$role" ]] ||
}
run_test 64e "Nodemap enforces chlg_ops RBAC roles"
+test_64f() {
+ local vaultdir=$DIR/$tdir/vault
+ local cli_enc
+ local policy
+ local protector
+
+ (( MDS1_VERSION >= $(version_code 2.15.54) )) ||
+ skip "Need MDS >= 2.15.54 for role-based controls"
+
+ cli_enc=$($LCTL get_param mdc.*.import | grep client_encryption)
+ [ -n "$cli_enc" ] || skip "Need enc support, skip fscrypt_admin role"
+ which fscrypt || skip "Need fscrypt, skip fscrypt_admin role"
+
+ stack_trap cleanup_64 EXIT
+ mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed"
+ setup_64
+
+ yes | fscrypt setup --force --verbose ||
+ echo "fscrypt global setup already done"
+ sed -i 's/\(.*\)policy_version\(.*\):\(.*\)\"[0-9]*\"\(.*\)/\1policy_version\2:\3"2"\4/' \
+ /etc/fscrypt.conf
+ yes | fscrypt setup --verbose $MOUNT ||
+ echo "fscrypt setup $MOUNT already done"
+ stack_trap "rm -rf $MOUNT/.fscrypt"
+
+ # file_perms is required because fscrypt uses chmod/chown
+ do_facet mgs $LCTL nodemap_modify --name c0 --property rbac \
+ --value fscrypt_admin,file_perms
+ wait_nm_sync c0 rbac
+
+ mkdir -p $vaultdir
+ set -vx
+ echo -e 'mypass\nmypass' | fscrypt encrypt --verbose \
+ --source=custom_passphrase --name=protector_64 $vaultdir ||
+ error "fscrypt encrypt $vaultdir failed"
+ fscrypt lock $vaultdir || error "fscrypt lock $vaultdir failed (1)"
+ policy=$(fscrypt status $vaultdir | awk '$1 == "Policy:"{print $2}')
+ [ -n "$policy" ] || error "could not get enc policy"
+ protector=$(fscrypt status $vaultdir |
+ awk 'BEGIN {found=0} { if (found == 1) { print $1 }} \
+ $1 == "PROTECTOR" {found=1}')
+ [ -n "$protector" ] || error "could not get enc protector"
+ set +vx
+
+ cancel_lru_locks
+ # file_perms is required because fscrypt uses chmod/chown
+ do_facet mgs $LCTL nodemap_modify --name c0 --property rbac \
+ --value file_perms
+ wait_nm_sync c0 rbac
+
+ set -vx
+ echo mypass | fscrypt unlock $vaultdir ||
+ error "fscrypt unlock $vaultdir failed"
+ fscrypt lock $vaultdir || error "fscrypt lock $vaultdir failed (2)"
+ fscrypt metadata destroy --protector=$MOUNT:$protector --force &&
+ error "destroy protector should fail"
+ fscrypt metadata destroy --policy=$MOUNT:$policy --force &&
+ error "destroy policy should fail"
+ mkdir -p ${vaultdir}2
+ echo -e 'mypass\nmypass' | fscrypt encrypt --verbose \
+ --source=custom_passphrase \
+ --name=protector_64bis ${vaultdir}2 &&
+ error "fscrypt encrypt ${vaultdir}2 should fail"
+ set +vx
+
+ cancel_lru_locks
+ do_facet mgs $LCTL nodemap_modify --name c0 --property rbac --value all
+ wait_nm_sync c0 rbac
+
+ set -vx
+ fscrypt metadata destroy --protector=$MOUNT:$protector --force ||
+ error "destroy protector failed"
+ fscrypt metadata destroy --policy=$MOUNT:$policy --force ||
+ error "destroy policy failed"
+ set +vx
+
+ rm -rf ${vaultdir}*
+}
+run_test 64f "Nodemap enforces fscrypt_admin RBAC roles"
+
log "cleanup: ======================================================"
sec_unsetup() {
CHECK_VALUE_X(NODEMAP_RBAC_QUOTA_OPS);
CHECK_VALUE_X(NODEMAP_RBAC_BYFID_OPS);
CHECK_VALUE_X(NODEMAP_RBAC_CHLG_OPS);
+ CHECK_VALUE_X(NODEMAP_RBAC_FSCRYPT_ADMIN);
CHECK_VALUE_X(NODEMAP_RBAC_NONE);
CHECK_VALUE_X(NODEMAP_RBAC_ALL);
}
(long long)NODEMAP_RBAC_BYFID_OPS);
LASSERTF(NODEMAP_RBAC_CHLG_OPS == 0x00000010UL, "found 0x%.8llxUL\n",
(long long)NODEMAP_RBAC_CHLG_OPS);
- LASSERTF(NODEMAP_RBAC_NONE == 0xFFFFFFE0UL, "found 0x%.8llxUL\n",
+ LASSERTF(NODEMAP_RBAC_FSCRYPT_ADMIN == 0x00000020UL, "found 0x%.8llxUL\n",
+ (long long)NODEMAP_RBAC_FSCRYPT_ADMIN);
+ LASSERTF(NODEMAP_RBAC_NONE == 0xFFFFFFC0UL, "found 0x%.8llxUL\n",
(long long)NODEMAP_RBAC_NONE);
LASSERTF(NODEMAP_RBAC_ALL == 0xFFFFFFFFUL, "found 0x%.8llxUL\n",
(long long)NODEMAP_RBAC_ALL);