Whamcloud - gitweb
LU-5560 security: send file security context for creates 71/19971/29
authorJohn L. Hammond <john.hammond@intel.com>
Thu, 11 Feb 2016 14:36:37 +0000 (08:36 -0600)
committerOleg Drokin <oleg.drokin@intel.com>
Thu, 11 Aug 2016 05:50:55 +0000 (05:50 +0000)
Send file security context to MDT along with create RPCs. This closes
the insecure window between creation and setting of the security
context that existed previously. It also avoids a potential LDLM hang
which arises from ll_create_it() when we send a MDS_SETXATTR RPC while
holding the lookup+layout lock returned from open.

Signed-off-by: John L. Hammond <john.hammond@intel.com>
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I21415593b7dd362fecbb18cf90b1dc9fbf1c13db
Reviewed-on: http://review.whamcloud.com/19971
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Dmitry Eremin <dmitry.eremin@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
16 files changed:
lustre/autoconf/lustre-core.m4
lustre/include/lustre_req_layout.h
lustre/include/md_object.h
lustre/include/obd.h
lustre/llite/dir.c
lustre/llite/llite_internal.h
lustre/llite/llite_lib.c
lustre/llite/namei.c
lustre/llite/xattr_security.c
lustre/mdc/mdc_internal.h
lustre/mdc/mdc_lib.c
lustre/mdc/mdc_locks.c
lustre/mdc/mdc_reint.c
lustre/mdd/mdd_dir.c
lustre/mdt/mdt_lib.c
lustre/ptlrpc/layout.c

index 41048be..f47d26c 100644 (file)
@@ -1431,6 +1431,23 @@ block_device_ops_release_return_int, [
 ]) # LC_BLKDEV_RELEASE_RETURN_INT
 
 #
 ]) # LC_BLKDEV_RELEASE_RETURN_INT
 
 #
