From fca35f74f9ec5c5ed77e774f3e3209d9df057a01 Mon Sep 17 00:00:00 2001 From: Bruno Faccini Date: Wed, 26 Apr 2017 12:35:28 +0200 Subject: [PATCH] LU-9193 security: return security context for metadata ops Security layer needs to fetch security context of files/dirs upon metadata ops like lookup, getattr, open, truncate, and layout, for its own purpose and control checks. Retrieving the security context consists in a getxattr operation at the file system level. The fact that the requested metadata operation and the getxattr are not atomic can create a window for a dead-lock situation where, based on some access patterns, all MDT service threads can become stuck waiting for lookup lock to be released and thus unable to serve getxattr for security context. Another problem is that sending an additional getxattr request for every metadata op hurts performance. This patch introduces a way to get atomicity by having the MDT return security context upon granted lock reply, sparing the client an additional getxattr request. Test-Parameters: serverbuildno=62488 serverjob=lustre-reviews testlist=sanity,sanity-selinux clientselinux Test-Parameters: clientbuildno=4033 clientjob=lustre-reviews-patchless testlist=sanity,sanity-selinux clientselinux Signed-off-by: Bruno Faccini Signed-off-by: Sebastien Buisson Change-Id: Iaaf4d93f8d3bf31b5a2c23e7db36b3cb3feb31ba Reviewed-on: https://review.whamcloud.com/26831 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- lustre/autoconf/lustre-core.m4 | 16 +++ lustre/include/obd.h | 3 +- lustre/include/uapi/linux/lustre/lustre_idl.h | 1 + lustre/llite/llite_internal.h | 3 + lustre/llite/namei.c | 68 +++++++++++- lustre/llite/xattr_security.c | 33 ++++++ lustre/lmv/lmv_intent.c | 21 +++- lustre/mdc/mdc_locks.c | 87 ++++++++++++--- lustre/mdc/mdc_request.c | 2 + lustre/mdt/mdt_handler.c | 147 ++++++++++++++++---------- lustre/mdt/mdt_internal.h | 2 + lustre/mdt/mdt_lib.c | 42 ++++++++ lustre/mdt/mdt_open.c | 6 +- lustre/ptlrpc/layout.c | 29 ++--- lustre/tests/sanity-selinux.sh | 79 ++++++++++++++ 15 files changed, 446 insertions(+), 93 deletions(-) diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index 84412d0..3dffc2c 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -1497,6 +1497,21 @@ security_dentry_init_security, [ ]) # LC_HAVE_SECURITY_DENTRY_INIT_SECURITY # +# 3.10 exports security_inode_listsecurity +# +AC_DEFUN([LC_HAVE_SECURITY_INODE_LISTSECURITY], [ +LB_CHECK_COMPILE([if security_inode_listsecurity() is available/exported], +security_inode_listsecurity, [ + #include +],[ + security_inode_listsecurity(NULL, NULL, 0); +],[ + AC_DEFINE(HAVE_SECURITY_INODE_LISTSECURITY, 1, + [security_inode_listsecurity() is available/exported]) +]) +]) # LC_HAVE_SECURITY_INODE_LISTSECURITY + +# # LC_INVALIDATE_RANGE # # 3.11 invalidatepage requires the length of the range to invalidate @@ -3157,6 +3172,7 @@ AC_DEFUN([LC_PROG_LINUX], [ LC_HAVE_PROC_REMOVE LC_HAVE_PROJECT_QUOTA LC_HAVE_SECURITY_DENTRY_INIT_SECURITY + LC_HAVE_SECURITY_INODE_LISTSECURITY # 3.11 LC_INVALIDATE_RANGE diff --git a/lustre/include/obd.h b/lustre/include/obd.h index 9460c49..85a7cc2 100644 --- a/lustre/include/obd.h +++ b/lustre/include/obd.h @@ -882,8 +882,9 @@ struct md_op_data { __u64 op_data_version; struct lustre_handle op_lease_handle; - /* File security context, for creates. */ + /* File security context, for creates/metadata ops */ const char *op_file_secctx_name; + __u32 op_file_secctx_name_size; void *op_file_secctx; __u32 op_file_secctx_size; diff --git a/lustre/include/uapi/linux/lustre/lustre_idl.h b/lustre/include/uapi/linux/lustre/lustre_idl.h index f7d9a01..f88a591 100644 --- a/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -1291,6 +1291,7 @@ lov_mds_md_max_stripe_count(size_t buf_size, __u32 lmm_magic) #define OBD_MD_DEFAULT_MEA (0x0040000000000000ULL) /* default MEA */ #define OBD_MD_FLOSTLAYOUT (0x0080000000000000ULL) /* contain ost_layout */ #define OBD_MD_FLPROJID (0x0100000000000000ULL) /* project ID */ +#define OBD_MD_SECCTX (0x0200000000000000ULL) /* embed security xattr */ #define OBD_MD_FLALLQUOTA (OBD_MD_FLUSRQUOTA | \ OBD_MD_FLGRPQUOTA | \ diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index 5bbe089..974ab92 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -320,6 +320,9 @@ int ll_dentry_init_security(struct dentry *dentry, int mode, struct qstr *name, int ll_inode_init_security(struct dentry *dentry, struct inode *inode, struct inode *dir); +int ll_listsecurity(struct inode *inode, char *secctx_name, + size_t secctx_name_size); + /* * Locking to guarantee consistency of non-atomic updates to long long i_size, * consistency between file size and KMS. diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c index 583a217..39778ea 100644 --- a/lustre/llite/namei.c +++ b/lustre/llite/namei.c @@ -601,7 +601,8 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de) static int ll_lookup_it_finish(struct ptlrpc_request *request, struct lookup_intent *it, - struct inode *parent, struct dentry **de) + struct inode *parent, struct dentry **de, + void *secctx, __u32 secctxlen) { struct inode *inode = NULL; __u64 bits = 0; @@ -614,6 +615,10 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, CDEBUG(D_DENTRY, "it %p it_disposition %x\n", it, it->it_disposition); if (!it_disposition(it, DISP_LOOKUP_NEG)) { + struct req_capsule *pill = &request->rq_pill; + struct mdt_body *body = req_capsule_server_get(pill, + &RMF_MDT_BODY); + rc = ll_prep_inode(&inode, request, (*de)->d_sb, it); if (rc) RETURN(rc); @@ -632,6 +637,33 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, * ll_glimpse_size or some equivalent themselves anyway. * Also see bug 7198. */ + + /* If security context was returned by MDT, put it in + * inode now to save an extra getxattr from security hooks, + * and avoid deadlock. + */ + if (body->mbo_valid & OBD_MD_SECCTX) { + secctx = req_capsule_server_get(pill, &RMF_FILE_SECCTX); + secctxlen = req_capsule_get_size(pill, + &RMF_FILE_SECCTX, + RCL_SERVER); + + if (secctxlen) + CDEBUG(D_SEC, "server returned security context" + " for "DFID"\n", + PFID(ll_inode2fid(inode))); + } + + if (secctx != NULL && secctxlen != 0) { + inode_lock(inode); + rc = security_inode_notifysecctx(inode, secctx, + secctxlen); + inode_unlock(inode); + if (rc) + CWARN("cannot set security context for " + DFID": rc = %d\n", + PFID(ll_inode2fid(inode)), rc); + } } /* Only hash *de if it is unhashed (new dentry). @@ -692,9 +724,11 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, struct dentry *save = dentry, *retval; struct ptlrpc_request *req = NULL; struct md_op_data *op_data = NULL; - __u32 opc; - int rc; - ENTRY; + __u32 opc; + int rc; + char secctx_name[XATTR_NAME_MAX + 1]; + + ENTRY; if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen) RETURN(ERR_PTR(-ENAMETOOLONG)); @@ -746,6 +780,28 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, *secctx = op_data->op_file_secctx; if (secctxlen != NULL) *secctxlen = op_data->op_file_secctx_size; + } else { + if (secctx != NULL) + *secctx = NULL; + if (secctxlen != NULL) + *secctxlen = 0; + } + + /* ask for security context upon intent */ + if (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_OPEN)) { + /* get name of security xattr to request to server */ + rc = ll_listsecurity(parent, secctx_name, + sizeof(secctx_name)); + if (rc < 0) { + CDEBUG(D_SEC, "cannot get security xattr name for " + DFID": rc = %d\n", + PFID(ll_inode2fid(parent)), rc); + } else if (rc > 0) { + op_data->op_file_secctx_name = secctx_name; + op_data->op_file_secctx_name_size = rc; + CDEBUG(D_SEC, "'%.*s' is security xattr for "DFID"\n", + rc, secctx_name, PFID(ll_inode2fid(parent))); + } } rc = md_intent_lock(ll_i2mdexp(parent), op_data, it, &req, @@ -781,7 +837,9 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, /* dir layout may change */ ll_unlock_md_op_lsm(op_data); - rc = ll_lookup_it_finish(req, it, parent, &dentry); + rc = ll_lookup_it_finish(req, it, parent, &dentry, + secctx != NULL ? *secctx : NULL, + secctxlen != NULL ? *secctxlen : 0); if (rc != 0) { ll_intent_release(it); GOTO(out, retval = ERR_PTR(rc)); diff --git a/lustre/llite/xattr_security.c b/lustre/llite/xattr_security.c index 82019cc..45f6483 100644 --- a/lustre/llite/xattr_security.c +++ b/lustre/llite/xattr_security.c @@ -187,3 +187,36 @@ out_free: return err; } #endif /* HAVE_SECURITY_IINITSEC_CALLBACK */ + +/** + * Get security context xattr name used by policy. + * + * \retval >= 0 length of xattr name + * \retval < 0 failure to get security context xattr name + */ +int +ll_listsecurity(struct inode *inode, char *secctx_name, size_t secctx_name_size) +{ + int rc; + + if (!selinux_is_enabled()) + return 0; + +#ifdef HAVE_SECURITY_INODE_LISTSECURITY + rc = security_inode_listsecurity(inode, secctx_name, secctx_name_size); + if (rc >= secctx_name_size) + rc = -ERANGE; + else if (rc >= 0) + secctx_name[rc] = '\0'; + return rc; +#else /* !HAVE_SECURITY_INODE_LISTSECURITY */ + rc = sizeof(XATTR_NAME_SELINUX); + if (secctx_name && rc < secctx_name_size) { + memcpy(secctx_name, XATTR_NAME_SELINUX, rc); + secctx_name[rc] = '\0'; + } else { + rc = -ERANGE; + } + return rc; +#endif /* HAVE_SECURITY_INODE_LISTSECURITY */ +} diff --git a/lustre/lmv/lmv_intent.c b/lustre/lmv/lmv_intent.c index 5cc1687..7cac3dc 100644 --- a/lustre/lmv/lmv_intent.c +++ b/lustre/lmv/lmv_intent.c @@ -54,7 +54,8 @@ static int lmv_intent_remote(struct obd_export *exp, struct lookup_intent *it, const struct lu_fid *parent_fid, struct ptlrpc_request **reqp, ldlm_blocking_callback cb_blocking, - __u64 extra_lock_flags) + __u64 extra_lock_flags, + const char *secctx_name, __u32 secctx_name_size) { struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; @@ -107,6 +108,16 @@ static int lmv_intent_remote(struct obd_export *exp, struct lookup_intent *it, CDEBUG(D_INODE, "REMOTE_INTENT with fid="DFID" -> mds #%u\n", PFID(&body->mbo_fid1), tgt->ltd_idx); + /* ask for security context upon intent */ + if (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_OPEN) && + secctx_name_size != 0 && secctx_name != NULL) { + op_data->op_file_secctx_name = secctx_name; + op_data->op_file_secctx_name_size = secctx_name_size; + CDEBUG(D_SEC, "'%.*s' is security xattr to fetch for " + DFID"\n", + secctx_name_size, secctx_name, PFID(&body->mbo_fid1)); + } + rc = md_intent_lock(tgt->ltd_exp, op_data, it, &req, cb_blocking, extra_lock_flags); if (rc) @@ -381,7 +392,9 @@ retry: /* Not cross-ref case, just get out of here. */ if (unlikely((body->mbo_valid & OBD_MD_MDS))) { rc = lmv_intent_remote(exp, it, &op_data->op_fid1, reqp, - cb_blocking, extra_lock_flags); + cb_blocking, extra_lock_flags, + op_data->op_file_secctx_name, + op_data->op_file_secctx_name_size); if (rc != 0) RETURN(rc); @@ -465,7 +478,9 @@ retry: /* Not cross-ref case, just get out of here. */ if (unlikely((body->mbo_valid & OBD_MD_MDS))) { rc = lmv_intent_remote(exp, it, NULL, reqp, cb_blocking, - extra_lock_flags); + extra_lock_flags, + op_data->op_file_secctx_name, + op_data->op_file_secctx_name_size); if (rc != 0) RETURN(rc); body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY); diff --git a/lustre/mdc/mdc_locks.c b/lustre/mdc/mdc_locks.c index accea01..5a5496e 100644 --- a/lustre/mdc/mdc_locks.c +++ b/lustre/mdc/mdc_locks.c @@ -314,7 +314,7 @@ mdc_intent_open_pack(struct obd_export *exp, struct lookup_intent *it, req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX_NAME, RCL_CLIENT, op_data->op_file_secctx_name != NULL ? - strlen(op_data->op_file_secctx_name) + 1 : 0); + op_data->op_file_secctx_name_size : 0); req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX, RCL_CLIENT, op_data->op_file_secctx_size); @@ -341,6 +341,30 @@ mdc_intent_open_pack(struct obd_export *exp, struct lookup_intent *it, obddev->u.cli.cl_max_mds_easize); req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, acl_bufsize); + if (!(it->it_op & IT_CREAT) && it->it_op & IT_OPEN && + req_capsule_has_field(&req->rq_pill, &RMF_FILE_SECCTX_NAME, + RCL_CLIENT) && + op_data->op_file_secctx_name_size > 0 && + op_data->op_file_secctx_name != NULL) { + char *secctx_name; + + secctx_name = req_capsule_client_get(&req->rq_pill, + &RMF_FILE_SECCTX_NAME); + memcpy(secctx_name, op_data->op_file_secctx_name, + op_data->op_file_secctx_name_size); + req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX, + RCL_SERVER, + obddev->u.cli.cl_max_mds_easize); + + CDEBUG(D_SEC, "packed '%.*s' as security xattr name\n", + op_data->op_file_secctx_name_size, + op_data->op_file_secctx_name); + + } else { + req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX, + RCL_SERVER, 0); + } + /** * Inline buffer for possible data from Data-on-MDT files. */ @@ -413,6 +437,8 @@ mdc_intent_getxattr_pack(struct obd_export *exp, /* pack the intent */ lit = req_capsule_client_get(&req->rq_pill, &RMF_LDLM_INTENT); lit->opc = IT_GETXATTR; + CDEBUG(D_INFO, "%s: get xattrs for "DFID"\n", + exp->exp_obd->obd_name, PFID(&op_data->op_fid1)); #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0) /* If the supplied buffer is too small then the server will @@ -460,25 +486,38 @@ mdc_intent_getattr_pack(struct obd_export *exp, struct lookup_intent *it, struct ldlm_intent *lit; int rc; __u32 easize; + bool have_secctx = false; ENTRY; - req = ptlrpc_request_alloc(class_exp2cliimp(exp), - &RQF_LDLM_INTENT_GETATTR); - if (req == NULL) - RETURN(ERR_PTR(-ENOMEM)); + req = ptlrpc_request_alloc(class_exp2cliimp(exp), + &RQF_LDLM_INTENT_GETATTR); + if (req == NULL) + RETURN(ERR_PTR(-ENOMEM)); - req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT, - op_data->op_namelen + 1); + /* send name of security xattr to get upon intent */ + if (it->it_op & (IT_LOOKUP | IT_GETATTR) && + req_capsule_has_field(&req->rq_pill, &RMF_FILE_SECCTX_NAME, + RCL_CLIENT) && + op_data->op_file_secctx_name_size > 0 && + op_data->op_file_secctx_name != NULL) { + have_secctx = true; + req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX_NAME, + RCL_CLIENT, + op_data->op_file_secctx_name_size); + } - rc = ldlm_prep_enqueue_req(exp, req, NULL, 0); - if (rc) { - ptlrpc_request_free(req); - RETURN(ERR_PTR(rc)); - } + req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT, + op_data->op_namelen + 1); + + rc = ldlm_prep_enqueue_req(exp, req, NULL, 0); + if (rc) { + ptlrpc_request_free(req); + RETURN(ERR_PTR(rc)); + } /* pack the intent */ - lit = req_capsule_client_get(&req->rq_pill, &RMF_LDLM_INTENT); - lit->opc = (__u64)it->it_op; + lit = req_capsule_client_get(&req->rq_pill, &RMF_LDLM_INTENT); + lit->opc = (__u64)it->it_op; if (obddev->u.cli.cl_default_mds_easize > 0) easize = obddev->u.cli.cl_default_mds_easize; @@ -490,6 +529,26 @@ mdc_intent_getattr_pack(struct obd_export *exp, struct lookup_intent *it, req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, easize); req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, acl_bufsize); + + if (have_secctx) { + char *secctx_name; + + secctx_name = req_capsule_client_get(&req->rq_pill, + &RMF_FILE_SECCTX_NAME); + memcpy(secctx_name, op_data->op_file_secctx_name, + op_data->op_file_secctx_name_size); + + req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX, + RCL_SERVER, easize); + + CDEBUG(D_SEC, "packed '%.*s' as security xattr name\n", + op_data->op_file_secctx_name_size, + op_data->op_file_secctx_name); + } else { + req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX, + RCL_SERVER, 0); + } + ptlrpc_request_set_replen(req); RETURN(req); } diff --git a/lustre/mdc/mdc_request.c b/lustre/mdc/mdc_request.c index 0cd273b..9b62958 100644 --- a/lustre/mdc/mdc_request.c +++ b/lustre/mdc/mdc_request.c @@ -440,6 +440,8 @@ static int mdc_getxattr(struct obd_export *exp, const struct lu_fid *fid, LASSERT(obd_md_valid == OBD_MD_FLXATTR || obd_md_valid == OBD_MD_FLXATTRLS); + CDEBUG(D_INFO, "%s: get xattr '%s' for "DFID"\n", + exp->exp_obd->obd_name, name, PFID(fid)); rc = mdc_xattr_common(exp, &RQF_MDS_GETXATTR, fid, MDS_GETXATTR, obd_md_valid, name, NULL, 0, buf_size, 0, -1, req); diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index c4dd912..923e42a 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -1622,9 +1622,11 @@ static int mdt_getattr_name_lock(struct mdt_thread_info *info, struct lu_name *lname = NULL; struct mdt_lock_handle *lhp = NULL; struct ldlm_lock *lock; + struct req_capsule *pill = info->mti_pill; __u64 try_bits = 0; bool is_resent; int ma_need = 0; + bool deal_with_dom = false; int rc; ENTRY; @@ -1681,18 +1683,20 @@ static int mdt_getattr_name_lock(struct mdt_thread_info *info, if (unlikely(rc != 0)) mdt_object_unlock(info, child, lhc, 1); - RETURN(rc); - } + mdt_pack_secctx_in_reply(info, child); + + RETURN(rc); + } lname = &info->mti_name; - mdt_name_unpack(info->mti_pill, &RMF_NAME, lname, MNF_FIX_ANON); + mdt_name_unpack(pill, &RMF_NAME, lname, MNF_FIX_ANON); if (lu_name_is_valid(lname)) { CDEBUG(D_INODE, "getattr with lock for "DFID"/"DNAME", " "ldlm_rep = %p\n", PFID(mdt_object_fid(parent)), PNAME(lname), ldlm_rep); } else { - reqbody = req_capsule_client_get(info->mti_pill, &RMF_MDT_BODY); + reqbody = req_capsule_client_get(pill, &RMF_MDT_BODY); if (unlikely(reqbody == NULL)) RETURN(err_serious(-EPROTO)); @@ -1845,16 +1849,17 @@ static int mdt_getattr_name_lock(struct mdt_thread_info *info, child_bits &= ~MDS_INODELOCK_UPDATE; rc = mdt_object_lock(info, child, lhc, child_bits); } - if (unlikely(rc != 0)) - GOTO(out_child, rc); - } + if (unlikely(rc != 0)) + GOTO(out_child, rc); + } - lock = ldlm_handle2lock(&lhc->mlh_reg_lh); + lock = ldlm_handle2lock(&lhc->mlh_reg_lh); - /* finally, we can get attr for child. */ - rc = mdt_getattr_internal(info, child, ma_need); - if (unlikely(rc != 0)) { - mdt_object_unlock(info, child, lhc, 1); + /* finally, we can get attr for child. */ + rc = mdt_getattr_internal(info, child, ma_need); + if (unlikely(rc != 0)) { + mdt_object_unlock(info, child, lhc, 1); + GOTO(out_lock, rc); } else if (lock) { /* Debugging code. */ LDLM_DEBUG(lock, "Returning lock to client"); @@ -1866,31 +1871,32 @@ static int mdt_getattr_name_lock(struct mdt_thread_info *info, if (S_ISREG(lu_object_attr(&child->mot_obj)) && mdt_object_exists(child) && !mdt_object_remote(child) && - child != parent) { - LDLM_LOCK_PUT(lock); - mdt_object_put(info->mti_env, child); - /* NB: call the mdt_pack_size2body always after - * mdt_object_put(), that is why this special - * exit path is used. */ - rc = mdt_pack_size2body(info, child_fid, - &lhc->mlh_reg_lh); - if (rc != 0 && child_bits & MDS_INODELOCK_DOM) { - /* DOM lock was taken in advance but this is - * not DoM file. Drop the lock. */ - lock_res_and_lock(lock); - ldlm_inodebits_drop(lock, MDS_INODELOCK_DOM); - unlock_res_and_lock(lock); - } - - GOTO(out_parent, rc = 0); - } + child != parent) + deal_with_dom = true; } + + mdt_pack_secctx_in_reply(info, child); + +out_lock: if (lock) LDLM_LOCK_PUT(lock); EXIT; out_child: mdt_object_put(info->mti_env, child); + if (deal_with_dom) { + rc = mdt_pack_size2body(info, child_fid, + &lhc->mlh_reg_lh); + if (rc != 0 && child_bits & MDS_INODELOCK_DOM) { + /* DOM lock was taken in advance but this is + * not DoM file. Drop the lock. + */ + lock_res_and_lock(lock); + ldlm_inodebits_drop(lock, MDS_INODELOCK_DOM); + unlock_res_and_lock(lock); + } + rc = 0; + } out_parent: if (lhp) mdt_object_unlock(info, parent, lhp, 1); @@ -2096,6 +2102,28 @@ static inline bool mdt_is_readonly_open(struct mdt_thread_info *info, __u32 op) !(info->mti_spec.sp_cr_flags & (MDS_FMODE_WRITE | MDS_OPEN_CREAT)); } +static void mdt_preset_secctx_size(struct mdt_thread_info *info) +{ + struct req_capsule *pill = info->mti_pill; + + if (req_capsule_has_field(pill, &RMF_FILE_SECCTX, + RCL_SERVER) && + req_capsule_has_field(pill, &RMF_FILE_SECCTX_NAME, + RCL_CLIENT)) { + if (req_capsule_get_size(pill, &RMF_FILE_SECCTX_NAME, + RCL_CLIENT) != 0) { + /* pre-set size in server part with max size */ + req_capsule_set_size(pill, &RMF_FILE_SECCTX, + RCL_SERVER, + info->mti_mdt->mdt_max_ea_size); + } else { + req_capsule_set_size(pill, &RMF_FILE_SECCTX, + RCL_SERVER, 0); + } + } + +} + static int mdt_reint_internal(struct mdt_thread_info *info, struct mdt_lock_handle *lhc, __u32 op) @@ -2124,7 +2152,7 @@ static int mdt_reint_internal(struct mdt_thread_info *info, DEF_REP_MD_SIZE); /* llog cookies are always 0, the field is kept for compatibility */ - if (req_capsule_has_field(pill, &RMF_LOGCOOKIES, RCL_SERVER)) + if (req_capsule_has_field(pill, &RMF_LOGCOOKIES, RCL_SERVER)) req_capsule_set_size(pill, &RMF_LOGCOOKIES, RCL_SERVER, 0); /* Set ACL reply buffer size as LUSTRE_POSIX_ACL_MAX_SIZE_OLD @@ -2134,33 +2162,35 @@ static int mdt_reint_internal(struct mdt_thread_info *info, req_capsule_set_size(pill, &RMF_ACL, RCL_SERVER, LUSTRE_POSIX_ACL_MAX_SIZE_OLD); - rc = req_capsule_server_pack(pill); - if (rc != 0) { - CERROR("Can't pack response, rc %d\n", rc); - RETURN(err_serious(rc)); - } + mdt_preset_secctx_size(info); + + rc = req_capsule_server_pack(pill); + if (rc != 0) { + CERROR("Can't pack response, rc %d\n", rc); + RETURN(err_serious(rc)); + } - if (req_capsule_has_field(pill, &RMF_MDT_BODY, RCL_SERVER)) { - repbody = req_capsule_server_get(pill, &RMF_MDT_BODY); - LASSERT(repbody); + if (req_capsule_has_field(pill, &RMF_MDT_BODY, RCL_SERVER)) { + repbody = req_capsule_server_get(pill, &RMF_MDT_BODY); + LASSERT(repbody); repbody->mbo_eadatasize = 0; repbody->mbo_aclsize = 0; - } + } - OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_REINT_DELAY, 10); + OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_REINT_DELAY, 10); - /* for replay no cookkie / lmm need, because client have this already */ - if (info->mti_spec.no_create) - if (req_capsule_has_field(pill, &RMF_MDT_MD, RCL_SERVER)) - req_capsule_set_size(pill, &RMF_MDT_MD, RCL_SERVER, 0); + /* for replay no cookkie / lmm need, because client have this already */ + if (info->mti_spec.no_create) + if (req_capsule_has_field(pill, &RMF_MDT_MD, RCL_SERVER)) + req_capsule_set_size(pill, &RMF_MDT_MD, RCL_SERVER, 0); - rc = mdt_init_ucred_reint(info); - if (rc) - GOTO(out_shrink, rc); + rc = mdt_init_ucred_reint(info); + if (rc) + GOTO(out_shrink, rc); - rc = mdt_fix_attr_ucred(info, op); - if (rc != 0) - GOTO(out_ucred, rc = err_serious(rc)); + rc = mdt_fix_attr_ucred(info, op); + if (rc != 0) + GOTO(out_ucred, rc = err_serious(rc)); rc = mdt_check_resent(info, mdt_reconstruct, lhc); if (rc < 0) { @@ -2168,12 +2198,12 @@ static int mdt_reint_internal(struct mdt_thread_info *info, } else if (rc == 1) { DEBUG_REQ(D_INODE, mdt_info_req(info), "resent opt."); rc = lustre_msg_get_status(mdt_info_req(info)->rq_repmsg); - GOTO(out_ucred, rc); - } - rc = mdt_reint_rec(info, lhc); - EXIT; + GOTO(out_ucred, rc); + } + rc = mdt_reint_rec(info, lhc); + EXIT; out_ucred: - mdt_exit_ucred(info); + mdt_exit_ucred(info); out_shrink: mdt_client_compatibility(info); @@ -3364,7 +3394,12 @@ static int mdt_unpack_req_pack_rep(struct mdt_thread_info *info, req_capsule_set_size(pill, &RMF_ACL, RCL_SERVER, LUSTRE_POSIX_ACL_MAX_SIZE_OLD); + mdt_preset_secctx_size(info); + rc = req_capsule_server_pack(pill); + if (rc) + CWARN("%s: cannot pack response: rc = %d\n", + mdt_obd_name(info->mti_mdt), rc); } RETURN(rc); } diff --git a/lustre/mdt/mdt_internal.h b/lustre/mdt/mdt_internal.h index 7784448..f42eb1c 100644 --- a/lustre/mdt/mdt_internal.h +++ b/lustre/mdt/mdt_internal.h @@ -898,6 +898,8 @@ int mdt_links_read(struct mdt_thread_info *info, struct linkea_data *ldata); int mdt_close_internal(struct mdt_thread_info *info, struct ptlrpc_request *req, struct mdt_body *repbody); +void mdt_pack_secctx_in_reply(struct mdt_thread_info *info, + struct mdt_object *child); static inline struct mdt_device *mdt_dev(struct lu_device *d) { diff --git a/lustre/mdt/mdt_lib.c b/lustre/mdt/mdt_lib.c index 6e5fbf3..7d2a7c0 100644 --- a/lustre/mdt/mdt_lib.c +++ b/lustre/mdt/mdt_lib.c @@ -1720,3 +1720,45 @@ int mdt_reint_unpack(struct mdt_thread_info *info, __u32 op) } RETURN(rc); } + +void mdt_pack_secctx_in_reply(struct mdt_thread_info *info, + struct mdt_object *child) +{ + char *secctx_name; + struct lu_buf *buffer; + struct mdt_body *repbody; + struct req_capsule *pill = info->mti_pill; + int rc; + + if (req_capsule_has_field(pill, &RMF_FILE_SECCTX, RCL_SERVER) && + req_capsule_get_size(pill, &RMF_FILE_SECCTX, RCL_SERVER) != 0) { + secctx_name = + req_capsule_client_get(pill, &RMF_FILE_SECCTX_NAME); + buffer = &info->mti_buf; + + /* fill reply buffer with security context now */ + buffer->lb_len = req_capsule_get_size(pill, &RMF_FILE_SECCTX, + RCL_SERVER); + buffer->lb_buf = req_capsule_server_get(info->mti_pill, + &RMF_FILE_SECCTX); + rc = mo_xattr_get(info->mti_env, mdt_object_child(child), + buffer, secctx_name); + if (rc >= 0) { + CDEBUG(D_SEC, + "found security context of size %d for "DFID"\n", + rc, PFID(mdt_object_fid(child))); + + repbody = req_capsule_server_get(pill, &RMF_MDT_BODY); + repbody->mbo_valid |= OBD_MD_SECCTX; + if (rc < buffer->lb_len) + req_capsule_shrink(pill, &RMF_FILE_SECCTX, rc, + RCL_SERVER); + } else { + CDEBUG(D_SEC, + "security context not found for "DFID": rc = %d\n", + PFID(mdt_object_fid(child)), rc); + req_capsule_shrink(pill, &RMF_FILE_SECCTX, 0, + RCL_SERVER); + } + } +} diff --git a/lustre/mdt/mdt_open.c b/lustre/mdt/mdt_open.c index 40025f6..f01571b 100644 --- a/lustre/mdt/mdt_open.c +++ b/lustre/mdt/mdt_open.c @@ -1214,6 +1214,8 @@ static int mdt_cross_open(struct mdt_thread_info *info, if (rc != 0) GOTO(out, rc); + mdt_pack_secctx_in_reply(info, o); + rc = mdt_finish_open(info, NULL, o, open_flags, 0, rep); } else { /* @@ -1566,7 +1568,9 @@ again: PNAME(&rr->rr_name), PFID(child_fid)); GOTO(out_child, result = -EIO); } - } + } + + mdt_pack_secctx_in_reply(info, child); rc = mdt_check_resent_lock(info, child, lhc); if (rc < 0) { diff --git a/lustre/ptlrpc/layout.c b/lustre/ptlrpc/layout.c index 281ad9c..23673df 100644 --- a/lustre/ptlrpc/layout.c +++ b/lustre/ptlrpc/layout.c @@ -435,24 +435,27 @@ static const struct req_msg_field *ldlm_intent_open_server[] = { &RMF_CAPA1, &RMF_CAPA2, &RMF_NIOBUF_INLINE, + &RMF_FILE_SECCTX }; static const struct req_msg_field *ldlm_intent_getattr_client[] = { - &RMF_PTLRPC_BODY, - &RMF_DLM_REQ, - &RMF_LDLM_INTENT, - &RMF_MDT_BODY, /* coincides with mds_getattr_name_client[] */ - &RMF_CAPA1, - &RMF_NAME + &RMF_PTLRPC_BODY, + &RMF_DLM_REQ, + &RMF_LDLM_INTENT, + &RMF_MDT_BODY, /* coincides with mds_getattr_name_client[] */ + &RMF_CAPA1, + &RMF_NAME, + &RMF_FILE_SECCTX_NAME }; static const struct req_msg_field *ldlm_intent_getattr_server[] = { - &RMF_PTLRPC_BODY, - &RMF_DLM_REP, - &RMF_MDT_BODY, - &RMF_MDT_MD, - &RMF_ACL, - &RMF_CAPA1 + &RMF_PTLRPC_BODY, + &RMF_DLM_REP, + &RMF_MDT_BODY, + &RMF_MDT_MD, + &RMF_ACL, + &RMF_CAPA1, + &RMF_FILE_SECCTX }; static const struct req_msg_field *ldlm_intent_create_client[] = { @@ -999,7 +1002,7 @@ struct req_msg_field RMF_FILE_SECCTX_NAME = EXPORT_SYMBOL(RMF_FILE_SECCTX_NAME); struct req_msg_field RMF_FILE_SECCTX = - DEFINE_MSGF("file_secctx", 0, -1, NULL, NULL); + DEFINE_MSGF("file_secctx", RMF_F_NO_SIZE_CHECK, -1, NULL, NULL); EXPORT_SYMBOL(RMF_FILE_SECCTX); struct req_msg_field RMF_LLOGD_BODY = diff --git a/lustre/tests/sanity-selinux.sh b/lustre/tests/sanity-selinux.sh index df3d512..e889432 100755 --- a/lustre/tests/sanity-selinux.sh +++ b/lustre/tests/sanity-selinux.sh @@ -381,6 +381,85 @@ test_20c() { } run_test 20c "[atomicity] concurrent access from another client (dir via lfs)" +cleanup_20d() { + umount_client $MOUNT || error "umount $MOUNT failed" + mountcli +} + +trace_cmd() { + local cmd="$@" + local xattr_prefix=$(grep -E \ + "#define[[:space:]]+XATTR_SECURITY_PREFIX[[:space:]]+" \ + /usr/include/linux/xattr.h 2>/dev/null | + awk '{print $3}' | sed s+\"++g) + local xattr_suffix=$(grep -E \ + "#define[[:space:]]+XATTR_SELINUX_SUFFIX[[:space:]]+" \ + /usr/include/linux/xattr.h 2>/dev/null | + awk '{print $3}' | sed s+\"++g) + local xattr_name=${xattr_prefix}${xattr_suffix} + + [ -z "$xattr_name" ] && xattr_name="security.selinux" + + # umount client + if [ "$MOUNT_2" ] && $(grep -q $MOUNT2' ' /proc/mounts); then + umount_client $MOUNT2 || error "umount $MOUNT2 failed" + fi + if $(grep -q $MOUNT' ' /proc/mounts); then + umount_client $MOUNT || error "umount $MOUNT failed" + fi + lustre_rmmod + # remount client + mount_client $MOUNT ${MOUNT_OPTS} || error "mount client failed" + + $LCTL set_param debug=+info + $LCTL clear + + echo $cmd + eval $cmd + + $LCTL dk | grep "get xattr '${xattr_name}'" + [ $? -eq 0 ] && error "get xattr event was triggered" || true +} + +test_20d() { + if [ $MDS1_VERSION -lt $(version_code 2.12.50) ] || + [ $CLIENT_VERSION -lt $(version_code 2.12.50) ]; then + skip "Need version >= 2.12.50" + fi + [ $MDSCOUNT -lt 2 ] && skip "needs >= 2 MDTs" + + stack_trap cleanup_20d EXIT + + local dirname=$DIR/$tdir/subdir + + mkdir -p $DIR/$tdir + mkdir $dirname + + trace_cmd stat $dirname + trace_cmd touch $dirname/f1 + trace_cmd stat $dirname/f1 + trace_cmd cat $dirname/f1 + dd if=/dev/zero of=$dirname/f1 bs=1M count=10 + trace_cmd /usr/bin/truncate -s 10240 $dirname/f1 + trace_cmd lfs setstripe -E -1 -S 4M $dirname/f2 + trace_cmd lfs migrate -E -1 -S 256K $dirname/f2 + trace_cmd lfs setdirstripe -i 1 $dirname/d2 + trace_cmd lfs migrate -m 0 $dirname/d2 + + lfs setdirstripe -i 1 -c 1 $dirname/d3 + dirname=$dirname/d3/subdir + mkdir $dirname + + trace_cmd stat $dirname + trace_cmd touch $dirname/f1 + trace_cmd stat $dirname/f1 + trace_cmd cat $dirname/f1 + dd if=/dev/zero of=$dirname/f1 bs=1M count=10 + trace_cmd /usr/bin/truncate -s 10240 $dirname/f1 + trace_cmd lfs setstripe -E -1 -S 4M $dirname/f2 + trace_cmd lfs migrate -E -1 -S 256K $dirname/f2 +} +run_test 20d "[atomicity] avoid getxattr for security context" complete $SECONDS check_and_cleanup_lustre -- 1.8.3.1