Whamcloud - gitweb
LU-5560 llite: basic support of SELinux in CLIO 48/11648/18
authorSebastien Buisson <sebastien.buisson@bull.net>
Tue, 4 Nov 2014 15:59:00 +0000 (16:59 +0100)
committerOleg Drokin <oleg.drokin@intel.com>
Mon, 29 Jun 2015 22:35:47 +0000 (22:35 +0000)
Bring the ability to properly initiate security context
on SELinux-enabled client and store it on server side via
extended attribute.

Security context initialization is not atomic, but that would
require a wire protocol change to send security label in the
creation request.

Filter out security.selinux from xattr cache as it is
already cached in system slab.

Signed-off-by: Sebastien Buisson <sebastien.buisson@bull.net>
Change-Id: Ie6db97be6f78b0b33da2ae54883a4051a2576af5
Reviewed-on: http://review.whamcloud.com/11648
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Dmitry Eremin <dmitry.eremin@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
lustre/autoconf/lustre-core.m4
lustre/include/lustre_compat.h
lustre/llite/Makefile.in
lustre/llite/dir.c
lustre/llite/llite_internal.h
lustre/llite/namei.c
lustre/llite/xattr.c
lustre/llite/xattr_cache.c
lustre/llite/xattr_security.c [new file with mode: 0644]

index 601da01..07a4d52 100644 (file)
@@ -929,6 +929,33 @@ inode_i_nlink_protected, [
 ]) # LC_HAVE_PROTECT_I_NLINK
 
 #
+# 2.6.39 security_inode_init_security takes a 'struct qstr' parameter
+#
+# 3.2 security_inode_init_security takes a callback to set xattrs
+#
+AC_DEFUN([LC_HAVE_SECURITY_IINITSEC], [
+LB_CHECK_COMPILE([if security_inode_init_security takes a callback],
+security_inode_init_security_callback, [
+       #include <linux/security.h>
+],[
+       security_inode_init_security(NULL, NULL, NULL, (const initxattrs)NULL, NULL);
+],[
+       AC_DEFINE(HAVE_SECURITY_IINITSEC_CALLBACK, 1,
+                 [security_inode_init_security takes a callback to set xattrs])
+],[
+       LB_CHECK_COMPILE([if security_inode_init_security takes a 'struct qstr' parameter],
+       security_inode_init_security_qstr, [
+               #include <linux/security.h>
+       ],[
+               security_inode_init_security(NULL, NULL, (struct qstr *)NULL, NULL, NULL, NULL);
+       ],[
+               AC_DEFINE(HAVE_SECURITY_IINITSEC_QSTR, 1,
+                         [security_inode_init_security takes a 'struct qstr' parameter])
+       ])
+])
+]) # LC_HAVE_SECURITY_IINITSEC
+
+#
 # LC_HAVE_MIGRATE_HEADER
 #
 # 3.3 introduces migrate_mode.h and migratepage has 4 args
@@ -1766,6 +1793,7 @@ AC_DEFUN([LC_PROG_LINUX], [
        LC_HAVE_FSTYPE_MOUNT
        LC_IOP_TRUNCATE
        LC_HAVE_INODE_OWNER_OR_CAPABLE
+       LC_HAVE_SECURITY_IINITSEC
 
        # 3.0
        LC_DIRTY_INODE_WITH_FLAG
index 4402683..627edf8 100644 (file)
@@ -387,4 +387,20 @@ static inline void truncate_inode_pages_final(struct address_space *map)
 #define SIZE_MAX       (~(size_t)0)
 #endif
 
+#ifdef HAVE_SECURITY_IINITSEC_CALLBACK
+# define ll_security_inode_init_security(inode, dir, name, value, len, \
+                                        initxattrs, dentry)           \
+        security_inode_init_security(inode, dir, &((dentry)->d_name), \
+                                     initxattrs, dentry)
+#elif defined HAVE_SECURITY_IINITSEC_QSTR
+# define ll_security_inode_init_security(inode, dir, name, value, len, \
+                                        initxattrs, dentry)           \
+        security_inode_init_security(inode, dir, &((dentry)->d_name), \
+                                     name, value, len)
+#else /* !HAVE_SECURITY_IINITSEC_CALLBACK && !HAVE_SECURITY_IINITSEC_QSTR */
+# define ll_security_inode_init_security(inode, dir, name, value, len, \
+                                        initxattrs, dentry)           \
+        security_inode_init_security(inode, dir, name, value, len)
+#endif
+
 #endif /* _LUSTRE_COMPAT_H */
