From: Sebastien Buisson Date: Mon, 9 Dec 2019 14:37:50 +0000 (+0900) Subject: LU-13064 sec: check permissions for changelogs access X-Git-Tag: 2.13.54~140 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=4e8fcee92d75102314f6c39c72b9c2cbce109bd4;p=fs%2Flustre-release.git LU-13064 sec: check permissions for changelogs access root permissions should be checked when reading or clearing changelogs from clients. In particular, if root is squashed via a nodemap entry, it should not be allowed to access changelogs. To achieve this send mdt body along with RQF_LLOG_ORIGIN_HANDLE_CREATE and RQF_MDT_SET_INFO requests. And on server side, retrieve user credentials and make sure they have root permission. Test-Parameters: clientversion=2.12 envdefinitions=SANITY_EXCEPT="27M 56ra 151 156 802" Test-Parameters: serverversion=2.12 Signed-off-by: Sebastien Buisson Change-Id: I0c6cc99f8a7c5a13c2b31009d73f38976931ec37 Reviewed-on: https://review.whamcloud.com/36990 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Emoly Liu Reviewed-by: Oleg Drokin --- diff --git a/lustre/include/lustre_req_layout.h b/lustre/include/lustre_req_layout.h index 8b2c924..707c27d 100644 --- a/lustre/include/lustre_req_layout.h +++ b/lustre/include/lustre_req_layout.h @@ -132,6 +132,7 @@ int req_check_sepol(struct req_capsule *pill); extern struct req_format RQF_OBD_PING; extern struct req_format RQF_OBD_SET_INFO; +extern struct req_format RQF_MDT_SET_INFO; extern struct req_format RQF_SEC_CTX; extern struct req_format RQF_OBD_IDX_READ; /* MGS req_format */ diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index e5ed97a..8b2eb1e 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -2273,6 +2273,8 @@ static int mdt_set_info(struct tgt_session_info *tsi) __swab32s(&cs->cs_id); } + if (!mdt_is_rootadmin(tsi2mdt_info(tsi))) + RETURN(-EACCES); rc = mdt_iocontrol(OBD_IOC_CHANGELOG_CLEAR, req->rq_export, vallen, val, NULL); } else if (KEY_IS(KEY_EVICT_BY_NID)) { @@ -5147,6 +5149,16 @@ static int mdt_tgt_getxattr(struct tgt_session_info *tsi) return rc; } +static int mdt_llog_open(struct tgt_session_info *tsi) +{ + ENTRY; + + if (!mdt_is_rootadmin(tsi2mdt_info(tsi))) + RETURN(err_serious(-EACCES)); + + RETURN(tgt_llog_open(tsi)); +} + #define OBD_FAIL_OST_READ_NET OBD_FAIL_OST_BRW_NET #define OBD_FAIL_OST_WRITE_NET OBD_FAIL_OST_BRW_NET #define OST_BRW_READ OST_READ @@ -5161,7 +5173,7 @@ TGT_RPC_HANDLER(MDS_FIRST_OPC, &RQF_MDS_DISCONNECT, LUSTRE_OBD_VERSION), TGT_RPC_HANDLER(MDS_FIRST_OPC, HAS_REPLY, MDS_SET_INFO, mdt_set_info, - &RQF_OBD_SET_INFO, LUSTRE_MDS_VERSION), + &RQF_MDT_SET_INFO, LUSTRE_MDS_VERSION), TGT_MDT_HDL(0, MDS_GET_INFO, mdt_get_info), TGT_MDT_HDL(HAS_REPLY, MDS_GET_ROOT, mdt_get_root), TGT_MDT_HDL(HAS_BODY, MDS_GETATTR, mdt_getattr), @@ -5214,6 +5226,13 @@ static struct tgt_handler mdt_quota_ops[] = { TGT_QUOTA_HDL(HAS_REPLY, QUOTA_DQACQ, mdt_quota_dqacq), }; +static struct tgt_handler mdt_llog_handlers[] = { + TGT_LLOG_HDL(0, LLOG_ORIGIN_HANDLE_CREATE, mdt_llog_open), + TGT_LLOG_HDL(0, LLOG_ORIGIN_HANDLE_NEXT_BLOCK, tgt_llog_next_block), + TGT_LLOG_HDL(0, LLOG_ORIGIN_HANDLE_READ_HEADER, tgt_llog_read_header), + TGT_LLOG_HDL(0, LLOG_ORIGIN_HANDLE_PREV_BLOCK, tgt_llog_prev_block), +}; + static struct tgt_opc_slice mdt_common_slice[] = { { .tos_opc_start = MDS_FIRST_OPC, @@ -5258,7 +5277,7 @@ static struct tgt_opc_slice mdt_common_slice[] = { { .tos_opc_start = LLOG_FIRST_OPC, .tos_opc_end = LLOG_LAST_OPC, - .tos_hs = tgt_llog_handlers + .tos_hs = mdt_llog_handlers }, { .tos_opc_start = LFSCK_FIRST_OPC, diff --git a/lustre/mdt/mdt_internal.h b/lustre/mdt/mdt_internal.h index e1d903d..820b6af 100644 --- a/lustre/mdt/mdt_internal.h +++ b/lustre/mdt/mdt_internal.h @@ -1365,4 +1365,32 @@ long mdt_grant_connect(const struct lu_env *env, struct obd_export *exp, u64 want, bool conservative); extern struct kmem_cache *ldlm_glimpse_work_kmem; +static inline bool mdt_is_rootadmin(struct mdt_thread_info *info) +{ + struct lu_ucred *uc = NULL; + bool is_admin; + int rc; + + if (info == NULL || info->mti_body == NULL) +#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 3, 0) + /* return true in case old client did not send mdt body */ + return true; +#else + return false +#endif + + rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body); + if (rc < 0) + return false; + + uc = mdt_ucred(info); + is_admin = (uc->uc_uid == 0 && uc->uc_gid == 0 && + md_capable(uc, CFS_CAP_SYS_ADMIN)); + + mdt_exit_ucred(info); + + return is_admin; +} + + #endif /* _MDT_INTERNAL_H */ diff --git a/lustre/ptlrpc/layout.c b/lustre/ptlrpc/layout.c index 48751d1..cabb8dc 100644 --- a/lustre/ptlrpc/layout.c +++ b/lustre/ptlrpc/layout.c @@ -365,6 +365,13 @@ static const struct req_msg_field *obd_set_info_client[] = { &RMF_SETINFO_VAL }; +static const struct req_msg_field *mdt_set_info_client[] = { + &RMF_PTLRPC_BODY, + &RMF_SETINFO_KEY, + &RMF_SETINFO_VAL, + &RMF_MDT_BODY +}; + static const struct req_msg_field *ost_grant_shrink_client[] = { &RMF_PTLRPC_BODY, &RMF_SETINFO_KEY, @@ -575,9 +582,10 @@ static const struct req_msg_field *mds_update_server[] = { }; static const struct req_msg_field *llog_origin_handle_create_client[] = { - &RMF_PTLRPC_BODY, - &RMF_LLOGD_BODY, - &RMF_NAME + &RMF_PTLRPC_BODY, + &RMF_LLOGD_BODY, + &RMF_NAME, + &RMF_MDT_BODY }; static const struct req_msg_field *llogd_body_only[] = { @@ -747,6 +755,7 @@ static const struct req_msg_field *obd_lfsck_reply[] = { static struct req_format *req_formats[] = { &RQF_OBD_PING, &RQF_OBD_SET_INFO, + &RQF_MDT_SET_INFO, &RQF_OBD_IDX_READ, &RQF_SEC_CTX, &RQF_MGS_TARGET_REG, @@ -1328,6 +1337,10 @@ struct req_format RQF_OBD_SET_INFO = DEFINE_REQ_FMT0("OBD_SET_INFO", obd_set_info_client, empty); EXPORT_SYMBOL(RQF_OBD_SET_INFO); +struct req_format RQF_MDT_SET_INFO = + DEFINE_REQ_FMT0("MDT_SET_INFO", mdt_set_info_client, empty); +EXPORT_SYMBOL(RQF_MDT_SET_INFO); + /* Read index file through the network */ struct req_format RQF_OBD_IDX_READ = DEFINE_REQ_FMT0("OBD_IDX_READ", diff --git a/lustre/ptlrpc/llog_client.c b/lustre/ptlrpc/llog_client.c index 251c5f4..fa9782e 100644 --- a/lustre/ptlrpc/llog_client.c +++ b/lustre/ptlrpc/llog_client.c @@ -45,6 +45,8 @@ #include #include +#include "ptlrpc_internal.h" + #define LLOG_CLIENT_ENTRY(ctxt, imp) do { \ mutex_lock(&ctxt->loc_mutex); \ if (ctxt->loc_imp) { \ @@ -121,6 +123,8 @@ static int llog_client_open(const struct lu_env *env, strlen(name) + 1); LASSERT(tmp); strcpy(tmp, name); + + do_pack_body(req); } rc = ptlrpc_queue_wait(req); diff --git a/lustre/ptlrpc/pack_generic.c b/lustre/ptlrpc/pack_generic.c index 90a13de1..087c491 100644 --- a/lustre/ptlrpc/pack_generic.c +++ b/lustre/ptlrpc/pack_generic.c @@ -1666,7 +1666,10 @@ int do_set_info_async(struct obd_import *imp, int rc; ENTRY; - req = ptlrpc_request_alloc(imp, &RQF_OBD_SET_INFO); + + req = ptlrpc_request_alloc(imp, KEY_IS(KEY_CHANGELOG_CLEAR) ? + &RQF_MDT_SET_INFO : + &RQF_OBD_SET_INFO); if (req == NULL) RETURN(-ENOMEM); @@ -1680,6 +1683,9 @@ int do_set_info_async(struct obd_import *imp, RETURN(rc); } + if (KEY_IS(KEY_CHANGELOG_CLEAR)) + do_pack_body(req); + tmp = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_KEY); memcpy(tmp, key, keylen); tmp = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_VAL); diff --git a/lustre/ptlrpc/ptlrpc_internal.h b/lustre/ptlrpc/ptlrpc_internal.h index c06885e..c3d817a 100644 --- a/lustre/ptlrpc/ptlrpc_internal.h +++ b/lustre/ptlrpc/ptlrpc_internal.h @@ -418,4 +418,23 @@ static inline bool ptlrpc_req_is_disconnect(struct ptlrpc_request *req) return false; } +static inline void do_pack_body(struct ptlrpc_request *req) +{ + struct mdt_body *b = req_capsule_client_get(&req->rq_pill, + &RMF_MDT_BODY); + + if (b == NULL) + return; + + b->mbo_valid = 0; + b->mbo_eadatasize = 0; + b->mbo_flags = 0; + b->mbo_suppgid = -1; + b->mbo_uid = from_kuid(&init_user_ns, current_uid()); + b->mbo_gid = from_kgid(&init_user_ns, current_gid()); + b->mbo_fsuid = from_kuid(&init_user_ns, current_fsuid()); + b->mbo_fsgid = from_kgid(&init_user_ns, current_fsgid()); + b->mbo_capability = cfs_curproc_cap_pack(); +} + #endif /* PTLRPC_INTERNAL_H */ diff --git a/lustre/target/tgt_handler.c b/lustre/target/tgt_handler.c index 1cc8067..7624a02 100644 --- a/lustre/target/tgt_handler.c +++ b/lustre/target/tgt_handler.c @@ -319,11 +319,15 @@ static int tgt_request_preprocess(struct tgt_session_info *tsi, h->th_fmt != NULL)); if (h->th_fmt != NULL) { req_capsule_set(pill, h->th_fmt); - if (req_capsule_has_field(pill, &RMF_MDT_BODY, RCL_CLIENT)) { + if (req_capsule_has_field(pill, &RMF_MDT_BODY, RCL_CLIENT) && + req_capsule_field_present(pill, &RMF_MDT_BODY, + RCL_CLIENT)) { rc = tgt_mdt_body_unpack(tsi, flags); if (rc < 0) RETURN(rc); } else if (req_capsule_has_field(pill, &RMF_OST_BODY, + RCL_CLIENT) && + req_capsule_field_present(pill, &RMF_OST_BODY, RCL_CLIENT)) { rc = tgt_ost_body_unpack(tsi, flags); if (rc < 0) diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index 1999151..7c50fea 100755 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -2623,6 +2623,44 @@ test_34() { } run_test 34 "deny_unknown on default nodemap" +test_35() { + [ $(lustre_version_code $SINGLEMDS) -ge $(version_code 2.13.50) ] || + skip "Need MDS >= 2.13.50" + + # activate changelogs + changelog_register || error "changelog_register failed" + local cl_user="${CL_USERS[$SINGLEMDS]%% *}" + changelog_users $SINGLEMDS | grep -q $cl_user || + error "User $cl_user not found in changelog_users" + changelog_chmask ALL + + # do some IOs + mkdir $DIR/$tdir || error "failed to mkdir $tdir" + touch $DIR/$tdir/$tfile || error "failed to touch $tfile" + + # access changelogs with root + changelog_dump || error "failed to dump changelogs" + changelog_clear 0 || error "failed to clear changelogs" + + # put clients in non-admin nodemap + nodemap_test_setup + stack_trap nodemap_test_cleanup EXIT + for i in $(seq 0 $((num_clients-1))); do + do_facet mgs $LCTL nodemap_modify --name c${i} \ + --property admin --value 0 + done + for i in $(seq 0 $((num_clients-1))); do + wait_nm_sync c${i} admin_nodemap + done + + # access with mapped root + changelog_dump && error "dump changelogs should have failed" + changelog_clear 0 && error "clear changelogs should have failed" + + exit 0 +} +run_test 35 "Check permissions when accessing changelogs" + log "cleanup: ======================================================" sec_unsetup() { diff --git a/lustre/tests/test-framework.sh b/lustre/tests/test-framework.sh index d994b5a..3c1d4b3 100755 --- a/lustre/tests/test-framework.sh +++ b/lustre/tests/test-framework.sh @@ -9599,12 +9599,24 @@ changelog_clear() { } changelog_dump() { + local rc + for M in $(seq $MDSCOUNT); do local facet=mds$M local mdt="$(facet_svc $facet)" - - $LFS changelog $mdt | sed -e 's/^/'$mdt'./' + local output + local ret + + output=$($LFS changelog $mdt) + ret=$? + if [ $ret -ne 0 ]; then + rc=${rc:-$ret} + elif [ -n "$output" ]; then + echo "$output" | sed -e 's/^/'$mdt'./' + fi done + + return ${rc:-0} } changelog_extract_field() {