[PATCH 13/25] fsinfo: Support SELinux superblock parameter retrieval [ver #13]

From: David Howells
Date: Tue May 28 2019 - 11:16:18 EST


Add support to SELinux for retrieval of the superblock parameters by
fsinfo(FSINFO_ATTR_LSM_PARAMETERS).

Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
---

security/selinux/hooks.c | 41 +++++++++++++++++++++++++++++
security/selinux/include/security.h | 2 +
security/selinux/ss/services.c | 49 +++++++++++++++++++++++++++++++++++
3 files changed, 92 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c61787b15f27..9b5dbdcde9e6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -91,6 +91,7 @@
#include <linux/bpf.h>
#include <linux/kernfs.h>
#include <linux/stringhash.h> /* for hashlen_string() */
+#include <linux/fsinfo.h>
#include <uapi/linux/mount.h>

#include "avc.h"
@@ -2735,6 +2736,43 @@ static int selinux_sb_statfs(struct dentry *dentry)
return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
}

+#ifdef CONFIG_FSINFO
+/*
+ * Retrieve the SELinux filesystem information, including mount parameters.
+ */
+static int selinux_sb_fsinfo(struct path *path, struct fsinfo_kparams *params)
+{
+ struct superblock_security_struct *sbsec = path->dentry->d_sb->s_security;
+
+ switch (params->request) {
+ case FSINFO_ATTR_LSM_PARAMETERS:
+ if (!(sbsec->flags & SE_SBINITIALIZED) ||
+ !selinux_state.initialized)
+ return params->usage;
+
+ if (sbsec->flags & FSCONTEXT_MNT)
+ fsinfo_note_sid(params, FSCONTEXT_STR, sbsec->sid);
+ if (sbsec->flags & CONTEXT_MNT)
+ fsinfo_note_sid(params, CONTEXT_STR, sbsec->mntpoint_sid);
+ if (sbsec->flags & DEFCONTEXT_MNT)
+ fsinfo_note_sid(params, DEFCONTEXT_STR, sbsec->def_sid);
+ if (sbsec->flags & ROOTCONTEXT_MNT) {
+ struct dentry *root = sbsec->sb->s_root;
+ struct inode_security_struct *isec = backing_inode_security(root);
+ fsinfo_note_sid(params, ROOTCONTEXT_STR, isec->sid);
+ }
+ if (sbsec->flags & SBLABEL_MNT)
+ fsinfo_note_param(params, SECLABEL_STR, NULL);
+
+ return params->usage;
+
+ default:
+ return -ENODATA;
+ }
+ return 0;
+}
+#endif
+
static int selinux_mount(const char *dev_name,
const struct path *path,
const char *type,
@@ -6761,6 +6799,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs),
+#ifdef CONFIG_FSINFO
+ LSM_HOOK_INIT(sb_fsinfo, selinux_sb_fsinfo),
+#endif
LSM_HOOK_INIT(sb_mount, selinux_mount),
LSM_HOOK_INIT(sb_umount, selinux_umount),
LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts),
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 111121281c47..e9617bfcc6ee 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -67,6 +67,7 @@
#define SECLABEL_STR "seclabel"

struct netlbl_lsm_secattr;
+struct fsinfo_kparams;

extern int selinux_enabled;

@@ -258,6 +259,7 @@ int security_sid_to_context_force(struct selinux_state *state,

int security_sid_to_context_inval(struct selinux_state *state,
u32 sid, char **scontext, u32 *scontext_len);
+void fsinfo_note_sid(struct fsinfo_kparams *params, const char *key, u32 sid);

int security_context_to_sid(struct selinux_state *state,
const char *scontext, u32 scontext_len,
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index cc043bc8fd4c..1111b02a999b 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -50,6 +50,7 @@
#include <linux/audit.h>
#include <linux/mutex.h>
#include <linux/vmalloc.h>
+#include <linux/fsinfo.h>
#include <net/netlabel.h>

#include "flask.h"
@@ -1374,6 +1375,54 @@ int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
scontext_len, 1, 1);
}

+#ifdef CONFIG_FSINFO
+void fsinfo_note_sid(struct fsinfo_kparams *params, const char *key, u32 sid)
+{
+ struct selinux_state *state = &selinux_state;
+ struct policydb *policydb;
+ struct context *context;
+ const char *val = "<<<INVALID>>>";
+ char *p;
+ int n;
+
+ if (!state->initialized) {
+ if (sid <= SECINITSID_NUM) {
+ val = initial_sid_to_string[sid];
+ goto out;
+ }
+
+ pr_err("SELinux: %s: called before initial "
+ "load_policy on unknown SID %d\n", __func__, sid);
+ goto out;
+ }
+
+ read_lock(&state->ss->policy_rwlock);
+
+ policydb = &state->ss->policydb;
+ context = sidtab_search(state->ss->sidtab, sid);
+ if (!context) {
+ pr_err("SELinux: %s: unrecognized SID %d\n", __func__, sid);
+ } else {
+ /* Copy the user name, role name and type name into the scratch
+ * buffer and then tack on the MLS.
+ */
+ val = p = params->scratch_buffer;
+ n = sprintf(p, "%s:%s:%s",
+ sym_name(policydb, SYM_USERS, context->user - 1),
+ sym_name(policydb, SYM_ROLES, context->role - 1),
+ sym_name(policydb, SYM_TYPES, context->type - 1));
+
+ p += n;
+ mls_sid_to_context(policydb, context, &p);
+ *p = 0;
+ }
+
+ read_unlock(&state->ss->policy_rwlock);
+out:
+ fsinfo_note_param(params, key, val);
+}
+#endif
+
/*
* Caveat: Mutates scontext.
*/