From 4ced247208624eb56c4e1ed23cacd31947883f34 Mon Sep 17 00:00:00 2001 From: Marc Vef Date: Mon, 25 Nov 2024 14:08:37 +0100 Subject: [PATCH] LU-18469 ptlrpc: Add flag to deny mounts for nodemaps Previously, nodemaps could only be activated and deactived globally. This patch adds the ability to deny mount attempts for individual nodemaps. Existing mounted clients are not evicted when the new flag is set. This feature is implemented by adding a new nodemap flag "deny_mount" and it is stored in the nodemap IAM config record. It is therefore persistent and the flag is automatically distributed across the cluster. Similar to other nodemap flags, the new "deny_mount" flag is set via "lctl nodemap_modify" and retrieved via "lctl get_param". Deny mounts for nodemap: lctl nodemap_modify --name --property deny_mount --value 1 Allow mounts for nodemap (default): lctl nodemap_modify --name --property deny_mount --value 0 Read nodemap deny_mount flag: lctl get_param nodemap..deny_mount A new sanity-sec test 74 was added to test this flag. Signed-off-by: Marc Vef Change-Id: Ibf05d3e04768a5702dc6070e2d35c9ac07e731ac Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/57096 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin Reviewed-by: Sebastien Buisson --- lustre/doc/lctl-nodemap-modify.8 | 5 + lustre/include/lustre_nodemap.h | 4 +- lustre/include/uapi/linux/lustre/lustre_cfg.h | 1 + lustre/include/uapi/linux/lustre/lustre_disk.h | 1 + lustre/mdt/mdt_handler.c | 30 ++- lustre/ptlrpc/nodemap_handler.c | 36 +++ lustre/ptlrpc/nodemap_lproc.c | 37 ++++ lustre/ptlrpc/nodemap_storage.c | 5 +- lustre/ptlrpc/wiretest.c | 4 + lustre/tests/sanity-sec.sh | 290 ++++++++++++------------- lustre/utils/obd.c | 4 +- lustre/utils/wirecheck.c | 2 + lustre/utils/wiretest.c | 4 + 13 files changed, 256 insertions(+), 167 deletions(-) diff --git a/lustre/doc/lctl-nodemap-modify.8 b/lustre/doc/lctl-nodemap-modify.8 index d620422..0fcdc2a 100644 --- a/lustre/doc/lctl-nodemap-modify.8 +++ b/lustre/doc/lctl-nodemap-modify.8 @@ -87,6 +87,11 @@ Set to 1 to prevent clients from using encryption. Defaults to 0, which lets clients mount in read-write mode. If set to 1, clients are forced to a read-only mount if not specified explicitly. .TP +.B deny_mount +Defaults to 0, accepting client mounts from nodes assigned to the nodemap. If +set to 1, nodes assigned to the nodemap can no longer mount new Lustre clients. +Existing clients remain operational until a remount is attempted. +.TP .B rbac Defaults to all, which means all roles are allowed. Other possible values (multiple can be specified, comma separated) are: diff --git a/lustre/include/lustre_nodemap.h b/lustre/include/lustre_nodemap.h index 001822d..55564f6 100644 --- a/lustre/include/lustre_nodemap.h +++ b/lustre/include/lustre_nodemap.h @@ -57,7 +57,8 @@ struct lu_nodemap { nmf_allow_root_access:1, nmf_enable_audit:1, nmf_forbid_encryption:1, - nmf_readonly_mount:1; + nmf_readonly_mount:1, + nmf_deny_mount:1; /* bitmap for mapping type */ enum nodemap_mapping_modes nmf_map_mode; /* bitmap for rbac, enum nodemap_rbac_roles */ @@ -154,6 +155,7 @@ int nodemap_set_squash_projid(const char *name, projid_t projid); int nodemap_set_audit_mode(const char *name, bool enable_audit); int nodemap_set_forbid_encryption(const char *name, bool forbid_encryption); int nodemap_set_readonly_mount(const char *name, bool readonly_mount); +int nodemap_set_deny_mount(const char *name, bool deny_mount); bool nodemap_can_setquota(struct lu_nodemap *nodemap, __u32 qc_type, __u32 id); int nodemap_add_idmap(const char *nodemap_name, enum nodemap_id_type id_type, const __u32 map[2]); diff --git a/lustre/include/uapi/linux/lustre/lustre_cfg.h b/lustre/include/uapi/linux/lustre/lustre_cfg.h index 7bf7687..de3dc29 100644 --- a/lustre/include/uapi/linux/lustre/lustre_cfg.h +++ b/lustre/include/uapi/linux/lustre/lustre_cfg.h @@ -126,6 +126,7 @@ enum lcfg_command_type { LCFG_NODEMAP_SQUASH_PROJID = 0x00ce05d, /**< default map projid */ LCFG_NODEMAP_READONLY_MOUNT = 0x00ce05e, /**< read-only mount */ LCFG_NODEMAP_RBAC = 0x00ce05f, /**< rbac */ + LCFG_NODEMAP_DENY_MOUNT = 0x00ce060, /**< deny mount */ }; struct lustre_cfg_bufs { diff --git a/lustre/include/uapi/linux/lustre/lustre_disk.h b/lustre/include/uapi/linux/lustre/lustre_disk.h index 75e6fe1..da56d26 100644 --- a/lustre/include/uapi/linux/lustre/lustre_disk.h +++ b/lustre/include/uapi/linux/lustre/lustre_disk.h @@ -258,6 +258,7 @@ enum nm_flag_bits { enum nm_flag2_bits { NM_FL2_READONLY_MOUNT = 0x1, + NM_FL2_DENY_MOUNT = 0x2, }; /* Nodemap records, uses 32 byte record length. diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index 2b27bb1..91f69c8 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -376,13 +376,14 @@ static int mdt_lookup_fileset(struct mdt_thread_info *info, const char *fileset, static int mdt_get_root(struct tgt_session_info *tsi) { - struct mdt_thread_info *info = tsi2mdt_info(tsi); - struct mdt_device *mdt = info->mti_mdt; - struct mdt_body *repbody; - char *fileset = NULL, *buffer = NULL; - int rc; - struct obd_export *exp = info->mti_exp; - char *nodemap_fileset; + struct mdt_thread_info *info = tsi2mdt_info(tsi); + struct obd_export *exp = info->mti_exp; + struct mdt_body *repbody; + struct lu_nodemap *nodemap = NULL; + struct mdt_device *mdt = info->mti_mdt; + char *fileset = NULL, *buffer = NULL; + char *nodemap_fileset = NULL; + int rc; ENTRY; @@ -400,8 +401,15 @@ static int mdt_get_root(struct tgt_session_info *tsi) GOTO(out, rc = err_serious(-EFAULT)); } - nodemap_fileset = nodemap_get_fileset(exp->exp_target_data.ted_nodemap); - if (nodemap_fileset && nodemap_fileset[0]) { + /* refuse access if this nodemap is set to deny mounts */ + nodemap = nodemap_get_from_exp(exp); + if (!IS_ERR_OR_NULL(nodemap)) { + if (nodemap->nmf_deny_mount) + GOTO(out, rc = err_serious(-EPERM)); + nodemap_fileset = nodemap_get_fileset(nodemap); + } + + if (nodemap_fileset != NULL && nodemap_fileset[0]) { CDEBUG(D_INFO, "nodemap fileset is %s\n", nodemap_fileset); if (fileset) { /* consider fileset from client as a sub-fileset @@ -435,6 +443,10 @@ static int mdt_get_root(struct tgt_session_info *tsi) out: mdt_thread_info_fini(info); OBD_FREE(buffer, PATH_MAX+1); + + if (!IS_ERR_OR_NULL(nodemap)) + nodemap_putref(nodemap); + return rc; } diff --git a/lustre/ptlrpc/nodemap_handler.c b/lustre/ptlrpc/nodemap_handler.c index cdd5572..f46d410 100644 --- a/lustre/ptlrpc/nodemap_handler.c +++ b/lustre/ptlrpc/nodemap_handler.c @@ -965,6 +965,7 @@ static void nodemap_inherit_properties(struct lu_nodemap *dst, dst->nmf_forbid_encryption = 0; dst->nmf_readonly_mount = 0; dst->nmf_rbac = NODEMAP_RBAC_ALL; + dst->nmf_deny_mount = 0; dst->nm_squash_uid = NODEMAP_NOBODY_UID; dst->nm_squash_gid = NODEMAP_NOBODY_GID; @@ -986,6 +987,7 @@ static void nodemap_inherit_properties(struct lu_nodemap *dst, dst->nmf_forbid_encryption = src->nmf_forbid_encryption; dst->nmf_readonly_mount = src->nmf_readonly_mount; dst->nmf_rbac = src->nmf_rbac; + dst->nmf_deny_mount = src->nmf_deny_mount; dst->nm_squash_uid = src->nm_squash_uid; dst->nm_squash_gid = src->nm_squash_gid; dst->nm_squash_projid = src->nm_squash_projid; @@ -1830,6 +1832,34 @@ out: EXPORT_SYMBOL(nodemap_set_readonly_mount); /** + * Set the nmf_deny_mount flag to true or false. + * \param name nodemap name + * \param deny_mount if true, rejects mount attempt + * \retval 0 on success + * + */ +int nodemap_set_deny_mount(const char *name, bool deny_mount) +{ + struct lu_nodemap *nodemap = NULL; + int rc = 0; + + mutex_lock(&active_config_lock); + nodemap = nodemap_lookup(name); + mutex_unlock(&active_config_lock); + if (IS_ERR(nodemap)) + RETURN(PTR_ERR(nodemap)); + + nodemap->nmf_deny_mount = deny_mount; + rc = nodemap_idx_nodemap_update(nodemap); + + nm_member_revoke_locks(nodemap); + nodemap_putref(nodemap); + + return rc; +} +EXPORT_SYMBOL(nodemap_set_deny_mount); + +/** * Add a nodemap * * \param name name of nodemap @@ -2505,6 +2535,11 @@ static int cfg_nodemap_cmd(enum lcfg_command_type cmd, const char *nodemap_name, rc = nodemap_set_readonly_mount(nodemap_name, bool_switch); break; + case LCFG_NODEMAP_DENY_MOUNT: + rc = kstrtobool(param, &bool_switch); + if (rc == 0) + rc = nodemap_set_deny_mount(nodemap_name, bool_switch); + break; case LCFG_NODEMAP_MAP_MODE: { char *p; @@ -2805,6 +2840,7 @@ int server_iocontrol_nodemap(struct obd_device *obd, case LCFG_NODEMAP_AUDIT_MODE: case LCFG_NODEMAP_FORBID_ENCRYPT: case LCFG_NODEMAP_READONLY_MOUNT: + case LCFG_NODEMAP_DENY_MOUNT: case LCFG_NODEMAP_RBAC: if (lcfg->lcfg_bufcount != 4) GOTO(out_lcfg, rc = -EINVAL); diff --git a/lustre/ptlrpc/nodemap_lproc.c b/lustre/ptlrpc/nodemap_lproc.c index ce51498..f3165e2 100644 --- a/lustre/ptlrpc/nodemap_lproc.c +++ b/lustre/ptlrpc/nodemap_lproc.c @@ -796,6 +796,34 @@ static int nodemap_readonly_mount_seq_show(struct seq_file *m, void *data) return 0; } +/** + * Reads and prints the deny_mount flag for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_deny_mount_seq_show(struct seq_file *m, void *data) +{ + struct lu_nodemap *nodemap; + int rc; + + mutex_lock(&active_config_lock); + nodemap = nodemap_lookup(m->private); + mutex_unlock(&active_config_lock); + if (IS_ERR(nodemap)) { + rc = PTR_ERR(nodemap); + CERROR("cannot find nodemap '%s': rc = %d\n", + (char *)m->private, rc); + return rc; + } + + seq_printf(m, "%d\n", (int)nodemap->nmf_deny_mount); + nodemap_putref(nodemap); + + return 0; +} + static struct lprocfs_vars lprocfs_nm_module_vars[] = { { .name = "active", @@ -819,6 +847,7 @@ LPROC_SEQ_FOPS_RO(nodemap_rbac); LPROC_SEQ_FOPS_RO(nodemap_audit_mode); LPROC_SEQ_FOPS_RO(nodemap_forbid_encryption); LPROC_SEQ_FOPS_RO(nodemap_readonly_mount); +LPROC_SEQ_FOPS_RO(nodemap_deny_mount); static const struct proc_ops nodemap_ranges_fops = { .proc_open = nodemap_ranges_open, @@ -896,6 +925,10 @@ static struct lprocfs_vars lprocfs_nodemap_vars[] = { .fops = &nodemap_readonly_mount_fops, }, { + .name = "deny_mount", + .fops = &nodemap_deny_mount_fops, + }, + { .name = "sepol", .fops = &nodemap_sepol_fops, }, @@ -959,6 +992,10 @@ static struct lprocfs_vars lprocfs_default_nodemap_vars[] = { .fops = &nodemap_readonly_mount_fops, }, { + .name = "deny_mount", + .fops = &nodemap_deny_mount_fops, + }, + { .name = "squash_gid", .fops = &nodemap_squash_gid_fops, }, diff --git a/lustre/ptlrpc/nodemap_storage.c b/lustre/ptlrpc/nodemap_storage.c index 31a02ce..44ecc82 100644 --- a/lustre/ptlrpc/nodemap_storage.c +++ b/lustre/ptlrpc/nodemap_storage.c @@ -87,8 +87,8 @@ static void nodemap_cluster_rec_init(union nodemap_rec *nr, (nodemap->nmf_forbid_encryption ? NM_FL_FORBID_ENCRYPT : 0); nr->ncr.ncr_flags2 = - (nodemap->nmf_readonly_mount ? - NM_FL2_READONLY_MOUNT : 0); + (nodemap->nmf_readonly_mount ? NM_FL2_READONLY_MOUNT : 0) | + (nodemap->nmf_deny_mount ? NM_FL2_DENY_MOUNT : 0); nr->ncr.ncr_padding1 = 0; nr->ncr.ncr_squash_projid = cpu_to_le32(nodemap->nm_squash_projid); nr->ncr.ncr_squash_uid = cpu_to_le32(nodemap->nm_squash_uid); @@ -864,6 +864,7 @@ static int nodemap_cluster_rec_helper(struct nodemap_config *config, nodemap->nmf_forbid_encryption = flags & NM_FL_FORBID_ENCRYPT; flags2 = rec->ncr.ncr_flags2; nodemap->nmf_readonly_mount = flags2 & NM_FL2_READONLY_MOUNT; + nodemap->nmf_deny_mount = flags2 & NM_FL2_DENY_MOUNT; /* by default, and in the absence of cluster_roles, grant all roles */ nodemap->nmf_rbac = NODEMAP_RBAC_ALL; diff --git a/lustre/ptlrpc/wiretest.c b/lustre/ptlrpc/wiretest.c index a8b5667..da50441 100644 --- a/lustre/ptlrpc/wiretest.c +++ b/lustre/ptlrpc/wiretest.c @@ -6487,6 +6487,8 @@ void lustre_assert_wire_constants(void) (unsigned)NM_FL_MAP_PROJID); LASSERTF(NM_FL2_READONLY_MOUNT == 0x00000001UL, "found 0x%.8xUL\n", (unsigned)NM_FL2_READONLY_MOUNT); + LASSERTF(NM_FL2_DENY_MOUNT == 0x00000002UL, "found 0x%.8xUL\n", + (unsigned int)NM_FL2_DENY_MOUNT); LASSERTF(NODEMAP_UID == 0, "found %lld\n", (long long)NODEMAP_UID); LASSERTF(NODEMAP_GID == 1, "found %lld\n", @@ -7103,6 +7105,8 @@ void lustre_assert_wire_constants(void) (unsigned)LCFG_NODEMAP_READONLY_MOUNT); LASSERTF(LCFG_NODEMAP_RBAC == 0x000ce05fUL, "found 0x%.8xUL\n", (unsigned)LCFG_NODEMAP_RBAC); + LASSERTF(LCFG_NODEMAP_DENY_MOUNT == 0x000ce060UL, "found 0x%.8xUL\n", + (unsigned int)LCFG_NODEMAP_DENY_MOUNT); #endif /* HAVE_SERVER_SUPPORT */ LASSERTF(PORTALS_CFG_TYPE == 1, "found %lld\n", (long long)PORTALS_CFG_TYPE); diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index 536e628..2f6974f 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -5339,29 +5339,74 @@ test_54() { } run_test 54 "Encryption policies with fscrypt" -cleanup_55() { - # unmount client - if is_mounted $MOUNT; then - umount_client $MOUNT || error "umount $MOUNT failed" +setup_local_client_nodemap() { + local nm_name=${1:-"c0"} + local nm_admin_val=${2:-0} + local nm_trusted_val=${3:-0} + local rc + + if $SHARED_KEY; then + export SK_UNIQUE_NM=true + export FILESET="/" fi - do_facet mgs $LCTL nodemap_del c0 + do_facet mgs $LCTL nodemap_del $nm_name || true + wait_nm_sync $nm_name id '' + do_facet mgs $LCTL nodemap_modify --name default \ - --property admin --value 0 + --property admin --value 1 do_facet mgs $LCTL nodemap_modify --name default \ - --property trusted --value 0 - wait_nm_sync default admin_nodemap + --property trusted --value 1 + wait_nm_sync default trusted_nodemap + + client_ip=$(host_nids_address $HOSTNAME $NETTYPE) + client_nid=$(h2nettype $client_ip) + do_facet mgs $LCTL nodemap_add $nm_name + do_facet mgs $LCTL nodemap_add_range \ + --name $nm_name --range $client_nid || + error "Add range $client_nid to $nm_name failed rc = $?" + do_facet mgs $LCTL nodemap_modify --name $nm_name \ + --property admin --value $nm_admin_val + do_facet mgs $LCTL nodemap_modify --name $nm_name \ + --property trusted --value $nm_trusted_val + + do_facet mgs $LCTL nodemap_activate 1 + wait_nm_sync active +} + +cleanup_local_client_nodemap() { + local nm_name=${1:-"c0"} + + do_facet mgs $LCTL nodemap_del $nm_name + do_facet mgs $LCTL nodemap_modify --name default \ + --property admin --value 0 + do_facet mgs $LCTL nodemap_modify --name default \ + --property trusted --value 0 wait_nm_sync default trusted_nodemap do_facet mgs $LCTL nodemap_activate 0 wait_nm_sync active 0 if $SHARED_KEY; then + unset FILESET export SK_UNIQUE_NM=false fi + if ! is_mounted $MOUNT; then + mount_client $MOUNT ${MOUNT_OPTS} || error "re-mount failed" + wait_ssk + fi +} - # remount client - mount_client $MOUNT ${MOUNT_OPTS} || error "remount failed" +cleanup_55() { + # unmount client + if is_mounted $MOUNT; then + umount_client $MOUNT || error "umount $MOUNT failed" + fi + + # reset and deactivate nodemaps, remount client + cleanup_local_client_nodemap + + # remount client on $MOUNT_2 if [ "$MOUNT_2" ]; then mount_client $MOUNT2 ${MOUNT_OPTS} || error "remount failed" fi @@ -5394,37 +5439,7 @@ test_55() { stack_trap cleanup_55 EXIT - do_facet mgs $LCTL nodemap_activate 1 - wait_nm_sync active - - do_facet mgs $LCTL nodemap_del c0 || true - wait_nm_sync c0 id '' - - do_facet mgs $LCTL nodemap_modify --name default \ - --property admin --value 1 - do_facet mgs $LCTL nodemap_modify --name default \ - --property trusted --value 1 - wait_nm_sync default admin_nodemap - wait_nm_sync default trusted_nodemap - - client_ip=$(host_nids_address $HOSTNAME $NETTYPE) - client_nid=$(h2nettype $client_ip) - do_facet mgs $LCTL nodemap_add c0 - do_facet mgs $LCTL nodemap_add_range \ - --name c0 --range $client_nid || - error "Add range $client_nid to c0 failed rc = $?" - do_facet mgs $LCTL nodemap_modify --name c0 \ - --property admin --value 0 - do_facet mgs $LCTL nodemap_modify --name c0 \ - --property trusted --value 1 - wait_nm_sync c0 admin_nodemap - wait_nm_sync c0 trusted_nodemap - - if $SHARED_KEY; then - export SK_UNIQUE_NM=true - # set some generic fileset to trigger SSK code - export FILESET=/ - fi + setup_local_client_nodemap "c0" 0 1 # remount client to take nodemap into account zconf_mount_clients $HOSTNAME $MOUNT $MOUNT_OPTS || @@ -5834,62 +5849,6 @@ test_60() { } run_test 60 "Subdirmount of encrypted dir" -setup_61() { - if $SHARED_KEY; then - export SK_UNIQUE_NM=true - export FILESET="/" - fi - - do_facet mgs $LCTL nodemap_activate 1 - wait_nm_sync active - - do_facet mgs $LCTL nodemap_del c0 || true - wait_nm_sync c0 id '' - - do_facet mgs $LCTL nodemap_modify --name default \ - --property admin --value 1 - do_facet mgs $LCTL nodemap_modify --name default \ - --property trusted --value 1 - wait_nm_sync default admin_nodemap - wait_nm_sync default trusted_nodemap - - client_ip=$(host_nids_address $HOSTNAME $NETTYPE) - client_nid=$(h2nettype $client_ip) - do_facet mgs $LCTL nodemap_add c0 - do_facet mgs $LCTL nodemap_add_range \ - --name c0 --range $client_nid || { - do_facet mgs $LCTL nodemap_del c0 - return 1 - } - do_facet mgs $LCTL nodemap_modify --name c0 \ - --property admin --value 1 - do_facet mgs $LCTL nodemap_modify --name c0 \ - --property trusted --value 1 - wait_nm_sync c0 admin_nodemap - wait_nm_sync c0 trusted_nodemap -} - -cleanup_61() { - do_facet mgs $LCTL nodemap_del c0 - do_facet mgs $LCTL nodemap_modify --name default \ - --property admin --value 0 - do_facet mgs $LCTL nodemap_modify --name default \ - --property trusted --value 0 - wait_nm_sync default admin_nodemap - wait_nm_sync default trusted_nodemap - - do_facet mgs $LCTL nodemap_activate 0 - wait_nm_sync active 0 - - if $SHARED_KEY; then - unset FILESET - export SK_UNIQUE_NM=false - fi - - mount_client $MOUNT ${MOUNT_OPTS} || error "re-mount failed" - wait_ssk -} - test_61() { local testfile=$DIR/$tdir/$tfile local readonly @@ -5899,7 +5858,7 @@ test_61() { [ -n "$readonly" ] || skip "Server does not have readonly_mount nodemap flag" - stack_trap cleanup_61 EXIT + stack_trap cleanup_local_client_nodemap EXIT for idx in $(seq 1 $MDSCOUNT); do wait_recovery_complete mds$idx done @@ -5907,7 +5866,7 @@ test_61() { # Activate nodemap, and mount rw. # Should succeed as rw mount is not forbidden by default. - setup_61 + setup_local_client_nodemap "c0" 1 1 readonly=$(do_facet mgs \ lctl get_param -n nodemap.default.readonly_mount) [ $readonly -eq 0 ] || @@ -6150,47 +6109,6 @@ test_63() { } run_test 63 "fid2path with encrypted files" -setup_64() { - do_facet mgs $LCTL nodemap_activate 1 - wait_nm_sync active - - do_facet mgs $LCTL nodemap_del c0 || true - wait_nm_sync c0 id '' - - do_facet mgs $LCTL nodemap_modify --name default \ - --property admin --value 1 - do_facet mgs $LCTL nodemap_modify --name default \ - --property trusted --value 1 - wait_nm_sync default admin_nodemap - wait_nm_sync default trusted_nodemap - - client_ip=$(host_nids_address $HOSTNAME $NETTYPE) - client_nid=$(h2nettype $client_ip) - do_facet mgs $LCTL nodemap_add c0 - do_facet mgs $LCTL nodemap_add_range \ - --name c0 --range $client_nid || - error "Add range $client_nid to c0 failed rc = $?" - do_facet mgs $LCTL nodemap_modify --name c0 \ - --property admin --value 1 - do_facet mgs $LCTL nodemap_modify --name c0 \ - --property trusted --value 1 - wait_nm_sync c0 admin_nodemap - wait_nm_sync c0 trusted_nodemap -} - -cleanup_64() { - do_facet mgs $LCTL nodemap_del c0 - do_facet mgs $LCTL nodemap_modify --name default \ - --property admin --value 0 - do_facet mgs $LCTL nodemap_modify --name default \ - --property trusted --value 0 - wait_nm_sync default admin_nodemap - wait_nm_sync default trusted_nodemap - - do_facet mgs $LCTL nodemap_activate 0 - wait_nm_sync active 0 -} - test_64a() { local testfile=$DIR/$tdir/$tfile local srv_uc="" @@ -6202,9 +6120,9 @@ test_64a() { (( MDS1_VERSION >= $(version_code 2.16.50) )) && srv_uc="server_upcall" - stack_trap cleanup_64 EXIT + stack_trap cleanup_local_client_nodemap EXIT mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed" - setup_64 + setup_local_client_nodemap "c0" 1 1 # check default value for rbac is all rbac=$(do_facet mds $LCTL get_param -n nodemap.c0.rbac) @@ -6270,9 +6188,9 @@ test_64b() { (( MDS1_VERSION >= $(version_code 2.16.50) )) && srv_uc="server_upcall" - stack_trap cleanup_64 EXIT + stack_trap cleanup_local_client_nodemap EXIT mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed" - setup_64 + setup_local_client_nodemap "c0" 1 1 dir_restripe=$(do_node $mds1_HOST \ "$LCTL get_param -n mdt.*MDT0000.enable_dir_restripe") @@ -6352,9 +6270,9 @@ test_64c() { (( MDS1_VERSION >= $(version_code 2.16.50) )) && srv_uc="server_upcall" - stack_trap cleanup_64 EXIT + stack_trap cleanup_local_client_nodemap EXIT mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed" - setup_64 + setup_local_client_nodemap "c0" 1 1 rbac="quota_ops" [ -z "$srv_uc" ] || rbac="$rbac,$srv_uc" @@ -6446,9 +6364,9 @@ test_64d() { (( MDS1_VERSION >= $(version_code 2.16.50) )) && srv_uc="server_upcall" - stack_trap cleanup_64 EXIT + stack_trap cleanup_local_client_nodemap EXIT mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed" - setup_64 + setup_local_client_nodemap "c0" 1 1 rbac="byfid_ops" [ -z "$srv_uc" ] || rbac="$rbac,$srv_uc" @@ -6499,9 +6417,9 @@ test_64e() { (( MDS1_VERSION >= $(version_code 2.16.50) )) && srv_uc="server_upcall" - stack_trap cleanup_64 EXIT + stack_trap cleanup_local_client_nodemap EXIT mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed" - setup_64 + setup_local_client_nodemap "c0" 1 1 # activate changelogs changelog_register || error "changelog_register failed" @@ -6576,9 +6494,9 @@ test_64f() { [ -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 + stack_trap cleanup_local_client_nodemap EXIT mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed" - setup_64 + setup_local_client_nodemap "c0" 1 1 yes | fscrypt setup --force --verbose || echo "fscrypt global setup already done" @@ -6676,8 +6594,8 @@ test_64g() { setfacl -m g:grptest64g2:rwx $DIR/$tdir ls -lR $DIR/$tdir - setup_64 - stack_trap cleanup_64 EXIT + setup_local_client_nodemap "c0" 1 1 + stack_trap cleanup_local_client_nodemap EXIT # remove server_upcall from rbac roles, # to make this client use INTERNAL upcall @@ -7350,6 +7268,70 @@ test_73() { } run_test 73 "encrypted names in changelogs" +test_74() { + local testfile="${DIR}/${tdir}/$tfile" + local deny_mount + + # check that deny_mount flag exists + deny_mount=$(do_facet mgs \ + $LCTL get_param -n nodemap.default.deny_mount) + [[ -n "$deny_mount" ]] || + skip "Server does not have the deny_mount nodemap flag" + + stack_trap cleanup_local_client_nodemap EXIT + + umount_client $MOUNT || error "umount $MOUNT failed (1)" + + # setup privileged nodemap for c0 + setup_local_client_nodemap "c0" 1 1 + + # check default deny_mount flags + (( $deny_mount == 0 )) || + error "wrong default for deny_mount flag on default nodemap" + deny_mount=$(do_facet mgs \ + $LCTL get_param -n nodemap.c0.deny_mount) + (( $deny_mount == 0 )) || + error "wrong default value for deny_mount on nodemap c0" + + # mount client with active nodemap + zconf_mount_clients $HOSTNAME $MOUNT ${MOUNT_OPTS} || + error "re-mount failed (1)" + wait_ssk + + # simple access test + $LFS mkdir -c 1 "${DIR}/$tdir" || error "mkdir ${DIR}/$tdir failed" + $LFS setstripe -c 1 $testfile || error "setstripe $testfile failed" + echo -n "a" > $testfile || error "(1) write $testfile failed" + + # set deny_mount flag. Access should still work for existing clients + do_facet mgs $LCTL nodemap_modify --name c0 \ + --property deny_mount --value 1 + wait_nm_sync c0 deny_mount + echo -n "b" >> $testfile || error "(2) write $testfile failed" + cat $testfile > /dev/null || error "read $testfile failed" + # unmount client + umount_client $MOUNT || error "umount $MOUNT failed (2)" + + # mount client should fail (nodemap is deny_mount) + zconf_mount_clients $HOSTNAME $MOUNT ${MOUNT_OPTS} && + error "mount should have failed. deny_mount flag is not honored" + + # set active flag for c0. Access should work again + do_facet mgs $LCTL nodemap_modify --name c0 \ + --property deny_mount --value 0 + wait_nm_sync c0 deny_mount + + zconf_mount_clients $HOSTNAME $MOUNT ${MOUNT_OPTS} || + error "re-mount failed (2)" + wait_ssk + + # check access + echo -n "c" >> $testfile || error "(3) write $testfile failed" + [[ $(cat $testfile) == "abc" ]] || + error "read access test for $testfile failed" +} +run_test 74 "Set nodemap deny_mount flag" + log "cleanup: ======================================================" sec_unsetup() { diff --git a/lustre/utils/obd.c b/lustre/utils/obd.c index ccfb210..3db76d6 100644 --- a/lustre/utils/obd.c +++ b/lustre/utils/obd.c @@ -4620,7 +4620,7 @@ modify_usage: "usage: %s --name NODEMAP_NAME --property PROPERTY_NAME --value VALUE\n", argv[0]); fprintf(stderr, - "valid properties: admin trusted map_mode squash_uid squash_gid squash_projid deny_unknown audit_mode forbid_encryption readonly_mount rbac\n"); + "valid properties: admin trusted map_mode squash_uid squash_gid squash_projid deny_unknown audit_mode forbid_encryption readonly_mount rbac deny_mount\n"); return -EINVAL; } if (!param) { @@ -4654,6 +4654,8 @@ modify_usage: cmd = LCFG_NODEMAP_READONLY_MOUNT; } else if (strcmp("rbac", param) == 0) { cmd = LCFG_NODEMAP_RBAC; + } else if (strcmp("deny_mount", param) == 0) { + cmd = LCFG_NODEMAP_DENY_MOUNT; } else { fprintf(stderr, "error: %s: nodemap_modify invalid property: %s\n", diff --git a/lustre/utils/wirecheck.c b/lustre/utils/wirecheck.c index 6e651ca..8690ef4 100644 --- a/lustre/utils/wirecheck.c +++ b/lustre/utils/wirecheck.c @@ -3061,6 +3061,7 @@ static void check_nodemap_key(void) CHECK_VALUE_X(NM_FL_FORBID_ENCRYPT); CHECK_VALUE_X(NM_FL_MAP_PROJID); CHECK_VALUE_X(NM_FL2_READONLY_MOUNT); + CHECK_VALUE_X(NM_FL2_DENY_MOUNT); CHECK_VALUE(NODEMAP_UID); CHECK_VALUE(NODEMAP_GID); @@ -3347,6 +3348,7 @@ check_lustre_cfg(void) CHECK_VALUE_X(LCFG_NODEMAP_SQUASH_PROJID); CHECK_VALUE_X(LCFG_NODEMAP_READONLY_MOUNT); CHECK_VALUE_X(LCFG_NODEMAP_RBAC); + CHECK_VALUE_X(LCFG_NODEMAP_DENY_MOUNT); printf("#endif /* HAVE_SERVER_SUPPORT */\n"); #endif /* !HAVE_NATIVE_LINUX_CLIENT */ CHECK_VALUE(PORTALS_CFG_TYPE); diff --git a/lustre/utils/wiretest.c b/lustre/utils/wiretest.c index 045ab8d..9e4819f 100644 --- a/lustre/utils/wiretest.c +++ b/lustre/utils/wiretest.c @@ -6530,6 +6530,8 @@ void lustre_assert_wire_constants(void) (unsigned)NM_FL_MAP_PROJID); LASSERTF(NM_FL2_READONLY_MOUNT == 0x00000001UL, "found 0x%.8xUL\n", (unsigned)NM_FL2_READONLY_MOUNT); + LASSERTF(NM_FL2_DENY_MOUNT == 0x00000002UL, "found 0x%.8xUL\n", + (unsigned int)NM_FL2_DENY_MOUNT); LASSERTF(NODEMAP_UID == 0, "found %lld\n", (long long)NODEMAP_UID); LASSERTF(NODEMAP_GID == 1, "found %lld\n", @@ -7146,6 +7148,8 @@ void lustre_assert_wire_constants(void) (unsigned)LCFG_NODEMAP_READONLY_MOUNT); LASSERTF(LCFG_NODEMAP_RBAC == 0x000ce05fUL, "found 0x%.8xUL\n", (unsigned)LCFG_NODEMAP_RBAC); + LASSERTF(LCFG_NODEMAP_DENY_MOUNT == 0x000ce060UL, "found 0x%.8xUL\n", + (unsigned int)LCFG_NODEMAP_DENY_MOUNT); #endif /* HAVE_SERVER_SUPPORT */ LASSERTF(PORTALS_CFG_TYPE == 1, "found %lld\n", (long long)PORTALS_CFG_TYPE); -- 1.8.3.1