From 8a11cb6282cfbdc8617b809344e6a11223e86a38 Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Tue, 4 Nov 2014 16:59:00 +0100 Subject: [PATCH] LU-5560 llite: basic support of SELinux in CLIO 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 Change-Id: Ie6db97be6f78b0b33da2ae54883a4051a2576af5 Reviewed-on: http://review.whamcloud.com/11648 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Dmitry Eremin Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- lustre/autoconf/lustre-core.m4 | 28 ++++++++ lustre/include/lustre_compat.h | 16 +++++ lustre/llite/Makefile.in | 2 +- lustre/llite/dir.c | 15 +++++ lustre/llite/llite_internal.h | 4 ++ lustre/llite/namei.c | 9 +++ lustre/llite/xattr.c | 5 +- lustre/llite/xattr_cache.c | 4 ++ lustre/llite/xattr_security.c | 145 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 226 insertions(+), 2 deletions(-) create mode 100644 lustre/llite/xattr_security.c diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index 601da01..07a4d52 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -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 +],[ + 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 + ],[ + 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 diff --git a/lustre/include/lustre_compat.h b/lustre/include/lustre_compat.h index 4402683..627edf8 100644 --- a/lustre/include/lustre_compat.h +++ b/lustre/include/lustre_compat.h @@ -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 */ diff --git a/lustre/llite/Makefile.in b/lustre/llite/Makefile.in index fb92688..35e11e5 100644 --- a/lustre/llite/Makefile.in +++ b/lustre/llite/Makefile.in @@ -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 diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index adf9a72..ef46098 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -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; diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index b4af770..3d06c68 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -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. diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c index aa6ce22..483ca43 100644 --- a/lustre/llite/namei.c +++ b/lustre/llite/namei.c @@ -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) diff --git a/lustre/llite/xattr.c b/lustre/llite/xattr.c index 35789c6..9cb21b8 100644 --- a/lustre/llite/xattr.c +++ b/lustre/llite/xattr.c @@ -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; diff --git a/lustre/llite/xattr_cache.c b/lustre/llite/xattr_cache.c index 1abd6ba..031a470 100644 --- a/lustre/llite/xattr_cache.c +++ b/lustre/llite/xattr_cache.c @@ -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 index 0000000..04471791 --- /dev/null +++ b/lustre/llite/xattr_security.c @@ -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 +#include +#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 */ -- 1.8.3.1