Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cee74f47 authored by Eric Paris's avatar Eric Paris Committed by James Morris
Browse files

SELinux: allow userspace to read policy back out of the kernel



There is interest in being able to see what the actual policy is that was
loaded into the kernel.  The patch creates a new selinuxfs file
/selinux/policy which can be read by userspace.  The actual policy that is
loaded into the kernel will be written back out to userspace.

Signed-off-by: default avatarEric Paris <eparis@redhat.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 00d85c83
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -17,7 +17,7 @@ struct security_class_mapping secclass_map[] = {
	  { "compute_av", "compute_create", "compute_member",
	  { "compute_av", "compute_create", "compute_member",
	    "check_context", "load_policy", "compute_relabel",
	    "check_context", "load_policy", "compute_relabel",
	    "compute_user", "setenforce", "setbool", "setsecparam",
	    "compute_user", "setenforce", "setbool", "setsecparam",
	    "setcheckreqprot", NULL } },
	    "setcheckreqprot", "read_policy", NULL } },
	{ "process",
	{ "process",
	  { "fork", "transition", "sigchld", "sigkill",
	  { "fork", "transition", "sigchld", "sigkill",
	    "sigstop", "signull", "signal", "ptrace", "getsched", "setsched",
	    "sigstop", "signull", "signal", "ptrace", "getsched", "setsched",
+2 −0
Original line number Original line Diff line number Diff line
@@ -83,6 +83,8 @@ extern int selinux_policycap_openperm;
int security_mls_enabled(void);
int security_mls_enabled(void);


int security_load_policy(void *data, size_t len);
int security_load_policy(void *data, size_t len);
int security_read_policy(void **data, ssize_t *len);
size_t security_policydb_len(void);


int security_policycap_supported(unsigned int req_cap);
int security_policycap_supported(unsigned int req_cap);


+95 −0
Original line number Original line Diff line number Diff line
@@ -68,6 +68,8 @@ static int *bool_pending_values;
static struct dentry *class_dir;
static struct dentry *class_dir;
static unsigned long last_class_ino;
static unsigned long last_class_ino;


static char policy_opened;

/* global data for policy capabilities */
/* global data for policy capabilities */
static struct dentry *policycap_dir;
static struct dentry *policycap_dir;


@@ -111,6 +113,7 @@ enum sel_inos {
	SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
	SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
	SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
	SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
	SEL_STATUS,	/* export current status using mmap() */
	SEL_STATUS,	/* export current status using mmap() */
	SEL_POLICY,	/* allow userspace to read the in kernel policy */
	SEL_INO_NEXT,	/* The next inode number to use */
	SEL_INO_NEXT,	/* The next inode number to use */
};
};


@@ -351,6 +354,97 @@ static const struct file_operations sel_mls_ops = {
	.llseek		= generic_file_llseek,
	.llseek		= generic_file_llseek,
};
};


struct policy_load_memory {
	size_t len;
	void *data;
};

static int sel_open_policy(struct inode *inode, struct file *filp)
{
	struct policy_load_memory *plm = NULL;
	int rc;

	BUG_ON(filp->private_data);

	mutex_lock(&sel_mutex);

	rc = task_has_security(current, SECURITY__READ_POLICY);
	if (rc)
		goto err;

	rc = -EBUSY;
	if (policy_opened)
		goto err;

	rc = -ENOMEM;
	plm = kzalloc(sizeof(*plm), GFP_KERNEL);
	if (!plm)
		goto err;

	if (i_size_read(inode) != security_policydb_len()) {
		mutex_lock(&inode->i_mutex);
		i_size_write(inode, security_policydb_len());
		mutex_unlock(&inode->i_mutex);
	}

	rc = security_read_policy(&plm->data, &plm->len);
	if (rc)
		goto err;

	policy_opened = 1;

	filp->private_data = plm;

	mutex_unlock(&sel_mutex);

	return 0;
err:
	mutex_unlock(&sel_mutex);

	if (plm)
		vfree(plm->data);
	kfree(plm);
	return rc;
}

static int sel_release_policy(struct inode *inode, struct file *filp)
{
	struct policy_load_memory *plm = filp->private_data;

	BUG_ON(!plm);

	policy_opened = 0;

	vfree(plm->data);
	kfree(plm);

	return 0;
}

static ssize_t sel_read_policy(struct file *filp, char __user *buf,
			       size_t count, loff_t *ppos)
{
	struct policy_load_memory *plm = filp->private_data;
	int ret;

	mutex_lock(&sel_mutex);

	ret = task_has_security(current, SECURITY__READ_POLICY);
	if (ret)
		goto out;

	ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
out:
	mutex_unlock(&sel_mutex);
	return ret;
}

static const struct file_operations sel_policy_ops = {
	.open		= sel_open_policy,
	.read		= sel_read_policy,
	.release	= sel_release_policy,
};

static ssize_t sel_write_load(struct file *file, const char __user *buf,
static ssize_t sel_write_load(struct file *file, const char __user *buf,
			      size_t count, loff_t *ppos)
			      size_t count, loff_t *ppos)


@@ -1668,6 +1762,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
		[SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
		[SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
		[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
		[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
		[SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
		[SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
		[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR},
		/* last one */ {""}
		/* last one */ {""}
	};
	};
	ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
	ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
+42 −0
Original line number Original line Diff line number Diff line
@@ -501,6 +501,48 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
	goto out;
	goto out;
}
}


int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp)
{
	__le16 buf16[4];
	__le32 buf32[1];
	int rc;

	buf16[0] = cpu_to_le16(cur->key.source_type);
	buf16[1] = cpu_to_le16(cur->key.target_type);
	buf16[2] = cpu_to_le16(cur->key.target_class);
	buf16[3] = cpu_to_le16(cur->key.specified);
	rc = put_entry(buf16, sizeof(u16), 4, fp);
	if (rc)
		return rc;
	buf32[0] = cpu_to_le32(cur->datum.data);
	rc = put_entry(buf32, sizeof(u32), 1, fp);
	if (rc)
		return rc;
	return 0;
}

int avtab_write(struct policydb *p, struct avtab *a, void *fp)
{
	unsigned int i;
	int rc = 0;
	struct avtab_node *cur;
	__le32 buf[1];

	buf[0] = cpu_to_le32(a->nel);
	rc = put_entry(buf, sizeof(u32), 1, fp);
	if (rc)
		return rc;

	for (i = 0; i < a->nslot; i++) {
		for (cur = a->htable[i]; cur; cur = cur->next) {
			rc = avtab_write_item(p, cur, fp);
			if (rc)
				return rc;
		}
	}

	return rc;
}
void avtab_cache_init(void)
void avtab_cache_init(void)
{
{
	avtab_node_cachep = kmem_cache_create("avtab_node",
	avtab_node_cachep = kmem_cache_create("avtab_node",
+2 −0
Original line number Original line Diff line number Diff line
@@ -71,6 +71,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
		    void *p);
		    void *p);


int avtab_read(struct avtab *a, void *fp, struct policydb *pol);
int avtab_read(struct avtab *a, void *fp, struct policydb *pol);
int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp);
int avtab_write(struct policydb *p, struct avtab *a, void *fp);


struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
					  struct avtab_datum *datum);
					  struct avtab_datum *datum);
Loading