index fb92688..35e11e5 100644 (file)
@@ -3,7 +3,7 @@ MODULES := lustre
 lustre-objs := dcache.o dir.o file.o llite_lib.o llite_nfs.o
 lustre-objs += rw.o lproc_llite.o namei.o symlink.o llite_mmap.o
 lustre-objs += xattr.o xattr_cache.o remote_perm.o llite_rmtacl.o
-lustre-objs += rw26.o super25.o statahead.o
+lustre-objs += rw26.o super25.o statahead.o xattr_security.o
 lustre-objs += glimpse.o
 lustre-objs += lcommon_cl.o
 lustre-objs += lcommon_misc.o
index adf9a72..ef46098 100644 (file)
@@ -449,6 +449,8 @@ static int ll_dir_setdirstripe(struct inode *parent, struct lmv_user_md *lump,
        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;
        int err;
        ENTRY;
 
@@ -484,6 +486,19 @@ static int ll_dir_setdirstripe(struct inode *parent, struct lmv_user_md *lump,
        ll_finish_md_op_data(op_data);
        if (err)
                GOTO(err_exit, err);
+
+       err = ll_prep_inode(&inode, request, parent->i_sb, NULL);
+       if (err)
+               GOTO(err_exit, err);
+
+       memset(&dentry, 0, sizeof(dentry));
+       dentry.d_inode = inode;
+
+       err = ll_init_security(&dentry, inode, parent);
+       iput(inode);
+       if (err)
+               GOTO(err_exit, err);
+
 err_exit:
        ptlrpc_req_finished(request);
        return err;
index b4af770..3d06c68 100644 (file)
@@ -313,6 +313,10 @@ int ll_xattr_cache_get(struct inode *inode,
                        size_t size,
                        __u64 valid);
 
+int ll_init_security(struct dentry *dentry,
+                           struct inode *inode,
+                           struct inode *dir);
+
 /*
  * Locking to guarantee consistency of non-atomic updates to long long i_size,
  * consistency between file size and KMS.
index aa6ce22..483ca43 100644 (file)
@@ -883,6 +883,11 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry,
                RETURN(PTR_ERR(inode));
 
        d_instantiate(dentry, inode);
+
+       rc = ll_init_security(dentry, inode, dir);
+       if (rc)
+               RETURN(rc);
+
        RETURN(0);
 }
 
@@ -975,6 +980,10 @@ again:
 
        d_instantiate(dchild, inode);
 
+       err = ll_init_security(dchild, inode, dir);
+       if (err)
+               GOTO(err_exit, err);
+
         EXIT;
 err_exit:
        if (request != NULL)
index 35789c6..9cb21b8 100644 (file)
@@ -361,7 +361,10 @@ int ll_getxattr_common(struct inode *inode, const char *name,
 #endif
 
 do_getxattr:
-       if (sbi->ll_xattr_cache_enabled && xattr_type != XATTR_ACL_ACCESS_T) {
+       if (sbi->ll_xattr_cache_enabled &&
+           xattr_type != XATTR_ACL_ACCESS_T &&
+           (xattr_type != XATTR_SECURITY_T ||
+               strcmp(name, "security.selinux") != 0)) {
                rc = ll_xattr_cache_get(inode, name, buffer, size, valid);
                if (rc == -EAGAIN)
                        goto getxattr_nocache;
index 1abd6ba..031a470 100644 (file)
@@ -461,6 +461,10 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit)
                        CDEBUG(D_CACHE, "not caching %s\n",
                               XATTR_NAME_ACL_ACCESS);
                        rc = 0;
+               } else if (!strcmp(xdata, "security.selinux")) {
+                       /* Filter out security.selinux, it is cached in slab */
+                       CDEBUG(D_CACHE, "not caching security.selinux\n");
+                       rc = 0;
                } else {
                        rc = ll_xattr_cache_add(&lli->lli_xattrs, xdata, xval,
                                                *xsizes);
diff --git a/lustre/llite/xattr_security.c b/lustre/llite/xattr_security.c
new file mode 100644 (file)
index 0000000..0447179
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014 Bull SAS
+ * Author: Sebastien Buisson sebastien.buisson@bull.net
+ */
+
+/*
+ * lustre/llite/xattr_security.c
+ * Handler for storing security labels as extended attributes.
+ */
+
+
+#include <linux/security.h>
+#include <linux/xattr.h>
+#include "llite_internal.h"
+
+#ifdef HAVE_SECURITY_IINITSEC_CALLBACK
+/**
+ * A helper function for ll_security_inode_init_security()
+ * that takes care of setting xattrs
+ *
+ * Get security context of @inode from @xattr_array,
+ * and put it in 'security.xxx' xattr of dentry
+ * stored in @fs_info.
+ *
+ * \retval 0        success
+ * \retval -ENOMEM  if no memory could be allocated for xattr name
+ * \retval < 0      failure to set xattr
+ */
+static int
+ll_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+             void *fs_info)
+{
+       const struct xattr *xattr;
+       struct dentry *dentry = fs_info;
+       size_t name_len;
+       char *full_name;
+       int err = 0;
+
+       for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+               name_len = strlen(XATTR_SECURITY_PREFIX) + strlen(xattr->name)
+                          + 1;
+               OBD_ALLOC(full_name, name_len);
+               if (full_name == NULL)
+                       return -ENOMEM;
+               strlcpy(full_name, XATTR_SECURITY_PREFIX, name_len);
+               strlcat(full_name, xattr->name, name_len);
+
+               err = ll_setxattr(dentry, full_name, xattr->value,
+                                 xattr->value_len, 0);
+
+               OBD_FREE(full_name, name_len);
+
+               if (err < 0)
+                       break;
+       }
+       return err;
+}
+
+/**
+ * Initializes security context
+ *
+ * Get security context of @inode in @dir,
+ * and put it in 'security.xxx' xattr of @dentry.
+ *
+ * \retval 0        success, or SELinux is disabled
+ * \retval -ENOMEM  if no memory could be allocated for xattr name
+ * \retval < 0      failure to get security context or set xattr
+ */
+int
+ll_init_security(struct dentry *dentry, struct inode *inode, struct inode *dir)
+{
+       if (!selinux_is_enabled())
+               return 0;
+
+       return ll_security_inode_init_security(inode, dir, NULL, NULL, 0,
+                                              &ll_initxattrs, dentry);
+}
+#else /* !HAVE_SECURITY_IINITSEC_CALLBACK */
+/**
+ * Initializes security context
+ *
+ * Get security context of @inode in @dir,
+ * and put it in 'security.xxx' xattr of @dentry.
+ *
+ * \retval 0        success, or SELinux is disabled
+ * \retval -ENOMEM  if no memory could be allocated for xattr name
+ * \retval < 0      failure to get security context or set xattr
+ */
+int
+ll_init_security(struct dentry *dentry, struct inode *inode, struct inode *dir)
+{
+       int err;
+       size_t len, name_len;
+       void *value;
+       char *name, *full_name;
+
+       if (!selinux_is_enabled())
+               return 0;
+
+       err = ll_security_inode_init_security(inode, dir, &name, &value, &len,
+                                             NULL, dentry);
+       if (err != 0) {
+               if (err == -EOPNOTSUPP)
+                       return 0;
+               return err;
+       }
+
+       name_len = strlen(XATTR_SECURITY_PREFIX) + strlen(name) + 1;
+       OBD_ALLOC(full_name, name_len);
+       if (full_name == NULL)
+               GOTO(out_free, err = -ENOMEM);
+       strlcpy(full_name, XATTR_SECURITY_PREFIX, name_len);
+       strlcat(full_name, name, name_len);
+
+       err = ll_setxattr(dentry, full_name, value, len, 0);
+       OBD_FREE(full_name, name_len);
+
+out_free:
+       kfree(name);
+       kfree(value);
+
+       return err;
+}
+#endif /* HAVE_SECURITY_IINITSEC_CALLBACK */