/*
* 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
* 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;
{
int rc;
- if (!selinux_is_enabled())
+ if (!ll_security_xattr_wanted(dir))
return 0;
rc = security_inode_init_security(inode, dir, NULL,
}
/**
- * 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;
+}