Whamcloud - gitweb
LU-9193 security: return security context for metadata ops 87/41387/3
authorBruno Faccini <bruno.faccini@intel.com>
Wed, 26 Apr 2017 10:35:28 +0000 (12:35 +0200)
committerOleg Drokin <green@whamcloud.com>
Thu, 4 Mar 2021 08:33:01 +0000 (08:33 +0000)
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.

LU-12212 mdt: fix SECCTX reply buffer handling

LU-9193 changes for inline SECCTX in reply may cause often
resends and reconnects in some loads, e.g. dbench runs.
That is caused by missed buffer shrink when SECCTX is not
used.

Patch shrinks SECCTX buffer if it is not used

Lustre-change: https://review.whamcloud.com/26831
Lustre-commit: fca35f74f9ec5c5ed77e774f3e3209d9df057a01

Lustre-change: https://review.whamcloud.com/34734
Lustre-commit: cb61ed93f8563c26b6a6db396478fe54f8dc42cb

Test-Parameters: clientselinux testlist=sanity envdefinitions=EXCEPT=103a
Test-Parameters: mdscount=2 mdtcount=4 clientselinux testlist=recovery-small,sanity-selinux
Signed-off-by: Bruno Faccini <bruno.faccini@intel.com>
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Signed-off-by: Sebastien Piechurski <sebastien.piechurski@atos.net>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Signed-off-by: Mikhail Pershin <mpershin@whamcloud.com>
Change-Id: I45659ffcb911a9d62e6d7e92bcdc251ae641b24b
Reviewed-on: https://review.whamcloud.com/41387
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
15 files changed:
lustre/autoconf/lustre-core.m4
lustre/include/obd.h
lustre/include/uapi/linux/lustre/lustre_idl.h
lustre/llite/llite_internal.h
lustre/llite/namei.c
lustre/llite/xattr_security.c
lustre/lmv/lmv_intent.c
lustre/mdc/mdc_locks.c
lustre/mdc/mdc_request.c
lustre/mdt/mdt_handler.c
lustre/mdt/mdt_internal.h
lustre/mdt/mdt_lib.c
lustre/mdt/mdt_open.c
lustre/ptlrpc/layout.c
lustre/tests/sanity-selinux.sh

index 13682c0..1e589e2 100644 (file)
@@ -1514,6 +1514,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 <linux/security.h>
+],[
+       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
@@ -3296,6 +3311,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
index 4356159..25b29fe 100644 (file)
@@ -885,8 +885,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;
 
index 336f2d2..c1fd62d 100644 (file)
@@ -1300,6 +1300,7 @@ lov_mds_md_max_stripe_count(__kernel_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_FLLAZYSIZE    (0x0400000000000000ULL) /* Lazy size */
 #define OBD_MD_FLLAZYBLOCKS  (0x0800000000000000ULL) /* Lazy blocks */
index e770557..a254348 100644 (file)
@@ -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.
index ce14962..36a949a 100644 (file)
@@ -620,7 +620,7 @@ 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,
-                              ktime_t kstart)
+                              void *secctx, __u32 secctxlen, ktime_t kstart)
 {
        struct inode             *inode = NULL;
        __u64                     bits = 0;
@@ -633,6 +633,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);
@@ -651,6 +655,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 && secctxlen) {
+                       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).
@@ -719,9 +750,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));
@@ -769,10 +802,32 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
                                             &op_data->op_file_secctx_size);
                if (rc < 0)
                        GOTO(out, retval = ERR_PTR(rc));
-               if (secctx != NULL)
+               if (secctx)
                        *secctx = op_data->op_file_secctx;
-               if (secctxlen != NULL)
+               if (secctxlen)
                        *secctxlen = op_data->op_file_secctx_size;
+       } else {
+               if (secctx)
+                       *secctx = NULL;
+               if (secctxlen)
+                       *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,
@@ -808,11 +863,13 @@ 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, kstart);
-        if (rc != 0) {
-                ll_intent_release(it);
-                GOTO(out, retval = ERR_PTR(rc));
-        }
+       rc = ll_lookup_it_finish(req, it, parent, &dentry,
+                                secctx ? *secctx : NULL,
+                                secctxlen ? *secctxlen : 0, kstart);
+       if (rc != 0) {
+               ll_intent_release(it);
+               GOTO(out, retval = ERR_PTR(rc));
+       }
 
         if ((it->it_op & IT_OPEN) && dentry->d_inode &&
             !S_ISREG(dentry->d_inode->i_mode) &&
@@ -825,7 +882,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
 
 out:
        if (op_data != NULL && !IS_ERR(op_data)) {
-               if (secctx != NULL && secctxlen != NULL) {
+               if (secctx && secctxlen) {
                        /* caller needs sec ctx info, so reset it in op_data to
                         * prevent it from being freed */
                        op_data->op_file_secctx = NULL;
@@ -1166,8 +1223,7 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(inode))
                RETURN(PTR_ERR(inode));
 
-       if ((ll_i2sbi(inode)->ll_flags & LL_SBI_FILE_SECCTX) &&
-           secctx != NULL) {
+       if ((ll_i2sbi(inode)->ll_flags & LL_SBI_FILE_SECCTX) && secctx) {
                inode_lock(inode);
                /* must be done before d_instantiate, because it calls
                 * security_d_instantiate, which means a getxattr if security
index 5a79702..e2bfe61 100644 (file)
@@ -199,3 +199,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 */
+}
index 361d970..83a28bf 100644 (file)
@@ -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)
@@ -402,7 +413,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);
 
@@ -507,7 +520,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);
index caffee4..f57d229 100644 (file)
@@ -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);
@@ -351,6 +351,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.
         */