+# LC_HAVE_SECURITY_DENTRY_INIT_SECURITY
+#
+# 3.10 introduced security_dentry_init_security()
+#
+AC_DEFUN([LC_HAVE_SECURITY_DENTRY_INIT_SECURITY], [
+LB_CHECK_COMPILE([if 'security_dentry_init_security' is defined],
+security_dentry_init_security, [
+       #include <linux/security.h>
+],[
+       security_dentry_init_security(NULL, 0, NULL, NULL, NULL);
+],[
+       AC_DEFINE(HAVE_SECURITY_DENTRY_INIT_SECURITY, 1,
+               [security_dentry_init_security' is defined])
+])
+]) # LC_HAVE_SECURITY_DENTRY_INIT_SECURITY
+
+#
 # LC_INVALIDATE_RANGE
 #
 # 3.11 invalidatepage requires the length of the range to invalidate
 # LC_INVALIDATE_RANGE
 #
 # 3.11 invalidatepage requires the length of the range to invalidate
@@ -2276,6 +2293,7 @@ AC_DEFUN([LC_PROG_LINUX], [
        LC_BLKDEV_RELEASE_RETURN_INT
        LC_HAVE_REMOVE_PROC_SUBTREE
        LC_HAVE_PROC_REMOVE
        LC_BLKDEV_RELEASE_RETURN_INT
        LC_HAVE_REMOVE_PROC_SUBTREE
        LC_HAVE_PROC_REMOVE
+       LC_HAVE_SECURITY_DENTRY_INIT_SECURITY
 
        # 3.11
        LC_INVALIDATE_RANGE
 
        # 3.11
        LC_INVALIDATE_RANGE
index 9fdc1e5..3eef31f 100644 (file)
@@ -61,7 +61,7 @@ enum req_location {
 };
 
 /* Maximal number of fields (buffers) in a request message. */
 };
 
 /* Maximal number of fields (buffers) in a request message. */
-#define REQ_MAX_FIELD_NR  9
+#define REQ_MAX_FIELD_NR 10
 
 struct req_capsule {
         struct ptlrpc_request   *rc_req;
 
 struct req_capsule {
         struct ptlrpc_request   *rc_req;
@@ -265,6 +265,8 @@ extern struct req_msg_field RMF_GETINFO_VALLEN;
 extern struct req_msg_field RMF_GETINFO_KEY;
 extern struct req_msg_field RMF_IDX_INFO;
 extern struct req_msg_field RMF_CLOSE_DATA;
 extern struct req_msg_field RMF_GETINFO_KEY;
 extern struct req_msg_field RMF_IDX_INFO;
 extern struct req_msg_field RMF_CLOSE_DATA;
+extern struct req_msg_field RMF_FILE_SECCTX_NAME;
+extern struct req_msg_field RMF_FILE_SECCTX;
 
 /*
  * connection handle received in MDS_CONNECT request.
 
 /*
  * connection handle received in MDS_CONNECT request.
index c34c6e2..1427189 100644 (file)
@@ -139,8 +139,13 @@ struct md_op_spec {
                 } sp_ea;
         } u;
 
                 } sp_ea;
         } u;
 
-        /** Create flag from client: such as MDS_OPEN_CREAT, and others. */
-        __u64      sp_cr_flags;
+       /** Create flag from client: such as MDS_OPEN_CREAT, and others. */
+       __u64      sp_cr_flags;
+
+       /* File security context for creates. */
+       const char      *sp_cr_file_secctx_name; /* (security) xattr name */
+       void            *sp_cr_file_secctx; /* xattr value */
+       size_t           sp_cr_file_secctx_size; /* xattr value size */
 
        /** don't create lov objects or llog cookie - this replay */
        unsigned int no_create:1,
 
        /** don't create lov objects or llog cookie - this replay */
        unsigned int no_create:1,
index 04cdca5..460ce5b 100644 (file)
@@ -834,6 +834,11 @@ struct md_op_data {
        __u64                   op_data_version;
        struct lustre_handle    op_lease_handle;
 
        __u64                   op_data_version;
        struct lustre_handle    op_lease_handle;
 
+       /* File security context, for creates. */
+       const char             *op_file_secctx_name;
+       void                   *op_file_secctx;
+       __u32                   op_file_secctx_size;
+
        /* default stripe offset */
        __u32                   op_default_stripe_offset;
 };
        /* default stripe offset */
        __u32                   op_default_stripe_offset;
 };
index 3536107..2018afa 100644 (file)
@@ -438,22 +438,30 @@ static int ll_send_mgc_param(struct obd_export *mgc, char *string)
 /**
  * Create striped directory with specified stripe(@lump)
  *
 /**
  * Create striped directory with specified stripe(@lump)
  *
- * param[in]parent     the parent of the directory.
- * param[in]lump       the specified stripes.
- * param[in]dirname    the name of the directory.
- * param[in]mode       the specified mode of the directory.
+ * \param[in] dparent  the parent of the directory.
+ * \param[in] lump     the specified stripes.
+ * \param[in] dirname  the name of the directory.
+ * \param[in] mode     the specified mode of the directory.
  *
  *
- * retval              =0 if striped directory is being created successfully.
+ * \retval             =0 if striped directory is being created successfully.
  *                      <0 if the creation is failed.
  */
  *                      <0 if the creation is failed.
  */
-static int ll_dir_setdirstripe(struct inode *parent, struct lmv_user_md *lump,
+static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
                               const char *dirname, umode_t mode)
 {
                               const char *dirname, umode_t mode)
 {
+       struct inode *parent = dparent->d_inode;
        struct ptlrpc_request *request = NULL;
        struct md_op_data *op_data;
        struct ll_sb_info *sbi = ll_i2sbi(parent);
        struct inode *inode = NULL;
        struct ptlrpc_request *request = NULL;
        struct md_op_data *op_data;
        struct ll_sb_info *sbi = ll_i2sbi(parent);
        struct inode *inode = NULL;
-       struct dentry dentry;
+       struct dentry dentry = {
+               .d_parent = dparent,
+               .d_name = {
+                       .name = dirname,
+                       .len = strlen(dirname),
+                       .hash = full_name_hash(dirname, strlen(dirname)),
+               },
+       };
        int err;
        ENTRY;
 
        int err;
        ENTRY;
 
@@ -483,33 +491,50 @@ static int ll_dir_setdirstripe(struct inode *parent, struct lmv_user_md *lump,
                                     strlen(dirname), mode, LUSTRE_OPC_MKDIR,
                                     lump);
        if (IS_ERR(op_data))
                                     strlen(dirname), mode, LUSTRE_OPC_MKDIR,
                                     lump);
        if (IS_ERR(op_data))
-               GOTO(err_exit, err = PTR_ERR(op_data));
+               RETURN(PTR_ERR(op_data));
+
+       if (sbi->ll_flags & LL_SBI_FILE_SECCTX) {
+               /* selinux_dentry_init_security() uses dentry->d_parent and name
+                * to determine the security context for the file. So our fake
+                * dentry should be real enough for this purpose. */
+               err = ll_dentry_init_security(&dentry, mode, &dentry.d_name,
+                                             &op_data->op_file_secctx_name,
+                                             &op_data->op_file_secctx,
+                                             &op_data->op_file_secctx_size);
+               if (err < 0)
+                       GOTO(out_op_data, err);
+       }
 
        op_data->op_cli_flags |= CLI_SET_MEA;
        err = md_create(sbi->ll_md_exp, op_data, lump, sizeof(*lump), mode,
                        from_kuid(&init_user_ns, current_fsuid()),
                        from_kgid(&init_user_ns, current_fsgid()),
                        cfs_curproc_cap_pack(), 0, &request);
 
        op_data->op_cli_flags |= CLI_SET_MEA;
        err = md_create(sbi->ll_md_exp, op_data, lump, sizeof(*lump), mode,
                        from_kuid(&init_user_ns, current_fsuid()),
                        from_kgid(&init_user_ns, current_fsgid()),
                        cfs_curproc_cap_pack(), 0, &request);
-       ll_finish_md_op_data(op_data);
        if (err)
        if (err)
-               GOTO(err_exit, err);
+               GOTO(out_request, err);
 
        CFS_FAIL_TIMEOUT(OBD_FAIL_LLITE_SETDIRSTRIPE_PAUSE, cfs_fail_val);
 
        err = ll_prep_inode(&inode, request, parent->i_sb, NULL);
        if (err)
 
        CFS_FAIL_TIMEOUT(OBD_FAIL_LLITE_SETDIRSTRIPE_PAUSE, cfs_fail_val);
 
        err = ll_prep_inode(&inode, request, parent->i_sb, NULL);
        if (err)
-               GOTO(err_exit, err);
+               GOTO(out_inode, err);
 
 
-       memset(&dentry, 0, sizeof(dentry));
        dentry.d_inode = inode;
 
        dentry.d_inode = inode;
 
-       err = ll_init_security(&dentry, inode, parent);
-       iput(inode);
-       if (err)
-               GOTO(err_exit, err);
+       if (!(sbi->ll_flags & LL_SBI_FILE_SECCTX)) {
+               err = ll_inode_init_security(&dentry, inode, parent);
+               if (err)
+                       GOTO(out_inode, err);
+       }
 
 
-err_exit:
+out_inode:
+       if (inode != NULL)
+               iput(inode);
+out_request:
        ptlrpc_req_finished(request);
        ptlrpc_req_finished(request);
+out_op_data:
+       ll_finish_md_op_data(op_data);
+
        return err;
 }
 
        return err;
 }
 
@@ -1093,6 +1118,7 @@ static char *ll_getname(const char __user *filename)
 
 static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 
 static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
+       struct dentry *dentry = file_dentry(file);
        struct inode *inode = file_inode(file);
         struct ll_sb_info *sbi = ll_i2sbi(inode);
         struct obd_ioctl_data *data;
        struct inode *inode = file_inode(file);
         struct ll_sb_info *sbi = ll_i2sbi(inode);
         struct obd_ioctl_data *data;
@@ -1201,7 +1227,7 @@ out_free:
 #else
                mode = data->ioc_type;
 #endif
 #else
                mode = data->ioc_type;
 #endif
-               rc = ll_dir_setdirstripe(inode, lum, filename, mode);
+               rc = ll_dir_setdirstripe(dentry, lum, filename, mode);
 lmv_out_free:
                obd_ioctl_freedata(buf, len);
                RETURN(rc);
 lmv_out_free:
                obd_ioctl_freedata(buf, len);
                RETURN(rc);
index f2971e5..f11ecdd 100644 (file)
@@ -291,9 +291,11 @@ int ll_xattr_cache_get(struct inode *inode,
                        size_t size,
                        __u64 valid);
 
                        size_t size,
                        __u64 valid);
 
-int ll_init_security(struct dentry *dentry,
-                           struct inode *inode,
-                           struct inode *dir);
+int ll_dentry_init_security(struct dentry *dentry, int mode, struct qstr *name,
+                           const char **secctx_name, void **secctx,
+                           __u32 *secctx_size);
+int ll_inode_init_security(struct dentry *dentry, struct inode *inode,
+                          struct inode *dir);
 
 /*
  * Locking to guarantee consistency of non-atomic updates to long long i_size,
 
 /*
  * Locking to guarantee consistency of non-atomic updates to long long i_size,
@@ -424,6 +426,7 @@ enum stats_track_type {
 #define LL_SBI_ALWAYS_PING   0x200000 /* always ping even if server
                                       * suppress_pings */
 #define LL_SBI_FAST_READ     0x400000 /* fast read support */
 #define LL_SBI_ALWAYS_PING   0x200000 /* always ping even if server
                                       * suppress_pings */
 #define LL_SBI_FAST_READ     0x400000 /* fast read support */
+#define LL_SBI_FILE_SECCTX   0x800000 /* set file security context at create */
 
 #define LL_SBI_FLAGS {         \
        "nolck",        \
 
 #define LL_SBI_FLAGS {         \
        "nolck",        \
@@ -449,6 +452,7 @@ enum stats_track_type {
        "norootsquash", \
        "always_ping",  \
        "fast_read",    \
        "norootsquash", \
        "always_ping",  \
        "fast_read",    \
+       "file_secctx",  \
 }
 
 /* This is embedded into llite super-blocks to keep track of connect
 }
 
 /* This is embedded into llite super-blocks to keep track of connect
index be4fc6f..edae212 100644 (file)
@@ -50,6 +50,7 @@
 #ifdef HAVE_UIDGID_HEADER
 # include <linux/uidgid.h>
 #endif
 #ifdef HAVE_UIDGID_HEADER
 # include <linux/uidgid.h>
 #endif
+#include <linux/security.h>
 
 #include <lustre_ioctl.h>
 #include <lustre_ha.h>
 
 #include <lustre_ioctl.h>
 #include <lustre_ha.h>
@@ -161,6 +162,12 @@ static void ll_free_sbi(struct super_block *sb)
        EXIT;
 }
 
        EXIT;
 }
 
+static inline int obd_connect_has_secctx(struct obd_connect_data *data)
+{
+       return data->ocd_connect_flags & OBD_CONNECT_FLAGS2 &&
+              data->ocd_connect_flags2 & OBD_CONNECT2_FILE_SECCTX;
+}
+
 static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
                                     struct vfsmount *mnt)
 {
 static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
                                     struct vfsmount *mnt)
 {
@@ -248,6 +255,10 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
        if (sbi->ll_flags & LL_SBI_ALWAYS_PING)
                data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS;
 
        if (sbi->ll_flags & LL_SBI_ALWAYS_PING)
                data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS;
 
+#ifdef HAVE_SECURITY_DENTRY_INIT_SECURITY
+       data->ocd_connect_flags2 |= OBD_CONNECT2_FILE_SECCTX;
+#endif /* HAVE_SECURITY_DENTRY_INIT_SECURITY */
+
        data->ocd_brw_size = MD_MAX_BRW_SIZE;
 
         err = obd_connect(NULL, &sbi->ll_md_exp, obd, &sbi->ll_sb_uuid, data, NULL);
        data->ocd_brw_size = MD_MAX_BRW_SIZE;
 
         err = obd_connect(NULL, &sbi->ll_md_exp, obd, &sbi->ll_sb_uuid, data, NULL);
@@ -352,6 +363,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
        if (data->ocd_connect_flags & OBD_CONNECT_LAYOUTLOCK)
                sbi->ll_flags |= LL_SBI_LAYOUT_LOCK;
 
        if (data->ocd_connect_flags & OBD_CONNECT_LAYOUTLOCK)
                sbi->ll_flags |= LL_SBI_LAYOUT_LOCK;
 
+       if (obd_connect_has_secctx(data))
+               sbi->ll_flags |= LL_SBI_FILE_SECCTX;
+
        if (data->ocd_ibits_known & MDS_INODELOCK_XATTR) {
                if (!(data->ocd_connect_flags & OBD_CONNECT_MAX_EASIZE)) {
                        LCONSOLE_INFO("%s: disabling xattr cache due to "
        if (data->ocd_ibits_known & MDS_INODELOCK_XATTR) {
                if (!(data->ocd_connect_flags & OBD_CONNECT_MAX_EASIZE)) {
                        LCONSOLE_INFO("%s: disabling xattr cache due to "
@@ -2465,6 +2479,8 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
 
 void ll_finish_md_op_data(struct md_op_data *op_data)
 {
 
 void ll_finish_md_op_data(struct md_op_data *op_data)
 {
+       security_release_secctx(op_data->op_file_secctx,
+                               op_data->op_file_secctx_size);
         OBD_FREE_PTR(op_data);
 }
 
         OBD_FREE_PTR(op_data);
 }
 
index 1427c6a..89624e6 100644 (file)
@@ -591,12 +591,23 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
        op_data = ll_prep_md_op_data(NULL, parent, NULL, dentry->d_name.name,
                                     dentry->d_name.len, 0, opc, NULL);
        if (IS_ERR(op_data))
        op_data = ll_prep_md_op_data(NULL, parent, NULL, dentry->d_name.name,
                                     dentry->d_name.len, 0, opc, NULL);
        if (IS_ERR(op_data))
-               RETURN((void *)op_data);
+               GOTO(out, retval = ERR_CAST(op_data));
 
        /* enforce umask if acl disabled or MDS doesn't support umask */
        if (!IS_POSIXACL(parent) || !exp_connect_umask(ll_i2mdexp(parent)))
                it->it_create_mode &= ~current_umask();
 
 
        /* enforce umask if acl disabled or MDS doesn't support umask */
        if (!IS_POSIXACL(parent) || !exp_connect_umask(ll_i2mdexp(parent)))
                it->it_create_mode &= ~current_umask();
 
+       if (it->it_op & IT_CREAT &&
+           ll_i2sbi(parent)->ll_flags & LL_SBI_FILE_SECCTX) {
+               rc = ll_dentry_init_security(dentry, it->it_create_mode,
+                                            &dentry->d_name,
+                                            &op_data->op_file_secctx_name,
+                                            &op_data->op_file_secctx,
+                                            &op_data->op_file_secctx_size);
+               if (rc < 0)
+                       GOTO(out, retval = ERR_PTR(rc));
+       }
+
        rc = md_intent_lock(ll_i2mdexp(parent), op_data, it, &req,
                            &ll_md_blocking_ast, 0);
        /* If the MDS allows the client to chgrp (CFS_SETGRP_PERM), but the
        rc = md_intent_lock(ll_i2mdexp(parent), op_data, it, &req,
                            &ll_md_blocking_ast, 0);
        /* If the MDS allows the client to chgrp (CFS_SETGRP_PERM), but the
@@ -920,9 +931,11 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry,
 
        d_instantiate(dentry, inode);
 
 
        d_instantiate(dentry, inode);
 
-       rc = ll_init_security(dentry, inode, dir);
-       if (rc)
-               RETURN(rc);
+       if (!(ll_i2sbi(inode)->ll_flags & LL_SBI_FILE_SECCTX)) {
+               rc = ll_inode_init_security(dentry, inode, dir);
+               if (rc)
+                       RETURN(rc);
+       }
 
        RETURN(0);
 }
 
        RETURN(0);
 }
@@ -962,16 +975,26 @@ static int ll_new_node(struct inode *dir, struct dentry *dchild,
                 tgt_len = strlen(tgt) + 1;
 
 again:
                 tgt_len = strlen(tgt) + 1;
 
 again:
-        op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name,
-                                     name->len, 0, opc, NULL);
-        if (IS_ERR(op_data))
-                GOTO(err_exit, err = PTR_ERR(op_data));
+       op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name,
+                                    name->len, 0, opc, NULL);
+       if (IS_ERR(op_data))
+               GOTO(err_exit, err = PTR_ERR(op_data));
+
+       if (sbi->ll_flags & LL_SBI_FILE_SECCTX) {
+               err = ll_dentry_init_security(dchild, mode, &dchild->d_name,
+                                             &op_data->op_file_secctx_name,
+                                             &op_data->op_file_secctx,
+                                             &op_data->op_file_secctx_size);
+               if (err < 0)
+                       GOTO(err_exit, err);
+       }
 
        err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
                        from_kuid(&init_user_ns, current_fsuid()),
                        from_kgid(&init_user_ns, current_fsgid()),
                        cfs_curproc_cap_pack(), rdev, &request);
        ll_finish_md_op_data(op_data);
 
        err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
                        from_kuid(&init_user_ns, current_fsuid()),
                        from_kgid(&init_user_ns, current_fsgid()),
                        cfs_curproc_cap_pack(), rdev, &request);
        ll_finish_md_op_data(op_data);
+       op_data = NULL;
        if (err < 0 && err != -EREMOTE)
                GOTO(err_exit, err);
 
        if (err < 0 && err != -EREMOTE)
                GOTO(err_exit, err);
 
@@ -1018,16 +1041,21 @@ again:
 
        d_instantiate(dchild, inode);
 
 
        d_instantiate(dchild, inode);
 
-       err = ll_init_security(dchild, inode, dir);
-       if (err)
-               GOTO(err_exit, err);
+       if (!(sbi->ll_flags & LL_SBI_FILE_SECCTX)) {
+               err = ll_inode_init_security(dchild, inode, dir);
+               if (err)
+                       GOTO(err_exit, err);
+       }
 
 
-        EXIT;
+       EXIT;
 err_exit:
        if (request != NULL)
                ptlrpc_req_finished(request);
 
 err_exit:
        if (request != NULL)
                ptlrpc_req_finished(request);
 
-        return err;
+       if (!IS_ERR_OR_NULL(op_data))
+               ll_finish_md_op_data(op_data);
+
+       return err;
 }
 
 static int ll_mknod(struct inode *dir, struct dentry *dchild, ll_umode_t mode,
 }
 
 static int ll_mknod(struct inode *dir, struct dentry *dchild, ll_umode_t mode,
index 4cb17b5..37ba2a4 100644 (file)
  * Handler for storing security labels as extended attributes.
  */
 
  * Handler for storing security labels as extended attributes.
  */
 
-
+#include <linux/types.h>
 #include <linux/security.h>
 #include <linux/selinux.h>
 #include <linux/xattr.h>
 #include "llite_internal.h"
 
 #include <linux/security.h>
 #include <linux/selinux.h>
 #include <linux/xattr.h>
 #include "llite_internal.h"
 
+#ifndef XATTR_SELINUX_SUFFIX
+# define XATTR_SELINUX_SUFFIX "selinux"
+#endif
+
+#ifndef XATTR_NAME_SELINUX
+# define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+#endif
+
+/*
+ * Check for LL_SBI_FILE_SECCTX before calling.
+ */
+int ll_dentry_init_security(struct dentry *dentry, int mode, struct qstr *name,
+                           const char **secctx_name, void **secctx,
+                           __u32 *secctx_size)
+{
+#ifdef HAVE_SECURITY_DENTRY_INIT_SECURITY
+       int rc;
+
+       /* security_dentry_init_security() is strange. Like
+        * security_inode_init_security() it may return a context (provided a
+        * Linux security module is enabled) but unlike
+        * security_inode_init_security() it does not return to us the name of
+        * the extended attribute to store the context under (for example
+        * "security.selinux"). So we only call it when we think we know what
+        * the name of the extended attribute will be. This is OK-ish since
+        * SELinux is the only module that implements
+        * security_dentry_init_security(). Note that the NFS client code just
+        * calls it and assumes that if anything is returned then it must come
+        * from SELinux. */
+
+       if (!selinux_is_enabled())
+               return 0;
+
+       rc = security_dentry_init_security(dentry, mode, name, secctx,
+                                          secctx_size);
+       if (rc < 0)
+               return rc;
+
+       *secctx_name = XATTR_NAME_SELINUX;
+#endif /* HAVE_SECURITY_DENTRY_INIT_SECURITY */
+
+       return 0;
+}
+
 #ifdef HAVE_SECURITY_IINITSEC_CALLBACK
 /**
  * A helper function for ll_security_inode_init_security()
 #ifdef HAVE_SECURITY_IINITSEC_CALLBACK
 /**
  * A helper function for ll_security_inode_init_security()
@@ -89,7 +133,8 @@ ll_initxattrs(struct inode *inode, const struct xattr *xattr_array,
  * \retval < 0      failure to get security context or set xattr
  */
 int
  * \retval < 0      failure to get security context or set xattr
  */
 int
-ll_init_security(struct dentry *dentry, struct inode *inode, struct inode *dir)
+ll_inode_init_security(struct dentry *dentry, struct inode *inode,
+                      struct inode *dir)
 {
        if (!selinux_is_enabled())
                return 0;
 {
        if (!selinux_is_enabled())
                return 0;
@@ -109,7 +154,8 @@ ll_init_security(struct dentry *dentry, struct inode *inode, struct inode *dir)
  * \retval < 0      failure to get security context or set xattr
  */
 int
  * \retval < 0      failure to get security context or set xattr
  */
 int
-ll_init_security(struct dentry *dentry, struct inode *inode, struct inode *dir)
+ll_inode_init_security(struct dentry *dentry, struct inode *inode,
+                      struct inode *dir)
 {
        int err;
        size_t len, name_len;
 {
        int err;
        size_t len, name_len;
index 48bad01..b88d7f5 100644 (file)
@@ -59,6 +59,10 @@ void mdc_create_pack(struct ptlrpc_request *req, struct md_op_data *op_data,
 void mdc_open_pack(struct ptlrpc_request *req, struct md_op_data *op_data,
                   umode_t mode, __u64 rdev, __u64 flags,
                   const void *data, size_t datalen);
 void mdc_open_pack(struct ptlrpc_request *req, struct md_op_data *op_data,
                   umode_t mode, __u64 rdev, __u64 flags,
                   const void *data, size_t datalen);
+void mdc_file_secctx_pack(struct ptlrpc_request *req,
+                         const char *secctx_name,
+                         const void *secctx, size_t secctx_size);
+
 void mdc_unlink_pack(struct ptlrpc_request *req, struct md_op_data *op_data);
 void mdc_getxattr_pack(struct ptlrpc_request *req, struct md_op_data *op_data);
 void mdc_link_pack(struct ptlrpc_request *req, struct md_op_data *op_data);
 void mdc_unlink_pack(struct ptlrpc_request *req, struct md_op_data *op_data);
 void mdc_getxattr_pack(struct ptlrpc_request *req, struct md_op_data *op_data);
 void mdc_link_pack(struct ptlrpc_request *req, struct md_op_data *op_data);
index 62e1cf9..f79c3a9 100644 (file)
@@ -119,6 +119,30 @@ static void mdc_pack_name(struct ptlrpc_request *req,
        LASSERT(cpy_len == name_len && lu_name_is_valid_2(buf, cpy_len));
 }
 
        LASSERT(cpy_len == name_len && lu_name_is_valid_2(buf, cpy_len));
 }
 
+void mdc_file_secctx_pack(struct ptlrpc_request *req, const char *secctx_name,
+                         const void *secctx, size_t secctx_size)
+{
+       void *buf;
+       size_t buf_size;
+
+       if (secctx_name == NULL)
+               return;
+
+       buf = req_capsule_client_get(&req->rq_pill, &RMF_FILE_SECCTX_NAME);
+       buf_size = req_capsule_get_size(&req->rq_pill, &RMF_FILE_SECCTX_NAME,
+                                       RCL_CLIENT);
+
+       LASSERT(buf_size == strlen(secctx_name) + 1);
+       memcpy(buf, secctx_name, buf_size);
+
+       buf = req_capsule_client_get(&req->rq_pill, &RMF_FILE_SECCTX);
+       buf_size = req_capsule_get_size(&req->rq_pill, &RMF_FILE_SECCTX,
+                                       RCL_CLIENT);
+
+       LASSERT(buf_size == secctx_size);
+       memcpy(buf, secctx, buf_size);
+}
+
 void mdc_readdir_pack(struct ptlrpc_request *req, __u64 pgoff, size_t size,
                      const struct lu_fid *fid)
 {
 void mdc_readdir_pack(struct ptlrpc_request *req, __u64 pgoff, size_t size,
                      const struct lu_fid *fid)
 {
@@ -168,6 +192,10 @@ void mdc_create_pack(struct ptlrpc_request *req, struct md_op_data *op_data,
                tmp = req_capsule_client_get(&req->rq_pill, &RMF_EADATA);
                memcpy(tmp, data, datalen);
        }
                tmp = req_capsule_client_get(&req->rq_pill, &RMF_EADATA);
                memcpy(tmp, data, datalen);
        }
+
+       mdc_file_secctx_pack(req, op_data->op_file_secctx_name,
+                            op_data->op_file_secctx,
+                            op_data->op_file_secctx_size);
 }
 
 static inline __u64 mds_pack_open_flags(__u64 flags)
 }
 
 static inline __u64 mds_pack_open_flags(__u64 flags)
@@ -237,6 +265,10 @@ void mdc_open_pack(struct ptlrpc_request *req, struct md_op_data *op_data,
                        if (op_data->op_bias & MDS_CREATE_VOLATILE)
                                cr_flags |= MDS_OPEN_VOLATILE;
                }
                        if (op_data->op_bias & MDS_CREATE_VOLATILE)
                                cr_flags |= MDS_OPEN_VOLATILE;
                }
+
+               mdc_file_secctx_pack(req, op_data->op_file_secctx_name,
+                                    op_data->op_file_secctx,
+                                    op_data->op_file_secctx_size);
        }
 
        if (lmm) {
        }
 
        if (lmm) {
index 53c74e7..08f226e 100644 (file)
@@ -295,6 +295,13 @@ mdc_intent_open_pack(struct obd_export *exp, struct lookup_intent *it,
        req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_CLIENT,
                             max(lmmsize, obddev->u.cli.cl_default_mds_easize));
 
        req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_CLIENT,
                             max(lmmsize, obddev->u.cli.cl_default_mds_easize));
 
+       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);
+
+       req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX, RCL_CLIENT,
+                            op_data->op_file_secctx_size);
+
        rc = ldlm_prep_enqueue_req(exp, req, &cancels, count);
        if (rc < 0) {
                ptlrpc_request_free(req);
        rc = ldlm_prep_enqueue_req(exp, req, &cancels, count);
        if (rc < 0) {
                ptlrpc_request_free(req);
index 4abd2bc..5044b89 100644 (file)
@@ -197,6 +197,13 @@ rebuild:
         req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_CLIENT,
                              data && datalen ? datalen : 0);
 
         req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_CLIENT,
                              data && datalen ? datalen : 0);
 
+       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);
+
+       req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX, RCL_CLIENT,
+                            op_data->op_file_secctx_size);
+
        rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
        if (rc) {
                ptlrpc_request_free(req);
        rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
        if (rc) {
                ptlrpc_request_free(req);
index bb96d7c..0e4d287 100644 (file)
@@ -2016,6 +2016,7 @@ static int mdd_declare_object_create(const struct lu_env *env,
                                     struct lu_buf *acl_buf,
                                     struct dt_allocation_hint *hint)
 {
                                     struct lu_buf *acl_buf,
                                     struct dt_allocation_hint *hint)
 {
+       const struct lu_buf *buf;
        int rc;
 
        rc = mdd_declare_object_create_internal(env, p, c, attr, handle, spec,
        int rc;
 
        rc = mdd_declare_object_create_internal(env, p, c, attr, handle, spec,
@@ -2051,8 +2052,6 @@ static int mdd_declare_object_create(const struct lu_env *env,
        /* replay case, create LOV EA from client data */
        if (spec->no_create ||
            (spec->sp_cr_flags & MDS_OPEN_HAS_EA && S_ISREG(attr->la_mode))) {
        /* replay case, create LOV EA from client data */
        if (spec->no_create ||
            (spec->sp_cr_flags & MDS_OPEN_HAS_EA && S_ISREG(attr->la_mode))) {
-               const struct lu_buf *buf;
-
                buf = mdd_buf_get_const(env, spec->u.sp_ea.eadata,
                                        spec->u.sp_ea.eadatalen);
                rc = mdo_declare_xattr_set(env, c, buf, XATTR_NAME_LOV, 0,
                buf = mdd_buf_get_const(env, spec->u.sp_ea.eadata,
                                        spec->u.sp_ea.eadatalen);
                rc = mdo_declare_xattr_set(env, c, buf, XATTR_NAME_LOV, 0,
@@ -2072,6 +2071,16 @@ static int mdd_declare_object_create(const struct lu_env *env,
                 if (rc)
                         GOTO(out, rc);
         }
                 if (rc)
                         GOTO(out, rc);
         }
+
+       if (spec->sp_cr_file_secctx_name != NULL) {
+               buf = mdd_buf_get_const(env, spec->sp_cr_file_secctx,
+                                       spec->sp_cr_file_secctx_size);
+               rc = mdo_declare_xattr_set(env, c, buf,
+                                          spec->sp_cr_file_secctx_name, 0,
+                                          handle);
+               if (rc < 0)
+                       GOTO(out, rc);
+       }
 out:
        return rc;
 }
 out:
        return rc;
 }
@@ -2182,6 +2191,7 @@ static int mdd_object_create(const struct lu_env *env, struct mdd_object *pobj,
                             struct dt_allocation_hint *hint,
                             struct thandle *handle)
 {
                             struct dt_allocation_hint *hint,
                             struct thandle *handle)
 {
+       const struct lu_buf    *buf;
        int                     rc;
 
        mdd_write_lock(env, son, MOR_TGT_CHILD);
        int                     rc;
 
        mdd_write_lock(env, son, MOR_TGT_CHILD);
@@ -2217,8 +2227,6 @@ static int mdd_object_create(const struct lu_env *env, struct mdd_object *pobj,
        if (spec->no_create ||
            (S_ISREG(attr->la_mode) && spec->sp_cr_flags & MDS_OPEN_HAS_EA) ||
            S_ISDIR(attr->la_mode)) {
        if (spec->no_create ||
            (S_ISREG(attr->la_mode) && spec->sp_cr_flags & MDS_OPEN_HAS_EA) ||
            S_ISDIR(attr->la_mode)) {
-               const struct lu_buf *buf;
-
                buf = mdd_buf_get_const(env, spec->u.sp_ea.eadata,
                                        spec->u.sp_ea.eadatalen);
                rc = mdo_xattr_set(env, son, buf,
                buf = mdd_buf_get_const(env, spec->u.sp_ea.eadata,
                                        spec->u.sp_ea.eadatalen);
                rc = mdo_xattr_set(env, son, buf,
@@ -2268,6 +2276,15 @@ static int mdd_object_create(const struct lu_env *env, struct mdd_object *pobj,
                        GOTO(err_initlized, rc = -EFAULT);
        }
 
                        GOTO(err_initlized, rc = -EFAULT);
        }
 
+       if (spec->sp_cr_file_secctx_name != NULL) {
+               buf = mdd_buf_get_const(env, spec->sp_cr_file_secctx,
+                                       spec->sp_cr_file_secctx_size);
+               rc = mdo_xattr_set(env, son, buf, spec->sp_cr_file_secctx_name,
+                                  0, handle);
+               if (rc < 0)
+                       GOTO(err_initlized, rc);
+       }
+
 err_initlized:
        if (unlikely(rc != 0)) {
                int rc2;
 err_initlized:
        if (unlikely(rc != 0)) {
                int rc2;
index 990b482..de68b11 100644 (file)
@@ -852,6 +852,41 @@ int mdt_name_unpack(struct req_capsule *pill,
        return 0;
 }
 
        return 0;
 }
 
+static int mdt_file_secctx_unpack(struct req_capsule *pill,
+                                 const char **secctx_name,
+                                 void **secctx, size_t *secctx_size)
+{
+       const char *name;
+       size_t name_size;
+
+       *secctx_name = NULL;
+       *secctx = NULL;
+       *secctx_size = 0;
+
+       if (!req_capsule_has_field(pill, &RMF_FILE_SECCTX_NAME, RCL_CLIENT) ||
+           !req_capsule_field_present(pill, &RMF_FILE_SECCTX_NAME, RCL_CLIENT))
+               return 0;
+
+       name_size = req_capsule_get_size(pill, &RMF_FILE_SECCTX_NAME,
+                                        RCL_CLIENT);
+       if (name_size == 0)
+               return 0;
+
+       name = req_capsule_client_get(pill, &RMF_FILE_SECCTX_NAME);
+       if (strnlen(name, name_size) != name_size - 1)
+               return -EPROTO;
+
+       if (!req_capsule_has_field(pill, &RMF_FILE_SECCTX, RCL_CLIENT) ||
+           !req_capsule_field_present(pill, &RMF_FILE_SECCTX, RCL_CLIENT))
+               return -EPROTO;
+
+       *secctx_name = name;
+       *secctx = req_capsule_client_get(pill, &RMF_FILE_SECCTX);
+       *secctx_size = req_capsule_get_size(pill, &RMF_FILE_SECCTX, RCL_CLIENT);
+
+       return 0;
+}
+
 static int mdt_setattr_unpack_rec(struct mdt_thread_info *info)
 {
        struct lu_ucred         *uc = mdt_ucred(info);
 static int mdt_setattr_unpack_rec(struct mdt_thread_info *info)
 {
        struct lu_ucred         *uc = mdt_ucred(info);
@@ -1087,6 +1122,12 @@ static int mdt_create_unpack(struct mdt_thread_info *info)
                }
        }
 
                }
        }
 
+       rc = mdt_file_secctx_unpack(pill, &sp->sp_cr_file_secctx_name,
+                                   &sp->sp_cr_file_secctx,
+                                   &sp->sp_cr_file_secctx_size);
+       if (rc < 0)
+               RETURN(rc);
+
        rc = mdt_dlmreq_unpack(info);
        RETURN(rc);
 }
        rc = mdt_dlmreq_unpack(info);
        RETURN(rc);
 }
@@ -1278,6 +1319,7 @@ static int mdt_open_unpack(struct mdt_thread_info *info)
         struct mdt_reint_record *rr   = &info->mti_rr;
         struct ptlrpc_request   *req  = mdt_info_req(info);
         struct md_op_spec       *sp   = &info->mti_spec;
         struct mdt_reint_record *rr   = &info->mti_rr;
         struct ptlrpc_request   *req  = mdt_info_req(info);
         struct md_op_spec       *sp   = &info->mti_spec;
+       int rc;
         ENTRY;
 
         CLASSERT(sizeof(struct mdt_rec_create) == sizeof(struct mdt_rec_reint));
         ENTRY;
 
         CLASSERT(sizeof(struct mdt_rec_create) == sizeof(struct mdt_rec_reint));
@@ -1337,7 +1379,11 @@ static int mdt_open_unpack(struct mdt_thread_info *info)
                        rr->rr_eadatalen = MIN_MD_SIZE;
        }
 
                        rr->rr_eadatalen = MIN_MD_SIZE;
        }
 
-        RETURN(0);
+       rc = mdt_file_secctx_unpack(pill, &sp->sp_cr_file_secctx_name,
+                                   &sp->sp_cr_file_secctx,
+                                   &sp->sp_cr_file_secctx_size);
+
+       RETURN(rc);
 }
 
 static int mdt_setxattr_unpack(struct mdt_thread_info *info)
 }
 
 static int mdt_setxattr_unpack(struct mdt_thread_info *info)
index 92f31e2..6bb87ec 100644 (file)
@@ -216,30 +216,36 @@ static const struct req_msg_field *mds_reint_create_slave_client[] = {
 };
 
 static const struct req_msg_field *mds_reint_create_acl_client[] = {
 };
 
 static const struct req_msg_field *mds_reint_create_acl_client[] = {
-        &RMF_PTLRPC_BODY,
-        &RMF_REC_REINT,
-        &RMF_CAPA1,
-        &RMF_NAME,
-        &RMF_EADATA,
-        &RMF_DLM_REQ
+       &RMF_PTLRPC_BODY,
+       &RMF_REC_REINT,
+       &RMF_CAPA1,
+       &RMF_NAME,
+       &RMF_EADATA,
+       &RMF_DLM_REQ,
+       &RMF_FILE_SECCTX_NAME,
+       &RMF_FILE_SECCTX
 };
 
 static const struct req_msg_field *mds_reint_create_sym_client[] = {
 };
 
 static const struct req_msg_field *mds_reint_create_sym_client[] = {
-        &RMF_PTLRPC_BODY,
-        &RMF_REC_REINT,
-        &RMF_CAPA1,
-        &RMF_NAME,
-        &RMF_SYMTGT,
-        &RMF_DLM_REQ
+       &RMF_PTLRPC_BODY,
+       &RMF_REC_REINT,
+       &RMF_CAPA1,
+       &RMF_NAME,
+       &RMF_SYMTGT,
+       &RMF_DLM_REQ,
+       &RMF_FILE_SECCTX_NAME,
+       &RMF_FILE_SECCTX
 };
 
 static const struct req_msg_field *mds_reint_open_client[] = {
 };
 
 static const struct req_msg_field *mds_reint_open_client[] = {
-        &RMF_PTLRPC_BODY,
-        &RMF_REC_REINT,
-        &RMF_CAPA1,
-        &RMF_CAPA2,
-        &RMF_NAME,
-        &RMF_EADATA
+       &RMF_PTLRPC_BODY,
+       &RMF_REC_REINT,
+       &RMF_CAPA1,
+       &RMF_CAPA2,
+       &RMF_NAME,
+       &RMF_EADATA,
+       &RMF_FILE_SECCTX_NAME,
+       &RMF_FILE_SECCTX
 };
 
 static const struct req_msg_field *mds_reint_open_server[] = {
 };
 
 static const struct req_msg_field *mds_reint_open_server[] = {
@@ -453,24 +459,28 @@ static const struct req_msg_field *ldlm_intent_getattr_server[] = {
 };
 
 static const struct req_msg_field *ldlm_intent_create_client[] = {
 };
 
 static const struct req_msg_field *ldlm_intent_create_client[] = {
-        &RMF_PTLRPC_BODY,
-        &RMF_DLM_REQ,
-        &RMF_LDLM_INTENT,
-        &RMF_REC_REINT,    /* coincides with mds_reint_create_client[] */
-        &RMF_CAPA1,
-        &RMF_NAME,
-        &RMF_EADATA
+       &RMF_PTLRPC_BODY,
+       &RMF_DLM_REQ,
+       &RMF_LDLM_INTENT,
+       &RMF_REC_REINT,    /* coincides with mds_reint_create_client[] */
+       &RMF_CAPA1,
+       &RMF_NAME,
+       &RMF_EADATA,
+       &RMF_FILE_SECCTX_NAME,
+       &RMF_FILE_SECCTX
 };
 
 static const struct req_msg_field *ldlm_intent_open_client[] = {
 };
 
 static const struct req_msg_field *ldlm_intent_open_client[] = {
-        &RMF_PTLRPC_BODY,
-        &RMF_DLM_REQ,
-        &RMF_LDLM_INTENT,
-        &RMF_REC_REINT,    /* coincides with mds_reint_open_client[] */
-        &RMF_CAPA1,
-        &RMF_CAPA2,
-        &RMF_NAME,
-        &RMF_EADATA
+       &RMF_PTLRPC_BODY,
+       &RMF_DLM_REQ,
+       &RMF_LDLM_INTENT,
+       &RMF_REC_REINT,    /* coincides with mds_reint_open_client[] */
+       &RMF_CAPA1,
+       &RMF_CAPA2,
+       &RMF_NAME,
+       &RMF_EADATA,
+       &RMF_FILE_SECCTX_NAME,
+       &RMF_FILE_SECCTX
 };
 
 static const struct req_msg_field *ldlm_intent_unlink_client[] = {
 };
 
 static const struct req_msg_field *ldlm_intent_unlink_client[] = {
@@ -997,6 +1007,14 @@ struct req_msg_field RMF_STRING =
         DEFINE_MSGF("string", RMF_F_STRING, -1, NULL, NULL);
 EXPORT_SYMBOL(RMF_STRING);
 
         DEFINE_MSGF("string", RMF_F_STRING, -1, NULL, NULL);
 EXPORT_SYMBOL(RMF_STRING);
 
+struct req_msg_field RMF_FILE_SECCTX_NAME =
+       DEFINE_MSGF("file_secctx_name", RMF_F_STRING, -1, NULL, NULL);
+EXPORT_SYMBOL(RMF_FILE_SECCTX_NAME);
+
+struct req_msg_field RMF_FILE_SECCTX =
+       DEFINE_MSGF("file_secctx", 0, -1, NULL, NULL);
+EXPORT_SYMBOL(RMF_FILE_SECCTX);
+
 struct req_msg_field RMF_LLOGD_BODY =
         DEFINE_MSGF("llogd_body", 0,
                     sizeof(struct llogd_body), lustre_swab_llogd_body, NULL);
 struct req_msg_field RMF_LLOGD_BODY =
         DEFINE_MSGF("llogd_body", 0,
                     sizeof(struct llogd_body), lustre_swab_llogd_body, NULL);