From 02a3973af6ea048f5f697400a3fc3740520acd36 Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Fri, 5 Jul 2024 16:51:44 +0200 Subject: [PATCH] LU-18005 gss: allow regular users to authenticate on MGS It can be useful for regular users to be able to authenticate against the MGS, for instance to run 'lfs check mgts'. Just allow this type of authentication request in the code, and take into account the MGC export when doing 'lfs flushctx', so that any user key associated with the MGS gets flushed as well. Add sanity-krb5 test_152 to exercise this capability. Test-Parameters: trivial Test-Parameters: testgroup=review-dne-selinux-ssk-part-1 Test-Parameters: testgroup=review-dne-selinux-ssk-part-2 Test-Parameters: kerberos=true testlist=sanity-krb5 Signed-off-by: Sebastien Buisson Change-Id: I4871b4ed61af918644e11d64ef5750a858713323 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/55640 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Aurelien Degremont Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- lustre/llite/llite_lib.c | 4 ++++ lustre/mgc/mgc_request.c | 7 ++++++ lustre/ptlrpc/gss/gss_svc_upcall.c | 5 +++- lustre/ptlrpc/gss/sec_gss.c | 19 +++++++++++---- lustre/ptlrpc/sec.c | 35 +++++++++++++++++++++++++-- lustre/tests/sanity-krb5.sh | 48 ++++++++++++++++++++++++++++++++++++++ lustre/utils/gss/svcgssd_proc.c | 44 ++++++++++++++++++++-------------- 7 files changed, 138 insertions(+), 24 deletions(-) diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index 183186f..0d97675 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -3492,10 +3492,14 @@ int ll_iocontrol(struct inode *inode, struct file *file, int ll_flush_ctx(struct inode *inode) { struct ll_sb_info *sbi = ll_i2sbi(inode); + struct lustre_sb_info *lsi = sbi->lsi; CDEBUG(D_SEC, "flush context for user %d\n", from_kuid(&init_user_ns, current_uid())); + obd_set_info_async(NULL, lsi->lsi_mgc->u.cli.cl_mgc_mgsexp, + sizeof(KEY_FLUSH_CTX), KEY_FLUSH_CTX, + 0, NULL, NULL); obd_set_info_async(NULL, sbi->ll_md_exp, sizeof(KEY_FLUSH_CTX), KEY_FLUSH_CTX, 0, NULL, NULL); diff --git a/lustre/mgc/mgc_request.c b/lustre/mgc/mgc_request.c index 8e34cc5..5f4ed83 100644 --- a/lustre/mgc/mgc_request.c +++ b/lustre/mgc/mgc_request.c @@ -1099,6 +1099,13 @@ static int mgc_set_info_async(const struct lu_env *env, struct obd_export *exp, RETURN(rc); } + if (KEY_IS(KEY_FLUSH_CTX)) { + struct obd_import *imp = class_exp2cliimp(exp); + + sptlrpc_import_flush_my_ctx(imp); + RETURN(0); + } + #ifdef HAVE_SERVER_SUPPORT rc = mgc_set_info_async_server(env, exp, keylen, key, vallen, val, set); #endif diff --git a/lustre/ptlrpc/gss/gss_svc_upcall.c b/lustre/ptlrpc/gss/gss_svc_upcall.c index 85b1ab6..242f7e4 100644 --- a/lustre/ptlrpc/gss/gss_svc_upcall.c +++ b/lustre/ptlrpc/gss/gss_svc_upcall.c @@ -887,7 +887,10 @@ int gss_svc_upcall_handle_init(struct ptlrpc_request *req, rscp->sc_target = target; CDEBUG(D_SEC, "%s: server create rsc %p(%u->%s)\n", - target->obd_name, rscp, rscp->sc_ctx.gsc_uid, + target->obd_name, rscp, + rscp->sc_ctx.gsc_mapped_uid != -1 ? + rscp->sc_ctx.gsc_mapped_uid : + rscp->sc_ctx.gsc_uid, libcfs_nidstr(&req->rq_peer.nid)); if (rsip->si_out_handle.len > PTLRPC_GSS_MAX_HANDLE_SIZE) { diff --git a/lustre/ptlrpc/gss/sec_gss.c b/lustre/ptlrpc/gss/sec_gss.c index 8e28b5c..00276cc 100644 --- a/lustre/ptlrpc/gss/sec_gss.c +++ b/lustre/ptlrpc/gss/sec_gss.c @@ -2064,7 +2064,10 @@ int gss_svc_handle_init(struct ptlrpc_request *req, struct gss_wire_ctx *gw) else CDEBUG(D_SEC, "%s: create svc ctx %p: accept user %u from %s\n", target->obd_name, - grctx->src_ctx, grctx->src_ctx->gsc_uid, + grctx->src_ctx, + grctx->src_ctx->gsc_mapped_uid != -1 ? + grctx->src_ctx->gsc_mapped_uid : + grctx->src_ctx->gsc_uid, libcfs_nidstr(&req->rq_peer.nid)); if (gw->gw_flags & LUSTRE_GSS_PACK_USER) { @@ -2284,7 +2287,10 @@ int gss_svc_handle_data(struct ptlrpc_request *req, struct gss_wire_ctx *gw) CERROR("svc %u failed: major 0x%08x: req xid %llu ctx %p idx %#llx(%u->%s)\n", gw->gw_svc, major, req->rq_xid, grctx->src_ctx, - gss_handle_to_u64(&gw->gw_handle), grctx->src_ctx->gsc_uid, + gss_handle_to_u64(&gw->gw_handle), + grctx->src_ctx->gsc_mapped_uid != -1 ? + grctx->src_ctx->gsc_mapped_uid : + grctx->src_ctx->gsc_uid, libcfs_nidstr(&req->rq_peer.nid)); error: /* we only notify client in case of NO_CONTEXT/BAD_SIG, which @@ -2323,7 +2329,10 @@ int gss_svc_handle_destroy(struct ptlrpc_request *req, struct gss_wire_ctx *gw) CDEBUG(D_SEC, "destroy svc ctx %p idx %#llx (%u->%s)\n", grctx->src_ctx, gss_handle_to_u64(&gw->gw_handle), - grctx->src_ctx->gsc_uid, libcfs_nidstr(&req->rq_peer.nid)); + grctx->src_ctx->gsc_mapped_uid != -1 ? + grctx->src_ctx->gsc_mapped_uid : + grctx->src_ctx->gsc_uid, + libcfs_nidstr(&req->rq_peer.nid)); gss_svc_upcall_destroy_ctx(grctx->src_ctx); @@ -2451,7 +2460,9 @@ void gss_svc_invalidate_ctx(struct ptlrpc_svc_ctx *svc_ctx) grctx = gss_svc_ctx2reqctx(svc_ctx); CWARN("gss svc invalidate ctx %p(%u)\n", grctx->src_ctx, - grctx->src_ctx->gsc_uid); + grctx->src_ctx->gsc_mapped_uid != -1 ? + grctx->src_ctx->gsc_mapped_uid : + grctx->src_ctx->gsc_uid); gss_svc_upcall_destroy_ctx(grctx->src_ctx); EXIT; diff --git a/lustre/ptlrpc/sec.c b/lustre/ptlrpc/sec.c index 641327c..b6b2209 100644 --- a/lustre/ptlrpc/sec.c +++ b/lustre/ptlrpc/sec.c @@ -2332,14 +2332,45 @@ static int sptlrpc_svc_check_from(struct ptlrpc_request *req, int svc_rc) } break; case LUSTRE_SP_MGS: - case LUSTRE_SP_MGC: if (!req->rq_auth_usr_root && !req->rq_auth_usr_mdt && !req->rq_auth_usr_ost) { /* The below message is checked in sanity-sec test_33 */ - DEBUG_REQ(D_ERROR, req, "faked source MGC/MGS"); + DEBUG_REQ(D_ERROR, req, "faked source MGS"); svc_rc = SECSVC_DROP; } break; + case LUSTRE_SP_MGC: { + bool faked = false; + + /* For krb, at most one of rq_auth_usr_root, rq_auth_usr_mdt, + * rq_auth_usr_ost can be non zero. + * For SSK, all of rq_auth_usr_root rq_auth_usr_mdt + * rq_auth_usr_ost must be 1 for server/root access, and all 0 + * for user access. + */ + switch (SPTLRPC_FLVR_MECH(req->rq_flvr.sf_rpc)) { + case SPTLRPC_MECH_GSS_KRB5: + if (req->rq_auth_usr_root + req->rq_auth_usr_mdt + + req->rq_auth_usr_ost > 1) + faked = true; + break; + case SPTLRPC_MECH_GSS_SK: + if ((!req->rq_auth_usr_root || !req->rq_auth_usr_mdt || + !req->rq_auth_usr_ost) && + (req->rq_auth_usr_root || req->rq_auth_usr_mdt || + req->rq_auth_usr_ost)) + faked = true; + break; + default: + faked = false; + } + if (faked) { + /* The below message is checked in sanity-sec test_33 */ + DEBUG_REQ(D_ERROR, req, "faked source MGC"); + svc_rc = SECSVC_DROP; + } + break; + } case LUSTRE_SP_ANY: default: DEBUG_REQ(D_ERROR, req, "invalid source %u", req->rq_sp_from); diff --git a/lustre/tests/sanity-krb5.sh b/lustre/tests/sanity-krb5.sh index 145e936..c0418b2 100755 --- a/lustre/tests/sanity-krb5.sh +++ b/lustre/tests/sanity-krb5.sh @@ -905,6 +905,54 @@ test_151() { } run_test 151 "secure mgs connection: server flavor control" +exit_152() { + zconf_umount $HOSTNAME $MOUNT + + # remove mgs rule + set_rule _mgs any any + + zconf_mount $HOSTNAME $MOUNT + if [ "$MOUNT_2" ]; then + zconf_mount $HOSTNAME $MOUNT2 + fi +} + +test_152() { + local mount_opts + local count + + (( MDS1_VERSION >= $(version_code 2.15.64) )) || + skip "Need MDS >= 2.15.64 for user context with MGS" + + stack_trap exit_152 EXIT + + if is_mounted $MOUNT2; then + umount_client $MOUNT2 || error "umount $MOUNT2 failed" + fi + + zconf_umount $HOSTNAME $MOUNT || error "umount $MOUNT failed" + + # set mgs rule to only accept krb5p + set_rule _mgs any any krb5p + + # start gss daemon on mgs node + combined_mgs_mds || start_gss_daemons $mgs_HOST $LSVCGSSD "-vvv" + + # re-mount client with mgssec=krb5p + mount_opts="${MOUNT_OPTS:+$MOUNT_OPTS,}mgssec=krb5p" + zconf_mount $HOSTNAME $MOUNT $mount_opts || + error "unable to mount client" + + $RUNAS $LFS check mgts || error "check mgts as user failed" + $RUNAS grep lgssc /proc/keys + + $RUNAS $LFS flushctx $MOUNT || error "flushctx as user failed" + $RUNAS grep lgssc /proc/keys + count=$($RUNAS grep lgssc /proc/keys | grep -v "Running as" | wc -l) + [[ $count == 0 ]] || error "remaining $count keys for user" +} +run_test 152 "secure mgs connection: user access" + test_200() { local nid=$(lctl list_nids | grep ${NETTYPE} | head -n1) local nidstr="peer_nid: ${nid}," diff --git a/lustre/utils/gss/svcgssd_proc.c b/lustre/utils/gss/svcgssd_proc.c index 3009d61..8cb61fc 100644 --- a/lustre/utils/gss/svcgssd_proc.c +++ b/lustre/utils/gss/svcgssd_proc.c @@ -351,7 +351,8 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, sname[name.length] = '\0'; gss_release_buffer(&min_stat, &name); - if (lustre_svc == LUSTRE_GSS_SVC_MDS && + if ((lustre_svc == LUSTRE_GSS_SVC_MDS || + lustre_svc == LUSTRE_GSS_SVC_MGS) && lookup_id(client_name, sname, nid, &cred->cr_mapped_uid)) printerr(LL_DEBUG, "no id found for %s\n", sname); @@ -376,24 +377,24 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, if (host) { if (lnet_nid2hostname(nid, namebuf, namebuf_size)) { printerr(LL_ERR, - "ERROR: failed to resolve hostname for %s/%s@%s from %016llx\n", - sname, host, realm, nid); + "ERROR: failed to resolve hostname for %s/%s@%s from %s\n", + sname, host, realm, libcfs_nid2str(nid)); goto out_free; } if (strcasecmp(host, namebuf)) { printerr(LL_ERR, - "ERROR: %s/%s@%s claimed hostname doesn't match %s, nid %016llx\n", + "ERROR: %s/%s@%s claimed hostname doesn't match %s, nid %s\n", sname, host, realm, - namebuf, nid); + namebuf, libcfs_nid2str(nid)); goto out_free; } } else { if (!strcmp(sname, GSSD_SERVICE_MDS) || !strcmp(sname, GSSD_SERVICE_OSS)) { printerr(LL_ERR, - "ERROR: %s@%s from %016llx doesn't bind with hostname\n", - sname, realm, nid); + "ERROR: %s@%s from %s doesn't bind with hostname\n", + sname, realm, libcfs_nid2str(nid)); goto out_free; } } @@ -408,9 +409,10 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, /* Prevent access to unmapped user from remote realm */ if (cred->cr_mapped_uid == -1) { printerr(LL_ERR, - "ERROR: %s%s%s@%s from %016llx is remote but without mapping\n", + "ERROR: %s%s%s@%s from %s is remote but without mapping\n", sname, host ? "/" : "", - host ? host : "", realm, nid); + host ? host : "", realm, + libcfs_nid2str(nid)); break; } goto valid; @@ -436,8 +438,8 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, } if (cred->cr_mapped_uid != -1) { printerr(LL_INFO, - "user %s from %016llx is mapped to %u\n", - sname, nid, + "user %s from %s is mapped to %u\n", + sname, libcfs_nid2str(nid), cred->cr_mapped_uid); goto valid; } @@ -448,8 +450,8 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, sname, cred->cr_uid); goto valid; } - printerr(LL_ERR, "ERROR: invalid user, %s/%s@%s from %016llx\n", - sname, host, realm, nid); + printerr(LL_ERR, "ERROR: invalid user, %s/%s@%s from %s\n", + sname, host, realm, libcfs_nid2str(nid)); break; valid: @@ -470,10 +472,17 @@ valid: cred->cr_uid = 0; cred->cr_usr_mds = 1; } + if (cred->cr_mapped_uid != -1) { + printerr(LL_INFO, + "user %s from %s is mapped to %u\n", + sname, libcfs_nid2str(nid), + cred->cr_mapped_uid); + goto valid; + } if (cred->cr_uid == -1) { printerr(LL_ERR, - "ERROR: svc %d doesn't accept user %s from %016llx\n", - lustre_svc, sname, nid); + "ERROR: svc %d doesn't accept user %s from %s\n", + lustre_svc, sname, libcfs_nid2str(nid)); break; } res = 0; @@ -484,9 +493,10 @@ valid: out_free: if (!res) - printerr(LL_WARN, "%s: authenticated %s%s%s@%s from %016llx\n", + printerr(LL_WARN, "%s: authenticated %s%s%s@%s from %s\n", lustre_svc_name[lustre_svc], sname, - host ? "/" : "", host ? host : "", realm, nid); + host ? "/" : "", host ? host : "", realm, + libcfs_nid2str(nid)); free(sname); return res; } -- 1.8.3.1