@@ -433,6 +457,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
@@ -483,25 +509,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;
@@ -513,6 +552,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);
 }
index 1806fd0..8b23d8a 100644 (file)
@@ -452,6 +452,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);
index bd3bfe7..d6ef09c 100644 (file)
@@ -1735,8 +1735,10 @@ 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);
@@ -1910,17 +1912,21 @@ 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);
+       /* 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_child, rc);
+       }
+
+       mdt_pack_secctx_in_reply(info, child);
 
-        /* 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);
-       } else if (lock) {
+       lock = ldlm_handle2lock(&lhc->mlh_reg_lh);
+       if (lock) {
                /* Debugging code. */
                LDLM_DEBUG(lock, "Returning lock to client");
                LASSERTF(fid_res_name_eq(mdt_object_fid(child),
@@ -1933,14 +1939,12 @@ static int mdt_getattr_name_lock(struct mdt_thread_info *info,
                    S_ISREG(lu_object_attr(&child->mot_obj)) &&
                    !mdt_object_remote(child) && child != parent) {
                        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) {
+                       if (rc && child_bits & MDS_INODELOCK_DOM) {
                                /* DOM lock was taken in advance but this is
-                                * not DoM file. Drop the lock. */
+                                * not DoM file. Drop the lock.
+                                */
                                lock_res_and_lock(lock);
                                ldlm_inodebits_drop(lock, MDS_INODELOCK_DOM);
                                unlock_res_and_lock(lock);
@@ -1948,9 +1952,8 @@ static int mdt_getattr_name_lock(struct mdt_thread_info *info,
                        LDLM_LOCK_PUT(lock);
                        GOTO(unlock_parent, rc = 0);
                }
-       }
-       if (lock)
                LDLM_LOCK_PUT(lock);
+       }
 
        EXIT;
 out_child:
@@ -2368,6 +2371,28 @@ static int mdt_fix_attr_ucred(struct mdt_thread_info *info, __u32 op)
        return 0;
 }
 
+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)
@@ -2390,7 +2415,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
@@ -2400,33 +2425,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);
 
-        if (req_capsule_has_field(pill, &RMF_MDT_BODY, RCL_SERVER)) {
-                repbody = req_capsule_server_get(pill, &RMF_MDT_BODY);
-                LASSERT(repbody);
+       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);
                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) {
@@ -2434,12 +2461,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);
 
@@ -3626,9 +3653,14 @@ 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);
 
-                rc = req_capsule_server_pack(pill);
-        }
-        RETURN(rc);
+               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);
 }
 
 void mdt_lock_handle_init(struct mdt_lock_handle *lh)
index 1c671f3..79a17e4 100644 (file)
@@ -903,6 +903,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)
 {
index 620b5ad..bae972a 100644 (file)
@@ -777,6 +777,12 @@ int mdt_fix_reply(struct mdt_thread_info *info)
                req_capsule_shrink(pill, &RMF_LOGCOOKIES, acl_size, RCL_SERVER);
        }
 
+       /* Shrink optional SECCTX buffer if it is not used */
+       if (req_capsule_has_field(pill, &RMF_FILE_SECCTX, RCL_SERVER) &&
+           req_capsule_get_size(pill, &RMF_FILE_SECCTX, RCL_SERVER) != 0 &&
+           !(body->mbo_valid & OBD_MD_SECCTX))
+               req_capsule_shrink(pill, &RMF_FILE_SECCTX, 0, RCL_SERVER);
+
        /*
         * Some more field should be shrinked if needed.
         * This should be done by those who added fields to reply message.
@@ -1853,3 +1859,45 @@ int mdt_is_remote_object(struct mdt_thread_info *info,
 
        RETURN(0);
 }
+
+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);
+               }
+       }
+}
index e8d0653..41e2120 100644 (file)
@@ -1221,6 +1221,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 {
                        /*
@@ -1576,7 +1578,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) {
index 19ff646..7db9465 100644 (file)
@@ -460,24 +460,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[] = {
@@ -1033,7 +1036,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 =
index 96ea5fa..37d18fd 100755 (executable)
@@ -388,6 +388,86 @@ 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"
+
 check_nodemap() {
        local nm=$1
        local key=$2