[PATCH v3 7/9] LSM: lsm_set_self_attr syscall for LSM self attributes

From: Casey Schaufler
Date: Wed Nov 23 2022 - 15:23:57 EST


Create a system call lsm_set_self_attr() to set a security
module maintained attribute of the current process. Historically
these attributes have been exposed to user space via entries in
procfs under /proc/self/attr.

The attribute value is provided in a lsm_ctx structure. The structure
identifys the size of the attribute, and the attribute value. The format
of the attribute value is defined by the security module, but will always
be \0 terminated if it is a string. The ctx_len value must always be
strlen(ctx)+1 if the value is a string. The flags field is reserved for
future security module specific use and must be 0.

---------------------------
| __u32 id |
---------------------------
| __u64 flags |
---------------------------
| __kernel_size_t ctx_len |
---------------------------
| __u8 ctx[ctx_len] |
---------------------------

Signed-off-by: Casey Schaufler <casey@xxxxxxxxxxxxxxxx>
---
Documentation/userspace-api/lsm.rst | 3 +++
include/linux/syscalls.h | 2 ++
kernel/sys_ni.c | 1 +
security/lsm_syscalls.c | 41 +++++++++++++++++++++++++++++
4 files changed, 47 insertions(+)

diff --git a/Documentation/userspace-api/lsm.rst b/Documentation/userspace-api/lsm.rst
index e342d75b99ab..c7da13801305 100644
--- a/Documentation/userspace-api/lsm.rst
+++ b/Documentation/userspace-api/lsm.rst
@@ -57,6 +57,9 @@ Get the security attributes of the current process
.. kernel-doc:: security/lsm_syscalls.c
:identifiers: sys_lsm_get_self_attr

+.. kernel-doc:: security/lsm_syscalls.c
+ :identifiers: sys_lsm_set_self_attr
+
.. kernel-doc:: security/lsm_syscalls.c
:identifiers: sys_lsm_module_list

diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 2411b4043752..75123c13a55f 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -1060,6 +1060,8 @@ asmlinkage long sys_set_mempolicy_home_node(unsigned long start, unsigned long l
asmlinkage long sys_lsm_get_self_attr(struct lsm_ctx *ctx, size_t *size,
int flags);
asmlinkage long sys_lsm_module_list(u32 *ids, size_t *size, int flags);
+asmlinkage long sys_lsm_set_self_attr(struct lsm_ctx *ctx, size_t size,
+ int flags);

/*
* Architecture-specific system calls
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index af1fd28c0420..c3884c1c7339 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -265,6 +265,7 @@ COND_SYSCALL(mremap);
/* security/lsm_syscalls.c */
COND_SYSCALL(lsm_get_self_attr);
COND_SYSCALL(lsm_module_list);
+COND_SYSCALL(lsm_set_self_attr);

/* security/keys/keyctl.c */
COND_SYSCALL(add_key);
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
index 3838cdf66310..b0dc11e7d3df 100644
--- a/security/lsm_syscalls.c
+++ b/security/lsm_syscalls.c
@@ -181,6 +181,47 @@ SYSCALL_DEFINE3(lsm_get_self_attr,
return rc;
}

+/**
+ * sys_lsm_set_self_attr - Set current task's security module attribute
+ * @ctx: the LSM contexts
+ * @size: size of @ctx
+ * @flags: which attribute to set
+ *
+ * Sets the calling task's LSM context. On success this function
+ * returns 0. If the attribute specified cannot be set a negative
+ * value indicating the reason for the error is returned.
+ */
+SYSCALL_DEFINE3(lsm_set_self_attr,
+ struct lsm_ctx __user *, ctx,
+ __kernel_size_t, size,
+ __u32, flags)
+{
+ int rc = -EINVAL;
+ int attr;
+ void *page;
+ struct lsm_ctx *ip;
+
+ if (size > PAGE_SIZE)
+ return -E2BIG;
+ if (size <= sizeof(*ip))
+ return -EINVAL;
+
+ attr = attr_used_index(flags);
+ if (attr < 0)
+ return attr;
+
+ page = memdup_user(ctx, size);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+
+ ip = page;
+ if (sizeof(*ip) + ip->ctx_len <= size)
+ rc = security_setprocattr(ip->id, lsm_attr_names[attr].name,
+ ip->ctx, ip->ctx_len);
+ kfree(page);
+ return (rc > 0) ? 0 : rc;
+}
+
/**
* sys_lsm_module_list - Return a list of the active security modules
* @ids: the LSM module ids
--
2.38.1