[PATCH 08/14] Implement TSEM control plane.

Greg KH gregkh at linuxfoundation.org
Thu Feb 9 11:30:51 UTC 2023


On Fri, Feb 03, 2023 at 11:09:48PM -0600, Dr. Greg wrote:
> The fs.c file contains the implementation of the TSEM control
> plane that is in the form of a pseudo-filesystem mounted on the
> following directory:
> 
> /sys/fs/tsem

Why are you using sysfs to mount this?

> 
> The following file documents the interface provided by the
> control plane:
> 
> Documentation/ABI/testing/tsemfs
> 
> The pseudo-files act on the modeling context of the process that
> is acting on the file.  For example, reading the 'id'
> pseudo-file, returns the modeling domain identifier that the
> process is running in.
> 
> The ExternalTMA directory is used to segreate the pseudo-files
> that are created in order to surface security event descriptions
> to an external trust orchestrator.  The files in this directory
> appear as the numeric value of the modeling domain they were
> created for.
> 
> The 'control' pseudo-file is the only writable file in the plane
> and is used to control the TSEM implementation.  The most
> important and primary roles are to create namespaces and set the
> trust status of a process modeled by an external TMA.
> 
> Signed-off-by: Greg Wettstein <greg at enjellic.com>
> ---
>  security/tsem/fs.c | 894 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 894 insertions(+)
>  create mode 100644 security/tsem/fs.c
> 
> diff --git a/security/tsem/fs.c b/security/tsem/fs.c
> new file mode 100644
> index 000000000000..2898a1cc8c97
> --- /dev/null
> +++ b/security/tsem/fs.c
> @@ -0,0 +1,894 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +/*
> + * Copyright (C) 2022 Enjellic Systems Development, LLC

It's 2023 :)

> + * Author: Dr. Greg Wettstein <greg at enjellic.com>
> + *
> + * Implements the sysfs based control plane.

This is NOT sysfs, it is your own filesystem, please don't confuse the
two.

> + */
> +
> +#include <linux/seq_file.h>
> +#include <linux/sysfs.h>
> +#include <linux/fs_context.h>
> +#include <linux/namei.h>
> +#include <linux/poll.h>
> +#include <uapi/linux/magic.h>
> +
> +#include "tsem.h"
> +
> +static int fs_init_context(struct fs_context *context);
> +static int fs_get_tree(struct fs_context *context);
> +
> +static struct file_system_type fs_definition = {
> +	.name = "tsemfs",
> +	.init_fs_context = fs_init_context,
> +	.kill_sb = kill_litter_super
> +};
> +
> +static struct fs_context_operations fs_operations = {
> +	.get_tree = fs_get_tree
> +};
> +
> +static struct vfsmount *fs_mount;
> +
> +static int fs_mount_cnt;
> +
> +static struct dentry *external_dentry;
> +
> +struct control_commands {
> +	char *cmd;
> +	enum tsem_control_type type;
> +};
> +
> +static struct control_commands commands[9] = {
> +	{"internal", TSEM_CONTROL_INTERNAL},
> +	{"external", TSEM_CONTROL_EXTERNAL},
> +	{"enforce", TSEM_CONTROL_ENFORCE},
> +	{"seal", TSEM_CONTROL_SEAL},
> +	{"trusted ", TSEM_CONTROL_TRUSTED},
> +	{"untrusted ", TSEM_CONTROL_UNTRUSTED},
> +	{"state ", TSEM_CONTROL_MAP_STATE},
> +	{"pseudonym ", TSEM_CONTROL_MAP_PSEUDONYM},
> +	{"base ", TSEM_CONTROL_MAP_BASE}
> +};
> +
> +static bool can_access_fs(void)
> +{
> +	struct tsem_TMA_context *ctx = tsem_context(current);
> +
> +	if (ctx->external)
> +		return false;
> +	if (capable(TSEM_CONTROL_CAPABILITY))
> +		return true;
> +	if (ctx->sealed)
> +		return false;
> +	return true;
> +}
> +
> +static int control_COE(pid_t pid, unsigned long cmd)
> +{
> +	bool wakeup = false;
> +	int retn = -ESRCH;
> +	struct task_struct *COE;
> +	struct tsem_task *task;
> +
> +	rcu_read_lock();
> +	COE = find_task_by_vpid(pid);
> +	if (COE != NULL) {
> +		task = tsem_task(COE);
> +		if (cmd == TSEM_CONTROL_UNTRUSTED)
> +			task->trust_status = TSEM_TASK_UNTRUSTED;
> +		if (cmd == TSEM_CONTROL_TRUSTED) {
> +			task->trust_status &= ~TSEM_TASK_TRUST_PENDING;
> +			if (tsem_task_trusted(COE))
> +				task->trust_status = TSEM_TASK_TRUSTED;
> +		}
> +
> +		retn = 0;
> +		wakeup = true;
> +	}
> +	rcu_read_unlock();
> +
> +	if (wakeup)
> +		wake_up_process(COE);
> +
> +	return retn;
> +}
> +
> +static int config_context(unsigned long cmd, char *bufr)
> +{
> +	int retn = -EINVAL;
> +	unsigned int lp;
> +	struct tsem_TMA_context *ctx = tsem_context(current);
> +
> +	if (ctx->sealed)
> +		return -EPERM;
> +
> +	if (cmd == TSEM_CONTROL_SEAL) {
> +		ctx->sealed = true;
> +		retn = 0;
> +	}
> +
> +	if (cmd == TSEM_CONTROL_ENFORCE) {
> +		for (lp = 0; lp < ARRAY_SIZE(tsem_root_actions); ++lp)
> +			ctx->actions[lp] = TSEM_ACTION_EPERM;
> +		retn = 0;
> +	}
> +
> +	return retn;
> +}
> +
> +static int config_point(enum tsem_control_type type, u8 *arg)
> +{
> +	int retn = -EINVAL;
> +	u8 mapping[WP256_DIGEST_SIZE];
> +
> +	if (*++arg == '\0')
> +		goto done;
> +	if (strlen(arg) != sizeof(mapping) * 2)
> +		goto done;
> +	if (hex2bin(mapping, arg, sizeof(mapping)))
> +		goto done;
> +
> +	if (type == TSEM_CONTROL_MAP_STATE)
> +		retn = tsem_model_load_point(mapping);
> +	else if (type == TSEM_CONTROL_MAP_PSEUDONYM)
> +		retn = tsem_model_load_pseudonym(mapping);
> +	else {
> +		tsem_model_load_base(mapping);
> +		retn = 0;
> +	}
> +
> + done:
> +	return retn;
> +}
> +
> +static void show_event(struct seq_file *c, struct tsem_event *ep, char *file)
> +{
> +	seq_printf(c, "event{process=%s, filename=%s, type=%s, task_id=%*phN}",
> +		   ep->comm, file ? file : "none", tsem_names[ep->event],
> +		   WP256_DIGEST_SIZE, ep->task_id);
> +	seq_printf(c, " COE{uid=%d, euid=%d, suid=%d, gid=%d, egid=%d, sgid=%d, fsuid=%d, fsgid=%d, cap=0x%llx} ",
> +		   ep->COE.uid, ep->COE.euid, ep->COE.suid, ep->COE.gid,
> +		   ep->COE.egid, ep->COE.sgid, ep->COE.fsuid, ep->COE.fsgid,
> +		   ep->COE.capability.value);
> +}

You are printing out a lot of specific data in a specific format that is
documented no where that I can see :(

Also, you are making the same mistake that /proc made decades ago,
creating files that must be parsed and can NEVER be changed in the
future.  Why not make this a one-value-per-file filesystem instead so
that you have flexibility going forward?

> +static void show_file(struct seq_file *c, struct tsem_event *ep)
> +{
> +	seq_printf(c, "file{flags=%u, uid=%d, gid=%d, mode=0%o, name_length=%u, name=%*phN, s_magic=0x%0x, s_id=%s, s_uuid=%*phN, digest=%*phN}\n",
> +		   ep->file.flags, ep->file.uid, ep->file.gid, ep->file.mode,
> +		   ep->file.name_length, WP256_DIGEST_SIZE, ep->file.name,
> +		   ep->file.s_magic, ep->file.s_id,
> +		   (int) sizeof(ep->file.s_uuid), ep->file.s_uuid,
> +		   WP256_DIGEST_SIZE, ep->file.digest);

Same here, where is the documentation for all of this and what userspace
tools parse it?

thanks,

greg k-h



More information about the Linux-security-module-archive mailing list