@@ -432,6 +432,7 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
.hash = full_name_hash(dparent, dirname,
strlen(dirname)),
},
+ .d_sb = dparent->d_sb,
};
bool encrypt = false;
int hash_flags;
@@ -511,14 +512,13 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
}
if (test_bit(LL_SBI_FILE_SECCTX, sbi->ll_flags)) {
- /*
- * selinux_dentry_init_security() uses dentry->d_parent and name
+ /* 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(parent,
- &dentry, mode, &dentry.d_name,
+ err = ll_dentry_init_security(&dentry, mode, &dentry.d_name,
&op_data->op_file_secctx_name,
+ &op_data->op_file_secctx_name_size,
&op_data->op_file_secctx,
&op_data->op_file_secctx_size);
if (err < 0)
@@ -550,17 +550,11 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
dentry.d_inode = inode;
- if (test_bit(LL_SBI_FILE_SECCTX, sbi->ll_flags)) {
- /* no need to protect selinux_inode_setsecurity() by
- * inode_lock. Taking it would lead to a client deadlock
- * LU-13617
- */
- err = security_inode_notifysecctx(inode,
- op_data->op_file_secctx,
- op_data->op_file_secctx_size);
- } else {
+ if (test_bit(LL_SBI_FILE_SECCTX, sbi->ll_flags))
+ err = ll_inode_notifysecctx(inode, op_data->op_file_secctx,
+ op_data->op_file_secctx_size);
+ else
err = ll_inode_init_security(&dentry, inode, parent);
- }
if (encrypt)
err = ll_set_encflags(inode, op_data->op_file_encctx,
@@ -447,15 +447,45 @@ static inline void obd_connect_set_secctx(struct obd_connect_data *data)
#endif
}
-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);
+/* Only smack and selinux is known to use security contexts */
+static inline bool ll_xattr_is_seclabel(const char *name)
+{
+ return !strcmp(name, XATTR_NAME_SELINUX) ||
+ !strcmp(name, XATTR_NAME_SMACK);
+}
+
+static inline bool ll_xattr_suffix_is_seclabel(const char *suffix)
+{
+ return !strcmp(suffix, XATTR_SELINUX_SUFFIX) ||
+ !strcmp(suffix, XATTR_SMACK_SUFFIX);
+}
+
+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);
int ll_inode_init_security(struct dentry *dentry, struct inode *inode,
struct inode *dir);
-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);
+
+void ll_secctx_name_free(struct ll_sb_info *sbi);
+
+int ll_secctx_name_store(struct inode *in);
+
+u32 ll_secctx_name_get(struct ll_sb_info *sbi, const char **secctx_name);
+
+int ll_security_secctx_name_filter(struct ll_sb_info *sbi, int xattr_type,
+ const char *suffix);
+
+static inline bool ll_security_xattr_wanted(struct inode *in)
+{
+#ifdef CONFIG_SECURITY
+ return in->i_security && in->i_sb->s_security;
+#else
+ return false;
+#endif
+}
static inline bool obd_connect_has_enc(struct obd_connect_data *data)
{
@@ -804,6 +834,10 @@ struct ll_sb_info {
struct ll_foreign_symlink_upcall_item *ll_foreign_symlink_upcall_items;
/* foreign symlink path upcall nb infos */
unsigned int ll_foreign_symlink_upcall_nb_items;
+
+ /* cached file security context xattr name. e.g: security.selinux */
+ char *ll_secctx_name;
+ u32 ll_secctx_name_size;
};
#define SBI_DEFAULT_HEAT_DECAY_WEIGHT ((80 * 256 + 50) / 100)
@@ -144,6 +144,9 @@ static struct ll_sb_info *ll_init_sbi(void)
* not enabled by default
*/
+ sbi->ll_secctx_name = NULL;
+ sbi->ll_secctx_name_size = 0;
+
sbi->ll_ra_info.ra_max_pages =
min(pages / 32, SBI_DEFAULT_READ_AHEAD_MAX);
sbi->ll_ra_info.ra_max_pages_per_file =
@@ -236,6 +239,8 @@ static void ll_free_sbi(struct super_block *sb)
kvfree(items);
sbi->ll_foreign_symlink_upcall_items = NULL;
}
+ ll_secctx_name_free(sbi);
+
ll_free_rw_stats_info(sbi);
pcc_super_fini(&sbi->ll_pcc_super);
kfree(sbi);
@@ -710,6 +715,12 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
goto out_root;
}
+ err = ll_secctx_name_store(root);
+ if (err < 0 && ll_security_xattr_wanted(root))
+ CWARN("%s: file security contextes not supported: rc = %d\n",
+ sbi->ll_fsname, err);
+
+ err = 0;
if (encctxlen) {
CDEBUG(D_SEC,
"server returned encryption ctx for root inode "DFID"\n",
@@ -712,20 +712,8 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request,
PFID(ll_inode2fid(inode)));
}
- if (secctx && secctxlen != 0) {
- /* 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",
- ll_i2sbi(inode)->ll_fsname,
- PFID(ll_inode2fid(inode)),
- rc);
- }
-
+ /* resume normally on error */
+ ll_inode_notifysecctx(inode, secctx, secctxlen);
}
alias = ll_splice_alias(inode, *de);
@@ -798,26 +786,26 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request,
}
static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
- struct lookup_intent *it, void **secctx,
- u32 *secctxlen,
+ struct lookup_intent *it,
+ void **secctx, u32 *secctxlen,
struct pcc_create_attach *pca,
bool encrypt,
void **encctx, u32 *encctxlen)
{
ktime_t kstart = ktime_get();
struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
+ struct ll_sb_info *sbi = ll_i2sbi(parent);
struct dentry *save = dentry, *retval;
struct ptlrpc_request *req = NULL;
struct md_op_data *op_data = NULL;
struct lov_user_md *lum = NULL;
- char secctx_name[XATTR_NAME_MAX + 1];
struct fscrypt_name fname;
struct inode *inode;
struct lu_fid fid;
u32 opc;
int rc;
- if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen)
+ if (dentry->d_name.len > sbi->ll_namelen)
return ERR_PTR(-ENAMETOOLONG);
CDEBUG(D_VFSTRACE, "VFS Op:name=%pd, dir=" DFID "(%p),intent=%s\n",
@@ -831,13 +819,8 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
if (it->it_op == IT_GETATTR && dentry_may_statahead(parent, dentry)) {
rc = ll_revalidate_statahead(parent, &dentry, 0);
- if (rc == 1) {
- if (dentry == save)
- retval = NULL;
- else
- retval = dentry;
- goto out;
- }
+ if (rc == 1)
+ return dentry == save ? NULL : dentry;
}
if (it->it_op & IT_OPEN && it->it_flags & FMODE_WRITE &&
@@ -872,7 +855,6 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
if (IS_ERR(op_data)) {
fscrypt_free_filename(&fname);
return ERR_CAST(op_data);
- goto out;
}
if (!fid_is_zero(&fid)) {
op_data->op_fid2 = fid;
@@ -886,11 +868,11 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
it->it_create_mode &= ~current_umask();
if (it->it_op & IT_CREAT &&
- test_bit(LL_SBI_FILE_SECCTX, ll_i2sbi(parent)->ll_flags)) {
- rc = ll_dentry_init_security(parent,
- dentry, it->it_create_mode,
+ test_bit(LL_SBI_FILE_SECCTX, sbi->ll_flags)) {
+ rc = ll_dentry_init_security(dentry, it->it_create_mode,
&dentry->d_name,
&op_data->op_file_secctx_name,
+ &op_data->op_file_secctx_name_size,
&op_data->op_file_secctx,
&op_data->op_file_secctx_size);
if (rc < 0) {
@@ -993,22 +975,12 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
*encctxlen = 0;
}
- /* ask for security context upon intent */
- if (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_OPEN)) {
- /* get name of security xattr to request to server */
- rc = ll_listsecurity(parent, secctx_name,
- sizeof(secctx_name));
- if (rc < 0) {
- CDEBUG(D_SEC,
- "cannot get security xattr name for " DFID ": rc = %d\n",
- PFID(ll_inode2fid(parent)), rc);
- } else if (rc > 0) {
- op_data->op_file_secctx_name = secctx_name;
- op_data->op_file_secctx_name_size = rc;
- CDEBUG(D_SEC, "'%.*s' is security xattr for " DFID "\n",
- rc, secctx_name, PFID(ll_inode2fid(parent)));
- }
- }
+ /* ask for security context upon intent:
+ * get name of security xattr to request to server
+ */
+ if (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_OPEN))
+ op_data->op_file_secctx_name_size =
+ ll_secctx_name_get(sbi, &op_data->op_file_secctx_name);
if (pca && pca->pca_dataset) {
lum = kzalloc(sizeof(*lum), GFP_NOFS);
@@ -1416,20 +1388,13 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode))
return PTR_ERR(inode);
- if (test_bit(LL_SBI_FILE_SECCTX, ll_i2sbi(inode)->ll_flags) &&
- secctx) {
- /* must be done before d_instantiate, because it calls
- * security_d_instantiate, which means a getxattr if security
- * context is not set yet
- */
- /* 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)
- return rc;
- }
+ /* must be done before d_instantiate, because it calls
+ * security_d_instantiate, which means a getxattr if security
+ * context is not set yet
+ */
+ rc = ll_inode_notifysecctx(inode, secctx, secctxlen);
+ if (rc)
+ return rc;
d_instantiate(dentry, inode);
@@ -1567,9 +1532,9 @@ static int ll_new_node(struct inode *dir, struct dentry *dchild,
ll_qos_mkdir_prep(op_data, dir);
if (test_bit(LL_SBI_FILE_SECCTX, sbi->ll_flags)) {
- err = ll_dentry_init_security(dir,
- dchild, mode, &dchild->d_name,
+ err = ll_dentry_init_security(dchild, mode, &dchild->d_name,
&op_data->op_file_secctx_name,
+ &op_data->op_file_secctx_name_size,
&op_data->op_file_secctx,
&op_data->op_file_secctx_size);
if (err < 0)
@@ -123,6 +123,10 @@ static int ll_xattr_set_common(const struct xattr_handler *handler,
(!strcmp(name, "ima") || !strcmp(name, "evm")))
return -EOPNOTSUPP;
+ rc = ll_security_secctx_name_filter(sbi, handler->flags, name);
+ if (rc)
+ return rc;
+
/*
* In user.* namespace, only regular files and directories can have
* extended attributes.
@@ -373,7 +377,7 @@ int ll_xattr_list(struct inode *inode, const char *name, int type, void *buffer,
}
if (sbi->ll_xattr_cache_enabled && type != XATTR_ACL_ACCESS_T &&
- (type != XATTR_SECURITY_T || strcmp(name, "security.selinux")) &&
+ (type != XATTR_SECURITY_T || !ll_xattr_is_seclabel(name)) &&
(type != XATTR_TRUSTED_T || strcmp(name, XATTR_NAME_SOM))) {
rc = ll_xattr_cache_get(inode, name, buffer, size, valid);
if (rc == -EAGAIN)
@@ -448,6 +452,10 @@ static int ll_xattr_get_common(const struct xattr_handler *handler,
if (rc)
return rc;
+ rc = ll_security_secctx_name_filter(sbi, handler->flags, name);
+ if (rc)
+ return rc;
+
#ifdef CONFIG_LUSTRE_FS_POSIX_ACL
/* posix acl is under protection of LOOKUP lock. when calling to this,
* we just have path resolution to the target inode, so we have great
@@ -461,9 +461,9 @@ static int ll_xattr_cache_refill(struct inode *inode)
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");
+ } else if (ll_xattr_is_seclabel(xdata)) {
+ /* Filter out security label, it is cached in slab */
+ CDEBUG(D_CACHE, "not caching %s\n", xdata);
rc = 0;
} else if (!strcmp(xdata, XATTR_NAME_SOM)) {
/* Filter out trusted.som, it is not cached on client */
@@ -38,19 +38,17 @@
/*
* 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);
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
@@ -59,30 +57,19 @@ int ll_dentry_init_security(struct inode *parent, struct dentry *dentry,
* from SELinux.
*/
- /* fetch length of security xattr name */
- rc = security_inode_listsecurity(parent, NULL, 0);
- /* xattr name length == 0 means SELinux is disabled */
- if (rc == 0)
+ *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;
- /* we support SELinux only */
- if (rc != strlen(XATTR_NAME_SELINUX) + 1)
- return -EOPNOTSUPP;
rc = security_dentry_init_security(dentry, mode, name, 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;
- *secctx_name = XATTR_NAME_SELINUX;
-
return 0;
}
@@ -139,31 +126,159 @@ int
ll_inode_init_security(struct dentry *dentry, struct inode *inode,
struct inode *dir)
{
- int err;
+ int rc;
- err = security_inode_init_security(inode, dir, NULL,
- &ll_initxattrs, dentry);
+ if (!ll_security_xattr_wanted(dir))
+ return 0;
- if (err == -EOPNOTSUPP)
+ rc = security_inode_init_security(inode, dir, NULL,
+ &ll_initxattrs, dentry);
+ if (rc == -EOPNOTSUPP)
return 0;
- return err;
+
+ return rc;
}
/**
- * 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
+ * Return 0 success, or SELinux is disabled or not supported by the fs
+ * < 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;
- rc = security_inode_listsecurity(inode, secctx_name, secctx_name_size);
- if (rc >= secctx_name_size)
+ if (!test_bit(LL_SBI_FILE_SECCTX, sbi->ll_flags) ||
+ !ll_security_xattr_wanted(inode) ||
+ !secctx || !secctxlen)
+ return 0;
+
+ /* 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)
+{
+ kfree(sbi->ll_secctx_name);
+ sbi->ll_secctx_name = NULL;
+ sbi->ll_secctx_name_size = 0;
+}
+
+/**
+ * Get security context xattr name used by policy and save it.
+ *
+ * Return > 0 length of xattr name
+ * == 0 no LSM module registered supporting security contexts
+ * <= 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;
+
+ ll_secctx_name_free(sbi);
+
+ sbi->ll_secctx_name = kzalloc(rc + 1, GFP_NOFS);
+ 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.
+ *
+ * Return security context xattr name size stored.
+ * 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.
+ *
+ * Return 0 xattr not filtered
+ * -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;
+}
@@ -1767,19 +1767,17 @@ static inline int sptlrpc_sepol_needs_check(struct ptlrpc_sec *imp_sec)
int sptlrpc_get_sepol(struct ptlrpc_request *req)
{
-#ifndef CONFIG_SECURITY_SELINUX
+ struct ptlrpc_sec *imp_sec = req->rq_import->imp_sec;
+ int rc = 0;
+
(req->rq_sepol)[0] = '\0';
+#ifndef CONFIG_SECURITY_SELINUX
if (unlikely(send_sepol != 0))
CDEBUG(D_SEC,
"Client cannot report SELinux status, it was not built against libselinux.\n");
return 0;
-#else
- struct ptlrpc_sec *imp_sec = req->rq_import->imp_sec;
- int rc = 0;
-
- (req->rq_sepol)[0] = '\0';
-
+#endif
if (send_sepol == 0)
return 0;
@@ -1794,10 +1792,13 @@ int sptlrpc_get_sepol(struct ptlrpc_request *req)
memcpy(req->rq_sepol, imp_sec->ps_sepol,
sizeof(req->rq_sepol));
spin_unlock(&imp_sec->ps_lock);
+ } else if (rc == -ENODEV) {
+ CDEBUG(D_SEC,
+ "Client cannot report SELinux status, SELinux is disabled.\n");
+ rc = 0;
}
return rc;
-#endif
}
EXPORT_SYMBOL(sptlrpc_get_sepol);