@@ -71,6 +71,7 @@ struct clone_args;
struct open_how;
struct mount_attr;
struct landlock_ruleset_attr;
+struct lsm_cxt;
enum landlock_rule_type;
#include <linux/types.h>
@@ -1056,6 +1057,7 @@ asmlinkage long sys_memfd_secret(unsigned int flags);
asmlinkage long sys_set_mempolicy_home_node(unsigned long start, unsigned long len,
unsigned long home_node,
unsigned long flags);
+asmlinkage long sys_lsm_self_attr(struct lsm_ctx *ctx, size_t *size, int flags);
/*
* Architecture-specific system calls
@@ -9,6 +9,27 @@
#ifndef _UAPI_LINUX_LSM_H
#define _UAPI_LINUX_LSM_H
+#include <linux/types.h>
+#include <linux/unistd.h>
+
+/**
+ * struct lsm_ctx - LSM context
+ * @id: the LSM id number, see LSM_ID_XXX
+ * @flags: context specifier and LSM specific flags
+ * @ctx_len: the size of @ctx
+ * @ctx: the LSM context, a nul terminated string
+ *
+ * @ctx in a nul terminated string.
+ * (strlen(@ctx) < @ctx_len) is always true.
+ * (strlen(@ctx) == @ctx_len + 1) is not guaranteed.
+ */
+struct lsm_ctx {
+ unsigned int id;
+ unsigned int flags;
+ __kernel_size_t ctx_len;
+ unsigned char ctx[];
+};
+
/*
* ID values to identify security modules.
* A system may use more than one security module.
@@ -262,6 +262,9 @@ COND_SYSCALL_COMPAT(recvmsg);
/* mm/nommu.c, also with MMU */
COND_SYSCALL(mremap);
+/* security/lsm_syscalls.c */
+COND_SYSCALL(lsm_self_attr);
+
/* security/keys/keyctl.c */
COND_SYSCALL(add_key);
COND_SYSCALL(request_key);
@@ -7,6 +7,7 @@ obj-$(CONFIG_KEYS) += keys/
# always enable default capabilities
obj-y += commoncap.o
+obj-$(CONFIG_SECURITY) += lsm_syscalls.o
obj-$(CONFIG_MMU) += min_addr.o
# Object file lists
new file mode 100644
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * System calls implementing the Linux Security Module API.
+ *
+ * Copyright (C) 2022 Casey Schaufler <casey@schaufler-ca.com>
+ * Copyright (C) Intel Corporation
+ */
+
+#include <asm/current.h>
+#include <linux/compiler_types.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/security.h>
+#include <linux/stddef.h>
+#include <linux/syscalls.h>
+#include <linux/types.h>
+#include <linux/lsm_hooks.h>
+#include <uapi/linux/lsm.h>
+
+struct feature_map {
+ char *name;
+ int feature;
+};
+
+static const struct feature_map lsm_attr_names[] = {
+ { .name = "current", .feature = LSM_ATTR_CURRENT, },
+ { .name = "exec", .feature = LSM_ATTR_EXEC, },
+ { .name = "fscreate", .feature = LSM_ATTR_FSCREATE, },
+ { .name = "keycreate", .feature = LSM_ATTR_KEYCREATE, },
+ { .name = "prev", .feature = LSM_ATTR_PREV, },
+ { .name = "sockcreate", .feature = LSM_ATTR_SOCKCREATE, },
+};
+
+/**
+ * lsm_self_attr - Return current task's security module attributes
+ * @ctx: the LSM contexts
+ * @size: size of @ctx, updated on return
+ * @flags: reserved for future use, must be zero
+ *
+ * Returns the calling task's LSM contexts. On success this
+ * function returns the number of @ctx array elements. This value
+ * may be zero if there are no LSM contexts assigned. If @size is
+ * insufficient to contain the return data -E2BIG is returned and
+ * @size is set to the minimum required size. In all other cases
+ * a negative value indicating the error is returned.
+ */
+SYSCALL_DEFINE3(lsm_self_attr,
+ struct lsm_ctx __user *, ctx,
+ size_t __user *, size,
+ int, flags)
+{
+ struct lsm_ctx *final = NULL;
+ struct lsm_ctx *interum;
+ struct lsm_ctx *ip;
+ void *curr;
+ char **interum_ctx;
+ char *cp;
+ size_t total_size = 0;
+ int count = 0;
+ int attr;
+ int len;
+ int rc = 0;
+ int i;
+
+ interum = kzalloc(ARRAY_SIZE(lsm_attr_names) * lsm_id *
+ sizeof(*interum), GFP_KERNEL);
+ if (interum == NULL)
+ return -ENOMEM;
+ ip = interum;
+
+ interum_ctx = kzalloc(ARRAY_SIZE(lsm_attr_names) * lsm_id *
+ sizeof(*interum_ctx), GFP_KERNEL);
+ if (interum_ctx == NULL) {
+ kfree(interum);
+ return -ENOMEM;
+ }
+
+ for (attr = 0; attr < ARRAY_SIZE(lsm_attr_names); attr++) {
+ for (i = 0; i < lsm_id; i++) {
+ if ((lsm_idlist[i]->features &
+ lsm_attr_names[attr].feature) == 0)
+ continue;
+
+ len = security_getprocattr(current, lsm_idlist[i]->id,
+ lsm_attr_names[attr].name,
+ &cp);
+ if (len <= 0)
+ continue;
+
+ ip->id = lsm_idlist[i]->id;
+ ip->flags = lsm_attr_names[attr].feature;
+ /* space for terminating \0 is allocated below */
+ ip->ctx_len = len + 1;
+ interum_ctx[count] = cp;
+ /*
+ * Security modules have been inconsistent about
+ * including the \0 terminator in the size. The
+ * context len has been adjusted to ensure there
+ * is one.
+ * At least one security module adds a \n at the
+ * end of a context to make it look nicer. Change
+ * that to a \0 so that user space doesn't have to
+ * work around it. Because of this meddling it is
+ * safe to assume that lsm_ctx.name is terminated
+ * and that strlen(lsm_ctx.name) < lsm.ctx_len.
+ */
+ total_size += sizeof(*interum) + ip->ctx_len;
+ cp = strnchr(cp, len, '\n');
+ if (cp != NULL)
+ *cp = '\0';
+ ip++;
+ count++;
+ }
+ }
+
+ if (count == 0)
+ goto free_out;
+
+ final = kzalloc(total_size, GFP_KERNEL);
+ if (final == NULL) {
+ rc = -ENOMEM;
+ goto free_out;
+ }
+
+ curr = final;
+ ip = interum;
+ for (i = 0; i < count; i++) {
+ memcpy(curr, ip, sizeof(*interum));
+ curr += sizeof(*interum);
+ memcpy(curr, interum_ctx[i], ip->ctx_len);
+ curr += ip->ctx_len;
+ ip++;
+ }
+
+ if (get_user(len, size)) {
+ rc = -EFAULT;
+ goto free_out;
+ }
+ if (total_size > len) {
+ rc = -ERANGE;
+ goto free_out;
+ }
+ if (copy_to_user(ctx, final, total_size) != 0 ||
+ put_user(total_size, size) != 0)
+ rc = -EFAULT;
+ else
+ rc = count;
+
+free_out:
+ for (i = 0; i < count; i++)
+ kfree(interum_ctx[i]);
+ kfree(interum_ctx);
+ kfree(interum);
+ kfree(final);
+ return rc;
+}
Create a system call lsm_self_attr() to provide the security module maintained attributes of the current process. Historically these attributes have been exposed to user space via entries in procfs under /proc/self/attr. Attributes are provided as a collection of lsm_ctx structures which are placed into a user supplied buffer. Each structure identifys the security module providing the attribute, which of the possible attributes is provided, the size of the attribute, and finally the attribute value. The format of the attribute value is defined by the security module, but will always be \0 terminated. The ctx_len value will be larger than strlen(ctx). ------------------------------ | unsigned int id | ------------------------------ | unsigned int flags | ------------------------------ | __kernel_size_t ctx_len | ------------------------------ | unsigned char ctx[ctx_len] | ------------------------------ | unsigned int id | ------------------------------ | unsigned int flags | ------------------------------ | __kernel_size_t ctx_len | ------------------------------ | unsigned char ctx[ctx_len] | ------------------------------ Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> --- include/linux/syscalls.h | 2 + include/uapi/linux/lsm.h | 21 ++++++ kernel/sys_ni.c | 3 + security/Makefile | 1 + security/lsm_syscalls.c | 156 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 183 insertions(+) create mode 100644 security/lsm_syscalls.c