From e7ce67de92dea68707c96ef44918ebdaacd6533b Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Fri, 14 Jan 2022 10:16:31 +0100 Subject: [PATCH] LU-15451 sec: read-only nodemap flag Add a new 'readonly_mount' property to nodemaps. When set, we return -EROFS from server side if the client is not mounting read-only. So the client will have to specify the read-only mount option to be allowed to mount. Fixes: 928714dddabb ("LU-5092 nodemap: save id maps to targets in new index file") Signed-off-by: Sebastien Buisson Change-Id: I9931844ae46dfd5d724f592f8dfacc4a8011c7e3 Reviewed-on: https://review.whamcloud.com/46149 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: James Simmons Reviewed-by: Oleg Drokin --- lustre/doc/lctl-nodemap-modify.8 | 6 +++ lustre/include/lustre_nodemap.h | 4 +- lustre/include/uapi/linux/lustre/lustre_cfg.h | 1 + lustre/include/uapi/linux/lustre/lustre_idl.h | 28 ++++++++--- lustre/mgs/mgs_handler.c | 1 + lustre/mgs/mgs_llog.c | 6 +++ lustre/ptlrpc/import.c | 3 +- lustre/ptlrpc/niobuf.c | 3 +- lustre/ptlrpc/nodemap_handler.c | 30 ++++++++++++ lustre/ptlrpc/nodemap_lproc.c | 36 ++++++++++++++ lustre/ptlrpc/nodemap_storage.c | 27 +++++------ lustre/ptlrpc/wiretest.c | 12 ++--- lustre/target/tgt_handler.c | 35 ++++++++++---- lustre/tests/sanity-sec.sh | 67 ++++++++++++++++++++++++++- lustre/utils/obd.c | 4 +- lustre/utils/wirecheck.c | 2 + lustre/utils/wiretest.c | 12 ++--- 17 files changed, 228 insertions(+), 49 deletions(-) diff --git a/lustre/doc/lctl-nodemap-modify.8 b/lustre/doc/lctl-nodemap-modify.8 index ab599c3..c46f7f4 100644 --- a/lustre/doc/lctl-nodemap-modify.8 +++ b/lustre/doc/lctl-nodemap-modify.8 @@ -74,6 +74,12 @@ Defaults to all, which means the nodemap maps UIDs, GIDs, and PROJIDs. Other possible values (multiple can be specified, comma separated) are uid to map UIDs, gid to map GIDs, both to map UIDs and GIDs, and projid to map PROJIDs. .RE +.PP +readonly_mount +.RS 4 +Defaults to off, which lets clients mount in read-write mode. If set to 1, +clients are only allowed to mount in read-only mount, and get -EROFS otherwise. +.RE .RE .I value diff --git a/lustre/include/lustre_nodemap.h b/lustre/include/lustre_nodemap.h index 80f123a..d0df6af 100644 --- a/lustre/include/lustre_nodemap.h +++ b/lustre/include/lustre_nodemap.h @@ -82,7 +82,8 @@ struct lu_nodemap { nmf_deny_unknown:1, nmf_allow_root_access:1, nmf_enable_audit:1, - nmf_forbid_encryption:1; + nmf_forbid_encryption:1, + nmf_readonly_mount:1; /* bitmap for mapping type */ enum nodemap_mapping_modes nmf_map_mode; @@ -156,6 +157,7 @@ int nodemap_set_squash_gid(const char *name, gid_t gid); 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); bool nodemap_can_setquota(struct lu_nodemap *nodemap, __u32 qc_type, __u32 id); int nodemap_add_idmap(const char *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 97bd28f..ab0dc0b 100644 --- a/lustre/include/uapi/linux/lustre/lustre_cfg.h +++ b/lustre/include/uapi/linux/lustre/lustre_cfg.h @@ -140,6 +140,7 @@ enum lcfg_command_type { LCFG_NODEMAP_SET_SEPOL = 0x00ce05b, /**< set SELinux policy */ LCFG_NODEMAP_FORBID_ENCRYPT = 0x00ce05c, /**< forbid encryption */ LCFG_NODEMAP_SQUASH_PROJID = 0x00ce05d, /**< default map projid */ + LCFG_NODEMAP_READONLY_MOUNT = 0x00ce05e, /**< read-only mount */ }; struct lustre_cfg_bufs { diff --git a/lustre/include/uapi/linux/lustre/lustre_idl.h b/lustre/include/uapi/linux/lustre/lustre_idl.h index af885fa..b70685f 100644 --- a/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -3588,15 +3588,31 @@ struct llog_update_record { SELINUX_POLICY_VER_LEN + \ SELINUX_POLICY_HASH_LEN + 3) +/* lu_nodemap flags */ +enum nm_flag_bits { + NM_FL_ALLOW_ROOT_ACCESS = 0x1, + NM_FL_TRUST_CLIENT_IDS = 0x2, + NM_FL_DENY_UNKNOWN = 0x4, + NM_FL_MAP_UID = 0x8, + NM_FL_MAP_GID = 0x10, + NM_FL_ENABLE_AUDIT = 0x20, + NM_FL_FORBID_ENCRYPT = 0x40, + NM_FL_MAP_PROJID = 0x80, +}; +enum nm_flag2_bits { + NM_FL2_READONLY_MOUNT = 0x1, +}; + /* nodemap records, uses 32 byte record length */ #define LUSTRE_NODEMAP_NAME_LENGTH 16 struct nodemap_cluster_rec { - char ncr_name[LUSTRE_NODEMAP_NAME_LENGTH + 1]; - __u8 ncr_flags; - __u16 ncr_padding1; - __u32 ncr_squash_projid; - __u32 ncr_squash_uid; - __u32 ncr_squash_gid; + char ncr_name[LUSTRE_NODEMAP_NAME_LENGTH + 1]; + enum nm_flag_bits ncr_flags:8; + enum nm_flag2_bits ncr_flags2:8; + __u8 ncr_padding1; + __u32 ncr_squash_projid; + __u32 ncr_squash_uid; + __u32 ncr_squash_gid; }; /* lnet_nid_t is 8 bytes */ diff --git a/lustre/mgs/mgs_handler.c b/lustre/mgs/mgs_handler.c index 688b538..33b0e27 100644 --- a/lustre/mgs/mgs_handler.c +++ b/lustre/mgs/mgs_handler.c @@ -862,6 +862,7 @@ static int mgs_iocontrol_nodemap(const struct lu_env *env, case LCFG_NODEMAP_MAP_MODE: case LCFG_NODEMAP_AUDIT_MODE: case LCFG_NODEMAP_FORBID_ENCRYPT: + case LCFG_NODEMAP_READONLY_MOUNT: if (lcfg->lcfg_bufcount != 4) GOTO(out_lcfg, rc = -EINVAL); nodemap_name = lustre_cfg_string(lcfg, 1); diff --git a/lustre/mgs/mgs_llog.c b/lustre/mgs/mgs_llog.c index 0762776..de9daf4 100644 --- a/lustre/mgs/mgs_llog.c +++ b/lustre/mgs/mgs_llog.c @@ -5521,6 +5521,12 @@ int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs, rc = nodemap_set_forbid_encryption(nodemap_name, bool_switch); break; + case LCFG_NODEMAP_READONLY_MOUNT: + rc = kstrtobool(param, &bool_switch); + if (rc == 0) + rc = nodemap_set_readonly_mount(nodemap_name, + bool_switch); + break; case LCFG_NODEMAP_MAP_MODE: { char *p; diff --git a/lustre/ptlrpc/import.c b/lustre/ptlrpc/import.c index b513815..2afcf6a 100644 --- a/lustre/ptlrpc/import.c +++ b/lustre/ptlrpc/import.c @@ -1338,10 +1338,11 @@ out: time64_t next_connect; import_set_state_nolock(imp, LUSTRE_IMP_DISCON); - if (rc == -EACCES) { + if (rc == -EACCES || rc == -EROFS) { /* * Give up trying to reconnect * EACCES means client has no permission for connection + * EROFS means client must mount read-only */ imp->imp_obd->obd_no_recov = 1; ptlrpc_deactivate_import_nolock(imp); diff --git a/lustre/ptlrpc/niobuf.c b/lustre/ptlrpc/niobuf.c index d73bc73..546c523 100644 --- a/lustre/ptlrpc/niobuf.c +++ b/lustre/ptlrpc/niobuf.c @@ -687,7 +687,8 @@ int ptlrpc_send_error(struct ptlrpc_request *req, int may_be_difficult) if (req->rq_status != -ENOSPC && req->rq_status != -EACCES && req->rq_status != -EPERM && req->rq_status != -ENOENT && - req->rq_status != -EINPROGRESS && req->rq_status != -EDQUOT) + req->rq_status != -EINPROGRESS && req->rq_status != -EDQUOT && + req->rq_status != -EROFS) req->rq_type = PTL_RPC_MSG_ERR; rc = ptlrpc_send_reply(req, may_be_difficult); diff --git a/lustre/ptlrpc/nodemap_handler.c b/lustre/ptlrpc/nodemap_handler.c index d793fe5..ec1008a 100644 --- a/lustre/ptlrpc/nodemap_handler.c +++ b/lustre/ptlrpc/nodemap_handler.c @@ -1184,6 +1184,7 @@ struct lu_nodemap *nodemap_create(const char *name, nodemap->nmf_map_mode = NODEMAP_MAP_ALL; nodemap->nmf_enable_audit = 1; nodemap->nmf_forbid_encryption = 0; + nodemap->nmf_readonly_mount = 0; nodemap->nm_squash_uid = NODEMAP_NOBODY_UID; nodemap->nm_squash_gid = NODEMAP_NOBODY_GID; @@ -1203,6 +1204,8 @@ struct lu_nodemap *nodemap_create(const char *name, nodemap->nmf_enable_audit = default_nodemap->nmf_enable_audit; nodemap->nmf_forbid_encryption = default_nodemap->nmf_forbid_encryption; + nodemap->nmf_readonly_mount = + default_nodemap->nmf_readonly_mount; nodemap->nm_squash_uid = default_nodemap->nm_squash_uid; nodemap->nm_squash_gid = default_nodemap->nm_squash_gid; @@ -1514,6 +1517,33 @@ out: } EXPORT_SYMBOL(nodemap_set_forbid_encryption); +/** + * Set the nmf_readonly_mount flag to true or false. + * \param name nodemap name + * \param readonly_mount if true, forbid rw mount + * \retval 0 on success + * + */ +int nodemap_set_readonly_mount(const char *name, bool readonly_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)) + GOTO(out, rc = PTR_ERR(nodemap)); + + nodemap->nmf_readonly_mount = readonly_mount; + rc = nodemap_idx_nodemap_update(nodemap); + + nm_member_revoke_locks(nodemap); + nodemap_putref(nodemap); +out: + return rc; +} +EXPORT_SYMBOL(nodemap_set_readonly_mount); /** * Add a nodemap diff --git a/lustre/ptlrpc/nodemap_lproc.c b/lustre/ptlrpc/nodemap_lproc.c index 841a88a..ec55dee 100644 --- a/lustre/ptlrpc/nodemap_lproc.c +++ b/lustre/ptlrpc/nodemap_lproc.c @@ -710,6 +710,33 @@ static int nodemap_forbid_encryption_seq_show(struct seq_file *m, void *data) return 0; } +/** + * Reads and prints the readonly_mount flag for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_readonly_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_readonly_mount); + nodemap_putref(nodemap); + return 0; +} + static struct lprocfs_vars lprocfs_nm_module_vars[] = { { .name = "active", @@ -730,6 +757,7 @@ LPROC_SEQ_FOPS_RO(nodemap_deny_unknown); LPROC_SEQ_FOPS_RO(nodemap_map_mode); LPROC_SEQ_FOPS_RO(nodemap_audit_mode); LPROC_SEQ_FOPS_RO(nodemap_forbid_encryption); +LPROC_SEQ_FOPS_RO(nodemap_readonly_mount); static const struct proc_ops nodemap_ranges_fops = { .proc_open = nodemap_ranges_open, @@ -782,6 +810,10 @@ static struct lprocfs_vars lprocfs_nodemap_vars[] = { .fops = &nodemap_forbid_encryption_fops, }, { + .name = "readonly_mount", + .fops = &nodemap_readonly_mount_fops, + }, + { .name = "squash_uid", .fops = &nodemap_squash_uid_fops, }, @@ -864,6 +896,10 @@ static struct lprocfs_vars lprocfs_default_nodemap_vars[] = { .fops = &nodemap_forbid_encryption_fops, }, { + .name = "readonly_mount", + .fops = &nodemap_readonly_mount_fops, + }, + { NULL } }; diff --git a/lustre/ptlrpc/nodemap_storage.c b/lustre/ptlrpc/nodemap_storage.c index 59ec6c7..fcdc7cd 100644 --- a/lustre/ptlrpc/nodemap_storage.c +++ b/lustre/ptlrpc/nodemap_storage.c @@ -67,18 +67,6 @@ static DEFINE_MUTEX(ncf_list_lock); /* MGS index is different than others, others are listeners to MGS idx */ static struct nm_config_file *nodemap_mgs_ncf; -/* lu_nodemap flags */ -enum nm_flag_shifts { - NM_FL_ALLOW_ROOT_ACCESS = 0x1, - NM_FL_TRUST_CLIENT_IDS = 0x2, - NM_FL_DENY_UNKNOWN = 0x4, - NM_FL_MAP_UID = 0x8, - NM_FL_MAP_GID = 0x10, - NM_FL_ENABLE_AUDIT = 0x20, - NM_FL_FORBID_ENCRYPT = 0x40, - NM_FL_MAP_PROJID = 0x80, -}; - static void nodemap_cluster_key_init(struct nodemap_key *nk, unsigned int nm_id) { nk->nk_nodemap_id = cpu_to_le32(nm_idx_set_type(nm_id, @@ -95,7 +83,7 @@ static void nodemap_cluster_rec_init(union nodemap_rec *nr, nr->ncr.ncr_squash_uid = cpu_to_le32(nodemap->nm_squash_uid); nr->ncr.ncr_squash_gid = cpu_to_le32(nodemap->nm_squash_gid); nr->ncr.ncr_squash_projid = cpu_to_le32(nodemap->nm_squash_projid); - nr->ncr.ncr_flags = cpu_to_le32( + nr->ncr.ncr_flags = (nodemap->nmf_trust_client_ids ? NM_FL_TRUST_CLIENT_IDS : 0) | (nodemap->nmf_allow_root_access ? @@ -111,7 +99,10 @@ static void nodemap_cluster_rec_init(union nodemap_rec *nr, (nodemap->nmf_enable_audit ? NM_FL_ENABLE_AUDIT : 0) | (nodemap->nmf_forbid_encryption ? - NM_FL_FORBID_ENCRYPT : 0)); + NM_FL_FORBID_ENCRYPT : 0); + nr->ncr.ncr_flags2 = + (nodemap->nmf_readonly_mount ? + NM_FL2_READONLY_MOUNT : 0); } static void nodemap_idmap_key_init(struct nodemap_key *nk, unsigned int nm_id, @@ -685,7 +676,8 @@ static int nodemap_process_keyrec(struct nodemap_config *config, struct lu_nodemap *nodemap = NULL; enum nodemap_idx_type type; enum nodemap_id_type id_type; - u8 flags; + enum nm_flag_bits flags; + enum nm_flag2_bits flags2; u32 nodemap_id; lnet_nid_t nid[2]; u32 map[2]; @@ -768,7 +760,7 @@ static int nodemap_process_keyrec(struct nodemap_config *config, nodemap->nm_squash_projid = le32_to_cpu(rec->ncr.ncr_squash_projid); - flags = le32_to_cpu(rec->ncr.ncr_flags); + flags = rec->ncr.ncr_flags; nodemap->nmf_allow_root_access = flags & NM_FL_ALLOW_ROOT_ACCESS; nodemap->nmf_trust_client_ids = @@ -787,6 +779,9 @@ static int nodemap_process_keyrec(struct nodemap_config *config, flags & NM_FL_ENABLE_AUDIT; nodemap->nmf_forbid_encryption = flags & NM_FL_FORBID_ENCRYPT; + flags2 = rec->ncr.ncr_flags2; + nodemap->nmf_readonly_mount = + flags2 & NM_FL2_READONLY_MOUNT; /* The fileset should be saved otherwise it will be empty * every time in case of "NODEMAP_CLUSTER_IDX". */ diff --git a/lustre/ptlrpc/wiretest.c b/lustre/ptlrpc/wiretest.c index 70d9475..17649be 100644 --- a/lustre/ptlrpc/wiretest.c +++ b/lustre/ptlrpc/wiretest.c @@ -5564,13 +5564,11 @@ void lustre_assert_wire_constants(void) (long long)(int)offsetof(struct nodemap_cluster_rec, ncr_name[16 + 1])); LASSERTF((int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_name[16 + 1]) == 1, "found %lld\n", (long long)(int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_name[16 + 1])); - LASSERTF((int)offsetof(struct nodemap_cluster_rec, ncr_flags) == 17, "found %lld\n", - (long long)(int)offsetof(struct nodemap_cluster_rec, ncr_flags)); - LASSERTF((int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_flags) == 1, "found %lld\n", - (long long)(int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_flags)); - LASSERTF((int)offsetof(struct nodemap_cluster_rec, ncr_padding1) == 18, "found %lld\n", + /* ncr_flags' address and size cannot be taken because it is a bit-field (8 bits) */ + /* ncr_flags2' address and size cannot be taken because it is a bit-field (8 bits) */ + LASSERTF((int)offsetof(struct nodemap_cluster_rec, ncr_padding1) == 19, "found %lld\n", (long long)(int)offsetof(struct nodemap_cluster_rec, ncr_padding1)); - LASSERTF((int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_padding1) == 2, "found %lld\n", + LASSERTF((int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_padding1) == 1, "found %lld\n", (long long)(int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_padding1)); LASSERTF((int)offsetof(struct nodemap_cluster_rec, ncr_squash_projid) == 20, "found %lld\n", (long long)(int)offsetof(struct nodemap_cluster_rec, ncr_squash_projid)); @@ -6094,6 +6092,8 @@ void lustre_assert_wire_constants(void) (unsigned)LCFG_NODEMAP_FORBID_ENCRYPT); LASSERTF(LCFG_NODEMAP_SQUASH_PROJID == 0x000ce05dUL, "found 0x%.8xUL\n", (unsigned)LCFG_NODEMAP_SQUASH_PROJID); + LASSERTF(LCFG_NODEMAP_READONLY_MOUNT == 0x000ce05eUL, "found 0x%.8xUL\n", + (unsigned)LCFG_NODEMAP_READONLY_MOUNT); #endif /* HAVE_SERVER_SUPPORT */ LASSERTF(PORTALS_CFG_TYPE == 1, "found %lld\n", (long long)PORTALS_CFG_TYPE); diff --git a/lustre/target/tgt_handler.c b/lustre/target/tgt_handler.c index c763e0a..998b1ee 100644 --- a/lustre/target/tgt_handler.c +++ b/lustre/target/tgt_handler.c @@ -1034,30 +1034,45 @@ int tgt_connect(struct tgt_session_info *tsi) if (strcmp(tsi->tsi_exp->exp_obd->obd_type->typ_name, LUSTRE_MDT_NAME) == 0) { + struct lu_nodemap *nm = NULL; + rc = req_check_sepol(tsi->tsi_pill); if (rc) GOTO(out, rc); + if (tsi->tsi_pill->rc_req->rq_export) + nm = + nodemap_get_from_exp(tsi->tsi_pill->rc_req->rq_export); + if (reply->ocd_connect_flags & OBD_CONNECT_FLAGS2 && - reply->ocd_connect_flags2 & OBD_CONNECT2_ENCRYPT && - tsi->tsi_pill->rc_req->rq_export) { + reply->ocd_connect_flags2 & OBD_CONNECT2_ENCRYPT) { bool forbid_encrypt = true; - struct lu_nodemap *nm = - nodemap_get_from_exp(tsi->tsi_pill->rc_req->rq_export); - if (!nm) { + if (!nm) /* nodemap_get_from_exp returns NULL in case * nodemap is not active, so we do not forbid */ forbid_encrypt = false; - } else if (!IS_ERR(nm)) { + else if (!IS_ERR(nm)) forbid_encrypt = nm->nmf_forbid_encryption; - nodemap_putref(nm); - } - if (forbid_encrypt) - GOTO(out, rc = -EACCES); + GOTO(put_nm, rc = -EACCES); } + + if (!(reply->ocd_connect_flags & OBD_CONNECT_RDONLY)) { + bool readonly = false; + + if (!IS_ERR_OR_NULL(nm)) + readonly = nm->nmf_readonly_mount; + if (unlikely(readonly)) + GOTO(put_nm, rc = -EROFS); + } + +put_nm: + if (!IS_ERR_OR_NULL(nm)) + nodemap_putref(nm); + if (rc) + GOTO(out, rc); } RETURN(0); diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index f3880e6..217ba39 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -2779,11 +2779,27 @@ cleanup_for_enc_tests() { } cleanup_nodemap_after_enc_tests() { + umount_client $MOUNT || true + do_facet mgs $LCTL nodemap_modify --name default \ --property forbid_encryption --value 0 - wait_nm_sync default forbid_encryption + do_facet mgs $LCTL nodemap_modify --name default \ + --property readonly_mount --value 0 || true + do_facet mgs $LCTL nodemap_modify --name default \ + --property trusted --value 0 + do_facet mgs $LCTL nodemap_modify --name default \ + --property admin --value 0 do_facet mgs $LCTL nodemap_activate 0 + + wait_nm_sync default forbid_encryption '' inactive + [ -z "$(do_facet mgs \ + lctl get_param -n nodemap.default.readonly_mount)" ] || + wait_nm_sync default readonly_mount '' inactive + wait_nm_sync default trusted_nodemap '' inactive + wait_nm_sync default admin_nodemap '' inactive wait_nm_sync active + + mount_client $MOUNT ${MOUNT_OPTS} || error "re-mount failed" } test_36() { @@ -4973,6 +4989,55 @@ test_60() { } run_test 60 "Subdirmount of encrypted dir" +test_61() { + local testfile=$DIR/$tdir/$tfile + local readonly + + readonly=$(do_facet mgs \ + lctl get_param -n nodemap.default.readonly_mount) + [ -n "$readonly" ] || + skip "Server does not have readonly_mount nodemap flag" + + stack_trap cleanup_nodemap_after_enc_tests EXIT + umount_client $MOUNT || error "umount $MOUNT failed (1)" + + # Activate nodemap, and mount rw. + # Should succeed as rw mount is not forbidden on default nodemap + # by default. + do_facet mgs $LCTL nodemap_activate 1 + wait_nm_sync active + 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 + readonly=$(do_facet mgs \ + lctl get_param -n nodemap.default.readonly_mount) + [ $readonly -eq 0 ] || error "wrong default value for readonly_mount" + + mount_client $MOUNT ${MOUNT_OPTS},rw || + error "mount '-o rw' failed with default" + findmnt $MOUNT --output=options -n -f | grep -q "rw," || + error "should be rw mount" + mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed" + echo a > $testfile || error "write $testfile failed" + umount_client $MOUNT || error "umount $MOUNT failed (2)" + + # Now enforce read-only, and retry. + do_facet mgs $LCTL nodemap_modify --name default \ + --property readonly_mount --value 1 + wait_nm_sync default readonly_mount + mount_client $MOUNT ${MOUNT_OPTS},rw && + error "mount '-o rw' should have failed" + mount_client $MOUNT ${MOUNT_OPTS},ro || + error "mount '-o ro' failed" + cat $testfile || error "read $testfile failed" + echo b > $testfile && error "write $testfile should fail" + umount_client $MOUNT || error "umount $MOUNT failed (3)" +} +run_test 61 "Nodemap enforces read-only mount" + log "cleanup: ======================================================" sec_unsetup() { diff --git a/lustre/utils/obd.c b/lustre/utils/obd.c index 328c7df..2e5130e 100644 --- a/lustre/utils/obd.c +++ b/lustre/utils/obd.c @@ -4769,7 +4769,7 @@ int jt_nodemap_modify(int argc, char **argv) fprintf(stderr, "usage: nodemap_modify --name --property --value \n"); fprintf(stderr, - "valid properties: admin trusted map_mode squash_uid squash_gid squash_projid deny_unknown audit_mode forbid_encryption\n"); + "valid properties: admin trusted map_mode squash_uid squash_gid squash_projid deny_unknown audit_mode forbid_encryption readonly_mount\n"); return -1; } @@ -4791,6 +4791,8 @@ int jt_nodemap_modify(int argc, char **argv) cmd = LCFG_NODEMAP_AUDIT_MODE; } else if (strcmp("forbid_encryption", param) == 0) { cmd = LCFG_NODEMAP_FORBID_ENCRYPT; + } else if (strcmp("readonly_mount", param) == 0) { + cmd = LCFG_NODEMAP_READONLY_MOUNT; } else { fprintf(stderr, "error: %s: nodemap_modify invalid subcommand: %s\n", diff --git a/lustre/utils/wirecheck.c b/lustre/utils/wirecheck.c index 5b2f64e..2fc48e2 100644 --- a/lustre/utils/wirecheck.c +++ b/lustre/utils/wirecheck.c @@ -2631,6 +2631,7 @@ static void check_nodemap_cluster_rec(void) CHECK_CDEFINE(LUSTRE_NODEMAP_NAME_LENGTH); CHECK_MEMBER(nodemap_cluster_rec, ncr_name[LUSTRE_NODEMAP_NAME_LENGTH + 1]); CHECK_MEMBER(nodemap_cluster_rec, ncr_flags); + CHECK_MEMBER(nodemap_cluster_rec, ncr_flags2); CHECK_MEMBER(nodemap_cluster_rec, ncr_padding1); CHECK_MEMBER(nodemap_cluster_rec, ncr_squash_projid); CHECK_MEMBER(nodemap_cluster_rec, ncr_squash_uid); @@ -2880,6 +2881,7 @@ check_lustre_cfg(void) CHECK_VALUE_X(LCFG_NODEMAP_SET_SEPOL); CHECK_VALUE_X(LCFG_NODEMAP_FORBID_ENCRYPT); CHECK_VALUE_X(LCFG_NODEMAP_SQUASH_PROJID); + CHECK_VALUE_X(LCFG_NODEMAP_READONLY_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 02e946f..133dd06 100644 --- a/lustre/utils/wiretest.c +++ b/lustre/utils/wiretest.c @@ -5591,13 +5591,11 @@ void lustre_assert_wire_constants(void) (long long)(int)offsetof(struct nodemap_cluster_rec, ncr_name[16 + 1])); LASSERTF((int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_name[16 + 1]) == 1, "found %lld\n", (long long)(int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_name[16 + 1])); - LASSERTF((int)offsetof(struct nodemap_cluster_rec, ncr_flags) == 17, "found %lld\n", - (long long)(int)offsetof(struct nodemap_cluster_rec, ncr_flags)); - LASSERTF((int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_flags) == 1, "found %lld\n", - (long long)(int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_flags)); - LASSERTF((int)offsetof(struct nodemap_cluster_rec, ncr_padding1) == 18, "found %lld\n", + /* ncr_flags' address and size cannot be taken because it is a bit-field (8 bits) */ + /* ncr_flags2' address and size cannot be taken because it is a bit-field (8 bits) */ + LASSERTF((int)offsetof(struct nodemap_cluster_rec, ncr_padding1) == 19, "found %lld\n", (long long)(int)offsetof(struct nodemap_cluster_rec, ncr_padding1)); - LASSERTF((int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_padding1) == 2, "found %lld\n", + LASSERTF((int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_padding1) == 1, "found %lld\n", (long long)(int)sizeof(((struct nodemap_cluster_rec *)0)->ncr_padding1)); LASSERTF((int)offsetof(struct nodemap_cluster_rec, ncr_squash_projid) == 20, "found %lld\n", (long long)(int)offsetof(struct nodemap_cluster_rec, ncr_squash_projid)); @@ -6121,6 +6119,8 @@ void lustre_assert_wire_constants(void) (unsigned)LCFG_NODEMAP_FORBID_ENCRYPT); LASSERTF(LCFG_NODEMAP_SQUASH_PROJID == 0x000ce05dUL, "found 0x%.8xUL\n", (unsigned)LCFG_NODEMAP_SQUASH_PROJID); + LASSERTF(LCFG_NODEMAP_READONLY_MOUNT == 0x000ce05eUL, "found 0x%.8xUL\n", + (unsigned)LCFG_NODEMAP_READONLY_MOUNT); #endif /* HAVE_SERVER_SUPPORT */ LASSERTF(PORTALS_CFG_TYPE == 1, "found %lld\n", (long long)PORTALS_CFG_TYPE); -- 1.8.3.1