X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;ds=sidebyside;f=lustre%2Fllite%2Fxattr_security.c;h=57e1d7abbc112299a944a75e6d0ee766f7bbc676;hb=1d8faaf6caf4acaf0e2d4943b51c024a96c80624;hp=9bcb800bf4c672815e34baace1e80f5841c610eb;hpb=6c93b9c3fcf581bb1fb04577fbcd803d0d02f802;p=fs%2Flustre-release.git diff --git a/lustre/llite/xattr_security.c b/lustre/llite/xattr_security.c index 9bcb800..57e1d7a 100644 --- a/lustre/llite/xattr_security.c +++ b/lustre/llite/xattr_security.c @@ -50,19 +50,20 @@ /* * Check for LL_SBI_FILE_SECCTX before calling. */ -int ll_dentry_init_security(struct inode *parent, struct dentry *dentry, - int mode, struct qstr *name, - const char **secctx_name, void **secctx, - __u32 *secctx_size) +int ll_dentry_init_security(struct dentry *dentry, int mode, struct qstr *name, + const char **secctx_name, __u32 *secctx_name_size, + void **secctx, __u32 *secctx_size) { + struct ll_sb_info *sbi = ll_s2sbi(dentry->d_sb); +#ifdef HAVE_SECURITY_DENTRY_INIT_WITH_XATTR_NAME_ARG + const char *secctx_name_lsm = NULL; +#endif 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 + * Before kernel 5.15-rc1-20-g15bf32398ad4, + * security_inode_init_security() 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 @@ -71,36 +72,28 @@ int ll_dentry_init_security(struct inode *parent, struct dentry *dentry, * from SELinux. */ - if (!selinux_is_enabled()) + *secctx_name_size = ll_secctx_name_get(sbi, secctx_name); + /* xattr name length == 0 means no LSM module manage file contexts */ + if (*secctx_name_size == 0) return 0; - /* fetch length of security xattr name */ - rc = security_inode_listsecurity(parent, NULL, 0); - /* xattr name length == 0 means SELinux is disabled */ - if (rc == 0) - return 0; - /* we support SELinux only */ - if (rc != strlen(XATTR_NAME_SELINUX) + 1) - return -EOPNOTSUPP; - rc = security_dentry_init_security(dentry, mode, name, #ifdef HAVE_SECURITY_DENTRY_INIT_WITH_XATTR_NAME_ARG - secctx_name, + &secctx_name_lsm, #endif secctx, secctx_size); - /* Usually, security_dentry_init_security() returns -EOPNOTSUPP when - * SELinux is disabled. - * But on some kernels (e.g. rhel 8.5) it returns 0 when SELinux is - * disabled, and in this case the security context is empty. - */ - if (rc == -EOPNOTSUPP || (rc == 0 && *secctx_size == 0)) - /* do nothing */ + /* ignore error if the hook is not supported by the LSM module */ + if (rc == -EOPNOTSUPP) return 0; if (rc < 0) return rc; -#ifndef HAVE_SECURITY_DENTRY_INIT_WITH_XATTR_NAME_ARG - *secctx_name = XATTR_NAME_SELINUX; +#ifdef HAVE_SECURITY_DENTRY_INIT_WITH_XATTR_NAME_ARG + if (strncmp(*secctx_name, secctx_name_lsm, *secctx_name_size) != 0) { + CERROR("%s: LSM secctx_name '%s' does not match the one stored by Lustre '%s'\n", + sbi->ll_fsname, secctx_name_lsm, *secctx_name); + return -EOPNOTSUPP; + } #endif return 0; @@ -161,7 +154,7 @@ ll_inode_init_security(struct dentry *dentry, struct inode *inode, { int rc; - if (!selinux_is_enabled()) + if (!ll_security_xattr_wanted(dir)) return 0; rc = security_inode_init_security(inode, dir, NULL, @@ -173,23 +166,146 @@ ll_inode_init_security(struct dentry *dentry, struct inode *inode, } /** - * Get security context xattr name used by policy. + * Notify security context to the security layer + * + * Notify security context @secctx of inode @inode to the security layer. * - * \retval >= 0 length of xattr name - * \retval < 0 failure to get security context xattr name + * \retval 0 success, or SELinux is disabled or not supported by the fs + * \retval < 0 failure to set the security context */ -int -ll_listsecurity(struct inode *inode, char *secctx_name, size_t secctx_name_size) +int ll_inode_notifysecctx(struct inode *inode, + void *secctx, __u32 secctxlen) { + struct ll_sb_info *sbi = ll_i2sbi(inode); int rc; - if (!selinux_is_enabled()) + if (!test_bit(LL_SBI_FILE_SECCTX, sbi->ll_flags) || + !ll_security_xattr_wanted(inode) || + !secctx || !secctxlen) return 0; - rc = security_inode_listsecurity(inode, secctx_name, secctx_name_size); - if (rc >= secctx_name_size) + /* no need to protect selinux_inode_setsecurity() by + * inode_lock. Taking it would lead to a client deadlock + * LU-13617 + */ + rc = security_inode_notifysecctx(inode, secctx, secctxlen); + if (rc) + CWARN("%s: cannot set security context for "DFID": rc = %d\n", + sbi->ll_fsname, PFID(ll_inode2fid(inode)), rc); + + return rc; +} + +/** + * Free the security context xattr name used by policy + */ +void ll_secctx_name_free(struct ll_sb_info *sbi) +{ + OBD_FREE(sbi->ll_secctx_name, sbi->ll_secctx_name_size + 1); + sbi->ll_secctx_name = NULL; + sbi->ll_secctx_name_size = 0; +} + +/** + * Get security context xattr name used by policy and save it. + * + * \retval > 0 length of xattr name + * \retval == 0 no LSM module registered supporting security contexts + * \retval <= 0 failure to get xattr name or xattr is not supported + */ +int ll_secctx_name_store(struct inode *in) +{ + struct ll_sb_info *sbi = ll_i2sbi(in); + int rc = 0; + + if (!ll_security_xattr_wanted(in)) + return 0; + + /* get size of xattr name */ + rc = security_inode_listsecurity(in, NULL, 0); + if (rc <= 0) + return rc; + + if (sbi->ll_secctx_name) + ll_secctx_name_free(sbi); + + OBD_ALLOC(sbi->ll_secctx_name, rc + 1); + if (!sbi->ll_secctx_name) + return -ENOMEM; + + /* save the xattr name */ + sbi->ll_secctx_name_size = rc; + rc = security_inode_listsecurity(in, sbi->ll_secctx_name, + sbi->ll_secctx_name_size); + if (rc <= 0) + goto err_free; + + if (rc > sbi->ll_secctx_name_size) { rc = -ERANGE; - else if (rc >= 0) - secctx_name[rc] = '\0'; + goto err_free; + } + + /* sanity check */ + sbi->ll_secctx_name[rc] = '\0'; + if (rc < sizeof(XATTR_SECURITY_PREFIX)) { + rc = -EINVAL; + goto err_free; + } + if (strncmp(sbi->ll_secctx_name, XATTR_SECURITY_PREFIX, + sizeof(XATTR_SECURITY_PREFIX) - 1) != 0) { + rc = -EOPNOTSUPP; + goto err_free; + } + + return rc; + +err_free: + ll_secctx_name_free(sbi); return rc; } + +/** + * Retrieved file security context xattr name stored. + * + * \retval security context xattr name size stored. + * \retval 0 no xattr name stored. + */ +__u32 ll_secctx_name_get(struct ll_sb_info *sbi, const char **secctx_name) +{ + if (!sbi->ll_secctx_name || !sbi->ll_secctx_name_size) + return 0; + + *secctx_name = sbi->ll_secctx_name; + + return sbi->ll_secctx_name_size; +} + +/** + * Filter out xattr file security context if not managed by LSM + * + * This is done to improve performance for application that blindly try to get + * file context (like "ls -l" for security.linux). + * See LU-549 for more information. + * + * \retval 0 xattr not filtered + * \retval -EOPNOTSUPP no enabled LSM security module supports the xattr + */ +int ll_security_secctx_name_filter(struct ll_sb_info *sbi, int xattr_type, + const char *suffix) +{ + const char *cached_suffix = NULL; + + if (xattr_type != XATTR_SECURITY_T || + !ll_xattr_suffix_is_seclabel(suffix)) + return 0; + + /* is the xattr label used by lsm ? */ + if (!ll_secctx_name_get(sbi, &cached_suffix)) + return -EOPNOTSUPP; + + cached_suffix += sizeof(XATTR_SECURITY_PREFIX) - 1; + if (strcmp(suffix, cached_suffix) != 0) + return -EOPNOTSUPP; + + return 0; +}