2023-09-12 23:37:00

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v15 00/11] LSM: Three basic syscalls

Add three system calls for the Linux Security Module ABI.

lsm_get_self_attr() provides the security module specific attributes
that have previously been visible in the /proc/self/attr directory.
For each security module that uses the specified attribute on the
current process the system call will return an LSM identifier and
the value of the attribute. The LSM and attribute identifier values
are defined in include/uapi/linux/lsm.h

LSM identifiers are simple integers and reflect the order in which
the LSM was added to the mainline kernel. This is a convention, not
a promise of the API. LSM identifiers below the value of 100 are
reserved for unspecified future uses. That could include information
about the security infrastructure itself, or about how multiple LSMs
might interact with each other.

A new LSM hook security_getselfattr() is introduced to get the
required information from the security modules. This is similar
to the existing security_getprocattr() hook, but specifies the
format in which string data is returned and requires the module
to put the information into a userspace destination.

lsm_set_self_attr() changes the specified LSM attribute. Only one
attribute can be changed at a time, and then only if the specified
security module allows the change.

A new LSM hook security_setselfattr() is introduced to set the
required information in the security modules. This is similar
to the existing security_setprocattr() hook, but specifies the
format in which string data is presented and requires the module
to get the information from a userspace destination.

lsm_list_modules() provides the LSM identifiers, in order, of the
security modules that are active on the system. This has been
available in the securityfs file /sys/kernel/security/lsm.

Patch 0001 changes the LSM registration from passing the name
of the module to passing a lsm_id structure that contains the
name of the module, an LSM identifier number and an attribute
identifier.
Patch 0002 adds the registered lsm_ids to a table.
Patch 0003 changes security_[gs]etprocattr() to use LSM IDs instead
of LSM names.
Patch 0004 implements lsm_get_self_attr() and lsm_set_self_attr().
New LSM hooks security_getselfattr() and security_setselfattr() are
defined.
Patch 0005 implements lsm_list_modules().
Patch 0006 wires up the syscalls.
Patch 0007 implements helper functions to make it easier for
security modules to use lsm_ctx structures.
Patch 0008 provides the Smack implementation for [gs]etselfattr().
Patch 0009 provides the AppArmor implementation for [gs]etselfattr().
Patch 0010 provides the SELinux implementation for [gs]etselfattr().
Patch 0011 implements selftests for the three new syscalls.

https://github.com/cschaufler/lsm-stacking.git#syscalls-6.5-rc7-v14

v15: Rebased on 6.6-rc1.
Adopt suggested improvements to security_getprocattr,
making the code easier to read.
Squash a code fix from 0011 to 0004.
v14: Make the handling of LSM_FLAG_SINGLE easier to understand.
Tighten the comments and documentation.
Better use of const, static, and __ro_after_init.
Add selftests for LSM_FLAG_SINGLE cases.
v13: Change the setselfattr code to do a single user copy.
Make the self tests more robust.
Improve use of const.
Change syscall numbers to reflect upstream additions.
v12: Repair a registration time overflow check.
v11: Remove redundent alignment code
Improve a few comments.
Use LSM_ATTR_UNDEF in place of 0 in a few places.
Correct a return of -EINVAL to -E2BIG.
v10: Correct use of __user.
Improve a few comments.
Revert unnecessary changes in module initialization.
v9: Support a flag LSM_FLAG_SINGLE in lsm_get_self_attr() that
instructs the call to provide only the attribute for the LSM
identified in the referenced lsm_ctx structure.
Fix a typing error.
Change some coding style.
v8: Allow an LSM to provide more than one instance of an attribute,
even though none of the existing modules do so.
Pad the data returned by lsm_get_self_attr() to the size of
the struct lsm_ctx.
Change some displeasing varilable names.
v7: Pass the attribute desired to lsm_[gs]et_self_attr in its own
parameter rather than encoding it in the flags.
Change the flags parameters to u32.
Don't shortcut out of calling LSM specific code in the
infrastructure, let the LSM report that doesn't support an
attribute instead. With that it is not necessary to maintain
a set of supported attributes in the lsm_id structure.
Fix a typing error.
v6: Switch from reusing security_[gs]procattr() to using new
security_[gs]selfattr() hooks. Use explicit sized data types
in the lsm_ctx structure.

v5: Correct syscall parameter data types.

v4: Restore "reserved" LSM ID values. Add explaination.
Squash patches that introduce fields in lsm_id.
Correct a wireup error.

v3: Add lsm_set_self_attr().
Rename lsm_self_attr() to lsm_get_self_attr().
Provide the values only for a specifed attribute in
lsm_get_self_attr().
Add selftests for the three new syscalls.
Correct some parameter checking.

v2: Use user-interface safe data types.
Remove "reserved" LSM ID values.
Improve kerneldoc comments
Include copyright dates
Use more descriptive name for LSM counter
Add documentation
Correct wireup errors

Casey Schaufler (11):
LSM: Identify modules by more than name
LSM: Maintain a table of LSM attribute data
proc: Use lsmids instead of lsm names for attrs
LSM: syscalls for current process attributes
LSM: Create lsm_list_modules system call
LSM: wireup Linux Security Module syscalls
LSM: Helpers for attribute names and filling lsm_ctx
Smack: implement setselfattr and getselfattr hooks
AppArmor: Add selfattr hooks
SELinux: Add selfattr hooks
LSM: selftests for Linux Security Module syscalls

Documentation/userspace-api/index.rst | 1 +
Documentation/userspace-api/lsm.rst | 73 +++++
MAINTAINERS | 2 +
arch/alpha/kernel/syscalls/syscall.tbl | 3 +
arch/arm/tools/syscall.tbl | 3 +
arch/arm64/include/asm/unistd.h | 2 +-
arch/arm64/include/asm/unistd32.h | 6 +
arch/ia64/kernel/syscalls/syscall.tbl | 3 +
arch/m68k/kernel/syscalls/syscall.tbl | 3 +
arch/microblaze/kernel/syscalls/syscall.tbl | 3 +
arch/mips/kernel/syscalls/syscall_n32.tbl | 3 +
arch/mips/kernel/syscalls/syscall_n64.tbl | 3 +
arch/mips/kernel/syscalls/syscall_o32.tbl | 3 +
arch/parisc/kernel/syscalls/syscall.tbl | 3 +
arch/powerpc/kernel/syscalls/syscall.tbl | 3 +
arch/s390/kernel/syscalls/syscall.tbl | 3 +
arch/sh/kernel/syscalls/syscall.tbl | 3 +
arch/sparc/kernel/syscalls/syscall.tbl | 3 +
arch/x86/entry/syscalls/syscall_32.tbl | 3 +
arch/x86/entry/syscalls/syscall_64.tbl | 3 +
arch/xtensa/kernel/syscalls/syscall.tbl | 3 +
fs/proc/base.c | 29 +-
fs/proc/internal.h | 2 +-
include/linux/lsm_hook_defs.h | 4 +
include/linux/lsm_hooks.h | 17 +-
include/linux/security.h | 46 ++-
include/linux/syscalls.h | 6 +
include/uapi/asm-generic/unistd.h | 9 +-
include/uapi/linux/lsm.h | 90 ++++++
kernel/sys_ni.c | 3 +
security/Makefile | 1 +
security/apparmor/include/procattr.h | 2 +-
security/apparmor/lsm.c | 99 ++++++-
security/apparmor/procattr.c | 10 +-
security/bpf/hooks.c | 9 +-
security/commoncap.c | 8 +-
security/landlock/cred.c | 2 +-
security/landlock/fs.c | 2 +-
security/landlock/ptrace.c | 2 +-
security/landlock/setup.c | 6 +
security/landlock/setup.h | 1 +
security/loadpin/loadpin.c | 9 +-
security/lockdown/lockdown.c | 8 +-
security/lsm_syscalls.c | 120 ++++++++
security/safesetid/lsm.c | 9 +-
security/security.c | 253 +++++++++++++++-
security/selinux/hooks.c | 143 +++++++--
security/smack/smack_lsm.c | 103 ++++++-
security/tomoyo/tomoyo.c | 9 +-
security/yama/yama_lsm.c | 8 +-
.../arch/mips/entry/syscalls/syscall_n64.tbl | 3 +
.../arch/powerpc/entry/syscalls/syscall.tbl | 3 +
.../perf/arch/s390/entry/syscalls/syscall.tbl | 3 +
.../arch/x86/entry/syscalls/syscall_64.tbl | 3 +
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/lsm/.gitignore | 1 +
tools/testing/selftests/lsm/Makefile | 17 ++
tools/testing/selftests/lsm/common.c | 89 ++++++
tools/testing/selftests/lsm/common.h | 33 +++
tools/testing/selftests/lsm/config | 3 +
.../selftests/lsm/lsm_get_self_attr_test.c | 275 ++++++++++++++++++
.../selftests/lsm/lsm_list_modules_test.c | 140 +++++++++
.../selftests/lsm/lsm_set_self_attr_test.c | 74 +++++
63 files changed, 1694 insertions(+), 93 deletions(-)
create mode 100644 Documentation/userspace-api/lsm.rst
create mode 100644 include/uapi/linux/lsm.h
create mode 100644 security/lsm_syscalls.c
create mode 100644 tools/testing/selftests/lsm/.gitignore
create mode 100644 tools/testing/selftests/lsm/Makefile
create mode 100644 tools/testing/selftests/lsm/common.c
create mode 100644 tools/testing/selftests/lsm/common.h
create mode 100644 tools/testing/selftests/lsm/config
create mode 100644 tools/testing/selftests/lsm/lsm_get_self_attr_test.c
create mode 100644 tools/testing/selftests/lsm/lsm_list_modules_test.c
create mode 100644 tools/testing/selftests/lsm/lsm_set_self_attr_test.c

--
2.41.0


2023-09-12 23:42:17

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v15 09/11] AppArmor: Add selfattr hooks

Add hooks for setselfattr and getselfattr. These hooks are not very
different from their setprocattr and getprocattr equivalents, and
much of the code is shared.

Signed-off-by: Casey Schaufler <[email protected]>
Acked-by: John Johansen <[email protected]>
Cc: John Johansen <[email protected]>
---
security/apparmor/include/procattr.h | 2 +-
security/apparmor/lsm.c | 91 ++++++++++++++++++++++++++--
security/apparmor/procattr.c | 10 +--
3 files changed, 92 insertions(+), 11 deletions(-)

diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h
index 31689437e0e1..03dbfdb2f2c0 100644
--- a/security/apparmor/include/procattr.h
+++ b/security/apparmor/include/procattr.h
@@ -11,7 +11,7 @@
#ifndef __AA_PROCATTR_H
#define __AA_PROCATTR_H

-int aa_getprocattr(struct aa_label *label, char **string);
+int aa_getprocattr(struct aa_label *label, char **string, bool newline);
int aa_setprocattr_changehat(char *args, size_t size, int flags);

#endif /* __AA_PROCATTR_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 20b93501fbd1..ac75e95e68a5 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -630,6 +630,55 @@ static int apparmor_sb_pivotroot(const struct path *old_path,
return error;
}

+static int apparmor_getselfattr(unsigned int attr, struct lsm_ctx __user *lx,
+ size_t *size, u32 flags)
+{
+ int error = -ENOENT;
+ struct aa_task_ctx *ctx = task_ctx(current);
+ struct aa_label *label = NULL;
+ size_t total_len = 0;
+ char *value;
+
+ switch (attr) {
+ case LSM_ATTR_CURRENT:
+ label = aa_get_newest_label(cred_label(current_cred()));
+ break;
+ case LSM_ATTR_PREV:
+ if (ctx->previous)
+ label = aa_get_newest_label(ctx->previous);
+ break;
+ case LSM_ATTR_EXEC:
+ if (ctx->onexec)
+ label = aa_get_newest_label(ctx->onexec);
+ break;
+ default:
+ error = -EOPNOTSUPP;
+ break;
+ }
+
+ if (label) {
+ error = aa_getprocattr(label, &value, false);
+ if (error > 0) {
+ total_len = ALIGN(struct_size(lx, ctx, error), 8);
+ if (total_len > *size)
+ error = -E2BIG;
+ else if (lx)
+ error = lsm_fill_user_ctx(lx, value, error,
+ LSM_ID_APPARMOR, 0);
+ else
+ error = 1;
+ }
+ kfree(value);
+ }
+
+ aa_put_label(label);
+
+ *size = total_len;
+ if (error < 0)
+ return error;
+ return 1;
+}
+
static int apparmor_getprocattr(struct task_struct *task, const char *name,
char **value)
{
@@ -649,7 +698,7 @@ static int apparmor_getprocattr(struct task_struct *task, const char *name,
error = -EINVAL;

if (label)
- error = aa_getprocattr(label, value);
+ error = aa_getprocattr(label, value, true);

aa_put_label(label);
put_cred(cred);
@@ -657,8 +706,7 @@ static int apparmor_getprocattr(struct task_struct *task, const char *name,
return error;
}

-static int apparmor_setprocattr(const char *name, void *value,
- size_t size)
+static int do_setattr(u64 attr, void *value, size_t size)
{
char *command, *largs = NULL, *args = value;
size_t arg_size;
@@ -689,7 +737,7 @@ static int apparmor_setprocattr(const char *name, void *value,
goto out;

arg_size = size - (args - (largs ? largs : (char *) value));
- if (strcmp(name, "current") == 0) {
+ if (attr == LSM_ATTR_CURRENT) {
if (strcmp(command, "changehat") == 0) {
error = aa_setprocattr_changehat(args, arg_size,
AA_CHANGE_NOFLAGS);
@@ -704,7 +752,7 @@ static int apparmor_setprocattr(const char *name, void *value,
error = aa_change_profile(args, AA_CHANGE_STACK);
} else
goto fail;
- } else if (strcmp(name, "exec") == 0) {
+ } else if (attr == LSM_ATTR_EXEC) {
if (strcmp(command, "exec") == 0)
error = aa_change_profile(args, AA_CHANGE_ONEXEC);
else if (strcmp(command, "stack") == 0)
@@ -724,13 +772,42 @@ static int apparmor_setprocattr(const char *name, void *value,

fail:
aad(&sa)->label = begin_current_label_crit_section();
- aad(&sa)->info = name;
+ if (attr == LSM_ATTR_CURRENT)
+ aad(&sa)->info = "current";
+ else if (attr == LSM_ATTR_EXEC)
+ aad(&sa)->info = "exec";
+ else
+ aad(&sa)->info = "invalid";
aad(&sa)->error = error = -EINVAL;
aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL);
end_current_label_crit_section(aad(&sa)->label);
goto out;
}

+static int apparmor_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
+ size_t size, u32 flags)
+{
+ int rc;
+
+ if (attr != LSM_ATTR_CURRENT && attr != LSM_ATTR_EXEC)
+ return -EOPNOTSUPP;
+
+ rc = do_setattr(attr, ctx->ctx, ctx->ctx_len);
+ if (rc > 0)
+ return 0;
+ return rc;
+}
+
+static int apparmor_setprocattr(const char *name, void *value,
+ size_t size)
+{
+ int attr = lsm_name_to_attr(name);
+
+ if (attr)
+ return do_setattr(attr, value, size);
+ return -EINVAL;
+}
+
/**
* apparmor_bprm_committing_creds - do task cleanup on committing new creds
* @bprm: binprm for the exec (NOT NULL)
@@ -1253,6 +1330,8 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(file_lock, apparmor_file_lock),
LSM_HOOK_INIT(file_truncate, apparmor_file_truncate),

+ LSM_HOOK_INIT(getselfattr, apparmor_getselfattr),
+ LSM_HOOK_INIT(setselfattr, apparmor_setselfattr),
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),

diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
index 197d41f9c32b..e3857e3d7c6c 100644
--- a/security/apparmor/procattr.c
+++ b/security/apparmor/procattr.c
@@ -20,6 +20,7 @@
* aa_getprocattr - Return the label information for @label
* @label: the label to print label info about (NOT NULL)
* @string: Returns - string containing the label info (NOT NULL)
+ * @newline: indicates that a newline should be added
*
* Requires: label != NULL && string != NULL
*
@@ -27,7 +28,7 @@
*
* Returns: size of string placed in @string else error code on failure
*/
-int aa_getprocattr(struct aa_label *label, char **string)
+int aa_getprocattr(struct aa_label *label, char **string, bool newline)
{
struct aa_ns *ns = labels_ns(label);
struct aa_ns *current_ns = aa_get_current_ns();
@@ -57,11 +58,12 @@ int aa_getprocattr(struct aa_label *label, char **string)
return len;
}

- (*string)[len] = '\n';
- (*string)[len + 1] = 0;
+ if (newline)
+ (*string)[len++] = '\n';
+ (*string)[len] = 0;

aa_put_ns(current_ns);
- return len + 1;
+ return len;
}

/**
--
2.41.0

2023-09-13 00:47:08

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

Create a system call to report the list of Linux Security Modules
that are active on the system. The list is provided as an array
of LSM ID numbers.

The calling application can use this list determine what LSM
specific actions it might take. That might include choosing an
output format, determining required privilege or bypassing
security module specific behavior.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: Serge Hallyn <[email protected]>
Reviewed-by: John Johansen <[email protected]>
---
Documentation/userspace-api/lsm.rst | 3 +++
include/linux/syscalls.h | 1 +
kernel/sys_ni.c | 1 +
security/lsm_syscalls.c | 39 +++++++++++++++++++++++++++++
4 files changed, 44 insertions(+)

diff --git a/Documentation/userspace-api/lsm.rst b/Documentation/userspace-api/lsm.rst
index f8499f3e2826..a76da373841b 100644
--- a/Documentation/userspace-api/lsm.rst
+++ b/Documentation/userspace-api/lsm.rst
@@ -63,6 +63,9 @@ Get the specified 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_list_modules
+
Additional documentation
========================

diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 8637287bd39d..323ef5e2667d 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -945,6 +945,7 @@ asmlinkage long sys_lsm_get_self_attr(unsigned int attr, struct lsm_ctx *ctx,
size_t *size, __u32 flags);
asmlinkage long sys_lsm_set_self_attr(unsigned int attr, struct lsm_ctx *ctx,
size_t size, __u32 flags);
+asmlinkage long sys_lsm_list_modules(u64 *ids, size_t *size, u32 flags);

/*
* Architecture-specific system calls
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index f81f2468c0ce..738ca470fcce 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -172,6 +172,7 @@ COND_SYSCALL(fadvise64_64);
COND_SYSCALL_COMPAT(fadvise64_64);
COND_SYSCALL(lsm_get_self_attr);
COND_SYSCALL(lsm_set_self_attr);
+COND_SYSCALL(lsm_list_modules);

/* CONFIG_MMU only */
COND_SYSCALL(swapon);
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
index 226ae80d9683..329aaca5efc0 100644
--- a/security/lsm_syscalls.c
+++ b/security/lsm_syscalls.c
@@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
{
return security_getselfattr(attr, ctx, size, flags);
}
+
+/**
+ * sys_lsm_list_modules - Return a list of the active security modules
+ * @ids: the LSM module ids
+ * @size: pointer to size of @ids, updated on return
+ * @flags: reserved for future use, must be zero
+ *
+ * Returns a list of the active LSM ids. On success this function
+ * returns the number of @ids array elements. This value may be zero
+ * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
+ u32, flags)
+{
+ size_t total_size = lsm_active_cnt * sizeof(*ids);
+ size_t usize;
+ int i;
+
+ if (flags)
+ return -EINVAL;
+
+ if (get_user(usize, size))
+ return -EFAULT;
+
+ if (put_user(total_size, size) != 0)
+ return -EFAULT;
+
+ if (usize < total_size)
+ return -E2BIG;
+
+ for (i = 0; i < lsm_active_cnt; i++)
+ if (put_user(lsm_idlist[i]->id, ids++))
+ return -EFAULT;
+
+ return lsm_active_cnt;
+}
--
2.41.0

2023-09-13 03:11:50

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v15 10/11] SELinux: Add selfattr hooks

Add hooks for setselfattr and getselfattr. These hooks are not very
different from their setprocattr and getprocattr equivalents, and
much of the code is shared.

Signed-off-by: Casey Schaufler <[email protected]>
Cc: [email protected]
Cc: Paul Moore <[email protected]>
---
security/selinux/hooks.c | 134 +++++++++++++++++++++++++++++++--------
1 file changed, 107 insertions(+), 27 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3ad500dff390..f066dcf30ec0 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6279,8 +6279,8 @@ static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
inode_doinit_with_dentry(inode, dentry);
}

-static int selinux_getprocattr(struct task_struct *p,
- const char *name, char **value)
+static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
+ char **value)
{
const struct task_security_struct *__tsec;
u32 sid;
@@ -6297,20 +6297,27 @@ static int selinux_getprocattr(struct task_struct *p,
goto bad;
}

- if (!strcmp(name, "current"))
+ switch (attr) {
+ case LSM_ATTR_CURRENT:
sid = __tsec->sid;
- else if (!strcmp(name, "prev"))
+ break;
+ case LSM_ATTR_PREV:
sid = __tsec->osid;
- else if (!strcmp(name, "exec"))
+ break;
+ case LSM_ATTR_EXEC:
sid = __tsec->exec_sid;
- else if (!strcmp(name, "fscreate"))
+ break;
+ case LSM_ATTR_FSCREATE:
sid = __tsec->create_sid;
- else if (!strcmp(name, "keycreate"))
+ break;
+ case LSM_ATTR_KEYCREATE:
sid = __tsec->keycreate_sid;
- else if (!strcmp(name, "sockcreate"))
+ break;
+ case LSM_ATTR_SOCKCREATE:
sid = __tsec->sockcreate_sid;
- else {
- error = -EINVAL;
+ break;
+ default:
+ error = -EOPNOTSUPP;
goto bad;
}
rcu_read_unlock();
@@ -6328,7 +6335,7 @@ static int selinux_getprocattr(struct task_struct *p,
return error;
}

-static int selinux_setprocattr(const char *name, void *value, size_t size)
+static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
{
struct task_security_struct *tsec;
struct cred *new;
@@ -6339,23 +6346,31 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
/*
* Basic control over ability to set these attributes at all.
*/
- if (!strcmp(name, "exec"))
+ switch (attr) {
+ case LSM_ATTR_EXEC:
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETEXEC, NULL);
- else if (!strcmp(name, "fscreate"))
+ break;
+ case LSM_ATTR_FSCREATE:
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETFSCREATE, NULL);
- else if (!strcmp(name, "keycreate"))
+ break;
+ case LSM_ATTR_KEYCREATE:
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETKEYCREATE, NULL);
- else if (!strcmp(name, "sockcreate"))
+ break;
+ case LSM_ATTR_SOCKCREATE:
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETSOCKCREATE, NULL);
- else if (!strcmp(name, "current"))
+ break;
+ case LSM_ATTR_CURRENT:
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETCURRENT, NULL);
- else
- error = -EINVAL;
+ break;
+ default:
+ error = -EOPNOTSUPP;
+ break;
+ }
if (error)
return error;

@@ -6367,13 +6382,14 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
}
error = security_context_to_sid(value, size,
&sid, GFP_KERNEL);
- if (error == -EINVAL && !strcmp(name, "fscreate")) {
+ if (error == -EINVAL && attr == LSM_ATTR_FSCREATE) {
if (!has_cap_mac_admin(true)) {
struct audit_buffer *ab;
size_t audit_size;

- /* We strip a nul only if it is at the end, otherwise the
- * context contains a nul and we should audit that */
+ /* We strip a nul only if it is at the end,
+ * otherwise the context contains a nul and
+ * we should audit that */
if (str[size - 1] == '\0')
audit_size = size - 1;
else
@@ -6384,7 +6400,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
if (!ab)
return error;
audit_log_format(ab, "op=fscreate invalid_context=");
- audit_log_n_untrustedstring(ab, value, audit_size);
+ audit_log_n_untrustedstring(ab, value,
+ audit_size);
audit_log_end(ab);

return error;
@@ -6407,11 +6424,11 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
checks and may_create for the file creation checks. The
operation will then fail if the context is not permitted. */
tsec = selinux_cred(new);
- if (!strcmp(name, "exec")) {
+ if (attr == LSM_ATTR_EXEC) {
tsec->exec_sid = sid;
- } else if (!strcmp(name, "fscreate")) {
+ } else if (attr == LSM_ATTR_FSCREATE) {
tsec->create_sid = sid;
- } else if (!strcmp(name, "keycreate")) {
+ } else if (attr == LSM_ATTR_KEYCREATE) {
if (sid) {
error = avc_has_perm(mysid, sid,
SECCLASS_KEY, KEY__CREATE, NULL);
@@ -6419,9 +6436,9 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
goto abort_change;
}
tsec->keycreate_sid = sid;
- } else if (!strcmp(name, "sockcreate")) {
+ } else if (attr == LSM_ATTR_SOCKCREATE) {
tsec->sockcreate_sid = sid;
- } else if (!strcmp(name, "current")) {
+ } else if (attr == LSM_ATTR_CURRENT) {
error = -EINVAL;
if (sid == 0)
goto abort_change;
@@ -6463,6 +6480,67 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
return error;
}

+static int selinux_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
+ size_t *size, u32 flags)
+{
+ char *value;
+ size_t total_len;
+ int len;
+ int rc = 0;
+
+ len = selinux_lsm_getattr(attr, current, &value);
+ if (len < 0)
+ return len;
+
+ total_len = ALIGN(struct_size(ctx, ctx, len), 8);
+
+ if (total_len > *size)
+ rc = -E2BIG;
+ else if (ctx)
+ rc = lsm_fill_user_ctx(ctx, value, len, LSM_ID_SELINUX, 0);
+
+ kfree(value);
+ *size = total_len;
+ if (rc < 0)
+ return rc;
+ return 1;
+}
+
+static int selinux_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
+ size_t size, u32 flags)
+{
+ int rc;
+
+ rc = selinux_lsm_setattr(attr, ctx->ctx, ctx->ctx_len);
+ if (rc > 0)
+ return 0;
+ return rc;
+}
+
+static int selinux_getprocattr(struct task_struct *p,
+ const char *name, char **value)
+{
+ unsigned int attr = lsm_name_to_attr(name);
+ int rc;
+
+ if (attr) {
+ rc = selinux_lsm_getattr(attr, p, value);
+ if (rc != -EOPNOTSUPP)
+ return rc;
+ }
+
+ return -EINVAL;
+}
+
+static int selinux_setprocattr(const char *name, void *value, size_t size)
+{
+ int attr = lsm_name_to_attr(name);
+
+ if (attr)
+ return selinux_lsm_setattr(attr, value, size);
+ return -EINVAL;
+}
+
static int selinux_ismaclabel(const char *name)
{
return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
@@ -7091,6 +7169,8 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {

LSM_HOOK_INIT(d_instantiate, selinux_d_instantiate),

+ LSM_HOOK_INIT(getselfattr, selinux_getselfattr),
+ LSM_HOOK_INIT(setselfattr, selinux_setselfattr),
LSM_HOOK_INIT(getprocattr, selinux_getprocattr),
LSM_HOOK_INIT(setprocattr, selinux_setprocattr),

--
2.41.0

2023-09-13 03:39:19

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v15 11/11] LSM: selftests for Linux Security Module syscalls

Add selftests for the three system calls supporting the LSM
infrastructure. This set of tests is limited by the differences
in access policy enforced by the existing security modules.

Signed-off-by: Casey Schaufler <[email protected]>
---
MAINTAINERS | 1 +
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/lsm/.gitignore | 1 +
tools/testing/selftests/lsm/Makefile | 17 ++
tools/testing/selftests/lsm/common.c | 89 ++++++
tools/testing/selftests/lsm/common.h | 33 +++
tools/testing/selftests/lsm/config | 3 +
.../selftests/lsm/lsm_get_self_attr_test.c | 275 ++++++++++++++++++
.../selftests/lsm/lsm_list_modules_test.c | 140 +++++++++
.../selftests/lsm/lsm_set_self_attr_test.c | 74 +++++
10 files changed, 634 insertions(+)
create mode 100644 tools/testing/selftests/lsm/.gitignore
create mode 100644 tools/testing/selftests/lsm/Makefile
create mode 100644 tools/testing/selftests/lsm/common.c
create mode 100644 tools/testing/selftests/lsm/common.h
create mode 100644 tools/testing/selftests/lsm/config
create mode 100644 tools/testing/selftests/lsm/lsm_get_self_attr_test.c
create mode 100644 tools/testing/selftests/lsm/lsm_list_modules_test.c
create mode 100644 tools/testing/selftests/lsm/lsm_set_self_attr_test.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 935334123b04..377cc124e615 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19309,6 +19309,7 @@ W: http://kernsec.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git
F: include/uapi/linux/lsm.h
F: security/
+F: tools/testing/selftests/lsm/
X: security/selinux/

SELINUX SECURITY MODULE
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 42806add0114..fc589775ca4c 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -42,6 +42,7 @@ TARGETS += landlock
TARGETS += lib
TARGETS += livepatch
TARGETS += lkdtm
+TARGETS += lsm
TARGETS += membarrier
TARGETS += memfd
TARGETS += memory-hotplug
diff --git a/tools/testing/selftests/lsm/.gitignore b/tools/testing/selftests/lsm/.gitignore
new file mode 100644
index 000000000000..bd68f6c3fd07
--- /dev/null
+++ b/tools/testing/selftests/lsm/.gitignore
@@ -0,0 +1 @@
+/*_test
diff --git a/tools/testing/selftests/lsm/Makefile b/tools/testing/selftests/lsm/Makefile
new file mode 100644
index 000000000000..3f80c0bc093d
--- /dev/null
+++ b/tools/testing/selftests/lsm/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# First run: make -C ../../../.. headers_install
+
+CFLAGS += -Wall -O2 $(KHDR_INCLUDES)
+LOCAL_HDRS += common.h
+
+TEST_GEN_PROGS := lsm_get_self_attr_test lsm_list_modules_test \
+ lsm_set_self_attr_test
+
+include ../lib.mk
+
+$(OUTPUT)/lsm_get_self_attr_test: lsm_get_self_attr_test.c common.c
+$(OUTPUT)/lsm_set_self_attr_test: lsm_set_self_attr_test.c common.c
+$(OUTPUT)/lsm_list_modules_test: lsm_list_modules_test.c common.c
+
+EXTRA_CLEAN = $(OUTPUT)/common.o
diff --git a/tools/testing/selftests/lsm/common.c b/tools/testing/selftests/lsm/common.c
new file mode 100644
index 000000000000..9ad258912646
--- /dev/null
+++ b/tools/testing/selftests/lsm/common.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Security Module infrastructure tests
+ *
+ * Copyright © 2023 Casey Schaufler <[email protected]>
+ */
+
+#define _GNU_SOURCE
+#include <linux/lsm.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "common.h"
+
+#define PROCATTR "/proc/self/attr/"
+
+int read_proc_attr(const char *attr, char *value, size_t size)
+{
+ int fd;
+ int len;
+ char *path;
+
+ len = strlen(PROCATTR) + strlen(attr) + 1;
+ path = calloc(len, 1);
+ if (path == NULL)
+ return -1;
+ sprintf(path, "%s%s", PROCATTR, attr);
+
+ fd = open(path, O_RDONLY);
+ free(path);
+
+ if (fd < 0)
+ return -1;
+ len = read(fd, value, size);
+
+ close(fd);
+
+ /* Ensure value is terminated */
+ if (len <= 0 || len == size)
+ return -1;
+ value[len] = '\0';
+
+ path = strchr(value, '\n');
+ if (path)
+ *path = '\0';
+
+ return 0;
+}
+
+int read_sysfs_lsms(char *lsms, size_t size)
+{
+ FILE *fp;
+ size_t red;
+
+ fp = fopen("/sys/kernel/security/lsm", "r");
+ if (fp == NULL)
+ return -1;
+ red = fread(lsms, 1, size, fp);
+ fclose(fp);
+
+ if (red <= 0 || red == size)
+ return -1;
+ lsms[red] = '\0';
+ return 0;
+}
+
+int attr_lsm_count(void)
+{
+ char *names = calloc(sysconf(_SC_PAGESIZE), 1);
+ int count = 0;
+
+ if (!names)
+ return 0;
+
+ if (read_sysfs_lsms(names, sysconf(_SC_PAGESIZE)))
+ return 0;
+
+ if (strstr(names, "selinux"))
+ count++;
+ if (strstr(names, "smack"))
+ count++;
+ if (strstr(names, "apparmor"))
+ count++;
+
+ return count;
+}
diff --git a/tools/testing/selftests/lsm/common.h b/tools/testing/selftests/lsm/common.h
new file mode 100644
index 000000000000..d404329e5eeb
--- /dev/null
+++ b/tools/testing/selftests/lsm/common.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Linux Security Module infrastructure tests
+ *
+ * Copyright © 2023 Casey Schaufler <[email protected]>
+ */
+
+#ifndef lsm_get_self_attr
+static inline int lsm_get_self_attr(unsigned int attr, struct lsm_ctx *ctx,
+ size_t *size, __u32 flags)
+{
+ return syscall(__NR_lsm_get_self_attr, attr, ctx, size, flags);
+}
+#endif
+
+#ifndef lsm_set_self_attr
+static inline int lsm_set_self_attr(unsigned int attr, struct lsm_ctx *ctx,
+ size_t size, __u32 flags)
+{
+ return syscall(__NR_lsm_set_self_attr, attr, ctx, size, flags);
+}
+#endif
+
+#ifndef lsm_list_modules
+static inline int lsm_list_modules(__u64 *ids, size_t *size, __u32 flags)
+{
+ return syscall(__NR_lsm_list_modules, ids, size, flags);
+}
+#endif
+
+extern int read_proc_attr(const char *attr, char *value, size_t size);
+extern int read_sysfs_lsms(char *lsms, size_t size);
+int attr_lsm_count(void);
diff --git a/tools/testing/selftests/lsm/config b/tools/testing/selftests/lsm/config
new file mode 100644
index 000000000000..1c0c4c020f9c
--- /dev/null
+++ b/tools/testing/selftests/lsm/config
@@ -0,0 +1,3 @@
+CONFIG_SYSFS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
diff --git a/tools/testing/selftests/lsm/lsm_get_self_attr_test.c b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c
new file mode 100644
index 000000000000..e0e313d9047a
--- /dev/null
+++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Security Module infrastructure tests
+ * Tests for the lsm_get_self_attr system call
+ *
+ * Copyright © 2022 Casey Schaufler <[email protected]>
+ */
+
+#define _GNU_SOURCE
+#include <linux/lsm.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "../kselftest_harness.h"
+#include "common.h"
+
+static struct lsm_ctx *next_ctx(struct lsm_ctx *ctxp)
+{
+ void *vp;
+
+ vp = (void *)ctxp + sizeof(*ctxp) + ctxp->ctx_len;
+ return (struct lsm_ctx *)vp;
+}
+
+TEST(size_null_lsm_get_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ struct lsm_ctx *ctx = calloc(page_size, 1);
+
+ ASSERT_NE(NULL, ctx);
+ errno = 0;
+ ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, NULL, 0));
+ ASSERT_EQ(EINVAL, errno);
+
+ free(ctx);
+}
+
+TEST(ctx_null_lsm_get_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ size_t size = page_size;
+ int rc;
+
+ rc = lsm_get_self_attr(LSM_ATTR_CURRENT, NULL, &size, 0);
+
+ if (attr_lsm_count()) {
+ ASSERT_NE(-1, rc);
+ ASSERT_NE(1, size);
+ } else {
+ ASSERT_EQ(-1, rc);
+ }
+}
+
+TEST(size_too_small_lsm_get_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ struct lsm_ctx *ctx = calloc(page_size, 1);
+ size_t size = 1;
+
+ ASSERT_NE(NULL, ctx);
+ errno = 0;
+ ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, 0));
+ if (attr_lsm_count()) {
+ ASSERT_EQ(E2BIG, errno);
+ } else {
+ ASSERT_EQ(EOPNOTSUPP, errno);
+ }
+ ASSERT_NE(1, size);
+
+ free(ctx);
+}
+
+TEST(flags_zero_lsm_get_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ struct lsm_ctx *ctx = calloc(page_size, 1);
+ __u64 *syscall_lsms = calloc(page_size, 1);
+ size_t size;
+ int lsmcount;
+ int i;
+
+ ASSERT_NE(NULL, ctx);
+ errno = 0;
+ size = page_size;
+ ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size,
+ LSM_FLAG_SINGLE));
+ ASSERT_EQ(EINVAL, errno);
+ ASSERT_EQ(page_size, size);
+
+ lsmcount = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0);
+ ASSERT_LE(1, lsmcount);
+ ASSERT_NE(NULL, syscall_lsms);
+
+ for (i = 0; i < lsmcount; i++) {
+ errno = 0;
+ size = page_size;
+ ctx->id = syscall_lsms[i];
+
+ if (syscall_lsms[i] == LSM_ID_SELINUX ||
+ syscall_lsms[i] == LSM_ID_SMACK ||
+ syscall_lsms[i] == LSM_ID_APPARMOR) {
+ ASSERT_EQ(1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx,
+ &size, LSM_FLAG_SINGLE));
+ } else {
+ ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx,
+ &size,
+ LSM_FLAG_SINGLE));
+ }
+ }
+
+ free(ctx);
+}
+
+TEST(flags_overset_lsm_get_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ struct lsm_ctx *ctx = calloc(page_size, 1);
+ size_t size;
+
+ ASSERT_NE(NULL, ctx);
+
+ errno = 0;
+ size = page_size;
+ ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx,
+ &size, 0));
+ ASSERT_EQ(EOPNOTSUPP, errno);
+
+ errno = 0;
+ size = page_size;
+ ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size,
+ LSM_FLAG_SINGLE |
+ (LSM_FLAG_SINGLE << 1)));
+ ASSERT_EQ(EINVAL, errno);
+
+ free(ctx);
+}
+
+TEST(basic_lsm_get_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ size_t size = page_size;
+ struct lsm_ctx *ctx = calloc(page_size, 1);
+ struct lsm_ctx *tctx = NULL;
+ __u64 *syscall_lsms = calloc(page_size, 1);
+ char *attr = calloc(page_size, 1);
+ int cnt_current = 0;
+ int cnt_exec = 0;
+ int cnt_fscreate = 0;
+ int cnt_keycreate = 0;
+ int cnt_prev = 0;
+ int cnt_sockcreate = 0;
+ int lsmcount;
+ int count;
+ int i;
+
+ ASSERT_NE(NULL, ctx);
+ ASSERT_NE(NULL, syscall_lsms);
+
+ lsmcount = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0);
+ ASSERT_LE(1, lsmcount);
+
+ for (i = 0; i < lsmcount; i++) {
+ switch (syscall_lsms[i]) {
+ case LSM_ID_SELINUX:
+ cnt_current++;
+ cnt_exec++;
+ cnt_fscreate++;
+ cnt_keycreate++;
+ cnt_prev++;
+ cnt_sockcreate++;
+ break;
+ case LSM_ID_SMACK:
+ cnt_current++;
+ break;
+ case LSM_ID_APPARMOR:
+ cnt_current++;
+ cnt_exec++;
+ cnt_prev++;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (cnt_current) {
+ size = page_size;
+ count = lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, 0);
+ ASSERT_EQ(cnt_current, count);
+ tctx = ctx;
+ ASSERT_EQ(0, read_proc_attr("current", attr, page_size));
+ ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
+ for (i = 1; i < count; i++) {
+ tctx = next_ctx(tctx);
+ ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
+ }
+ }
+ if (cnt_exec) {
+ size = page_size;
+ count = lsm_get_self_attr(LSM_ATTR_EXEC, ctx, &size, 0);
+ ASSERT_GE(cnt_exec, count);
+ if (count > 0) {
+ tctx = ctx;
+ if (read_proc_attr("exec", attr, page_size) == 0)
+ ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
+ }
+ for (i = 1; i < count; i++) {
+ tctx = next_ctx(tctx);
+ ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
+ }
+ }
+ if (cnt_fscreate) {
+ size = page_size;
+ count = lsm_get_self_attr(LSM_ATTR_FSCREATE, ctx, &size, 0);
+ ASSERT_GE(cnt_fscreate, count);
+ if (count > 0) {
+ tctx = ctx;
+ if (read_proc_attr("fscreate", attr, page_size) == 0)
+ ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
+ }
+ for (i = 1; i < count; i++) {
+ tctx = next_ctx(tctx);
+ ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
+ }
+ }
+ if (cnt_keycreate) {
+ size = page_size;
+ count = lsm_get_self_attr(LSM_ATTR_KEYCREATE, ctx, &size, 0);
+ ASSERT_GE(cnt_keycreate, count);
+ if (count > 0) {
+ tctx = ctx;
+ if (read_proc_attr("keycreate", attr, page_size) == 0)
+ ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
+ }
+ for (i = 1; i < count; i++) {
+ tctx = next_ctx(tctx);
+ ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
+ }
+ }
+ if (cnt_prev) {
+ size = page_size;
+ count = lsm_get_self_attr(LSM_ATTR_PREV, ctx, &size, 0);
+ ASSERT_GE(cnt_prev, count);
+ if (count > 0) {
+ tctx = ctx;
+ ASSERT_EQ(0, read_proc_attr("prev", attr, page_size));
+ ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
+ for (i = 1; i < count; i++) {
+ tctx = next_ctx(tctx);
+ ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
+ }
+ }
+ }
+ if (cnt_sockcreate) {
+ size = page_size;
+ count = lsm_get_self_attr(LSM_ATTR_SOCKCREATE, ctx, &size, 0);
+ ASSERT_GE(cnt_sockcreate, count);
+ if (count > 0) {
+ tctx = ctx;
+ if (read_proc_attr("sockcreate", attr, page_size) == 0)
+ ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
+ }
+ for (i = 1; i < count; i++) {
+ tctx = next_ctx(tctx);
+ ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
+ }
+ }
+
+ free(ctx);
+ free(attr);
+ free(syscall_lsms);
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/lsm/lsm_list_modules_test.c b/tools/testing/selftests/lsm/lsm_list_modules_test.c
new file mode 100644
index 000000000000..445c02f09c74
--- /dev/null
+++ b/tools/testing/selftests/lsm/lsm_list_modules_test.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Security Module infrastructure tests
+ * Tests for the lsm_list_modules system call
+ *
+ * Copyright © 2022 Casey Schaufler <[email protected]>
+ */
+
+#define _GNU_SOURCE
+#include <linux/lsm.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "../kselftest_harness.h"
+#include "common.h"
+
+TEST(size_null_lsm_list_modules)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ __u64 *syscall_lsms = calloc(page_size, 1);
+
+ ASSERT_NE(NULL, syscall_lsms);
+ errno = 0;
+ ASSERT_EQ(-1, lsm_list_modules(syscall_lsms, NULL, 0));
+ ASSERT_EQ(EFAULT, errno);
+
+ free(syscall_lsms);
+}
+
+TEST(ids_null_lsm_list_modules)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ size_t size = page_size;
+
+ errno = 0;
+ ASSERT_EQ(-1, lsm_list_modules(NULL, &size, 0));
+ ASSERT_EQ(EFAULT, errno);
+ ASSERT_NE(1, size);
+}
+
+TEST(size_too_small_lsm_list_modules)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ __u64 *syscall_lsms = calloc(page_size, 1);
+ size_t size = 1;
+
+ ASSERT_NE(NULL, syscall_lsms);
+ errno = 0;
+ ASSERT_EQ(-1, lsm_list_modules(syscall_lsms, &size, 0));
+ ASSERT_EQ(E2BIG, errno);
+ ASSERT_NE(1, size);
+
+ free(syscall_lsms);
+}
+
+TEST(flags_set_lsm_list_modules)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ __u64 *syscall_lsms = calloc(page_size, 1);
+ size_t size = page_size;
+
+ ASSERT_NE(NULL, syscall_lsms);
+ errno = 0;
+ ASSERT_EQ(-1, lsm_list_modules(syscall_lsms, &size, 7));
+ ASSERT_EQ(EINVAL, errno);
+ ASSERT_EQ(page_size, size);
+
+ free(syscall_lsms);
+}
+
+TEST(correct_lsm_list_modules)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ size_t size = page_size;
+ __u64 *syscall_lsms = calloc(page_size, 1);
+ char *sysfs_lsms = calloc(page_size, 1);
+ char *name;
+ char *cp;
+ int count;
+ int i;
+
+ ASSERT_NE(NULL, sysfs_lsms);
+ ASSERT_NE(NULL, syscall_lsms);
+ ASSERT_EQ(0, read_sysfs_lsms(sysfs_lsms, page_size));
+
+ count = lsm_list_modules(syscall_lsms, &size, 0);
+ ASSERT_LE(1, count);
+ cp = sysfs_lsms;
+ for (i = 0; i < count; i++) {
+ switch (syscall_lsms[i]) {
+ case LSM_ID_CAPABILITY:
+ name = "capability";
+ break;
+ case LSM_ID_SELINUX:
+ name = "selinux";
+ break;
+ case LSM_ID_SMACK:
+ name = "smack";
+ break;
+ case LSM_ID_TOMOYO:
+ name = "tomoyo";
+ break;
+ case LSM_ID_IMA:
+ name = "ima";
+ break;
+ case LSM_ID_APPARMOR:
+ name = "apparmor";
+ break;
+ case LSM_ID_YAMA:
+ name = "yama";
+ break;
+ case LSM_ID_LOADPIN:
+ name = "loadpin";
+ break;
+ case LSM_ID_SAFESETID:
+ name = "safesetid";
+ break;
+ case LSM_ID_LOCKDOWN:
+ name = "lockdown";
+ break;
+ case LSM_ID_BPF:
+ name = "bpf";
+ break;
+ case LSM_ID_LANDLOCK:
+ name = "landlock";
+ break;
+ default:
+ name = "INVALID";
+ break;
+ }
+ ASSERT_EQ(0, strncmp(cp, name, strlen(name)));
+ cp += strlen(name) + 1;
+ }
+
+ free(sysfs_lsms);
+ free(syscall_lsms);
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/lsm/lsm_set_self_attr_test.c b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c
new file mode 100644
index 000000000000..e9712c6cf596
--- /dev/null
+++ b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Security Module infrastructure tests
+ * Tests for the lsm_set_self_attr system call
+ *
+ * Copyright © 2022 Casey Schaufler <[email protected]>
+ */
+
+#define _GNU_SOURCE
+#include <linux/lsm.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "../kselftest_harness.h"
+#include "common.h"
+
+TEST(ctx_null_lsm_set_self_attr)
+{
+ ASSERT_EQ(-1, lsm_set_self_attr(LSM_ATTR_CURRENT, NULL,
+ sizeof(struct lsm_ctx), 0));
+}
+
+TEST(size_too_small_lsm_set_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ struct lsm_ctx *ctx = calloc(page_size, 1);
+ size_t size = page_size;
+
+ ASSERT_NE(NULL, ctx);
+ if (attr_lsm_count()) {
+ ASSERT_LE(1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size,
+ 0));
+ }
+ ASSERT_EQ(-1, lsm_set_self_attr(LSM_ATTR_CURRENT, ctx, 1, 0));
+
+ free(ctx);
+}
+
+TEST(flags_zero_lsm_set_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ struct lsm_ctx *ctx = calloc(page_size, 1);
+ size_t size = page_size;
+
+ ASSERT_NE(NULL, ctx);
+ if (attr_lsm_count()) {
+ ASSERT_LE(1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size,
+ 0));
+ }
+ ASSERT_EQ(-1, lsm_set_self_attr(LSM_ATTR_CURRENT, ctx, size, 1));
+
+ free(ctx);
+}
+
+TEST(flags_overset_lsm_set_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ char *ctx = calloc(page_size, 1);
+ size_t size = page_size;
+ struct lsm_ctx *tctx = (struct lsm_ctx *)ctx;
+
+ ASSERT_NE(NULL, ctx);
+ if (attr_lsm_count()) {
+ ASSERT_LE(1, lsm_get_self_attr(LSM_ATTR_CURRENT, tctx, &size,
+ 0));
+ }
+ ASSERT_EQ(-1, lsm_set_self_attr(LSM_ATTR_CURRENT | LSM_ATTR_PREV, tctx,
+ size, 0));
+
+ free(ctx);
+}
+
+TEST_HARNESS_MAIN
--
2.41.0

2023-09-13 05:02:44

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v15 07/11] LSM: Helpers for attribute names and filling lsm_ctx

Add lsm_name_to_attr(), which translates a text string to a
LSM_ATTR value if one is available.

Add lsm_fill_user_ctx(), which fills a struct lsm_ctx, including
the trailing attribute value.

Both are used in module specific components of LSM system calls.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: John Johansen <[email protected]>
Reviewed-by: Serge Hallyn <[email protected]>
---
include/linux/security.h | 14 ++++++++++++++
security/lsm_syscalls.c | 24 +++++++++++++++++++++++
security/security.c | 41 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 79 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index 8831d7cf0a6b..e567f910a1c2 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -32,6 +32,7 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/sockptr.h>
+#include <uapi/linux/lsm.h>

struct linux_binprm;
struct cred;
@@ -264,6 +265,7 @@ int unregister_blocking_lsm_notifier(struct notifier_block *nb);
/* prototypes */
extern int security_init(void);
extern int early_security_init(void);
+extern u64 lsm_name_to_attr(const char *name);

/* Security operations */
int security_binder_set_context_mgr(const struct cred *mgr);
@@ -490,6 +492,8 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
int security_locked_down(enum lockdown_reason what);
+int lsm_fill_user_ctx(struct lsm_ctx __user *ctx, void *context,
+ size_t context_size, u64 id, u64 flags);
#else /* CONFIG_SECURITY */

static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data)
@@ -507,6 +511,11 @@ static inline int unregister_blocking_lsm_notifier(struct notifier_block *nb)
return 0;
}

+static inline u64 lsm_name_to_attr(const char *name)
+{
+ return LSM_ATTR_UNDEF;
+}
+
static inline void security_free_mnt_opts(void **mnt_opts)
{
}
@@ -1415,6 +1424,11 @@ static inline int security_locked_down(enum lockdown_reason what)
{
return 0;
}
+static inline int lsm_fill_user_ctx(struct lsm_ctx __user *ctx, void *context,
+ size_t context_size, u64 id, u64 flags)
+{
+ return -EOPNOTSUPP;
+}
#endif /* CONFIG_SECURITY */

#if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
index 329aaca5efc0..5d391b1f7e69 100644
--- a/security/lsm_syscalls.c
+++ b/security/lsm_syscalls.c
@@ -17,6 +17,30 @@
#include <linux/lsm_hooks.h>
#include <uapi/linux/lsm.h>

+/**
+ * lsm_name_to_attr - map an LSM attribute name to its ID
+ * @name: name of the attribute
+ *
+ * Returns the LSM attribute value associated with @name, or 0 if
+ * there is no mapping.
+ */
+u64 lsm_name_to_attr(const char *name)
+{
+ if (!strcmp(name, "current"))
+ return LSM_ATTR_CURRENT;
+ if (!strcmp(name, "exec"))
+ return LSM_ATTR_EXEC;
+ if (!strcmp(name, "fscreate"))
+ return LSM_ATTR_FSCREATE;
+ if (!strcmp(name, "keycreate"))
+ return LSM_ATTR_KEYCREATE;
+ if (!strcmp(name, "prev"))
+ return LSM_ATTR_PREV;
+ if (!strcmp(name, "sockcreate"))
+ return LSM_ATTR_SOCKCREATE;
+ return LSM_ATTR_UNDEF;
+}
+
/**
* sys_lsm_set_self_attr - Set current task's security module attribute
* @attr: which attribute to set
diff --git a/security/security.c b/security/security.c
index 0d179750d964..9136a4c3b0bc 100644
--- a/security/security.c
+++ b/security/security.c
@@ -771,6 +771,47 @@ static int lsm_superblock_alloc(struct super_block *sb)
return 0;
}

+/**
+ * lsm_fill_user_ctx - Fill a user space lsm_ctx structure
+ * @ctx: an LSM context to be filled
+ * @context: the new context value
+ * @context_size: the size of the new context value
+ * @id: LSM id
+ * @flags: LSM defined flags
+ *
+ * Fill all of the fields in a user space lsm_ctx structure.
+ * Caller is assumed to have verified that @ctx has enough space
+ * for @context.
+ *
+ * Returns 0 on success, -EFAULT on a copyout error, -ENOMEM
+ * if memory can't be allocated.
+ */
+int lsm_fill_user_ctx(struct lsm_ctx __user *ctx, void *context,
+ size_t context_size, u64 id, u64 flags)
+{
+ struct lsm_ctx *lctx;
+ size_t locallen = struct_size(lctx, ctx, context_size);
+ int rc = 0;
+
+ lctx = kzalloc(locallen, GFP_KERNEL);
+ if (lctx == NULL)
+ return -ENOMEM;
+
+ lctx->id = id;
+ lctx->flags = flags;
+ lctx->ctx_len = context_size;
+ lctx->len = locallen;
+
+ memcpy(lctx->ctx, context, context_size);
+
+ if (copy_to_user(ctx, lctx, locallen))
+ rc = -EFAULT;
+
+ kfree(lctx);
+
+ return rc;
+}
+
/*
* The default value of the LSM hook is defined in linux/lsm_hook_defs.h and
* can be accessed with:
--
2.41.0

2023-09-13 05:30:20

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v15 01/11] LSM: Identify modules by more than name

Create a struct lsm_id to contain identifying information about Linux
Security Modules (LSMs). At inception this contains the name of the
module and an identifier associated with the security module. Change
the security_add_hooks() interface to use this structure. Change the
individual modules to maintain their own struct lsm_id and pass it to
security_add_hooks().

The values are for LSM identifiers are defined in a new UAPI
header file linux/lsm.h. Each existing LSM has been updated to
include it's LSMID in the lsm_id.

The LSM ID values are sequential, with the oldest module
LSM_ID_CAPABILITY being the lowest value and the existing modules
numbered in the order they were included in the main line kernel.
This is an arbitrary convention for assigning the values, but
none better presents itself. The value 0 is defined as being invalid.
The values 1-99 are reserved for any special case uses which may
arise in the future. This may include attributes of the LSM
infrastructure itself, possibly related to namespacing or network
attribute management. A special range is identified for such attributes
to help reduce confusion for developers unfamiliar with LSMs.

LSM attribute values are defined for the attributes presented by
modules that are available today. As with the LSM IDs, The value 0
is defined as being invalid. The values 1-99 are reserved for any
special case uses which may arise in the future.

Signed-off-by: Casey Schaufler <[email protected]>
Cc: linux-security-module <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: Serge Hallyn <[email protected]>
Reviewed-by: Mickael Salaun <[email protected]>
Reviewed-by: John Johansen <[email protected]>
---
Documentation/userspace-api/index.rst | 1 +
MAINTAINERS | 1 +
include/linux/lsm_hooks.h | 16 +++++++-
include/uapi/linux/lsm.h | 54 +++++++++++++++++++++++++++
security/apparmor/lsm.c | 8 +++-
security/bpf/hooks.c | 9 ++++-
security/commoncap.c | 8 +++-
security/landlock/cred.c | 2 +-
security/landlock/fs.c | 2 +-
security/landlock/ptrace.c | 2 +-
security/landlock/setup.c | 6 +++
security/landlock/setup.h | 1 +
security/loadpin/loadpin.c | 9 ++++-
security/lockdown/lockdown.c | 8 +++-
security/safesetid/lsm.c | 9 ++++-
security/security.c | 12 +++---
security/selinux/hooks.c | 9 ++++-
security/smack/smack_lsm.c | 8 +++-
security/tomoyo/tomoyo.c | 9 ++++-
security/yama/yama_lsm.c | 8 +++-
20 files changed, 161 insertions(+), 21 deletions(-)
create mode 100644 include/uapi/linux/lsm.h

diff --git a/Documentation/userspace-api/index.rst b/Documentation/userspace-api/index.rst
index 72a65db0c498..b5fa29c077eb 100644
--- a/Documentation/userspace-api/index.rst
+++ b/Documentation/userspace-api/index.rst
@@ -32,6 +32,7 @@ place where this information is gathered.
sysfs-platform_profile
vduse
futex2
+ lsm

.. only:: subproject and html

diff --git a/MAINTAINERS b/MAINTAINERS
index 90f13281d297..935334123b04 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19307,6 +19307,7 @@ L: [email protected] (suggested Cc:)
S: Supported
W: http://kernsec.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git
+F: include/uapi/linux/lsm.h
F: security/
X: security/selinux/

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index dcb5e5b5eb13..7f0adb33caaa 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -42,6 +42,18 @@ struct security_hook_heads {
#undef LSM_HOOK
} __randomize_layout;

+/**
+ * struct lsm_id - Identify a Linux Security Module.
+ * @lsm: name of the LSM, must be approved by the LSM maintainers
+ * @id: LSM ID number from uapi/linux/lsm.h
+ *
+ * Contains the information that identifies the LSM.
+ */
+struct lsm_id {
+ const char *name;
+ u64 id;
+};
+
/*
* Security module hook list structure.
* For use with generic list macros for common operations.
@@ -50,7 +62,7 @@ struct security_hook_list {
struct hlist_node list;
struct hlist_head *head;
union security_list_options hook;
- const char *lsm;
+ const struct lsm_id *lsmid;
} __randomize_layout;

/*
@@ -104,7 +116,7 @@ extern struct security_hook_heads security_hook_heads;
extern char *lsm_names;

extern void security_add_hooks(struct security_hook_list *hooks, int count,
- const char *lsm);
+ const struct lsm_id *lsmid);

#define LSM_FLAG_LEGACY_MAJOR BIT(0)
#define LSM_FLAG_EXCLUSIVE BIT(1)
diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
new file mode 100644
index 000000000000..f27c9a9cc376
--- /dev/null
+++ b/include/uapi/linux/lsm.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Linux Security Modules (LSM) - User space API
+ *
+ * Copyright (C) 2022 Casey Schaufler <[email protected]>
+ * Copyright (C) 2022 Intel Corporation
+ */
+
+#ifndef _UAPI_LINUX_LSM_H
+#define _UAPI_LINUX_LSM_H
+
+/*
+ * ID tokens to identify Linux Security Modules (LSMs)
+ *
+ * These token values are used to uniquely identify specific LSMs
+ * in the kernel as well as in the kernel's LSM userspace API.
+ *
+ * A value of zero/0 is considered undefined and should not be used
+ * outside the kernel. Values 1-99 are reserved for potential
+ * future use.
+ */
+#define LSM_ID_UNDEF 0
+#define LSM_ID_CAPABILITY 100
+#define LSM_ID_SELINUX 101
+#define LSM_ID_SMACK 102
+#define LSM_ID_TOMOYO 103
+#define LSM_ID_IMA 104
+#define LSM_ID_APPARMOR 105
+#define LSM_ID_YAMA 106
+#define LSM_ID_LOADPIN 107
+#define LSM_ID_SAFESETID 108
+#define LSM_ID_LOCKDOWN 109
+#define LSM_ID_BPF 110
+#define LSM_ID_LANDLOCK 111
+
+/*
+ * LSM_ATTR_XXX definitions identify different LSM attributes
+ * which are used in the kernel's LSM userspace API. Support
+ * for these attributes vary across the different LSMs. None
+ * are required.
+ *
+ * A value of zero/0 is considered undefined and should not be used
+ * outside the kernel. Values 1-99 are reserved for potential
+ * future use.
+ */
+#define LSM_ATTR_UNDEF 0
+#define LSM_ATTR_CURRENT 100
+#define LSM_ATTR_EXEC 101
+#define LSM_ATTR_FSCREATE 102
+#define LSM_ATTR_KEYCREATE 103
+#define LSM_ATTR_PREV 104
+#define LSM_ATTR_SOCKCREATE 105
+
+#endif /* _UAPI_LINUX_LSM_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 108eccc5ada5..20b93501fbd1 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -24,6 +24,7 @@
#include <linux/zstd.h>
#include <net/sock.h>
#include <uapi/linux/mount.h>
+#include <uapi/linux/lsm.h>

#include "include/apparmor.h"
#include "include/apparmorfs.h"
@@ -1215,6 +1216,11 @@ struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
.lbs_task = sizeof(struct aa_task_ctx),
};

+const struct lsm_id apparmor_lsmid = {
+ .name = "apparmor",
+ .id = LSM_ID_APPARMOR,
+};
+
static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
@@ -1904,7 +1910,7 @@ static int __init apparmor_init(void)
goto buffers_out;
}
security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks),
- "apparmor");
+ &apparmor_lsmid);

/* Report that AppArmor successfully initialized */
apparmor_initialized = 1;
diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
index cfaf1d0e6a5f..91011e0c361a 100644
--- a/security/bpf/hooks.c
+++ b/security/bpf/hooks.c
@@ -5,6 +5,7 @@
*/
#include <linux/lsm_hooks.h>
#include <linux/bpf_lsm.h>
+#include <uapi/linux/lsm.h>

static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
#define LSM_HOOK(RET, DEFAULT, NAME, ...) \
@@ -15,9 +16,15 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
LSM_HOOK_INIT(task_free, bpf_task_storage_free),
};

+const struct lsm_id bpf_lsmid = {
+ .name = "bpf",
+ .id = LSM_ID_BPF,
+};
+
static int __init bpf_lsm_init(void)
{
- security_add_hooks(bpf_lsm_hooks, ARRAY_SIZE(bpf_lsm_hooks), "bpf");
+ security_add_hooks(bpf_lsm_hooks, ARRAY_SIZE(bpf_lsm_hooks),
+ &bpf_lsmid);
pr_info("LSM support for eBPF active\n");
return 0;
}
diff --git a/security/commoncap.c b/security/commoncap.c
index bc0521104197..9aaad2c3e54a 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -25,6 +25,7 @@
#include <linux/binfmts.h>
#include <linux/personality.h>
#include <linux/mnt_idmapping.h>
+#include <uapi/linux/lsm.h>

/*
* If a non-root user executes a setuid-root binary in
@@ -1440,6 +1441,11 @@ int cap_mmap_file(struct file *file, unsigned long reqprot,

#ifdef CONFIG_SECURITY

+const struct lsm_id capability_lsmid = {
+ .name = "capability",
+ .id = LSM_ID_CAPABILITY,
+};
+
static struct security_hook_list capability_hooks[] __ro_after_init = {
LSM_HOOK_INIT(capable, cap_capable),
LSM_HOOK_INIT(settime, cap_settime),
@@ -1464,7 +1470,7 @@ static struct security_hook_list capability_hooks[] __ro_after_init = {
static int __init capability_init(void)
{
security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks),
- "capability");
+ &capability_lsmid);
return 0;
}

diff --git a/security/landlock/cred.c b/security/landlock/cred.c
index 13dff2a31545..786af18c4a1c 100644
--- a/security/landlock/cred.c
+++ b/security/landlock/cred.c
@@ -42,5 +42,5 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = {
__init void landlock_add_cred_hooks(void)
{
security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
- LANDLOCK_NAME);
+ &landlock_lsmid);
}
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index 1c0c198f6fdb..db5ebecfbf02 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -1307,5 +1307,5 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = {
__init void landlock_add_fs_hooks(void)
{
security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
- LANDLOCK_NAME);
+ &landlock_lsmid);
}
diff --git a/security/landlock/ptrace.c b/security/landlock/ptrace.c
index 8a06d6c492bf..2bfc533d36e4 100644
--- a/security/landlock/ptrace.c
+++ b/security/landlock/ptrace.c
@@ -116,5 +116,5 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = {
__init void landlock_add_ptrace_hooks(void)
{
security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
- LANDLOCK_NAME);
+ &landlock_lsmid);
}
diff --git a/security/landlock/setup.c b/security/landlock/setup.c
index 0f6113528fa4..aab13750edde 100644
--- a/security/landlock/setup.c
+++ b/security/landlock/setup.c
@@ -8,6 +8,7 @@

#include <linux/init.h>
#include <linux/lsm_hooks.h>
+#include <uapi/linux/lsm.h>

#include "common.h"
#include "cred.h"
@@ -24,6 +25,11 @@ struct lsm_blob_sizes landlock_blob_sizes __ro_after_init = {
.lbs_superblock = sizeof(struct landlock_superblock_security),
};

+const struct lsm_id landlock_lsmid = {
+ .name = LANDLOCK_NAME,
+ .id = LSM_ID_LANDLOCK,
+};
+
static int __init landlock_init(void)
{
landlock_add_cred_hooks();
diff --git a/security/landlock/setup.h b/security/landlock/setup.h
index 1daffab1ab4b..c4252d46d49d 100644
--- a/security/landlock/setup.h
+++ b/security/landlock/setup.h
@@ -14,5 +14,6 @@
extern bool landlock_initialized;

extern struct lsm_blob_sizes landlock_blob_sizes;
+extern const struct lsm_id landlock_lsmid;

#endif /* _SECURITY_LANDLOCK_SETUP_H */
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index a9d40456a064..d682a851de58 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -20,6 +20,7 @@
#include <linux/string_helpers.h>
#include <linux/dm-verity-loadpin.h>
#include <uapi/linux/loadpin.h>
+#include <uapi/linux/lsm.h>

#define VERITY_DIGEST_FILE_HEADER "# LOADPIN_TRUSTED_VERITY_ROOT_DIGESTS"

@@ -208,6 +209,11 @@ static int loadpin_load_data(enum kernel_load_data_id id, bool contents)
return loadpin_check(NULL, (enum kernel_read_file_id) id);
}

+const struct lsm_id loadpin_lsmid = {
+ .name = "loadpin",
+ .id = LSM_ID_LOADPIN,
+};
+
static struct security_hook_list loadpin_hooks[] __ro_after_init = {
LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security),
LSM_HOOK_INIT(kernel_read_file, loadpin_read_file),
@@ -259,7 +265,8 @@ static int __init loadpin_init(void)
if (!register_sysctl("kernel/loadpin", loadpin_sysctl_table))
pr_notice("sysctl registration failed!\n");
#endif
- security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
+ security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks),
+ &loadpin_lsmid);

return 0;
}
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
index 68d19632aeb7..cd84d8ea1dfb 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -13,6 +13,7 @@
#include <linux/security.h>
#include <linux/export.h>
#include <linux/lsm_hooks.h>
+#include <uapi/linux/lsm.h>

static enum lockdown_reason kernel_locked_down;

@@ -75,6 +76,11 @@ static struct security_hook_list lockdown_hooks[] __ro_after_init = {
LSM_HOOK_INIT(locked_down, lockdown_is_locked_down),
};

+const struct lsm_id lockdown_lsmid = {
+ .name = "lockdown",
+ .id = LSM_ID_LOCKDOWN,
+};
+
static int __init lockdown_lsm_init(void)
{
#if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY)
@@ -83,7 +89,7 @@ static int __init lockdown_lsm_init(void)
lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY_MAX);
#endif
security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks),
- "lockdown");
+ &lockdown_lsmid);
return 0;
}

diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
index 5be5894aa0ea..f42d5af5ffb0 100644
--- a/security/safesetid/lsm.c
+++ b/security/safesetid/lsm.c
@@ -19,6 +19,7 @@
#include <linux/ptrace.h>
#include <linux/sched/task_stack.h>
#include <linux/security.h>
+#include <uapi/linux/lsm.h>
#include "lsm.h"

/* Flag indicating whether initialization completed */
@@ -261,6 +262,11 @@ static int safesetid_task_fix_setgroups(struct cred *new, const struct cred *old
return 0;
}

+const struct lsm_id safesetid_lsmid = {
+ .name = "safesetid",
+ .id = LSM_ID_SAFESETID,
+};
+
static struct security_hook_list safesetid_security_hooks[] = {
LSM_HOOK_INIT(task_fix_setuid, safesetid_task_fix_setuid),
LSM_HOOK_INIT(task_fix_setgid, safesetid_task_fix_setgid),
@@ -271,7 +277,8 @@ static struct security_hook_list safesetid_security_hooks[] = {
static int __init safesetid_security_init(void)
{
security_add_hooks(safesetid_security_hooks,
- ARRAY_SIZE(safesetid_security_hooks), "safesetid");
+ ARRAY_SIZE(safesetid_security_hooks),
+ &safesetid_lsmid);

/* Report that SafeSetID successfully initialized */
safesetid_initialized = 1;
diff --git a/security/security.c b/security/security.c
index 23b129d482a7..ea69e83936fc 100644
--- a/security/security.c
+++ b/security/security.c
@@ -513,17 +513,17 @@ static int lsm_append(const char *new, char **result)
* security_add_hooks - Add a modules hooks to the hook lists.
* @hooks: the hooks to add
* @count: the number of hooks to add
- * @lsm: the name of the security module
+ * @lsmid: the identification information for the security module
*
* Each LSM has to register its hooks with the infrastructure.
*/
void __init security_add_hooks(struct security_hook_list *hooks, int count,
- const char *lsm)
+ const struct lsm_id *lsmid)
{
int i;

for (i = 0; i < count; i++) {
- hooks[i].lsm = lsm;
+ hooks[i].lsmid = lsmid;
hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);
}

@@ -532,7 +532,7 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
* and fix this up afterwards.
*/
if (slab_is_available()) {
- if (lsm_append(lsm, &lsm_names) < 0)
+ if (lsm_append(lsmid->name, &lsm_names) < 0)
panic("%s - Cannot get early memory.\n", __func__);
}
}
@@ -3817,7 +3817,7 @@ int security_getprocattr(struct task_struct *p, const char *lsm,
struct security_hook_list *hp;

hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
- if (lsm != NULL && strcmp(lsm, hp->lsm))
+ if (lsm != NULL && strcmp(lsm, hp->lsmid->name))
continue;
return hp->hook.getprocattr(p, name, value);
}
@@ -3842,7 +3842,7 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
struct security_hook_list *hp;

hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
- if (lsm != NULL && strcmp(lsm, hp->lsm))
+ if (lsm != NULL && strcmp(lsm, hp->lsmid->name))
continue;
return hp->hook.setprocattr(name, value, size);
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 10350534de6d..3ad500dff390 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -92,6 +92,7 @@
#include <linux/fsnotify.h>
#include <linux/fanotify.h>
#include <linux/io_uring.h>
+#include <uapi/linux/lsm.h>

#include "avc.h"
#include "objsec.h"
@@ -6944,6 +6945,11 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
}
#endif /* CONFIG_IO_URING */

+const struct lsm_id selinux_lsmid = {
+ .name = "selinux",
+ .id = LSM_ID_SELINUX,
+};
+
/*
* IMPORTANT NOTE: When adding new hooks, please be careful to keep this order:
* 1. any hooks that don't belong to (2.) or (3.) below,
@@ -7264,7 +7270,8 @@ static __init int selinux_init(void)

hashtab_cache_init();

- security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
+ security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks),
+ &selinux_lsmid);

if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
panic("SELinux: Unable to register AVC netcache callback\n");
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 65130a791f57..f73f9a2834eb 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -43,6 +43,7 @@
#include <linux/fs_parser.h>
#include <linux/watch_queue.h>
#include <linux/io_uring.h>
+#include <uapi/linux/lsm.h>
#include "smack.h"

#define TRANS_TRUE "TRUE"
@@ -4933,6 +4934,11 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
};

+const struct lsm_id smack_lsmid = {
+ .name = "smack",
+ .id = LSM_ID_SMACK,
+};
+
static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
@@ -5140,7 +5146,7 @@ static __init int smack_init(void)
/*
* Register with LSM
*/
- security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
+ security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), &smack_lsmid);
smack_enabled = 1;

pr_info("Smack: Initializing.\n");
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 25006fddc964..556f8daecb07 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -6,6 +6,7 @@
*/

#include <linux/lsm_hooks.h>
+#include <uapi/linux/lsm.h>
#include "common.h"

/**
@@ -542,6 +543,11 @@ static void tomoyo_task_free(struct task_struct *task)
}
}

+const struct lsm_id tomoyo_lsmid = {
+ .name = "tomoyo",
+ .id = LSM_ID_TOMOYO,
+};
+
/*
* tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO.
@@ -595,7 +601,8 @@ static int __init tomoyo_init(void)
struct tomoyo_task *s = tomoyo_task(current);

/* register ourselves with the security framework */
- security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo");
+ security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks),
+ &tomoyo_lsmid);
pr_info("TOMOYO Linux initialized\n");
s->domain_info = &tomoyo_kernel_domain;
atomic_inc(&tomoyo_kernel_domain.users);
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 2503cf153d4a..5cdff292fcae 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -18,6 +18,7 @@
#include <linux/task_work.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
+#include <uapi/linux/lsm.h>

#define YAMA_SCOPE_DISABLED 0
#define YAMA_SCOPE_RELATIONAL 1
@@ -421,6 +422,11 @@ static int yama_ptrace_traceme(struct task_struct *parent)
return rc;
}

+const struct lsm_id yama_lsmid = {
+ .name = "yama",
+ .id = LSM_ID_YAMA,
+};
+
static struct security_hook_list yama_hooks[] __ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme),
@@ -471,7 +477,7 @@ static inline void yama_init_sysctl(void) { }
static int __init yama_init(void)
{
pr_info("Yama: becoming mindful.\n");
- security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), "yama");
+ security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), &yama_lsmid);
yama_init_sysctl();
return 0;
}
--
2.41.0

2023-09-13 10:25:10

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v15 04/11] LSM: syscalls for current process attributes

Create a system call lsm_get_self_attr() to provide the security
module maintained attributes of the current process.
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
identifies the size of the attribute, and the attribute value. The format
of the attribute value is defined by the security module. A flags field
is included for LSM specific information. It is currently unused and must
be 0. The total size of the data, including the lsm_ctx structure and any
padding, is maintained as well.

struct lsm_ctx {
__u64 id;
__u64 flags;
__u64 len;
__u64 ctx_len;
__u8 ctx[];
};

Two new LSM hooks are used to interface with the LSMs.
security_getselfattr() collects the lsm_ctx values from the
LSMs that support the hook, accounting for space requirements.
security_setselfattr() identifies which LSM the attribute is
intended for and passes it along.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: Serge Hallyn <[email protected]>
Reviewed-by: John Johansen <[email protected]>
---
Documentation/userspace-api/lsm.rst | 70 +++++++++++++
include/linux/lsm_hook_defs.h | 4 +
include/linux/lsm_hooks.h | 1 +
include/linux/security.h | 19 ++++
include/linux/syscalls.h | 5 +
include/uapi/linux/lsm.h | 36 +++++++
kernel/sys_ni.c | 2 +
security/Makefile | 1 +
security/lsm_syscalls.c | 57 +++++++++++
security/security.c | 152 ++++++++++++++++++++++++++++
10 files changed, 347 insertions(+)
create mode 100644 Documentation/userspace-api/lsm.rst
create mode 100644 security/lsm_syscalls.c

diff --git a/Documentation/userspace-api/lsm.rst b/Documentation/userspace-api/lsm.rst
new file mode 100644
index 000000000000..f8499f3e2826
--- /dev/null
+++ b/Documentation/userspace-api/lsm.rst
@@ -0,0 +1,70 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. Copyright (C) 2022 Casey Schaufler <[email protected]>
+.. Copyright (C) 2022 Intel Corporation
+
+=====================================
+Linux Security Modules
+=====================================
+
+:Author: Casey Schaufler
+:Date: July 2023
+
+Linux security modules (LSM) provide a mechanism to implement
+additional access controls to the Linux security policies.
+
+The various security modules may support any of these attributes:
+
+``LSM_ATTR_CURRENT`` is the current, active security context of the
+process.
+The proc filesystem provides this value in ``/proc/self/attr/current``.
+This is supported by the SELinux, Smack and AppArmor security modules.
+Smack also provides this value in ``/proc/self/attr/smack/current``.
+AppArmor also provides this value in ``/proc/self/attr/apparmor/current``.
+
+``LSM_ATTR_EXEC`` is the security context of the process at the time the
+current image was executed.
+The proc filesystem provides this value in ``/proc/self/attr/exec``.
+This is supported by the SELinux and AppArmor security modules.
+AppArmor also provides this value in ``/proc/self/attr/apparmor/exec``.
+
+``LSM_ATTR_FSCREATE`` is the security context of the process used when
+creating file system objects.
+The proc filesystem provides this value in ``/proc/self/attr/fscreate``.
+This is supported by the SELinux security module.
+
+``LSM_ATTR_KEYCREATE`` is the security context of the process used when
+creating key objects.
+The proc filesystem provides this value in ``/proc/self/attr/keycreate``.
+This is supported by the SELinux security module.
+
+``LSM_ATTR_PREV`` is the security context of the process at the time the
+current security context was set.
+The proc filesystem provides this value in ``/proc/self/attr/prev``.
+This is supported by the SELinux and AppArmor security modules.
+AppArmor also provides this value in ``/proc/self/attr/apparmor/prev``.
+
+``LSM_ATTR_SOCKCREATE`` is the security context of the process used when
+creating socket objects.
+The proc filesystem provides this value in ``/proc/self/attr/sockcreate``.
+This is supported by the SELinux security module.
+
+Kernel interface
+================
+
+Set a security attribute of the current process
+-----------------------------------------------
+
+.. kernel-doc:: security/lsm_syscalls.c
+ :identifiers: sys_lsm_set_self_attr
+
+Get the specified security attributes of the current process
+------------------------------------------------------------
+
+.. kernel-doc:: security/lsm_syscalls.c
+ :identifiers: sys_lsm_get_self_attr
+
+Additional documentation
+========================
+
+* Documentation/security/lsm.rst
+* Documentation/security/lsm-development.rst
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index ac962c4cb44b..97233e6e2091 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -262,6 +262,10 @@ LSM_HOOK(int, 0, sem_semop, struct kern_ipc_perm *perm, struct sembuf *sops,
LSM_HOOK(int, 0, netlink_send, struct sock *sk, struct sk_buff *skb)
LSM_HOOK(void, LSM_RET_VOID, d_instantiate, struct dentry *dentry,
struct inode *inode)
+LSM_HOOK(int, -EOPNOTSUPP, getselfattr, unsigned int attr,
+ struct lsm_ctx __user *ctx, size_t *size, u32 flags)
+LSM_HOOK(int, -EOPNOTSUPP, setselfattr, unsigned int attr,
+ struct lsm_ctx *ctx, size_t size, u32 flags)
LSM_HOOK(int, -EINVAL, getprocattr, struct task_struct *p, const char *name,
char **value)
LSM_HOOK(int, -EINVAL, setprocattr, const char *name, void *value, size_t size)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 7f0adb33caaa..a2ade0ffe9e7 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -25,6 +25,7 @@
#ifndef __LINUX_LSM_HOOKS_H
#define __LINUX_LSM_HOOKS_H

+#include <uapi/linux/lsm.h>
#include <linux/security.h>
#include <linux/init.h>
#include <linux/rculist.h>
diff --git a/include/linux/security.h b/include/linux/security.h
index 3f79bc191a7c..8831d7cf0a6b 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -60,6 +60,7 @@ struct fs_parameter;
enum fs_value_type;
struct watch;
struct watch_notification;
+struct lsm_ctx;

/* Default (no) options for the capable function */
#define CAP_OPT_NONE 0x0
@@ -472,6 +473,10 @@ int security_sem_semctl(struct kern_ipc_perm *sma, int cmd);
int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops,
unsigned nsops, int alter);
void security_d_instantiate(struct dentry *dentry, struct inode *inode);
+int security_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
+ size_t __user *size, u32 flags);
+int security_setselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
+ size_t size, u32 flags);
int security_getprocattr(struct task_struct *p, int lsmid, const char *name,
char **value);
int security_setprocattr(int lsmid, const char *name, void *value, size_t size);
@@ -1338,6 +1343,20 @@ static inline void security_d_instantiate(struct dentry *dentry,
struct inode *inode)
{ }

+static inline int security_getselfattr(unsigned int attr,
+ struct lsm_ctx __user *ctx,
+ size_t __user *size, u32 flags)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int security_setselfattr(unsigned int attr,
+ struct lsm_ctx __user *ctx,
+ size_t size, u32 flags)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int security_getprocattr(struct task_struct *p, int lsmid,
const char *name, char **value)
{
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 22bc6bc147f8..8637287bd39d 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -71,6 +71,7 @@ struct clone_args;
struct open_how;
struct mount_attr;
struct landlock_ruleset_attr;
+struct lsm_ctx;
enum landlock_rule_type;
struct cachestat_range;
struct cachestat;
@@ -940,6 +941,10 @@ asmlinkage long sys_cachestat(unsigned int fd,
struct cachestat_range __user *cstat_range,
struct cachestat __user *cstat, unsigned int flags);
asmlinkage long sys_map_shadow_stack(unsigned long addr, unsigned long size, unsigned int flags);
+asmlinkage long sys_lsm_get_self_attr(unsigned int attr, struct lsm_ctx *ctx,
+ size_t *size, __u32 flags);
+asmlinkage long sys_lsm_set_self_attr(unsigned int attr, struct lsm_ctx *ctx,
+ size_t size, __u32 flags);

/*
* Architecture-specific system calls
diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
index f27c9a9cc376..eeda59a77c02 100644
--- a/include/uapi/linux/lsm.h
+++ b/include/uapi/linux/lsm.h
@@ -9,6 +9,36 @@
#ifndef _UAPI_LINUX_LSM_H
#define _UAPI_LINUX_LSM_H

+#include <linux/types.h>
+#include <linux/unistd.h>
+
+/**
+ * struct lsm_ctx - LSM context information
+ * @id: the LSM id number, see LSM_ID_XXX
+ * @flags: LSM specific flags
+ * @len: length of the lsm_ctx struct, @ctx and any other data or padding
+ * @ctx_len: the size of @ctx
+ * @ctx: the LSM context value
+ *
+ * The @len field MUST be equal to the size of the lsm_ctx struct
+ * plus any additional padding and/or data placed after @ctx.
+ *
+ * In all cases @ctx_len MUST be equal to the length of @ctx.
+ * If @ctx is a string value it should be nul terminated with
+ * @ctx_len equal to `strlen(@ctx) + 1`. Binary values are
+ * supported.
+ *
+ * The @flags and @ctx fields SHOULD only be interpreted by the
+ * LSM specified by @id; they MUST be set to zero/0 when not used.
+ */
+struct lsm_ctx {
+ __u64 id;
+ __u64 flags;
+ __u64 len;
+ __u64 ctx_len;
+ __u8 ctx[];
+};
+
/*
* ID tokens to identify Linux Security Modules (LSMs)
*
@@ -51,4 +81,10 @@
#define LSM_ATTR_PREV 104
#define LSM_ATTR_SOCKCREATE 105

+/*
+ * LSM_FLAG_XXX definitions identify special handling instructions
+ * for the API.
+ */
+#define LSM_FLAG_SINGLE 0x0001
+
#endif /* _UAPI_LINUX_LSM_H */
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index e137c1385c56..f81f2468c0ce 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -170,6 +170,8 @@ COND_SYSCALL(landlock_add_rule);
COND_SYSCALL(landlock_restrict_self);
COND_SYSCALL(fadvise64_64);
COND_SYSCALL_COMPAT(fadvise64_64);
+COND_SYSCALL(lsm_get_self_attr);
+COND_SYSCALL(lsm_set_self_attr);

/* CONFIG_MMU only */
COND_SYSCALL(swapon);
diff --git a/security/Makefile b/security/Makefile
index 18121f8f85cd..59f238490665 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -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
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
new file mode 100644
index 000000000000..226ae80d9683
--- /dev/null
+++ b/security/lsm_syscalls.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * System calls implementing the Linux Security Module API.
+ *
+ * Copyright (C) 2022 Casey Schaufler <[email protected]>
+ * Copyright (C) 2022 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>
+
+/**
+ * sys_lsm_set_self_attr - Set current task's security module attribute
+ * @attr: which attribute to set
+ * @ctx: the LSM contexts
+ * @size: size of @ctx
+ * @flags: reserved for future use
+ *
+ * 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_DEFINE4(lsm_set_self_attr, unsigned int, attr, struct lsm_ctx __user *,
+ ctx, size_t, size, u32, flags)
+{
+ return security_setselfattr(attr, ctx, size, flags);
+}
+
+/**
+ * sys_lsm_get_self_attr - Return current task's security module attributes
+ * @attr: which attribute to return
+ * @ctx: the user-space destination for the information, or NULL
+ * @size: pointer to the size of space available to receive the data
+ * @flags: special handling options. LSM_FLAG_SINGLE indicates that only
+ * attributes associated with the LSM identified in the passed @ctx be
+ * reported.
+ *
+ * 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_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
+ ctx, size_t __user *, size, u32, flags)
+{
+ return security_getselfattr(attr, ctx, size, flags);
+}
diff --git a/security/security.c b/security/security.c
index a3489c04b783..0d179750d964 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3837,6 +3837,158 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
}
EXPORT_SYMBOL(security_d_instantiate);

+/*
+ * Please keep this in sync with it's counterpart in security/lsm_syscalls.c
+ */
+
+/**
+ * security_getselfattr - Read an LSM attribute of the current process.
+ * @attr: which attribute to return
+ * @uctx: the user-space destination for the information, or NULL
+ * @size: pointer to the size of space available to receive the data
+ * @flags: special handling options. LSM_FLAG_SINGLE indicates that only
+ * attributes associated with the LSM identified in the passed @ctx be
+ * reported.
+ *
+ * A NULL value for @uctx can be used to get both the number of attributes
+ * and the size of the data.
+ *
+ * Returns the number of attributes found on success, negative value
+ * on error. @size is reset to the total size of the data.
+ * If @size is insufficient to contain the data -E2BIG is returned.
+ */
+int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
+ size_t __user *size, u32 flags)
+{
+ struct security_hook_list *hp;
+ struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
+ u8 __user *base = (u8 __user *)uctx;
+ size_t total = 0;
+ size_t entrysize;
+ size_t left;
+ bool toobig = false;
+ bool single = false;
+ int count = 0;
+ int rc;
+
+ if (attr == LSM_ATTR_UNDEF)
+ return -EINVAL;
+ if (size == NULL)
+ return -EINVAL;
+ if (get_user(left, size))
+ return -EFAULT;
+
+ if (flags) {
+ /*
+ * Only flag supported is LSM_FLAG_SINGLE
+ */
+ if (flags != LSM_FLAG_SINGLE)
+ return -EINVAL;
+ if (uctx && copy_from_user(&lctx, uctx, sizeof(lctx)))
+ return -EFAULT;
+ /*
+ * If the LSM ID isn't specified it is an error.
+ */
+ if (lctx.id == LSM_ID_UNDEF)
+ return -EINVAL;
+ single = true;
+ }
+
+ /*
+ * In the usual case gather all the data from the LSMs.
+ * In the single case only get the data from the LSM specified.
+ */
+ hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
+ if (single && lctx.id != hp->lsmid->id)
+ continue;
+ entrysize = left;
+ if (base)
+ uctx = (struct lsm_ctx __user *)(base + total);
+ rc = hp->hook.getselfattr(attr, uctx, &entrysize, flags);
+ if (rc == -EOPNOTSUPP) {
+ rc = 0;
+ continue;
+ }
+ if (rc == -E2BIG) {
+ toobig = true;
+ left = 0;
+ } else if (rc < 0)
+ return rc;
+ else
+ left -= entrysize;
+
+ total += entrysize;
+ count += rc;
+ if (single)
+ break;
+ }
+ if (put_user(total, size))
+ return -EFAULT;
+ if (toobig)
+ return -E2BIG;
+ if (count == 0)
+ return LSM_RET_DEFAULT(getselfattr);
+ return count;
+}
+
+/*
+ * Please keep this in sync with it's counterpart in security/lsm_syscalls.c
+ */
+
+/**
+ * security_setselfattr - Set an LSM attribute on the current process.
+ * @attr: which attribute to set
+ * @uctx: the user-space source for the information
+ * @size: the size of the data
+ * @flags: reserved for future use, must be 0
+ *
+ * Set an LSM attribute for the current process. The LSM, attribute
+ * and new value are included in @uctx.
+ *
+ * Returns 0 on success, -EINVAL if the input is inconsistent, -EFAULT
+ * if the user buffer is inaccessible, E2BIG if size is too big, or an
+ * LSM specific failure.
+ */
+int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
+ size_t size, u32 flags)
+{
+ struct security_hook_list *hp;
+ struct lsm_ctx *lctx;
+ int rc = LSM_RET_DEFAULT(setselfattr);
+
+ if (flags)
+ return -EINVAL;
+ if (size < sizeof(*lctx))
+ return -EINVAL;
+ if (size > PAGE_SIZE)
+ return -E2BIG;
+
+ lctx = kmalloc(size, GFP_KERNEL);
+ if (lctx == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(lctx, uctx, size)) {
+ rc = -EFAULT;
+ goto free_out;
+ }
+
+ if (size < lctx->len || size < lctx->ctx_len + sizeof(*lctx) ||
+ lctx->len < lctx->ctx_len + sizeof(*lctx)) {
+ rc = -EINVAL;
+ goto free_out;
+ }
+
+ hlist_for_each_entry(hp, &security_hook_heads.setselfattr, list)
+ if ((hp->lsmid->id) == lctx->id) {
+ rc = hp->hook.setselfattr(attr, lctx, size, flags);
+ break;
+ }
+
+free_out:
+ kfree(lctx);
+ return rc;
+}
+
/**
* security_getprocattr() - Read an attribute for a task
* @p: the task
--
2.41.0

2023-09-13 14:15:27

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v15 08/11] Smack: implement setselfattr and getselfattr hooks

Implement Smack support for security_[gs]etselfattr.
Refactor the setprocattr hook to avoid code duplication.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: John Johansen <[email protected]>
---
security/smack/smack_lsm.c | 95 ++++++++++++++++++++++++++++++++++++--
1 file changed, 90 insertions(+), 5 deletions(-)

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index f73f9a2834eb..12160d060cc1 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3626,6 +3626,46 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
return;
}

+/**
+ * smack_getselfattr - Smack current process attribute
+ * @attr: which attribute to fetch
+ * @ctx: buffer to receive the result
+ * @size: available size in, actual size out
+ * @flags: unused
+ *
+ * Fill the passed user space @ctx with the details of the requested
+ * attribute.
+ *
+ * Returns the number of attributes on success, an error code otherwise.
+ * There will only ever be one attribute.
+ */
+static int smack_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
+ size_t *size, u32 flags)
+{
+ struct smack_known *skp = smk_of_current();
+ int total;
+ int slen;
+ int rc;
+
+ if (attr != LSM_ATTR_CURRENT)
+ return -EOPNOTSUPP;
+
+ slen = strlen(skp->smk_known) + 1;
+ total = ALIGN(slen + sizeof(*ctx), 8);
+ if (total > *size)
+ rc = -E2BIG;
+ else if (ctx)
+ rc = lsm_fill_user_ctx(ctx, skp->smk_known, slen, LSM_ID_SMACK,
+ 0);
+ else
+ rc = 1;
+
+ *size = total;
+ if (rc >= 0)
+ return 1;
+ return rc;
+}
+
/**
* smack_getprocattr - Smack process attribute access
* @p: the object task
@@ -3655,8 +3695,8 @@ static int smack_getprocattr(struct task_struct *p, const char *name, char **val
}

/**
- * smack_setprocattr - Smack process attribute setting
- * @name: the name of the attribute in /proc/.../attr
+ * do_setattr - Smack process attribute setting
+ * @attr: the ID of the attribute
* @value: the value to set
* @size: the size of the value
*
@@ -3665,7 +3705,7 @@ static int smack_getprocattr(struct task_struct *p, const char *name, char **val
*
* Returns the length of the smack label or an error code
*/
-static int smack_setprocattr(const char *name, void *value, size_t size)
+static int do_setattr(u64 attr, void *value, size_t size)
{
struct task_smack *tsp = smack_cred(current_cred());
struct cred *new;
@@ -3679,8 +3719,8 @@ static int smack_setprocattr(const char *name, void *value, size_t size)
if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
return -EINVAL;

- if (strcmp(name, "current") != 0)
- return -EINVAL;
+ if (attr != LSM_ATTR_CURRENT)
+ return -EOPNOTSUPP;

skp = smk_import_entry(value, size);
if (IS_ERR(skp))
@@ -3719,6 +3759,49 @@ static int smack_setprocattr(const char *name, void *value, size_t size)
return size;
}

+/**
+ * smack_setselfattr - Set a Smack process attribute
+ * @attr: which attribute to set
+ * @ctx: buffer containing the data
+ * @size: size of @ctx
+ * @flags: unused
+ *
+ * Fill the passed user space @ctx with the details of the requested
+ * attribute.
+ *
+ * Returns 0 on success, an error code otherwise.
+ */
+static int smack_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
+ size_t size, u32 flags)
+{
+ int rc;
+
+ rc = do_setattr(attr, ctx->ctx, ctx->ctx_len);
+ if (rc > 0)
+ return 0;
+ return rc;
+}
+
+/**
+ * smack_setprocattr - Smack process attribute setting
+ * @name: the name of the attribute in /proc/.../attr
+ * @value: the value to set
+ * @size: the size of the value
+ *
+ * Sets the Smack value of the task. Only setting self
+ * is permitted and only with privilege
+ *
+ * Returns the length of the smack label or an error code
+ */
+static int smack_setprocattr(const char *name, void *value, size_t size)
+{
+ int attr = lsm_name_to_attr(name);
+
+ if (attr != LSM_ATTR_UNDEF)
+ return do_setattr(attr, value, size);
+ return -EINVAL;
+}
+
/**
* smack_unix_stream_connect - Smack access on UDS
* @sock: one sock
@@ -5033,6 +5116,8 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {

LSM_HOOK_INIT(d_instantiate, smack_d_instantiate),

+ LSM_HOOK_INIT(getselfattr, smack_getselfattr),
+ LSM_HOOK_INIT(setselfattr, smack_setselfattr),
LSM_HOOK_INIT(getprocattr, smack_getprocattr),
LSM_HOOK_INIT(setprocattr, smack_setprocattr),

--
2.41.0

2023-09-15 15:41:04

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 2023/09/13 5:56, Casey Schaufler wrote:
> Create a struct lsm_id to contain identifying information about Linux
> Security Modules (LSMs). At inception this contains the name of the
> module and an identifier associated with the security module. Change
> the security_add_hooks() interface to use this structure. Change the
> individual modules to maintain their own struct lsm_id and pass it to
> security_add_hooks().
>
> The values are for LSM identifiers are defined in a new UAPI
> header file linux/lsm.h. Each existing LSM has been updated to
> include it's LSMID in the lsm_id.
>
> The LSM ID values are sequential, with the oldest module
> LSM_ID_CAPABILITY being the lowest value and the existing modules
> numbered in the order they were included in the main line kernel.
> This is an arbitrary convention for assigning the values, but
> none better presents itself. The value 0 is defined as being invalid.
> The values 1-99 are reserved for any special case uses which may
> arise in the future. This may include attributes of the LSM
> infrastructure itself, possibly related to namespacing or network
> attribute management. A special range is identified for such attributes
> to help reduce confusion for developers unfamiliar with LSMs.
>
> LSM attribute values are defined for the attributes presented by
> modules that are available today. As with the LSM IDs, The value 0
> is defined as being invalid. The values 1-99 are reserved for any
> special case uses which may arise in the future.
>
> Signed-off-by: Casey Schaufler <[email protected]>
> Cc: linux-security-module <[email protected]>
> Reviewed-by: Kees Cook <[email protected]>
> Reviewed-by: Serge Hallyn <[email protected]>
> Reviewed-by: Mickael Salaun <[email protected]>
> Reviewed-by: John Johansen <[email protected]>

Nacked-by: Tetsuo Handa <[email protected]>

https://lkml.kernel.org/r/[email protected]

2023-09-15 23:35:44

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 9/15/2023 4:32 AM, Tetsuo Handa wrote:
> On 2023/09/13 5:56, Casey Schaufler wrote:
>> Create a struct lsm_id to contain identifying information about Linux
>> Security Modules (LSMs). At inception this contains the name of the
>> module and an identifier associated with the security module. Change
>> the security_add_hooks() interface to use this structure. Change the
>> individual modules to maintain their own struct lsm_id and pass it to
>> security_add_hooks().
>>
>> The values are for LSM identifiers are defined in a new UAPI
>> header file linux/lsm.h. Each existing LSM has been updated to
>> include it's LSMID in the lsm_id.
>>
>> The LSM ID values are sequential, with the oldest module
>> LSM_ID_CAPABILITY being the lowest value and the existing modules
>> numbered in the order they were included in the main line kernel.
>> This is an arbitrary convention for assigning the values, but
>> none better presents itself. The value 0 is defined as being invalid.
>> The values 1-99 are reserved for any special case uses which may
>> arise in the future. This may include attributes of the LSM
>> infrastructure itself, possibly related to namespacing or network
>> attribute management. A special range is identified for such attributes
>> to help reduce confusion for developers unfamiliar with LSMs.
>>
>> LSM attribute values are defined for the attributes presented by
>> modules that are available today. As with the LSM IDs, The value 0
>> is defined as being invalid. The values 1-99 are reserved for any
>> special case uses which may arise in the future.
>>
>> Signed-off-by: Casey Schaufler <[email protected]>
>> Cc: linux-security-module <[email protected]>
>> Reviewed-by: Kees Cook <[email protected]>
>> Reviewed-by: Serge Hallyn <[email protected]>
>> Reviewed-by: Mickael Salaun <[email protected]>
>> Reviewed-by: John Johansen <[email protected]>
> Nacked-by: Tetsuo Handa <[email protected]>

I *could* respond with:

-#define LSM_ID_TOMOYO 103

but I won't. I won't make a difference because TOMOYO doesn't present
any attributes. I understand your objections, but don't believe that
they can't be worked around. The argument that a LSM ID will prevent
new LSM development is rebuffed by the exact same situation with system
calls, PRCTL and IOCTL values. The argument that it somehow prevents
out-of-tree modules falls on deaf ears. The argument that it prevents
dynamic security modules is subsumed by the other issues surrounding
dynamic security modules, and does nothing to decrease the likelihood
of that facility going upstream. Especially since, to the best of my
knowledge, no one is working on it.


> https://lkml.kernel.org/r/[email protected]
>

2023-09-16 06:34:14

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 2023/09/16 2:53, Casey Schaufler wrote:
> I *could* respond with:
>
> -#define LSM_ID_TOMOYO 103
>
> but I won't. I won't make a difference because TOMOYO doesn't present
> any attributes. I understand your objections, but don't believe that
> they can't be worked around. The argument that a LSM ID will prevent
> new LSM development is rebuffed by the exact same situation with system
> calls, PRCTL and IOCTL values. The argument that it somehow prevents
> out-of-tree modules falls on deaf ears. The argument that it prevents
> dynamic security modules is subsumed by the other issues surrounding
> dynamic security modules, and does nothing to decrease the likelihood
> of that facility going upstream. Especially since, to the best of my
> knowledge, no one is working on it.

+/**
+ * struct lsm_id - Identify a Linux Security Module.
+ * @lsm: name of the LSM, must be approved by the LSM maintainers

Why can't you understand that "approved by the LSM maintainers" is a horrible
requirement for LSM modules which cannot become one of in-tree LSMs?

One of reasons for not every proposed LSM module can become in-tree is out of
the LSM community's resources for reviewing/maintaining (or failure to acquire
attention from the LSM community enough to get reviewed).

+ * @id: LSM ID number from uapi/linux/lsm.h

Since the LSM community cannot accept all of proposed LSMs due to limited resources,
the LSM community is responsible for allowing whatever proposed LSMs (effectively any
publicly available LSMs) to live as out-of-tree LSMs, by approving the LSM name and
assigning a permanent LSM ID number.

The only exception the LSM community can refuse to approve/assign would be that the name
is not appropriate (e.g. a LSM module named "FuckYou") or the name is misleading (e.g.
"selinux+", "smock", "tomato", "apparmour"). Otherwise, no matter how many times you repeat
"we don't care out-of-tree LSMs" or "I do not intentionally plan to make life difficult for
the out-of-tree LSMs", this patch is intended to lock out out-of-tree LSMs.

+ *
+ * Contains the information that identifies the LSM.
+ */
+struct lsm_id {
+ const char *name;
+ u64 id;
+};

Therefore, unless you change the policy for assigning LSM ID, I keep NACK on this change.

2023-09-17 22:06:03

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 9/15/2023 11:32 PM, Tetsuo Handa wrote:
> On 2023/09/16 2:53, Casey Schaufler wrote:
>> I *could* respond with:
>>
>> -#define LSM_ID_TOMOYO 103
>>
>> but I won't. I won't make a difference because TOMOYO doesn't present
>> any attributes. I understand your objections, but don't believe that
>> they can't be worked around. The argument that a LSM ID will prevent
>> new LSM development is rebuffed by the exact same situation with system
>> calls, PRCTL and IOCTL values. The argument that it somehow prevents
>> out-of-tree modules falls on deaf ears. The argument that it prevents
>> dynamic security modules is subsumed by the other issues surrounding
>> dynamic security modules, and does nothing to decrease the likelihood
>> of that facility going upstream. Especially since, to the best of my
>> knowledge, no one is working on it.
> +/**
> + * struct lsm_id - Identify a Linux Security Module.
> + * @lsm: name of the LSM, must be approved by the LSM maintainers
>
> Why can't you understand that "approved by the LSM maintainers" is a horrible
> requirement for LSM modules which cannot become one of in-tree LSMs?
>
> One of reasons for not every proposed LSM module can become in-tree is out of
> the LSM community's resources for reviewing/maintaining (or failure to acquire
> attention from the LSM community enough to get reviewed).
>
> + * @id: LSM ID number from uapi/linux/lsm.h
>
> Since the LSM community cannot accept all of proposed LSMs due to limited resources,
> the LSM community is responsible for allowing whatever proposed LSMs (effectively any
> publicly available LSMs) to live as out-of-tree LSMs, by approving the LSM name and
> assigning a permanent LSM ID number.
>
> The only exception the LSM community can refuse to approve/assign would be that the name
> is not appropriate (e.g. a LSM module named "FuckYou") or the name is misleading (e.g.
> "selinux+", "smock", "tomato", "apparmour"). Otherwise, no matter how many times you repeat
> "we don't care out-of-tree LSMs" or "I do not intentionally plan to make life difficult for
> the out-of-tree LSMs", this patch is intended to lock out out-of-tree LSMs.

That is a false statement. There is a huge difference between apathy and malice.

>
> + *
> + * Contains the information that identifies the LSM.
> + */
> +struct lsm_id {
> + const char *name;
> + u64 id;
> +};
>
> Therefore, unless you change the policy for assigning LSM ID, I keep NACK on this change.
>

2023-09-20 10:29:38

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 2023/09/18 1:38, Casey Schaufler wrote:
> On 9/15/2023 11:32 PM, Tetsuo Handa wrote:
>> +/**
>> + * struct lsm_id - Identify a Linux Security Module.
>> + * @lsm: name of the LSM, must be approved by the LSM maintainers
>>
>> Why can't you understand that "approved by the LSM maintainers" is a horrible
>> requirement for LSM modules which cannot become one of in-tree LSMs?
>>
>> One of reasons for not every proposed LSM module can become in-tree is out of
>> the LSM community's resources for reviewing/maintaining (or failure to acquire
>> attention from the LSM community enough to get reviewed).
>>
>> + * @id: LSM ID number from uapi/linux/lsm.h
>>
>> Since the LSM community cannot accept all of proposed LSMs due to limited resources,
>> the LSM community is responsible for allowing whatever proposed LSMs (effectively any
>> publicly available LSMs) to live as out-of-tree LSMs, by approving the LSM name and
>> assigning a permanent LSM ID number.
>>
>> The only exception the LSM community can refuse to approve/assign would be that the name
>> is not appropriate (e.g. a LSM module named "FuckYou") or the name is misleading (e.g.
>> "selinux+", "smock", "tomato", "apparmour"). Otherwise, no matter how many times you repeat
>> "we don't care out-of-tree LSMs" or "I do not intentionally plan to make life difficult for
>> the out-of-tree LSMs", this patch is intended to lock out out-of-tree LSMs.
>
> That is a false statement. There is a huge difference between apathy and malice.

Dave Chinner wrote at https://lkml.kernel.org/r/[email protected]
as a response to "We don't care about out of tree filesystems.":

In this case, we most certainly do care. Downstream distros support
all sorts of out of tree filesystems loaded via kernel modules, so a
syscall that is used to uniquely identify a filesystem type to
userspace *must* have a mechanism for the filesystem to provide that
unique identifier to userspace.

Fundamentally, the kernel does not and should not dictate what
filesystem types it supports; the user decides what filesystem they
need to use, and it is the kernel's job to provide infrastructure
that works with that user's choice.

Can you see? What you are trying to is NACKed by simple s/filesystem/LSM/g .

The kernel is ultimately there for users. The kernel is never there for doing patent
acquisition competition. If the LSM community accepts only LSMs which won the patent
acquisition competition as in-tree (as described in "ANN: new LSM guidelines"),
the LSM community is responsible for allowing any publicly available LSMs to live as
out of tree modules.

Unless the policy is updated to approve any publicly available LSMs and assign a unique
identifier (which can be passed to the syscalls introduced by this series) to each
publicly available LSM, this series is a regression.

The "[PATCH v15 01/11] LSM: Identify modules by more than name" is exactly doing
"LSM: allow only in-tree LSM modules, lock out out-of-tree LSM modules".
Nack, Nack, Nack, Nack, Nack!!!!!

>
>>
>> + *
>> + * Contains the information that identifies the LSM.
>> + */
>> +struct lsm_id {
>> + const char *name;
>> + u64 id;
>> +};
>>
>> Therefore, unless you change the policy for assigning LSM ID, I keep NACK on this change.
>>

2023-09-21 00:27:44

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On Wed, Sep 20, 2023 at 07:20:35PM +0900, Tetsuo Handa wrote:
> On 2023/09/18 1:38, Casey Schaufler wrote:
> > On 9/15/2023 11:32 PM, Tetsuo Handa wrote:
> >> +/**
> >> + * struct lsm_id - Identify a Linux Security Module.
> >> + * @lsm: name of the LSM, must be approved by the LSM maintainers
> >>
> >> Why can't you understand that "approved by the LSM maintainers" is a horrible
> >> requirement for LSM modules which cannot become one of in-tree LSMs?
> >>
> >> One of reasons for not every proposed LSM module can become in-tree is out of
> >> the LSM community's resources for reviewing/maintaining (or failure to acquire
> >> attention from the LSM community enough to get reviewed).
> >>
> >> + * @id: LSM ID number from uapi/linux/lsm.h
> >>
> >> Since the LSM community cannot accept all of proposed LSMs due to limited resources,
> >> the LSM community is responsible for allowing whatever proposed LSMs (effectively any
> >> publicly available LSMs) to live as out-of-tree LSMs, by approving the LSM name and
> >> assigning a permanent LSM ID number.
> >>
> >> The only exception the LSM community can refuse to approve/assign would be that the name
> >> is not appropriate (e.g. a LSM module named "FuckYou") or the name is misleading (e.g.
> >> "selinux+", "smock", "tomato", "apparmour"). Otherwise, no matter how many times you repeat
> >> "we don't care out-of-tree LSMs" or "I do not intentionally plan to make life difficult for
> >> the out-of-tree LSMs", this patch is intended to lock out out-of-tree LSMs.
> >
> > That is a false statement. There is a huge difference between apathy and malice.
>
> Dave Chinner wrote at https://lkml.kernel.org/r/[email protected]
> as a response to "We don't care about out of tree filesystems.":
>
> In this case, we most certainly do care. Downstream distros support
> all sorts of out of tree filesystems loaded via kernel modules, so a
> syscall that is used to uniquely identify a filesystem type to
> userspace *must* have a mechanism for the filesystem to provide that
> unique identifier to userspace.
>
> Fundamentally, the kernel does not and should not dictate what
> filesystem types it supports; the user decides what filesystem they
> need to use, and it is the kernel's job to provide infrastructure
> that works with that user's choice.
>
> Can you see? What you are trying to is NACKed by simple s/filesystem/LSM/g .
>
> The kernel is ultimately there for users. The kernel is never there for doing patent
> acquisition competition. If the LSM community accepts only LSMs which won the patent
> acquisition competition as in-tree (as described in "ANN: new LSM guidelines"),
> the LSM community is responsible for allowing any publicly available LSMs to live as
> out of tree modules.
>
> Unless the policy is updated to approve any publicly available LSMs and assign a unique
> identifier (which can be passed to the syscalls introduced by this series) to each
> publicly available LSM, this series is a regression.
>
> The "[PATCH v15 01/11] LSM: Identify modules by more than name" is exactly doing
> "LSM: allow only in-tree LSM modules, lock out out-of-tree LSM modules".
> Nack, Nack, Nack, Nack, Nack!!!!!

I feel like you are willfully not listening to us when we say that this
doesn't block out of tree LSMs. Again, there is nothing here that stops
it. To prove this point, here is an out of tree LSM that works with this
series. So let's move from theoretical to practical: given this example,
why do you think out of tree LSMs are blocked?


From a6f50cb719aac2452506babda07657f9f6961a95 Mon Sep 17 00:00:00 2001
From: Kees Cook <[email protected]>
Date: Wed, 20 Sep 2023 08:00:31 -0700
Subject: [PATCH] security: Add GOAT LSM

This will never go upstream, but it still works with the new LSM
syscalls.

Cc: Paul Moore <[email protected]>
Cc: James Morris <[email protected]>
Cc: "Serge E. Hallyn" <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
include/uapi/linux/lsm.h | 2 ++
security/Kconfig | 1 +
security/Makefile | 1 +
security/goat/Kconfig | 9 +++++++
security/goat/Makefile | 2 ++
security/goat/goat.c | 51 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 66 insertions(+)
create mode 100644 security/goat/Kconfig
create mode 100644 security/goat/Makefile
create mode 100644 security/goat/goat.c

diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
index eeda59a77c02..23b7a8f79cef 100644
--- a/include/uapi/linux/lsm.h
+++ b/include/uapi/linux/lsm.h
@@ -63,6 +63,8 @@ struct lsm_ctx {
#define LSM_ID_BPF 110
#define LSM_ID_LANDLOCK 111

+#define LSM_ID_GOAT 1138
+
/*
* LSM_ATTR_XXX definitions identify different LSM attributes
* which are used in the kernel's LSM userspace API. Support
diff --git a/security/Kconfig b/security/Kconfig
index 52c9af08ad35..0c692913a1a6 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -194,6 +194,7 @@ source "security/yama/Kconfig"
source "security/safesetid/Kconfig"
source "security/lockdown/Kconfig"
source "security/landlock/Kconfig"
+source "security/goat/Kconfig"

source "security/integrity/Kconfig"

diff --git a/security/Makefile b/security/Makefile
index 59f238490665..1d260f994fac 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/
obj-$(CONFIG_CGROUPS) += device_cgroup.o
obj-$(CONFIG_BPF_LSM) += bpf/
obj-$(CONFIG_SECURITY_LANDLOCK) += landlock/
+obj-$(CONFIG_SECURITY_GOAT) += goat/

# Object integrity file lists
obj-$(CONFIG_INTEGRITY) += integrity/
diff --git a/security/goat/Kconfig b/security/goat/Kconfig
new file mode 100644
index 000000000000..dd25848e3204
--- /dev/null
+++ b/security/goat/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config SECURITY_GOAT
+ bool "Greatest Of All Time security features"
+ depends on SECURITY
+ help
+ This LSM provides the greatest security features of all
+ time.
+
+ If in doubt, choose "Heck yeah".
diff --git a/security/goat/Makefile b/security/goat/Makefile
new file mode 100644
index 000000000000..e673c913f66f
--- /dev/null
+++ b/security/goat/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_SECURITY_GOAT) += goat.o
diff --git a/security/goat/goat.c b/security/goat/goat.c
new file mode 100644
index 000000000000..f1eee60c9217
--- /dev/null
+++ b/security/goat/goat.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Greatest Linux Security Module Of All Time
+ *
+ * Author: Kees Cook <[email protected]>
+ */
+
+#define pr_fmt(fmt) "GOAT: " fmt
+
+#include <linux/module.h>
+#include <linux/lsm_hooks.h>
+#include <uapi/linux/lsm.h>
+
+const struct lsm_id goat_lsmid = {
+ .name = "goat",
+ .id = LSM_ID_GOAT,
+};
+
+static int goat_read_file(struct file *file, enum kernel_read_file_id id,
+ bool contents)
+{
+ pr_info("universally allowing file read\n");
+ return 0;
+}
+
+static int goat_load_data(enum kernel_load_data_id id, bool contents)
+{
+ pr_info("No blobs allowed!\n");
+ return -EUCLEAN;
+}
+
+static struct security_hook_list goat_hooks[] __ro_after_init = {
+ LSM_HOOK_INIT(kernel_read_file, goat_read_file),
+ LSM_HOOK_INIT(kernel_load_data, goat_load_data),
+};
+
+static int __init goat_init(void)
+{
+ pr_info("GOAT loading: Bleeeaaaeeeeggh\n");
+
+ security_add_hooks(goat_hooks, ARRAY_SIZE(goat_hooks), &goat_lsmid);
+
+ return 0;
+}
+
+DEFINE_LSM(goat) = {
+ .name = "goat",
+ .init = goat_init,
+};
--
2.34.1


--
Kees Cook

2023-09-23 04:47:39

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 2023/09/21 0:08, Kees Cook wrote:
> I feel like you are willfully not listening to us when we say that this
> doesn't block out of tree LSMs. Again, there is nothing here that stops
> it. To prove this point, here is an out of tree LSM that works with this
> series. So let's move from theoretical to practical: given this example,
> why do you think out of tree LSMs are blocked?

Because an LSM ID value

> diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
> index eeda59a77c02..23b7a8f79cef 100644
> --- a/include/uapi/linux/lsm.h
> +++ b/include/uapi/linux/lsm.h
> @@ -63,6 +63,8 @@ struct lsm_ctx {
> #define LSM_ID_BPF 110
> #define LSM_ID_LANDLOCK 111
>
> +#define LSM_ID_GOAT 1138
> +
> /*
> * LSM_ATTR_XXX definitions identify different LSM attributes
> * which are used in the kernel's LSM userspace API. Support

is assigned to LSM only when that LSM became no longer out of tree.

I'm against the policy that only LSM modules that succeeded to become
in-tree are assigned LSM ID. That's not a good usage of identifier.

Quoting from https://lkml.kernel.org/r/[email protected] :

The sane and the better usage of LSM ID is to register any publicly available
LSMs. If LSM ID serves as an index for what LSMs are available in the world,
by maintaining "the LSM module name, the LSM ID value, short description about
that LSM module, the public git repository or web site for more information
about that LSM module" pairs, people can easily find what LSMs could be used
for their purpose, and developers can avoid re-inventing similar LSM modules
which are already available somewhere in the world (and optionally helps
avoiding module name collisions with any publicly available LSMs).

You must not say "We don't care about out of tree LSMs." when talking about this patch.

2023-09-24 08:34:47

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On Sat, Sep 23, 2023 at 01:46:35PM +0900, Tetsuo Handa wrote:
> On 2023/09/21 0:08, Kees Cook wrote:
> > I feel like you are willfully not listening to us when we say that this
> > doesn't block out of tree LSMs. Again, there is nothing here that stops
> > it. To prove this point, here is an out of tree LSM that works with this
> > series. So let's move from theoretical to practical: given this example,
> > why do you think out of tree LSMs are blocked?
>
> Because an LSM ID value

But my example includes one.

> > diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
> > index eeda59a77c02..23b7a8f79cef 100644
> > --- a/include/uapi/linux/lsm.h
> > +++ b/include/uapi/linux/lsm.h
> > @@ -63,6 +63,8 @@ struct lsm_ctx {
> > #define LSM_ID_BPF 110
> > #define LSM_ID_LANDLOCK 111
> >
> > +#define LSM_ID_GOAT 1138
> > +
> > /*
> > * LSM_ATTR_XXX definitions identify different LSM attributes
> > * which are used in the kernel's LSM userspace API. Support
>
> is assigned to LSM only when that LSM became no longer out of tree.

Why? My example code will work just fine. The only possible reason
it could be awkward would be if an out of tree LSM became so useful
that the author decided to upstream it, and risked colliding with an
existing LSM id. But lsm_id::id is a u64 (not an enum!), so there is
a HUGE space available. If out of tree LSMs used the epoch time they
were first authored as their id, the chances of a collision would be
approaching zero. There isn't an out of tree LSM written every second,
but if there were, it would take 584 billion years to run out of LSM ids.

And, as mentioned several times before, this is _not a new problem_, and
exists for out of tree syscalls, out of tree prctls, etc. I even DID
this for the Yama LSM when it looked like it wasn't going to get
upstream in the early days. Its prctl number _is not sequential_:

include/uapi/linux/prctl.h:#define PR_SET_PTRACER 0x59616d61

(And you'll see 0x59616d61 in ASCII is "Yama"; my effort to avoid
collision.)

So, there is both ability (u64) and precedent (Yama) for this. Having an
LSM id is _not_ a blocker for out of tree LSMs, and I've given the proof.

-Kees

--
Kees Cook

2023-09-24 11:06:59

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

Patch description says

The LSM ID values are sequential, with the oldest module
LSM_ID_CAPABILITY being the lowest value and the existing modules
numbered in the order they were included in the main line kernel.
This is an arbitrary convention for assigning the values, but
none better presents itself. The value 0 is defined as being invalid.

and your non-sequential assignment

> But lsm_id::id is a u64 (not an enum!), so there is a HUGE space available.

violated it. include/uapi/linux/lsm.h is a userspace API file, where
we can't change this value after once defined.

You withdraw your "Reviewed-by" response unless "The LSM ID values are sequential"
and "must be approved by the LSM maintainers" are removed and "the LSM maintainers/community
shall never complain about what names and/or values are assigned" is added, don't you?

Quoting from https://lkml.kernel.org/r/[email protected] :

You are intentionally making life difficult for the out-of-tree LSMs, by
requiring an LSM ID (and facilitating LSM ID collisions). No matter how
priority of out-of-tree LSMs is low for you, what you are about to merge
goes against the "developers try to avoid identifier collisions" effort.

Introducing a numeric identifier is a good opportunity for permanently
eliminating possibility of identifier collisions. But current usage of this
numeric identifier is designed for facilitating possibility of identifier
collisions.

Keeping how the HUGE space is used under control of the LSM community will be
better for both in-tree and out-of-tree LSM modules. I really can't understand
why you don't want to utilize this opportunity.

2023-09-24 19:48:28

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On September 24, 2023 4:06:07 AM PDT, Tetsuo Handa <[email protected]> wrote:
>Patch description says
>
> The LSM ID values are sequential, with the oldest module
> LSM_ID_CAPABILITY being the lowest value and the existing modules
> numbered in the order they were included in the main line kernel.
> This is an arbitrary convention for assigning the values, but
> none better presents itself. The value 0 is defined as being invalid.

"in the order they were included in the main line kernel" Out of trees aren't in main line.

And "This is an arbitrary convention" specifically says it's arbitrary.

There is literally nothing here stopping out of tree modules. I have proven this, and so have you with these quotes. What is left to object to?

>You withdraw your "Reviewed-by" response unless "The LSM ID values are sequential"
>and "must be approved by the LSM maintainers" are removed and "the LSM maintainers/community
>shall never complain about what names and/or values are assigned" is added, don't you?

*For main line kernels*

Please, understand both the *intent* and *reality*: this does not block out of tree LSMs, full stop.

>Keeping how the HUGE space is used under control of the LSM community will be
>better for both in-tree and out-of-tree LSM modules. I really can't understand
>why you don't want to utilize this opportunity.

I cannot understand what else you need to hear.

-Kees


--
Kees Cook

2023-10-03 14:09:40

by Mickaël Salaün

[permalink] [raw]
Subject: Re: [PATCH v15 04/11] LSM: syscalls for current process attributes

On Tue, Sep 12, 2023 at 01:56:49PM -0700, Casey Schaufler wrote:
> Create a system call lsm_get_self_attr() to provide the security
> module maintained attributes of the current process.
> 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
> identifies the size of the attribute, and the attribute value. The format
> of the attribute value is defined by the security module. A flags field
> is included for LSM specific information. It is currently unused and must
> be 0. The total size of the data, including the lsm_ctx structure and any
> padding, is maintained as well.
>
> struct lsm_ctx {
> __u64 id;
> __u64 flags;
> __u64 len;
> __u64 ctx_len;
> __u8 ctx[];
> };
>
> Two new LSM hooks are used to interface with the LSMs.
> security_getselfattr() collects the lsm_ctx values from the
> LSMs that support the hook, accounting for space requirements.
> security_setselfattr() identifies which LSM the attribute is
> intended for and passes it along.
>
> Signed-off-by: Casey Schaufler <[email protected]>
> Reviewed-by: Kees Cook <[email protected]>
> Reviewed-by: Serge Hallyn <[email protected]>
> Reviewed-by: John Johansen <[email protected]>
> ---
> Documentation/userspace-api/lsm.rst | 70 +++++++++++++
> include/linux/lsm_hook_defs.h | 4 +
> include/linux/lsm_hooks.h | 1 +
> include/linux/security.h | 19 ++++
> include/linux/syscalls.h | 5 +
> include/uapi/linux/lsm.h | 36 +++++++
> kernel/sys_ni.c | 2 +
> security/Makefile | 1 +
> security/lsm_syscalls.c | 57 +++++++++++
> security/security.c | 152 ++++++++++++++++++++++++++++
> 10 files changed, 347 insertions(+)
> create mode 100644 Documentation/userspace-api/lsm.rst
> create mode 100644 security/lsm_syscalls.c
>

> diff --git a/security/security.c b/security/security.c
> index a3489c04b783..0d179750d964 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -3837,6 +3837,158 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
> }
> EXPORT_SYMBOL(security_d_instantiate);
>
> +/*
> + * Please keep this in sync with it's counterpart in security/lsm_syscalls.c
> + */
> +
> +/**
> + * security_getselfattr - Read an LSM attribute of the current process.
> + * @attr: which attribute to return
> + * @uctx: the user-space destination for the information, or NULL
> + * @size: pointer to the size of space available to receive the data
> + * @flags: special handling options. LSM_FLAG_SINGLE indicates that only
> + * attributes associated with the LSM identified in the passed @ctx be
> + * reported.
> + *
> + * A NULL value for @uctx can be used to get both the number of attributes
> + * and the size of the data.
> + *
> + * Returns the number of attributes found on success, negative value
> + * on error. @size is reset to the total size of the data.
> + * If @size is insufficient to contain the data -E2BIG is returned.
> + */
> +int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
> + size_t __user *size, u32 flags)
> +{
> + struct security_hook_list *hp;
> + struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
> + u8 __user *base = (u8 __user *)uctx;
> + size_t total = 0;
> + size_t entrysize;
> + size_t left;
> + bool toobig = false;
> + bool single = false;
> + int count = 0;
> + int rc;
> +
> + if (attr == LSM_ATTR_UNDEF)
> + return -EINVAL;
> + if (size == NULL)
> + return -EINVAL;
> + if (get_user(left, size))
> + return -EFAULT;
> +
> + if (flags) {
> + /*
> + * Only flag supported is LSM_FLAG_SINGLE
> + */
> + if (flags != LSM_FLAG_SINGLE)
> + return -EINVAL;
> + if (uctx && copy_from_user(&lctx, uctx, sizeof(lctx)))

I'm not sure if we should return -EINVAL or -EFAULT when uctx == NULL.
Because uctx is optional (when LSM_FLAG_SINGLE is not set), I guess
-EINVAL is OK.

> + return -EFAULT;
> + /*
> + * If the LSM ID isn't specified it is an error.
> + */
> + if (lctx.id == LSM_ID_UNDEF)
> + return -EINVAL;
> + single = true;
> + }
> +
> + /*
> + * In the usual case gather all the data from the LSMs.
> + * In the single case only get the data from the LSM specified.
> + */
> + hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
> + if (single && lctx.id != hp->lsmid->id)
> + continue;
> + entrysize = left;
> + if (base)
> + uctx = (struct lsm_ctx __user *)(base + total);
> + rc = hp->hook.getselfattr(attr, uctx, &entrysize, flags);
> + if (rc == -EOPNOTSUPP) {
> + rc = 0;
> + continue;
> + }
> + if (rc == -E2BIG) {
> + toobig = true;
> + left = 0;
> + } else if (rc < 0)
> + return rc;
> + else
> + left -= entrysize;
> +
> + total += entrysize;
> + count += rc;

There is a bug if rc == -E2BIG

> + if (single)
> + break;
> + }
> + if (put_user(total, size))
> + return -EFAULT;
> + if (toobig)
> + return -E2BIG;
> + if (count == 0)
> + return LSM_RET_DEFAULT(getselfattr);
> + return count;
> +}

2023-10-03 14:27:31

by Mickaël Salaün

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
> Create a system call to report the list of Linux Security Modules
> that are active on the system. The list is provided as an array
> of LSM ID numbers.
>
> The calling application can use this list determine what LSM
> specific actions it might take. That might include choosing an
> output format, determining required privilege or bypassing
> security module specific behavior.
>
> Signed-off-by: Casey Schaufler <[email protected]>
> Reviewed-by: Kees Cook <[email protected]>
> Reviewed-by: Serge Hallyn <[email protected]>
> Reviewed-by: John Johansen <[email protected]>

Reviewed-by: Mickaël Salaün <[email protected]>

> ---
> Documentation/userspace-api/lsm.rst | 3 +++
> include/linux/syscalls.h | 1 +
> kernel/sys_ni.c | 1 +
> security/lsm_syscalls.c | 39 +++++++++++++++++++++++++++++
> 4 files changed, 44 insertions(+)
>
> diff --git a/Documentation/userspace-api/lsm.rst b/Documentation/userspace-api/lsm.rst
> index f8499f3e2826..a76da373841b 100644
> --- a/Documentation/userspace-api/lsm.rst
> +++ b/Documentation/userspace-api/lsm.rst
> @@ -63,6 +63,9 @@ Get the specified 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_list_modules
> +
> Additional documentation
> ========================
>
> diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
> index 8637287bd39d..323ef5e2667d 100644
> --- a/include/linux/syscalls.h
> +++ b/include/linux/syscalls.h
> @@ -945,6 +945,7 @@ asmlinkage long sys_lsm_get_self_attr(unsigned int attr, struct lsm_ctx *ctx,
> size_t *size, __u32 flags);
> asmlinkage long sys_lsm_set_self_attr(unsigned int attr, struct lsm_ctx *ctx,
> size_t size, __u32 flags);
> +asmlinkage long sys_lsm_list_modules(u64 *ids, size_t *size, u32 flags);
>
> /*
> * Architecture-specific system calls
> diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
> index f81f2468c0ce..738ca470fcce 100644
> --- a/kernel/sys_ni.c
> +++ b/kernel/sys_ni.c
> @@ -172,6 +172,7 @@ COND_SYSCALL(fadvise64_64);
> COND_SYSCALL_COMPAT(fadvise64_64);
> COND_SYSCALL(lsm_get_self_attr);
> COND_SYSCALL(lsm_set_self_attr);
> +COND_SYSCALL(lsm_list_modules);
>
> /* CONFIG_MMU only */
> COND_SYSCALL(swapon);
> diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
> index 226ae80d9683..329aaca5efc0 100644
> --- a/security/lsm_syscalls.c
> +++ b/security/lsm_syscalls.c
> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
> {
> return security_getselfattr(attr, ctx, size, flags);
> }
> +
> +/**
> + * sys_lsm_list_modules - Return a list of the active security modules
> + * @ids: the LSM module ids
> + * @size: pointer to size of @ids, updated on return
> + * @flags: reserved for future use, must be zero
> + *
> + * Returns a list of the active LSM ids. On success this function
> + * returns the number of @ids array elements. This value may be zero
> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
> + u32, flags)
> +{
> + size_t total_size = lsm_active_cnt * sizeof(*ids);
> + size_t usize;
> + int i;
> +
> + if (flags)
> + return -EINVAL;
> +
> + if (get_user(usize, size))
> + return -EFAULT;
> +
> + if (put_user(total_size, size) != 0)
> + return -EFAULT;
> +
> + if (usize < total_size)
> + return -E2BIG;
> +
> + for (i = 0; i < lsm_active_cnt; i++)
> + if (put_user(lsm_idlist[i]->id, ids++))
> + return -EFAULT;
> +
> + return lsm_active_cnt;
> +}
> --
> 2.41.0
>

2023-10-03 14:28:28

by Mickaël Salaün

[permalink] [raw]
Subject: Re: [PATCH v15 08/11] Smack: implement setselfattr and getselfattr hooks

On Tue, Sep 12, 2023 at 01:56:53PM -0700, Casey Schaufler wrote:
> Implement Smack support for security_[gs]etselfattr.
> Refactor the setprocattr hook to avoid code duplication.
>
> Signed-off-by: Casey Schaufler <[email protected]>
> Reviewed-by: John Johansen <[email protected]>
> ---
> security/smack/smack_lsm.c | 95 ++++++++++++++++++++++++++++++++++++--
> 1 file changed, 90 insertions(+), 5 deletions(-)
>
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index f73f9a2834eb..12160d060cc1 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -3626,6 +3626,46 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
> return;
> }
>
> +/**
> + * smack_getselfattr - Smack current process attribute
> + * @attr: which attribute to fetch
> + * @ctx: buffer to receive the result
> + * @size: available size in, actual size out
> + * @flags: unused
> + *
> + * Fill the passed user space @ctx with the details of the requested
> + * attribute.
> + *
> + * Returns the number of attributes on success, an error code otherwise.
> + * There will only ever be one attribute.
> + */
> +static int smack_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
> + size_t *size, u32 flags)
> +{
> + struct smack_known *skp = smk_of_current();
> + int total;
> + int slen;
> + int rc;
> +
> + if (attr != LSM_ATTR_CURRENT)
> + return -EOPNOTSUPP;
> +
> + slen = strlen(skp->smk_known) + 1;


> + total = ALIGN(slen + sizeof(*ctx), 8);
> + if (total > *size)
> + rc = -E2BIG;
> + else if (ctx)
> + rc = lsm_fill_user_ctx(ctx, skp->smk_known, slen, LSM_ID_SMACK,
> + 0);
> + else
> + rc = 1;

Can we move these checks into lsm_fill_user_ctx()? They are similar for
AppArmor and SELinux.

> +
> + *size = total;
> + if (rc >= 0)
> + return 1;
> + return rc;
> +}

2023-10-03 14:28:29

by Mickaël Salaün

[permalink] [raw]
Subject: Re: [PATCH v15 07/11] LSM: Helpers for attribute names and filling lsm_ctx

On Tue, Sep 12, 2023 at 01:56:52PM -0700, Casey Schaufler wrote:
> Add lsm_name_to_attr(), which translates a text string to a
> LSM_ATTR value if one is available.
>
> Add lsm_fill_user_ctx(), which fills a struct lsm_ctx, including
> the trailing attribute value.
>
> Both are used in module specific components of LSM system calls.
>
> Signed-off-by: Casey Schaufler <[email protected]>
> Reviewed-by: John Johansen <[email protected]>
> Reviewed-by: Serge Hallyn <[email protected]>

Reviewed-by: Mickaël Salaün <[email protected]>

> ---
> include/linux/security.h | 14 ++++++++++++++
> security/lsm_syscalls.c | 24 +++++++++++++++++++++++
> security/security.c | 41 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 79 insertions(+)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 8831d7cf0a6b..e567f910a1c2 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -32,6 +32,7 @@
> #include <linux/string.h>
> #include <linux/mm.h>
> #include <linux/sockptr.h>
> +#include <uapi/linux/lsm.h>
>
> struct linux_binprm;
> struct cred;
> @@ -264,6 +265,7 @@ int unregister_blocking_lsm_notifier(struct notifier_block *nb);
> /* prototypes */
> extern int security_init(void);
> extern int early_security_init(void);
> +extern u64 lsm_name_to_attr(const char *name);
>
> /* Security operations */
> int security_binder_set_context_mgr(const struct cred *mgr);
> @@ -490,6 +492,8 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
> int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
> int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
> int security_locked_down(enum lockdown_reason what);
> +int lsm_fill_user_ctx(struct lsm_ctx __user *ctx, void *context,
> + size_t context_size, u64 id, u64 flags);
> #else /* CONFIG_SECURITY */
>
> static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data)
> @@ -507,6 +511,11 @@ static inline int unregister_blocking_lsm_notifier(struct notifier_block *nb)
> return 0;
> }
>
> +static inline u64 lsm_name_to_attr(const char *name)
> +{
> + return LSM_ATTR_UNDEF;
> +}
> +
> static inline void security_free_mnt_opts(void **mnt_opts)
> {
> }
> @@ -1415,6 +1424,11 @@ static inline int security_locked_down(enum lockdown_reason what)
> {
> return 0;
> }
> +static inline int lsm_fill_user_ctx(struct lsm_ctx __user *ctx, void *context,
> + size_t context_size, u64 id, u64 flags)
> +{
> + return -EOPNOTSUPP;
> +}
> #endif /* CONFIG_SECURITY */
>
> #if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)
> diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
> index 329aaca5efc0..5d391b1f7e69 100644
> --- a/security/lsm_syscalls.c
> +++ b/security/lsm_syscalls.c
> @@ -17,6 +17,30 @@
> #include <linux/lsm_hooks.h>
> #include <uapi/linux/lsm.h>
>
> +/**
> + * lsm_name_to_attr - map an LSM attribute name to its ID
> + * @name: name of the attribute
> + *
> + * Returns the LSM attribute value associated with @name, or 0 if
> + * there is no mapping.
> + */
> +u64 lsm_name_to_attr(const char *name)
> +{
> + if (!strcmp(name, "current"))
> + return LSM_ATTR_CURRENT;
> + if (!strcmp(name, "exec"))
> + return LSM_ATTR_EXEC;
> + if (!strcmp(name, "fscreate"))
> + return LSM_ATTR_FSCREATE;
> + if (!strcmp(name, "keycreate"))
> + return LSM_ATTR_KEYCREATE;
> + if (!strcmp(name, "prev"))
> + return LSM_ATTR_PREV;
> + if (!strcmp(name, "sockcreate"))
> + return LSM_ATTR_SOCKCREATE;
> + return LSM_ATTR_UNDEF;
> +}
> +
> /**
> * sys_lsm_set_self_attr - Set current task's security module attribute
> * @attr: which attribute to set
> diff --git a/security/security.c b/security/security.c
> index 0d179750d964..9136a4c3b0bc 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -771,6 +771,47 @@ static int lsm_superblock_alloc(struct super_block *sb)
> return 0;
> }
>
> +/**
> + * lsm_fill_user_ctx - Fill a user space lsm_ctx structure
> + * @ctx: an LSM context to be filled
> + * @context: the new context value
> + * @context_size: the size of the new context value
> + * @id: LSM id
> + * @flags: LSM defined flags
> + *
> + * Fill all of the fields in a user space lsm_ctx structure.
> + * Caller is assumed to have verified that @ctx has enough space
> + * for @context.
> + *
> + * Returns 0 on success, -EFAULT on a copyout error, -ENOMEM
> + * if memory can't be allocated.
> + */
> +int lsm_fill_user_ctx(struct lsm_ctx __user *ctx, void *context,
> + size_t context_size, u64 id, u64 flags)
> +{
> + struct lsm_ctx *lctx;
> + size_t locallen = struct_size(lctx, ctx, context_size);
> + int rc = 0;
> +
> + lctx = kzalloc(locallen, GFP_KERNEL);
> + if (lctx == NULL)
> + return -ENOMEM;
> +
> + lctx->id = id;
> + lctx->flags = flags;
> + lctx->ctx_len = context_size;
> + lctx->len = locallen;
> +
> + memcpy(lctx->ctx, context, context_size);
> +
> + if (copy_to_user(ctx, lctx, locallen))
> + rc = -EFAULT;
> +
> + kfree(lctx);
> +
> + return rc;
> +}
> +
> /*
> * The default value of the LSM hook is defined in linux/lsm_hook_defs.h and
> * can be accessed with:
> --
> 2.41.0
>

2023-10-03 14:28:58

by Mickaël Salaün

[permalink] [raw]
Subject: Re: [PATCH v15 11/11] LSM: selftests for Linux Security Module syscalls

On Tue, Sep 12, 2023 at 01:56:56PM -0700, Casey Schaufler wrote:
> Add selftests for the three system calls supporting the LSM
> infrastructure. This set of tests is limited by the differences
> in access policy enforced by the existing security modules.
>
> Signed-off-by: Casey Schaufler <[email protected]>

I'd like more corner case tests, but these are good. Thanks for writing
them!

Reviewed-by: Mickaël Salaün <[email protected]>
Tested-by: Mickaël Salaün <[email protected]>

> ---
> MAINTAINERS | 1 +
> tools/testing/selftests/Makefile | 1 +
> tools/testing/selftests/lsm/.gitignore | 1 +
> tools/testing/selftests/lsm/Makefile | 17 ++
> tools/testing/selftests/lsm/common.c | 89 ++++++
> tools/testing/selftests/lsm/common.h | 33 +++
> tools/testing/selftests/lsm/config | 3 +
> .../selftests/lsm/lsm_get_self_attr_test.c | 275 ++++++++++++++++++
> .../selftests/lsm/lsm_list_modules_test.c | 140 +++++++++
> .../selftests/lsm/lsm_set_self_attr_test.c | 74 +++++
> 10 files changed, 634 insertions(+)
> create mode 100644 tools/testing/selftests/lsm/.gitignore
> create mode 100644 tools/testing/selftests/lsm/Makefile
> create mode 100644 tools/testing/selftests/lsm/common.c
> create mode 100644 tools/testing/selftests/lsm/common.h
> create mode 100644 tools/testing/selftests/lsm/config
> create mode 100644 tools/testing/selftests/lsm/lsm_get_self_attr_test.c
> create mode 100644 tools/testing/selftests/lsm/lsm_list_modules_test.c
> create mode 100644 tools/testing/selftests/lsm/lsm_set_self_attr_test.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 935334123b04..377cc124e615 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19309,6 +19309,7 @@ W: http://kernsec.org/
> T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git
> F: include/uapi/linux/lsm.h
> F: security/
> +F: tools/testing/selftests/lsm/
> X: security/selinux/
>
> SELINUX SECURITY MODULE
> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
> index 42806add0114..fc589775ca4c 100644
> --- a/tools/testing/selftests/Makefile
> +++ b/tools/testing/selftests/Makefile
> @@ -42,6 +42,7 @@ TARGETS += landlock
> TARGETS += lib
> TARGETS += livepatch
> TARGETS += lkdtm
> +TARGETS += lsm
> TARGETS += membarrier
> TARGETS += memfd
> TARGETS += memory-hotplug
> diff --git a/tools/testing/selftests/lsm/.gitignore b/tools/testing/selftests/lsm/.gitignore
> new file mode 100644
> index 000000000000..bd68f6c3fd07
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/.gitignore
> @@ -0,0 +1 @@
> +/*_test
> diff --git a/tools/testing/selftests/lsm/Makefile b/tools/testing/selftests/lsm/Makefile
> new file mode 100644
> index 000000000000..3f80c0bc093d
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/Makefile
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# First run: make -C ../../../.. headers_install
> +
> +CFLAGS += -Wall -O2 $(KHDR_INCLUDES)
> +LOCAL_HDRS += common.h
> +
> +TEST_GEN_PROGS := lsm_get_self_attr_test lsm_list_modules_test \
> + lsm_set_self_attr_test
> +
> +include ../lib.mk
> +
> +$(OUTPUT)/lsm_get_self_attr_test: lsm_get_self_attr_test.c common.c
> +$(OUTPUT)/lsm_set_self_attr_test: lsm_set_self_attr_test.c common.c
> +$(OUTPUT)/lsm_list_modules_test: lsm_list_modules_test.c common.c
> +
> +EXTRA_CLEAN = $(OUTPUT)/common.o
> diff --git a/tools/testing/selftests/lsm/common.c b/tools/testing/selftests/lsm/common.c
> new file mode 100644
> index 000000000000..9ad258912646
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/common.c
> @@ -0,0 +1,89 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Linux Security Module infrastructure tests
> + *
> + * Copyright © 2023 Casey Schaufler <[email protected]>
> + */
> +
> +#define _GNU_SOURCE
> +#include <linux/lsm.h>
> +#include <fcntl.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include "common.h"
> +
> +#define PROCATTR "/proc/self/attr/"
> +
> +int read_proc_attr(const char *attr, char *value, size_t size)
> +{
> + int fd;
> + int len;
> + char *path;
> +
> + len = strlen(PROCATTR) + strlen(attr) + 1;
> + path = calloc(len, 1);
> + if (path == NULL)
> + return -1;
> + sprintf(path, "%s%s", PROCATTR, attr);
> +
> + fd = open(path, O_RDONLY);
> + free(path);
> +
> + if (fd < 0)
> + return -1;
> + len = read(fd, value, size);
> +
> + close(fd);
> +
> + /* Ensure value is terminated */
> + if (len <= 0 || len == size)
> + return -1;
> + value[len] = '\0';
> +
> + path = strchr(value, '\n');
> + if (path)
> + *path = '\0';
> +
> + return 0;
> +}
> +
> +int read_sysfs_lsms(char *lsms, size_t size)
> +{
> + FILE *fp;
> + size_t red;
> +
> + fp = fopen("/sys/kernel/security/lsm", "r");
> + if (fp == NULL)
> + return -1;
> + red = fread(lsms, 1, size, fp);
> + fclose(fp);
> +
> + if (red <= 0 || red == size)
> + return -1;
> + lsms[red] = '\0';
> + return 0;
> +}
> +
> +int attr_lsm_count(void)
> +{
> + char *names = calloc(sysconf(_SC_PAGESIZE), 1);
> + int count = 0;
> +
> + if (!names)
> + return 0;
> +
> + if (read_sysfs_lsms(names, sysconf(_SC_PAGESIZE)))
> + return 0;
> +
> + if (strstr(names, "selinux"))
> + count++;
> + if (strstr(names, "smack"))
> + count++;
> + if (strstr(names, "apparmor"))
> + count++;
> +
> + return count;
> +}
> diff --git a/tools/testing/selftests/lsm/common.h b/tools/testing/selftests/lsm/common.h
> new file mode 100644
> index 000000000000..d404329e5eeb
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/common.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Linux Security Module infrastructure tests
> + *
> + * Copyright © 2023 Casey Schaufler <[email protected]>
> + */
> +
> +#ifndef lsm_get_self_attr
> +static inline int lsm_get_self_attr(unsigned int attr, struct lsm_ctx *ctx,
> + size_t *size, __u32 flags)
> +{
> + return syscall(__NR_lsm_get_self_attr, attr, ctx, size, flags);
> +}
> +#endif
> +
> +#ifndef lsm_set_self_attr
> +static inline int lsm_set_self_attr(unsigned int attr, struct lsm_ctx *ctx,
> + size_t size, __u32 flags)
> +{
> + return syscall(__NR_lsm_set_self_attr, attr, ctx, size, flags);
> +}
> +#endif
> +
> +#ifndef lsm_list_modules
> +static inline int lsm_list_modules(__u64 *ids, size_t *size, __u32 flags)
> +{
> + return syscall(__NR_lsm_list_modules, ids, size, flags);
> +}
> +#endif
> +
> +extern int read_proc_attr(const char *attr, char *value, size_t size);
> +extern int read_sysfs_lsms(char *lsms, size_t size);
> +int attr_lsm_count(void);
> diff --git a/tools/testing/selftests/lsm/config b/tools/testing/selftests/lsm/config
> new file mode 100644
> index 000000000000..1c0c4c020f9c
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/config
> @@ -0,0 +1,3 @@
> +CONFIG_SYSFS=y
> +CONFIG_SECURITY=y
> +CONFIG_SECURITYFS=y
> diff --git a/tools/testing/selftests/lsm/lsm_get_self_attr_test.c b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c
> new file mode 100644
> index 000000000000..e0e313d9047a
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c
> @@ -0,0 +1,275 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Linux Security Module infrastructure tests
> + * Tests for the lsm_get_self_attr system call
> + *
> + * Copyright © 2022 Casey Schaufler <[email protected]>
> + */
> +
> +#define _GNU_SOURCE
> +#include <linux/lsm.h>
> +#include <fcntl.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include "../kselftest_harness.h"
> +#include "common.h"
> +
> +static struct lsm_ctx *next_ctx(struct lsm_ctx *ctxp)
> +{
> + void *vp;
> +
> + vp = (void *)ctxp + sizeof(*ctxp) + ctxp->ctx_len;
> + return (struct lsm_ctx *)vp;
> +}
> +
> +TEST(size_null_lsm_get_self_attr)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + struct lsm_ctx *ctx = calloc(page_size, 1);
> +
> + ASSERT_NE(NULL, ctx);
> + errno = 0;
> + ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, NULL, 0));
> + ASSERT_EQ(EINVAL, errno);
> +
> + free(ctx);
> +}
> +
> +TEST(ctx_null_lsm_get_self_attr)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + size_t size = page_size;
> + int rc;
> +
> + rc = lsm_get_self_attr(LSM_ATTR_CURRENT, NULL, &size, 0);
> +
> + if (attr_lsm_count()) {
> + ASSERT_NE(-1, rc);
> + ASSERT_NE(1, size);
> + } else {
> + ASSERT_EQ(-1, rc);
> + }
> +}
> +
> +TEST(size_too_small_lsm_get_self_attr)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + struct lsm_ctx *ctx = calloc(page_size, 1);
> + size_t size = 1;
> +
> + ASSERT_NE(NULL, ctx);
> + errno = 0;
> + ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, 0));
> + if (attr_lsm_count()) {
> + ASSERT_EQ(E2BIG, errno);
> + } else {
> + ASSERT_EQ(EOPNOTSUPP, errno);
> + }
> + ASSERT_NE(1, size);
> +
> + free(ctx);
> +}
> +
> +TEST(flags_zero_lsm_get_self_attr)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + struct lsm_ctx *ctx = calloc(page_size, 1);
> + __u64 *syscall_lsms = calloc(page_size, 1);
> + size_t size;
> + int lsmcount;
> + int i;
> +
> + ASSERT_NE(NULL, ctx);
> + errno = 0;
> + size = page_size;
> + ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size,
> + LSM_FLAG_SINGLE));
> + ASSERT_EQ(EINVAL, errno);
> + ASSERT_EQ(page_size, size);
> +
> + lsmcount = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0);
> + ASSERT_LE(1, lsmcount);
> + ASSERT_NE(NULL, syscall_lsms);
> +
> + for (i = 0; i < lsmcount; i++) {
> + errno = 0;
> + size = page_size;
> + ctx->id = syscall_lsms[i];
> +
> + if (syscall_lsms[i] == LSM_ID_SELINUX ||
> + syscall_lsms[i] == LSM_ID_SMACK ||
> + syscall_lsms[i] == LSM_ID_APPARMOR) {
> + ASSERT_EQ(1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx,
> + &size, LSM_FLAG_SINGLE));
> + } else {
> + ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx,
> + &size,
> + LSM_FLAG_SINGLE));
> + }
> + }
> +
> + free(ctx);
> +}
> +
> +TEST(flags_overset_lsm_get_self_attr)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + struct lsm_ctx *ctx = calloc(page_size, 1);
> + size_t size;
> +
> + ASSERT_NE(NULL, ctx);
> +
> + errno = 0;
> + size = page_size;
> + ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx,
> + &size, 0));
> + ASSERT_EQ(EOPNOTSUPP, errno);
> +
> + errno = 0;
> + size = page_size;
> + ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size,
> + LSM_FLAG_SINGLE |
> + (LSM_FLAG_SINGLE << 1)));
> + ASSERT_EQ(EINVAL, errno);
> +
> + free(ctx);
> +}
> +
> +TEST(basic_lsm_get_self_attr)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + size_t size = page_size;
> + struct lsm_ctx *ctx = calloc(page_size, 1);
> + struct lsm_ctx *tctx = NULL;
> + __u64 *syscall_lsms = calloc(page_size, 1);
> + char *attr = calloc(page_size, 1);
> + int cnt_current = 0;
> + int cnt_exec = 0;
> + int cnt_fscreate = 0;
> + int cnt_keycreate = 0;
> + int cnt_prev = 0;
> + int cnt_sockcreate = 0;
> + int lsmcount;
> + int count;
> + int i;
> +
> + ASSERT_NE(NULL, ctx);
> + ASSERT_NE(NULL, syscall_lsms);
> +
> + lsmcount = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0);
> + ASSERT_LE(1, lsmcount);
> +
> + for (i = 0; i < lsmcount; i++) {
> + switch (syscall_lsms[i]) {
> + case LSM_ID_SELINUX:
> + cnt_current++;
> + cnt_exec++;
> + cnt_fscreate++;
> + cnt_keycreate++;
> + cnt_prev++;
> + cnt_sockcreate++;
> + break;
> + case LSM_ID_SMACK:
> + cnt_current++;
> + break;
> + case LSM_ID_APPARMOR:
> + cnt_current++;
> + cnt_exec++;
> + cnt_prev++;
> + break;
> + default:
> + break;
> + }
> + }
> +
> + if (cnt_current) {
> + size = page_size;
> + count = lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, 0);
> + ASSERT_EQ(cnt_current, count);
> + tctx = ctx;
> + ASSERT_EQ(0, read_proc_attr("current", attr, page_size));
> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
> + for (i = 1; i < count; i++) {
> + tctx = next_ctx(tctx);
> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
> + }
> + }
> + if (cnt_exec) {
> + size = page_size;
> + count = lsm_get_self_attr(LSM_ATTR_EXEC, ctx, &size, 0);
> + ASSERT_GE(cnt_exec, count);
> + if (count > 0) {
> + tctx = ctx;
> + if (read_proc_attr("exec", attr, page_size) == 0)
> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
> + }
> + for (i = 1; i < count; i++) {
> + tctx = next_ctx(tctx);
> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
> + }
> + }
> + if (cnt_fscreate) {
> + size = page_size;
> + count = lsm_get_self_attr(LSM_ATTR_FSCREATE, ctx, &size, 0);
> + ASSERT_GE(cnt_fscreate, count);
> + if (count > 0) {
> + tctx = ctx;
> + if (read_proc_attr("fscreate", attr, page_size) == 0)
> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
> + }
> + for (i = 1; i < count; i++) {
> + tctx = next_ctx(tctx);
> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
> + }
> + }
> + if (cnt_keycreate) {
> + size = page_size;
> + count = lsm_get_self_attr(LSM_ATTR_KEYCREATE, ctx, &size, 0);
> + ASSERT_GE(cnt_keycreate, count);
> + if (count > 0) {
> + tctx = ctx;
> + if (read_proc_attr("keycreate", attr, page_size) == 0)
> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
> + }
> + for (i = 1; i < count; i++) {
> + tctx = next_ctx(tctx);
> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
> + }
> + }
> + if (cnt_prev) {
> + size = page_size;
> + count = lsm_get_self_attr(LSM_ATTR_PREV, ctx, &size, 0);
> + ASSERT_GE(cnt_prev, count);
> + if (count > 0) {
> + tctx = ctx;
> + ASSERT_EQ(0, read_proc_attr("prev", attr, page_size));
> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
> + for (i = 1; i < count; i++) {
> + tctx = next_ctx(tctx);
> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
> + }
> + }
> + }
> + if (cnt_sockcreate) {
> + size = page_size;
> + count = lsm_get_self_attr(LSM_ATTR_SOCKCREATE, ctx, &size, 0);
> + ASSERT_GE(cnt_sockcreate, count);
> + if (count > 0) {
> + tctx = ctx;
> + if (read_proc_attr("sockcreate", attr, page_size) == 0)
> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
> + }
> + for (i = 1; i < count; i++) {
> + tctx = next_ctx(tctx);
> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
> + }
> + }
> +
> + free(ctx);
> + free(attr);
> + free(syscall_lsms);
> +}
> +
> +TEST_HARNESS_MAIN
> diff --git a/tools/testing/selftests/lsm/lsm_list_modules_test.c b/tools/testing/selftests/lsm/lsm_list_modules_test.c
> new file mode 100644
> index 000000000000..445c02f09c74
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/lsm_list_modules_test.c
> @@ -0,0 +1,140 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Linux Security Module infrastructure tests
> + * Tests for the lsm_list_modules system call
> + *
> + * Copyright © 2022 Casey Schaufler <[email protected]>
> + */
> +
> +#define _GNU_SOURCE
> +#include <linux/lsm.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include "../kselftest_harness.h"
> +#include "common.h"
> +
> +TEST(size_null_lsm_list_modules)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + __u64 *syscall_lsms = calloc(page_size, 1);
> +
> + ASSERT_NE(NULL, syscall_lsms);
> + errno = 0;
> + ASSERT_EQ(-1, lsm_list_modules(syscall_lsms, NULL, 0));
> + ASSERT_EQ(EFAULT, errno);
> +
> + free(syscall_lsms);
> +}
> +
> +TEST(ids_null_lsm_list_modules)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + size_t size = page_size;
> +
> + errno = 0;
> + ASSERT_EQ(-1, lsm_list_modules(NULL, &size, 0));
> + ASSERT_EQ(EFAULT, errno);
> + ASSERT_NE(1, size);
> +}
> +
> +TEST(size_too_small_lsm_list_modules)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + __u64 *syscall_lsms = calloc(page_size, 1);
> + size_t size = 1;
> +
> + ASSERT_NE(NULL, syscall_lsms);
> + errno = 0;
> + ASSERT_EQ(-1, lsm_list_modules(syscall_lsms, &size, 0));
> + ASSERT_EQ(E2BIG, errno);
> + ASSERT_NE(1, size);
> +
> + free(syscall_lsms);
> +}
> +
> +TEST(flags_set_lsm_list_modules)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + __u64 *syscall_lsms = calloc(page_size, 1);
> + size_t size = page_size;
> +
> + ASSERT_NE(NULL, syscall_lsms);
> + errno = 0;
> + ASSERT_EQ(-1, lsm_list_modules(syscall_lsms, &size, 7));
> + ASSERT_EQ(EINVAL, errno);
> + ASSERT_EQ(page_size, size);
> +
> + free(syscall_lsms);
> +}
> +
> +TEST(correct_lsm_list_modules)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + size_t size = page_size;
> + __u64 *syscall_lsms = calloc(page_size, 1);
> + char *sysfs_lsms = calloc(page_size, 1);
> + char *name;
> + char *cp;
> + int count;
> + int i;
> +
> + ASSERT_NE(NULL, sysfs_lsms);
> + ASSERT_NE(NULL, syscall_lsms);
> + ASSERT_EQ(0, read_sysfs_lsms(sysfs_lsms, page_size));
> +
> + count = lsm_list_modules(syscall_lsms, &size, 0);
> + ASSERT_LE(1, count);
> + cp = sysfs_lsms;
> + for (i = 0; i < count; i++) {
> + switch (syscall_lsms[i]) {
> + case LSM_ID_CAPABILITY:
> + name = "capability";
> + break;
> + case LSM_ID_SELINUX:
> + name = "selinux";
> + break;
> + case LSM_ID_SMACK:
> + name = "smack";
> + break;
> + case LSM_ID_TOMOYO:
> + name = "tomoyo";
> + break;
> + case LSM_ID_IMA:
> + name = "ima";
> + break;
> + case LSM_ID_APPARMOR:
> + name = "apparmor";
> + break;
> + case LSM_ID_YAMA:
> + name = "yama";
> + break;
> + case LSM_ID_LOADPIN:
> + name = "loadpin";
> + break;
> + case LSM_ID_SAFESETID:
> + name = "safesetid";
> + break;
> + case LSM_ID_LOCKDOWN:
> + name = "lockdown";
> + break;
> + case LSM_ID_BPF:
> + name = "bpf";
> + break;
> + case LSM_ID_LANDLOCK:
> + name = "landlock";
> + break;
> + default:
> + name = "INVALID";
> + break;
> + }
> + ASSERT_EQ(0, strncmp(cp, name, strlen(name)));
> + cp += strlen(name) + 1;
> + }
> +
> + free(sysfs_lsms);
> + free(syscall_lsms);
> +}
> +
> +TEST_HARNESS_MAIN
> diff --git a/tools/testing/selftests/lsm/lsm_set_self_attr_test.c b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c
> new file mode 100644
> index 000000000000..e9712c6cf596
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c
> @@ -0,0 +1,74 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Linux Security Module infrastructure tests
> + * Tests for the lsm_set_self_attr system call
> + *
> + * Copyright © 2022 Casey Schaufler <[email protected]>
> + */
> +
> +#define _GNU_SOURCE
> +#include <linux/lsm.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include "../kselftest_harness.h"
> +#include "common.h"
> +
> +TEST(ctx_null_lsm_set_self_attr)
> +{
> + ASSERT_EQ(-1, lsm_set_self_attr(LSM_ATTR_CURRENT, NULL,
> + sizeof(struct lsm_ctx), 0));
> +}
> +
> +TEST(size_too_small_lsm_set_self_attr)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + struct lsm_ctx *ctx = calloc(page_size, 1);
> + size_t size = page_size;
> +
> + ASSERT_NE(NULL, ctx);
> + if (attr_lsm_count()) {
> + ASSERT_LE(1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size,
> + 0));
> + }
> + ASSERT_EQ(-1, lsm_set_self_attr(LSM_ATTR_CURRENT, ctx, 1, 0));
> +
> + free(ctx);
> +}
> +
> +TEST(flags_zero_lsm_set_self_attr)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + struct lsm_ctx *ctx = calloc(page_size, 1);
> + size_t size = page_size;
> +
> + ASSERT_NE(NULL, ctx);
> + if (attr_lsm_count()) {
> + ASSERT_LE(1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size,
> + 0));
> + }
> + ASSERT_EQ(-1, lsm_set_self_attr(LSM_ATTR_CURRENT, ctx, size, 1));
> +
> + free(ctx);
> +}
> +
> +TEST(flags_overset_lsm_set_self_attr)
> +{
> + const long page_size = sysconf(_SC_PAGESIZE);
> + char *ctx = calloc(page_size, 1);
> + size_t size = page_size;
> + struct lsm_ctx *tctx = (struct lsm_ctx *)ctx;
> +
> + ASSERT_NE(NULL, ctx);
> + if (attr_lsm_count()) {
> + ASSERT_LE(1, lsm_get_self_attr(LSM_ATTR_CURRENT, tctx, &size,
> + 0));
> + }
> + ASSERT_EQ(-1, lsm_set_self_attr(LSM_ATTR_CURRENT | LSM_ATTR_PREV, tctx,
> + size, 0));
> +
> + free(ctx);
> +}
> +
> +TEST_HARNESS_MAIN
> --
> 2.41.0
>

2023-10-05 15:13:27

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 2023/09/13 5:56, Casey Schaufler wrote:
> Create a struct lsm_id to contain identifying information about Linux
> Security Modules (LSMs). At inception this contains the name of the
> module and an identifier associated with the security module. Change
> the security_add_hooks() interface to use this structure. Change the
> individual modules to maintain their own struct lsm_id and pass it to
> security_add_hooks().

I came to worry about what purpose does the LSM ID value (or more precisely,
"struct lsm_id") is used for. If the LSM ID value is used for only switch
{reading,writing} /proc/self/attr/ of specific LSM module's information, only
LSM modules that use /proc/self/attr/ will need the LSM ID value.

But this series uses "struct lsm_id" as one of arguments for security_add_hooks(),
and might be reused for different purposes.

Then, BPF-based LSMs (which are not considered as in-tree LSM modules, for
only BPF hook is considered as in-tree LSM module) might receive unfavorable
treatment than non BPF-based LSMs?

[PATCH v15 05/11] says

Create a system call to report the list of Linux Security Modules
that are active on the system. The list is provided as an array
of LSM ID numbers.

The calling application can use this list determine what LSM
specific actions it might take. That might include choosing an
output format, determining required privilege or bypassing
security module specific behavior.

but, at least, name of BPF-based LSMs won't be shown up in lsm_list_modules()
compared to non BPF-based LSMs? Then, the calling application can't use this
list determine what BPF-based LSM specific actions it might take?

2023-10-06 01:05:04

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 04/11] LSM: syscalls for current process attributes

On Tue, Oct 3, 2023 at 10:09 AM Mickaël Salaün <[email protected]> wrote:
> On Tue, Sep 12, 2023 at 01:56:49PM -0700, Casey Schaufler wrote:
> > Create a system call lsm_get_self_attr() to provide the security
> > module maintained attributes of the current process.
> > 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
> > identifies the size of the attribute, and the attribute value. The format
> > of the attribute value is defined by the security module. A flags field
> > is included for LSM specific information. It is currently unused and must
> > be 0. The total size of the data, including the lsm_ctx structure and any
> > padding, is maintained as well.
> >
> > struct lsm_ctx {
> > __u64 id;
> > __u64 flags;
> > __u64 len;
> > __u64 ctx_len;
> > __u8 ctx[];
> > };
> >
> > Two new LSM hooks are used to interface with the LSMs.
> > security_getselfattr() collects the lsm_ctx values from the
> > LSMs that support the hook, accounting for space requirements.
> > security_setselfattr() identifies which LSM the attribute is
> > intended for and passes it along.
> >
> > Signed-off-by: Casey Schaufler <[email protected]>
> > Reviewed-by: Kees Cook <[email protected]>
> > Reviewed-by: Serge Hallyn <[email protected]>
> > Reviewed-by: John Johansen <[email protected]>
> > ---
> > Documentation/userspace-api/lsm.rst | 70 +++++++++++++
> > include/linux/lsm_hook_defs.h | 4 +
> > include/linux/lsm_hooks.h | 1 +
> > include/linux/security.h | 19 ++++
> > include/linux/syscalls.h | 5 +
> > include/uapi/linux/lsm.h | 36 +++++++
> > kernel/sys_ni.c | 2 +
> > security/Makefile | 1 +
> > security/lsm_syscalls.c | 57 +++++++++++
> > security/security.c | 152 ++++++++++++++++++++++++++++
> > 10 files changed, 347 insertions(+)
> > create mode 100644 Documentation/userspace-api/lsm.rst
> > create mode 100644 security/lsm_syscalls.c

...

> > diff --git a/security/security.c b/security/security.c
> > index a3489c04b783..0d179750d964 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -3837,6 +3837,158 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
> > }
> > EXPORT_SYMBOL(security_d_instantiate);
> >
> > +/*
> > + * Please keep this in sync with it's counterpart in security/lsm_syscalls.c
> > + */
> > +
> > +/**
> > + * security_getselfattr - Read an LSM attribute of the current process.
> > + * @attr: which attribute to return
> > + * @uctx: the user-space destination for the information, or NULL
> > + * @size: pointer to the size of space available to receive the data
> > + * @flags: special handling options. LSM_FLAG_SINGLE indicates that only
> > + * attributes associated with the LSM identified in the passed @ctx be
> > + * reported.
> > + *
> > + * A NULL value for @uctx can be used to get both the number of attributes
> > + * and the size of the data.
> > + *
> > + * Returns the number of attributes found on success, negative value
> > + * on error. @size is reset to the total size of the data.
> > + * If @size is insufficient to contain the data -E2BIG is returned.
> > + */
> > +int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
> > + size_t __user *size, u32 flags)
> > +{
> > + struct security_hook_list *hp;
> > + struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
> > + u8 __user *base = (u8 __user *)uctx;
> > + size_t total = 0;
> > + size_t entrysize;
> > + size_t left;
> > + bool toobig = false;
> > + bool single = false;
> > + int count = 0;
> > + int rc;
> > +
> > + if (attr == LSM_ATTR_UNDEF)
> > + return -EINVAL;
> > + if (size == NULL)
> > + return -EINVAL;
> > + if (get_user(left, size))
> > + return -EFAULT;
> > +
> > + if (flags) {
> > + /*
> > + * Only flag supported is LSM_FLAG_SINGLE
> > + */
> > + if (flags != LSM_FLAG_SINGLE)
> > + return -EINVAL;
> > + if (uctx && copy_from_user(&lctx, uctx, sizeof(lctx)))
>
> I'm not sure if we should return -EINVAL or -EFAULT when uctx == NULL.
> Because uctx is optional (when LSM_FLAG_SINGLE is not set), I guess
> -EINVAL is OK.

That's a good point, we should probably the error codes here: if uctx
is NULL in the LSM_FLAG_SINGLE case we should return -EINVAL, if the
copy_from_user() fails we should return -EFAULT.

> > + return -EFAULT;
> > + /*
> > + * If the LSM ID isn't specified it is an error.
> > + */
> > + if (lctx.id == LSM_ID_UNDEF)
> > + return -EINVAL;
> > + single = true;
> > + }
> > +
> > + /*
> > + * In the usual case gather all the data from the LSMs.
> > + * In the single case only get the data from the LSM specified.
> > + */
> > + hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
> > + if (single && lctx.id != hp->lsmid->id)
> > + continue;
> > + entrysize = left;
> > + if (base)
> > + uctx = (struct lsm_ctx __user *)(base + total);
> > + rc = hp->hook.getselfattr(attr, uctx, &entrysize, flags);
> > + if (rc == -EOPNOTSUPP) {
> > + rc = 0;
> > + continue;
> > + }
> > + if (rc == -E2BIG) {
> > + toobig = true;
> > + left = 0;
> > + } else if (rc < 0)
> > + return rc;
> > + else
> > + left -= entrysize;
> > +
> > + total += entrysize;
> > + count += rc;
>
> There is a bug if rc == -E2BIG

Can you elaborate a bit more on this? Nothing is jumping out at me as
obviously broken... are you talking about @count becoming garbage due
to @rc being equal to -E2BIG? If that is the case it should be okay
since we explicitly return -E2BIG, not @count, if @toobig is true.

> > + if (single)
> > + break;
> > + }
> > + if (put_user(total, size))
> > + return -EFAULT;
> > + if (toobig)
> > + return -E2BIG;
> > + if (count == 0)
> > + return LSM_RET_DEFAULT(getselfattr);
> > + return count;
> > +}

--
paul-moore.com

2023-10-09 15:39:09

by Mickaël Salaün

[permalink] [raw]
Subject: Re: [PATCH v15 04/11] LSM: syscalls for current process attributes

On Thu, Oct 05, 2023 at 09:04:34PM -0400, Paul Moore wrote:
> On Tue, Oct 3, 2023 at 10:09 AM Mickaël Salaün <[email protected]> wrote:
> > On Tue, Sep 12, 2023 at 01:56:49PM -0700, Casey Schaufler wrote:
> > > Create a system call lsm_get_self_attr() to provide the security
> > > module maintained attributes of the current process.
> > > 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
> > > identifies the size of the attribute, and the attribute value. The format
> > > of the attribute value is defined by the security module. A flags field
> > > is included for LSM specific information. It is currently unused and must
> > > be 0. The total size of the data, including the lsm_ctx structure and any
> > > padding, is maintained as well.
> > >
> > > struct lsm_ctx {
> > > __u64 id;
> > > __u64 flags;
> > > __u64 len;
> > > __u64 ctx_len;
> > > __u8 ctx[];
> > > };
> > >
> > > Two new LSM hooks are used to interface with the LSMs.
> > > security_getselfattr() collects the lsm_ctx values from the
> > > LSMs that support the hook, accounting for space requirements.
> > > security_setselfattr() identifies which LSM the attribute is
> > > intended for and passes it along.
> > >
> > > Signed-off-by: Casey Schaufler <[email protected]>
> > > Reviewed-by: Kees Cook <[email protected]>
> > > Reviewed-by: Serge Hallyn <[email protected]>
> > > Reviewed-by: John Johansen <[email protected]>
> > > ---
> > > Documentation/userspace-api/lsm.rst | 70 +++++++++++++
> > > include/linux/lsm_hook_defs.h | 4 +
> > > include/linux/lsm_hooks.h | 1 +
> > > include/linux/security.h | 19 ++++
> > > include/linux/syscalls.h | 5 +
> > > include/uapi/linux/lsm.h | 36 +++++++
> > > kernel/sys_ni.c | 2 +
> > > security/Makefile | 1 +
> > > security/lsm_syscalls.c | 57 +++++++++++
> > > security/security.c | 152 ++++++++++++++++++++++++++++
> > > 10 files changed, 347 insertions(+)
> > > create mode 100644 Documentation/userspace-api/lsm.rst
> > > create mode 100644 security/lsm_syscalls.c
>
> ...
>
> > > diff --git a/security/security.c b/security/security.c
> > > index a3489c04b783..0d179750d964 100644
> > > --- a/security/security.c
> > > +++ b/security/security.c
> > > @@ -3837,6 +3837,158 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
> > > }
> > > EXPORT_SYMBOL(security_d_instantiate);
> > >
> > > +/*
> > > + * Please keep this in sync with it's counterpart in security/lsm_syscalls.c
> > > + */
> > > +
> > > +/**
> > > + * security_getselfattr - Read an LSM attribute of the current process.
> > > + * @attr: which attribute to return
> > > + * @uctx: the user-space destination for the information, or NULL
> > > + * @size: pointer to the size of space available to receive the data
> > > + * @flags: special handling options. LSM_FLAG_SINGLE indicates that only
> > > + * attributes associated with the LSM identified in the passed @ctx be
> > > + * reported.
> > > + *
> > > + * A NULL value for @uctx can be used to get both the number of attributes
> > > + * and the size of the data.
> > > + *
> > > + * Returns the number of attributes found on success, negative value
> > > + * on error. @size is reset to the total size of the data.
> > > + * If @size is insufficient to contain the data -E2BIG is returned.
> > > + */
> > > +int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
> > > + size_t __user *size, u32 flags)
> > > +{
> > > + struct security_hook_list *hp;
> > > + struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
> > > + u8 __user *base = (u8 __user *)uctx;
> > > + size_t total = 0;
> > > + size_t entrysize;
> > > + size_t left;
> > > + bool toobig = false;
> > > + bool single = false;
> > > + int count = 0;
> > > + int rc;
> > > +
> > > + if (attr == LSM_ATTR_UNDEF)
> > > + return -EINVAL;
> > > + if (size == NULL)
> > > + return -EINVAL;
> > > + if (get_user(left, size))
> > > + return -EFAULT;
> > > +
> > > + if (flags) {
> > > + /*
> > > + * Only flag supported is LSM_FLAG_SINGLE
> > > + */
> > > + if (flags != LSM_FLAG_SINGLE)
> > > + return -EINVAL;
> > > + if (uctx && copy_from_user(&lctx, uctx, sizeof(lctx)))
> >
> > I'm not sure if we should return -EINVAL or -EFAULT when uctx == NULL.
> > Because uctx is optional (when LSM_FLAG_SINGLE is not set), I guess
> > -EINVAL is OK.
>
> That's a good point, we should probably the error codes here: if uctx
> is NULL in the LSM_FLAG_SINGLE case we should return -EINVAL, if the
> copy_from_user() fails we should return -EFAULT.
>
> > > + return -EFAULT;
> > > + /*
> > > + * If the LSM ID isn't specified it is an error.
> > > + */
> > > + if (lctx.id == LSM_ID_UNDEF)
> > > + return -EINVAL;
> > > + single = true;
> > > + }
> > > +
> > > + /*
> > > + * In the usual case gather all the data from the LSMs.
> > > + * In the single case only get the data from the LSM specified.
> > > + */
> > > + hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
> > > + if (single && lctx.id != hp->lsmid->id)
> > > + continue;
> > > + entrysize = left;
> > > + if (base)
> > > + uctx = (struct lsm_ctx __user *)(base + total);
> > > + rc = hp->hook.getselfattr(attr, uctx, &entrysize, flags);
> > > + if (rc == -EOPNOTSUPP) {
> > > + rc = 0;
> > > + continue;
> > > + }
> > > + if (rc == -E2BIG) {
> > > + toobig = true;
> > > + left = 0;
> > > + } else if (rc < 0)
> > > + return rc;
> > > + else
> > > + left -= entrysize;
> > > +
> > > + total += entrysize;
> > > + count += rc;
> >
> > There is a bug if rc == -E2BIG
>
> Can you elaborate a bit more on this? Nothing is jumping out at me as
> obviously broken... are you talking about @count becoming garbage due
> to @rc being equal to -E2BIG? If that is the case it should be okay
> since we explicitly return -E2BIG, not @count, if @toobig is true.

Indeed, in this case count will not be returned thanks to toobig. I'd
suggest to "continue" if rc == -E2BIG (like for -EOPNOTSUPP) to avoid an
inconsistent count value, which could bite us one day.

>
> > > + if (single)
> > > + break;
> > > + }
> > > + if (put_user(total, size))
> > > + return -EFAULT;
> > > + if (toobig)
> > > + return -E2BIG;
> > > + if (count == 0)
> > > + return LSM_RET_DEFAULT(getselfattr);
> > > + return count;
> > > +}
>
> --
> paul-moore.com

2023-10-09 16:05:11

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 04/11] LSM: syscalls for current process attributes

On Mon, Oct 9, 2023 at 11:37 AM Mickaël Salaün <[email protected]> wrote:
> On Thu, Oct 05, 2023 at 09:04:34PM -0400, Paul Moore wrote:
> > On Tue, Oct 3, 2023 at 10:09 AM Mickaël Salaün <[email protected]> wrote:
> > > On Tue, Sep 12, 2023 at 01:56:49PM -0700, Casey Schaufler wrote:
> > > > Create a system call lsm_get_self_attr() to provide the security
> > > > module maintained attributes of the current process.
> > > > 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
> > > > identifies the size of the attribute, and the attribute value. The format
> > > > of the attribute value is defined by the security module. A flags field
> > > > is included for LSM specific information. It is currently unused and must
> > > > be 0. The total size of the data, including the lsm_ctx structure and any
> > > > padding, is maintained as well.
> > > >
> > > > struct lsm_ctx {
> > > > __u64 id;
> > > > __u64 flags;
> > > > __u64 len;
> > > > __u64 ctx_len;
> > > > __u8 ctx[];
> > > > };
> > > >
> > > > Two new LSM hooks are used to interface with the LSMs.
> > > > security_getselfattr() collects the lsm_ctx values from the
> > > > LSMs that support the hook, accounting for space requirements.
> > > > security_setselfattr() identifies which LSM the attribute is
> > > > intended for and passes it along.
> > > >
> > > > Signed-off-by: Casey Schaufler <[email protected]>
> > > > Reviewed-by: Kees Cook <[email protected]>
> > > > Reviewed-by: Serge Hallyn <[email protected]>
> > > > Reviewed-by: John Johansen <[email protected]>
> > > > ---
> > > > Documentation/userspace-api/lsm.rst | 70 +++++++++++++
> > > > include/linux/lsm_hook_defs.h | 4 +
> > > > include/linux/lsm_hooks.h | 1 +
> > > > include/linux/security.h | 19 ++++
> > > > include/linux/syscalls.h | 5 +
> > > > include/uapi/linux/lsm.h | 36 +++++++
> > > > kernel/sys_ni.c | 2 +
> > > > security/Makefile | 1 +
> > > > security/lsm_syscalls.c | 57 +++++++++++
> > > > security/security.c | 152 ++++++++++++++++++++++++++++
> > > > 10 files changed, 347 insertions(+)
> > > > create mode 100644 Documentation/userspace-api/lsm.rst
> > > > create mode 100644 security/lsm_syscalls.c
> >
> > ...
> >
> > > > diff --git a/security/security.c b/security/security.c
> > > > index a3489c04b783..0d179750d964 100644
> > > > --- a/security/security.c
> > > > +++ b/security/security.c
> > > > @@ -3837,6 +3837,158 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
> > > > }
> > > > EXPORT_SYMBOL(security_d_instantiate);
> > > >
> > > > +/*
> > > > + * Please keep this in sync with it's counterpart in security/lsm_syscalls.c
> > > > + */
> > > > +
> > > > +/**
> > > > + * security_getselfattr - Read an LSM attribute of the current process.
> > > > + * @attr: which attribute to return
> > > > + * @uctx: the user-space destination for the information, or NULL
> > > > + * @size: pointer to the size of space available to receive the data
> > > > + * @flags: special handling options. LSM_FLAG_SINGLE indicates that only
> > > > + * attributes associated with the LSM identified in the passed @ctx be
> > > > + * reported.
> > > > + *
> > > > + * A NULL value for @uctx can be used to get both the number of attributes
> > > > + * and the size of the data.
> > > > + *
> > > > + * Returns the number of attributes found on success, negative value
> > > > + * on error. @size is reset to the total size of the data.
> > > > + * If @size is insufficient to contain the data -E2BIG is returned.
> > > > + */
> > > > +int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
> > > > + size_t __user *size, u32 flags)
> > > > +{
> > > > + struct security_hook_list *hp;
> > > > + struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
> > > > + u8 __user *base = (u8 __user *)uctx;
> > > > + size_t total = 0;
> > > > + size_t entrysize;
> > > > + size_t left;
> > > > + bool toobig = false;
> > > > + bool single = false;
> > > > + int count = 0;
> > > > + int rc;
> > > > +
> > > > + if (attr == LSM_ATTR_UNDEF)
> > > > + return -EINVAL;
> > > > + if (size == NULL)
> > > > + return -EINVAL;
> > > > + if (get_user(left, size))
> > > > + return -EFAULT;
> > > > +
> > > > + if (flags) {
> > > > + /*
> > > > + * Only flag supported is LSM_FLAG_SINGLE
> > > > + */
> > > > + if (flags != LSM_FLAG_SINGLE)
> > > > + return -EINVAL;
> > > > + if (uctx && copy_from_user(&lctx, uctx, sizeof(lctx)))
> > >
> > > I'm not sure if we should return -EINVAL or -EFAULT when uctx == NULL.
> > > Because uctx is optional (when LSM_FLAG_SINGLE is not set), I guess
> > > -EINVAL is OK.
> >
> > That's a good point, we should probably the error codes here: if uctx
> > is NULL in the LSM_FLAG_SINGLE case we should return -EINVAL, if the
> > copy_from_user() fails we should return -EFAULT.
> >
> > > > + return -EFAULT;
> > > > + /*
> > > > + * If the LSM ID isn't specified it is an error.
> > > > + */
> > > > + if (lctx.id == LSM_ID_UNDEF)
> > > > + return -EINVAL;
> > > > + single = true;
> > > > + }
> > > > +
> > > > + /*
> > > > + * In the usual case gather all the data from the LSMs.
> > > > + * In the single case only get the data from the LSM specified.
> > > > + */
> > > > + hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
> > > > + if (single && lctx.id != hp->lsmid->id)
> > > > + continue;
> > > > + entrysize = left;
> > > > + if (base)
> > > > + uctx = (struct lsm_ctx __user *)(base + total);
> > > > + rc = hp->hook.getselfattr(attr, uctx, &entrysize, flags);
> > > > + if (rc == -EOPNOTSUPP) {
> > > > + rc = 0;
> > > > + continue;
> > > > + }
> > > > + if (rc == -E2BIG) {
> > > > + toobig = true;
> > > > + left = 0;
> > > > + } else if (rc < 0)
> > > > + return rc;
> > > > + else
> > > > + left -= entrysize;
> > > > +
> > > > + total += entrysize;
> > > > + count += rc;
> > >
> > > There is a bug if rc == -E2BIG
> >
> > Can you elaborate a bit more on this? Nothing is jumping out at me as
> > obviously broken... are you talking about @count becoming garbage due
> > to @rc being equal to -E2BIG? If that is the case it should be okay
> > since we explicitly return -E2BIG, not @count, if @toobig is true.
>
> Indeed, in this case count will not be returned thanks to toobig. I'd
> suggest to "continue" if rc == -E2BIG (like for -EOPNOTSUPP) to avoid an
> inconsistent count value, which could bite us one day.

Okay, how about we reset @rc to zero in the -E2BIG case? We don't
want to bypass the lower part of the loop in this case as we still
need to update @total.

if (rc == -E2BIG) {
rc = 0;
left = 0;
toobig = true;
}

--
paul-moore.com

2023-10-10 09:14:27

by Mickaël Salaün

[permalink] [raw]
Subject: Re: [PATCH v15 04/11] LSM: syscalls for current process attributes

On Mon, Oct 09, 2023 at 12:04:31PM -0400, Paul Moore wrote:
> On Mon, Oct 9, 2023 at 11:37 AM Mickaël Salaün <[email protected]> wrote:
> > On Thu, Oct 05, 2023 at 09:04:34PM -0400, Paul Moore wrote:
> > > On Tue, Oct 3, 2023 at 10:09 AM Mickaël Salaün <[email protected]> wrote:
> > > > On Tue, Sep 12, 2023 at 01:56:49PM -0700, Casey Schaufler wrote:
> > > > > Create a system call lsm_get_self_attr() to provide the security
> > > > > module maintained attributes of the current process.
> > > > > 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
> > > > > identifies the size of the attribute, and the attribute value. The format
> > > > > of the attribute value is defined by the security module. A flags field
> > > > > is included for LSM specific information. It is currently unused and must
> > > > > be 0. The total size of the data, including the lsm_ctx structure and any
> > > > > padding, is maintained as well.
> > > > >
> > > > > struct lsm_ctx {
> > > > > __u64 id;
> > > > > __u64 flags;
> > > > > __u64 len;
> > > > > __u64 ctx_len;
> > > > > __u8 ctx[];
> > > > > };
> > > > >
> > > > > Two new LSM hooks are used to interface with the LSMs.
> > > > > security_getselfattr() collects the lsm_ctx values from the
> > > > > LSMs that support the hook, accounting for space requirements.
> > > > > security_setselfattr() identifies which LSM the attribute is
> > > > > intended for and passes it along.
> > > > >
> > > > > Signed-off-by: Casey Schaufler <[email protected]>
> > > > > Reviewed-by: Kees Cook <[email protected]>
> > > > > Reviewed-by: Serge Hallyn <[email protected]>
> > > > > Reviewed-by: John Johansen <[email protected]>
> > > > > ---
> > > > > Documentation/userspace-api/lsm.rst | 70 +++++++++++++
> > > > > include/linux/lsm_hook_defs.h | 4 +
> > > > > include/linux/lsm_hooks.h | 1 +
> > > > > include/linux/security.h | 19 ++++
> > > > > include/linux/syscalls.h | 5 +
> > > > > include/uapi/linux/lsm.h | 36 +++++++
> > > > > kernel/sys_ni.c | 2 +
> > > > > security/Makefile | 1 +
> > > > > security/lsm_syscalls.c | 57 +++++++++++
> > > > > security/security.c | 152 ++++++++++++++++++++++++++++
> > > > > 10 files changed, 347 insertions(+)
> > > > > create mode 100644 Documentation/userspace-api/lsm.rst
> > > > > create mode 100644 security/lsm_syscalls.c
> > >
> > > ...
> > >
> > > > > diff --git a/security/security.c b/security/security.c
> > > > > index a3489c04b783..0d179750d964 100644
> > > > > --- a/security/security.c
> > > > > +++ b/security/security.c
> > > > > @@ -3837,6 +3837,158 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
> > > > > }
> > > > > EXPORT_SYMBOL(security_d_instantiate);
> > > > >
> > > > > +/*
> > > > > + * Please keep this in sync with it's counterpart in security/lsm_syscalls.c
> > > > > + */
> > > > > +
> > > > > +/**
> > > > > + * security_getselfattr - Read an LSM attribute of the current process.
> > > > > + * @attr: which attribute to return
> > > > > + * @uctx: the user-space destination for the information, or NULL
> > > > > + * @size: pointer to the size of space available to receive the data
> > > > > + * @flags: special handling options. LSM_FLAG_SINGLE indicates that only
> > > > > + * attributes associated with the LSM identified in the passed @ctx be
> > > > > + * reported.
> > > > > + *
> > > > > + * A NULL value for @uctx can be used to get both the number of attributes
> > > > > + * and the size of the data.
> > > > > + *
> > > > > + * Returns the number of attributes found on success, negative value
> > > > > + * on error. @size is reset to the total size of the data.
> > > > > + * If @size is insufficient to contain the data -E2BIG is returned.
> > > > > + */
> > > > > +int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
> > > > > + size_t __user *size, u32 flags)
> > > > > +{
> > > > > + struct security_hook_list *hp;
> > > > > + struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
> > > > > + u8 __user *base = (u8 __user *)uctx;
> > > > > + size_t total = 0;
> > > > > + size_t entrysize;
> > > > > + size_t left;
> > > > > + bool toobig = false;
> > > > > + bool single = false;
> > > > > + int count = 0;
> > > > > + int rc;
> > > > > +
> > > > > + if (attr == LSM_ATTR_UNDEF)
> > > > > + return -EINVAL;
> > > > > + if (size == NULL)
> > > > > + return -EINVAL;
> > > > > + if (get_user(left, size))
> > > > > + return -EFAULT;
> > > > > +
> > > > > + if (flags) {
> > > > > + /*
> > > > > + * Only flag supported is LSM_FLAG_SINGLE
> > > > > + */
> > > > > + if (flags != LSM_FLAG_SINGLE)
> > > > > + return -EINVAL;
> > > > > + if (uctx && copy_from_user(&lctx, uctx, sizeof(lctx)))
> > > >
> > > > I'm not sure if we should return -EINVAL or -EFAULT when uctx == NULL.
> > > > Because uctx is optional (when LSM_FLAG_SINGLE is not set), I guess
> > > > -EINVAL is OK.
> > >
> > > That's a good point, we should probably the error codes here: if uctx
> > > is NULL in the LSM_FLAG_SINGLE case we should return -EINVAL, if the
> > > copy_from_user() fails we should return -EFAULT.
> > >
> > > > > + return -EFAULT;
> > > > > + /*
> > > > > + * If the LSM ID isn't specified it is an error.
> > > > > + */
> > > > > + if (lctx.id == LSM_ID_UNDEF)
> > > > > + return -EINVAL;
> > > > > + single = true;
> > > > > + }
> > > > > +
> > > > > + /*
> > > > > + * In the usual case gather all the data from the LSMs.
> > > > > + * In the single case only get the data from the LSM specified.
> > > > > + */
> > > > > + hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
> > > > > + if (single && lctx.id != hp->lsmid->id)
> > > > > + continue;
> > > > > + entrysize = left;
> > > > > + if (base)
> > > > > + uctx = (struct lsm_ctx __user *)(base + total);
> > > > > + rc = hp->hook.getselfattr(attr, uctx, &entrysize, flags);
> > > > > + if (rc == -EOPNOTSUPP) {
> > > > > + rc = 0;
> > > > > + continue;
> > > > > + }
> > > > > + if (rc == -E2BIG) {
> > > > > + toobig = true;
> > > > > + left = 0;
> > > > > + } else if (rc < 0)
> > > > > + return rc;
> > > > > + else
> > > > > + left -= entrysize;
> > > > > +
> > > > > + total += entrysize;
> > > > > + count += rc;
> > > >
> > > > There is a bug if rc == -E2BIG
> > >
> > > Can you elaborate a bit more on this? Nothing is jumping out at me as
> > > obviously broken... are you talking about @count becoming garbage due
> > > to @rc being equal to -E2BIG? If that is the case it should be okay
> > > since we explicitly return -E2BIG, not @count, if @toobig is true.
> >
> > Indeed, in this case count will not be returned thanks to toobig. I'd
> > suggest to "continue" if rc == -E2BIG (like for -EOPNOTSUPP) to avoid an
> > inconsistent count value, which could bite us one day.
>
> Okay, how about we reset @rc to zero in the -E2BIG case? We don't
> want to bypass the lower part of the loop in this case as we still
> need to update @total.
>
> if (rc == -E2BIG) {
> rc = 0;
> left = 0;
> toobig = true;
> }

Indeed, this is better.

To avoid useless calls to getselfattr hooks, we could also patch the
last part of the loop:
- if (single)
+ if (single || left <= 0)
break;

>
> --
> paul-moore.com

2023-10-10 13:11:18

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 04/11] LSM: syscalls for current process attributes

On Tue, Oct 10, 2023 at 5:14 AM Mickaël Salaün <[email protected]> wrote:
> On Mon, Oct 09, 2023 at 12:04:31PM -0400, Paul Moore wrote:
> > On Mon, Oct 9, 2023 at 11:37 AM Mickaël Salaün <[email protected]> wrote:
> > > On Thu, Oct 05, 2023 at 09:04:34PM -0400, Paul Moore wrote:
> > > > On Tue, Oct 3, 2023 at 10:09 AM Mickaël Salaün <[email protected]> wrote:
> > > > > On Tue, Sep 12, 2023 at 01:56:49PM -0700, Casey Schaufler wrote:
> > > > > > Create a system call lsm_get_self_attr() to provide the security
> > > > > > module maintained attributes of the current process.
> > > > > > 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
> > > > > > identifies the size of the attribute, and the attribute value. The format
> > > > > > of the attribute value is defined by the security module. A flags field
> > > > > > is included for LSM specific information. It is currently unused and must
> > > > > > be 0. The total size of the data, including the lsm_ctx structure and any
> > > > > > padding, is maintained as well.
> > > > > >
> > > > > > struct lsm_ctx {
> > > > > > __u64 id;
> > > > > > __u64 flags;
> > > > > > __u64 len;
> > > > > > __u64 ctx_len;
> > > > > > __u8 ctx[];
> > > > > > };
> > > > > >
> > > > > > Two new LSM hooks are used to interface with the LSMs.
> > > > > > security_getselfattr() collects the lsm_ctx values from the
> > > > > > LSMs that support the hook, accounting for space requirements.
> > > > > > security_setselfattr() identifies which LSM the attribute is
> > > > > > intended for and passes it along.
> > > > > >
> > > > > > Signed-off-by: Casey Schaufler <[email protected]>
> > > > > > Reviewed-by: Kees Cook <[email protected]>
> > > > > > Reviewed-by: Serge Hallyn <[email protected]>
> > > > > > Reviewed-by: John Johansen <[email protected]>
> > > > > > ---
> > > > > > Documentation/userspace-api/lsm.rst | 70 +++++++++++++
> > > > > > include/linux/lsm_hook_defs.h | 4 +
> > > > > > include/linux/lsm_hooks.h | 1 +
> > > > > > include/linux/security.h | 19 ++++
> > > > > > include/linux/syscalls.h | 5 +
> > > > > > include/uapi/linux/lsm.h | 36 +++++++
> > > > > > kernel/sys_ni.c | 2 +
> > > > > > security/Makefile | 1 +
> > > > > > security/lsm_syscalls.c | 57 +++++++++++
> > > > > > security/security.c | 152 ++++++++++++++++++++++++++++
> > > > > > 10 files changed, 347 insertions(+)
> > > > > > create mode 100644 Documentation/userspace-api/lsm.rst
> > > > > > create mode 100644 security/lsm_syscalls.c
> > > >
> > > > ...
> > > >
> > > > > > diff --git a/security/security.c b/security/security.c
> > > > > > index a3489c04b783..0d179750d964 100644
> > > > > > --- a/security/security.c
> > > > > > +++ b/security/security.c
> > > > > > @@ -3837,6 +3837,158 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
> > > > > > }
> > > > > > EXPORT_SYMBOL(security_d_instantiate);
> > > > > >
> > > > > > +/*
> > > > > > + * Please keep this in sync with it's counterpart in security/lsm_syscalls.c
> > > > > > + */
> > > > > > +
> > > > > > +/**
> > > > > > + * security_getselfattr - Read an LSM attribute of the current process.
> > > > > > + * @attr: which attribute to return
> > > > > > + * @uctx: the user-space destination for the information, or NULL
> > > > > > + * @size: pointer to the size of space available to receive the data
> > > > > > + * @flags: special handling options. LSM_FLAG_SINGLE indicates that only
> > > > > > + * attributes associated with the LSM identified in the passed @ctx be
> > > > > > + * reported.
> > > > > > + *
> > > > > > + * A NULL value for @uctx can be used to get both the number of attributes
> > > > > > + * and the size of the data.
> > > > > > + *
> > > > > > + * Returns the number of attributes found on success, negative value
> > > > > > + * on error. @size is reset to the total size of the data.
> > > > > > + * If @size is insufficient to contain the data -E2BIG is returned.
> > > > > > + */
> > > > > > +int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
> > > > > > + size_t __user *size, u32 flags)
> > > > > > +{
> > > > > > + struct security_hook_list *hp;
> > > > > > + struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
> > > > > > + u8 __user *base = (u8 __user *)uctx;
> > > > > > + size_t total = 0;
> > > > > > + size_t entrysize;
> > > > > > + size_t left;
> > > > > > + bool toobig = false;
> > > > > > + bool single = false;
> > > > > > + int count = 0;
> > > > > > + int rc;
> > > > > > +
> > > > > > + if (attr == LSM_ATTR_UNDEF)
> > > > > > + return -EINVAL;
> > > > > > + if (size == NULL)
> > > > > > + return -EINVAL;
> > > > > > + if (get_user(left, size))
> > > > > > + return -EFAULT;
> > > > > > +
> > > > > > + if (flags) {
> > > > > > + /*
> > > > > > + * Only flag supported is LSM_FLAG_SINGLE
> > > > > > + */
> > > > > > + if (flags != LSM_FLAG_SINGLE)
> > > > > > + return -EINVAL;
> > > > > > + if (uctx && copy_from_user(&lctx, uctx, sizeof(lctx)))
> > > > >
> > > > > I'm not sure if we should return -EINVAL or -EFAULT when uctx == NULL.
> > > > > Because uctx is optional (when LSM_FLAG_SINGLE is not set), I guess
> > > > > -EINVAL is OK.
> > > >
> > > > That's a good point, we should probably the error codes here: if uctx
> > > > is NULL in the LSM_FLAG_SINGLE case we should return -EINVAL, if the
> > > > copy_from_user() fails we should return -EFAULT.
> > > >
> > > > > > + return -EFAULT;
> > > > > > + /*
> > > > > > + * If the LSM ID isn't specified it is an error.
> > > > > > + */
> > > > > > + if (lctx.id == LSM_ID_UNDEF)
> > > > > > + return -EINVAL;
> > > > > > + single = true;
> > > > > > + }
> > > > > > +
> > > > > > + /*
> > > > > > + * In the usual case gather all the data from the LSMs.
> > > > > > + * In the single case only get the data from the LSM specified.
> > > > > > + */
> > > > > > + hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
> > > > > > + if (single && lctx.id != hp->lsmid->id)
> > > > > > + continue;
> > > > > > + entrysize = left;
> > > > > > + if (base)
> > > > > > + uctx = (struct lsm_ctx __user *)(base + total);
> > > > > > + rc = hp->hook.getselfattr(attr, uctx, &entrysize, flags);
> > > > > > + if (rc == -EOPNOTSUPP) {
> > > > > > + rc = 0;
> > > > > > + continue;
> > > > > > + }
> > > > > > + if (rc == -E2BIG) {
> > > > > > + toobig = true;
> > > > > > + left = 0;
> > > > > > + } else if (rc < 0)
> > > > > > + return rc;
> > > > > > + else
> > > > > > + left -= entrysize;
> > > > > > +
> > > > > > + total += entrysize;
> > > > > > + count += rc;
> > > > >
> > > > > There is a bug if rc == -E2BIG
> > > >
> > > > Can you elaborate a bit more on this? Nothing is jumping out at me as
> > > > obviously broken... are you talking about @count becoming garbage due
> > > > to @rc being equal to -E2BIG? If that is the case it should be okay
> > > > since we explicitly return -E2BIG, not @count, if @toobig is true.
> > >
> > > Indeed, in this case count will not be returned thanks to toobig. I'd
> > > suggest to "continue" if rc == -E2BIG (like for -EOPNOTSUPP) to avoid an
> > > inconsistent count value, which could bite us one day.
> >
> > Okay, how about we reset @rc to zero in the -E2BIG case? We don't
> > want to bypass the lower part of the loop in this case as we still
> > need to update @total.
> >
> > if (rc == -E2BIG) {
> > rc = 0;
> > left = 0;
> > toobig = true;
> > }
>
> Indeed, this is better.
>
> To avoid useless calls to getselfattr hooks, we could also patch the
> last part of the loop:
> - if (single)
> + if (single || left <= 0)
> break;
>

They aren't useless calls, we keep calling into the LSMs so that we
can return a buffer size hint in the @size parameter when the getattr
syscall returns -E2BIG.

--
paul-moore.com

2023-10-12 22:07:51

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Tue, Sep 12, 2023 at 4:57 PM Casey Schaufler <[email protected]> wrote:
>
> Add three system calls for the Linux Security Module ABI ...

First off, a big thank you to Casey who took it upon himself to turn
my pseudo-code syscall suggestion into a proper patchset and saw it
through 15 revisions. Thanks also go out to everyone that has helped
review and comment on this effort; I know everyone is busy, but these
reviews are important.

I'm happy to say that I think we're in a good place with this revision
of the LSM syscall patchset. I only see two outstanding issues, and
neither of those are bugs/showstoppers that affect the API, they are
simply areas where the implementation could be improved. With the
understanding that Casey is busy for the rest of the month, and my
desire to make sure this patchset gets a full dev cycle in linux-next,
I'm going to suggest merging this into the lsm/next-queue branch soon
(likely tomorrow) in preparation for merging it into lsm/next once the
upcoming merge window closes. Those who want to help improve the
implementation, as suggested in the feedback on this revision or
otherwise, are welcome to submit patches against the lsm/next-queue
branch and I will merge them into that branch once they pass review.

If I don't hear any objections I'll plan on merging this patchset
tomorrow, I'll send a follow-up reply to this email when it's done.

--
paul-moore.com

2023-10-13 21:55:24

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Thu, Oct 12, 2023 at 6:07 PM Paul Moore <[email protected]> wrote:
>
> On Tue, Sep 12, 2023 at 4:57 PM Casey Schaufler <[email protected]> wrote:
> >
> > Add three system calls for the Linux Security Module ABI ...
>
> First off, a big thank you to Casey who took it upon himself to turn
> my pseudo-code syscall suggestion into a proper patchset and saw it
> through 15 revisions. Thanks also go out to everyone that has helped
> review and comment on this effort; I know everyone is busy, but these
> reviews are important.
>
> I'm happy to say that I think we're in a good place with this revision
> of the LSM syscall patchset. I only see two outstanding issues, and
> neither of those are bugs/showstoppers that affect the API, they are
> simply areas where the implementation could be improved. With the
> understanding that Casey is busy for the rest of the month, and my
> desire to make sure this patchset gets a full dev cycle in linux-next,
> I'm going to suggest merging this into the lsm/next-queue branch soon
> (likely tomorrow) in preparation for merging it into lsm/next once the
> upcoming merge window closes. Those who want to help improve the
> implementation, as suggested in the feedback on this revision or
> otherwise, are welcome to submit patches against the lsm/next-queue
> branch and I will merge them into that branch once they pass review.
>
> If I don't hear any objections I'll plan on merging this patchset
> tomorrow, I'll send a follow-up reply to this email when it's done.

Since it's been *almost* a full 24 hours and no objections I went
ahead and merged this patchset into lsm/next-queue with the intention
of bringing them into lsm/next after the upcoming merge window closes.
For those of you who have suggested changes, please feel free to
submit patches against the lsm/next-queue branch and we can get them
queued up along with these patches.

Thanks everyone!

--
paul-moore.com

2023-10-16 12:05:21

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Fri, 2023-10-13 at 17:55 -0400, Paul Moore wrote:
> On Thu, Oct 12, 2023 at 6:07 PM Paul Moore <[email protected]> wrote:
> >
> > On Tue, Sep 12, 2023 at 4:57 PM Casey Schaufler <[email protected]> wrote:
> > >
> > > Add three system calls for the Linux Security Module ABI ...
> >
> > First off, a big thank you to Casey who took it upon himself to turn
> > my pseudo-code syscall suggestion into a proper patchset and saw it
> > through 15 revisions. Thanks also go out to everyone that has helped
> > review and comment on this effort; I know everyone is busy, but these
> > reviews are important.
> >
> > I'm happy to say that I think we're in a good place with this revision
> > of the LSM syscall patchset. I only see two outstanding issues, and
> > neither of those are bugs/showstoppers that affect the API, they are
> > simply areas where the implementation could be improved. With the
> > understanding that Casey is busy for the rest of the month, and my
> > desire to make sure this patchset gets a full dev cycle in linux-next,
> > I'm going to suggest merging this into the lsm/next-queue branch soon
> > (likely tomorrow) in preparation for merging it into lsm/next once the
> > upcoming merge window closes. Those who want to help improve the
> > implementation, as suggested in the feedback on this revision or
> > otherwise, are welcome to submit patches against the lsm/next-queue
> > branch and I will merge them into that branch once they pass review.
> >
> > If I don't hear any objections I'll plan on merging this patchset
> > tomorrow, I'll send a follow-up reply to this email when it's done.
>
> Since it's been *almost* a full 24 hours and no objections I went
> ahead and merged this patchset into lsm/next-queue with the intention
> of bringing them into lsm/next after the upcoming merge window closes.
> For those of you who have suggested changes, please feel free to
> submit patches against the lsm/next-queue branch and we can get them
> queued up along with these patches.

Sorry, I just noticed LSM_ID_IMA. Since we have the 'integrity' LSM, I
think it should be LSM_ID_INTEGRITY.

Mimi, all, do you agree? If yes, I send a patch shortly.

Thanks

Roberto

2023-10-16 15:07:05

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Mon, Oct 16, 2023 at 8:05 AM Roberto Sassu
<[email protected]> wrote:
>
> Sorry, I just noticed LSM_ID_IMA. Since we have the 'integrity' LSM, I
> think it should be LSM_ID_INTEGRITY.
>
> Mimi, all, do you agree? If yes, I send a patch shortly.

I believe LSM_ID_IMA is the better option, despite "integrity" already
being present in Kconfig and possibly other areas. "IMA" is a
specific thing/LSM whereas "integrity" is a property, principle, or
quality. Especially as we move forward with promoting IMA as a full
and proper LSM, we should work towards referring to it as "IMA" and
not "integrity".

If anything we should be working to support "IMA" in places where we
currently have "integrity" so that we can eventually deprecate
"integrity".

--
paul-moore.com

2023-10-17 07:02:18

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Mon, 2023-10-16 at 11:06 -0400, Paul Moore wrote:
> On Mon, Oct 16, 2023 at 8:05 AM Roberto Sassu
> <[email protected]> wrote:
> >
> > Sorry, I just noticed LSM_ID_IMA. Since we have the 'integrity' LSM, I
> > think it should be LSM_ID_INTEGRITY.
> >
> > Mimi, all, do you agree? If yes, I send a patch shortly.
>
> I believe LSM_ID_IMA is the better option, despite "integrity" already
> being present in Kconfig and possibly other areas. "IMA" is a
> specific thing/LSM whereas "integrity" is a property, principle, or
> quality. Especially as we move forward with promoting IMA as a full
> and proper LSM, we should work towards referring to it as "IMA" and
> not "integrity".
>
> If anything we should be working to support "IMA" in places where we
> currently have "integrity" so that we can eventually deprecate
> "integrity".

Hi Paul

I fully understand your argument. However, 'integrity' has been the
word to identify the integrity subsystem since long time ago.

Reducing the scope to 'ima' would create some confusion since, while
'ima' is associated to integrity, it would not encompass EVM.

The term 'integrity', although it is a property, it precisely
identifies in the kernel context the scope and goals of the subsystem,
and is general enough to encompass new projects going in a similar
direction (such as my integrity digest cache).

From a technical perspective, at the moment it is not possible to split
'integrity' in two standalone LSMs 'ima' and 'evm', as IMA and EVM work
on shared integrity metadata. Also my integrity digest cache is using
the same metadata.

In addition, making IMA and EVM as standalone LSMs would require a much
longer development cycle to make them use disjoint metadata and to
define proper communication interfaces. It would be not anymore a
technical move of function calls from a place to another, like for the
current patch set, but would require substantial time to validate the
new design.

To submit my patch set in the current state, the only thing I need is
to have LSM_ID_INTEGRITY defined.

Roberto

2023-10-17 15:58:55

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Tue, Oct 17, 2023 at 3:01 AM Roberto Sassu
<[email protected]> wrote:
> On Mon, 2023-10-16 at 11:06 -0400, Paul Moore wrote:
> > On Mon, Oct 16, 2023 at 8:05 AM Roberto Sassu
> > <[email protected]> wrote:
> > >
> > > Sorry, I just noticed LSM_ID_IMA. Since we have the 'integrity' LSM, I
> > > think it should be LSM_ID_INTEGRITY.
> > >
> > > Mimi, all, do you agree? If yes, I send a patch shortly.
> >
> > I believe LSM_ID_IMA is the better option, despite "integrity" already
> > being present in Kconfig and possibly other areas. "IMA" is a
> > specific thing/LSM whereas "integrity" is a property, principle, or
> > quality. Especially as we move forward with promoting IMA as a full
> > and proper LSM, we should work towards referring to it as "IMA" and
> > not "integrity".
> >
> > If anything we should be working to support "IMA" in places where we
> > currently have "integrity" so that we can eventually deprecate
> > "integrity".
>
> Hi Paul
>
> I fully understand your argument. However, 'integrity' has been the
> word to identify the integrity subsystem since long time ago.
>
> Reducing the scope to 'ima' would create some confusion since, while
> 'ima' is associated to integrity, it would not encompass EVM.

Using LSM_ID_IMA to reference the combination of IMA+EVM makes much
more sense to me than using LSM_ID_INTEGRITY, especially as we move
towards promoting IMA+EVM and adopting LSM hooks for integrity
verification, opening the door for other integrity focused LSMs.

--
paul-moore.com

2023-10-17 16:08:47

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Tue, 2023-10-17 at 11:58 -0400, Paul Moore wrote:
> On Tue, Oct 17, 2023 at 3:01 AM Roberto Sassu
> <[email protected]> wrote:
> > On Mon, 2023-10-16 at 11:06 -0400, Paul Moore wrote:
> > > On Mon, Oct 16, 2023 at 8:05 AM Roberto Sassu
> > > <[email protected]> wrote:
> > > >
> > > > Sorry, I just noticed LSM_ID_IMA. Since we have the 'integrity' LSM, I
> > > > think it should be LSM_ID_INTEGRITY.
> > > >
> > > > Mimi, all, do you agree? If yes, I send a patch shortly.
> > >
> > > I believe LSM_ID_IMA is the better option, despite "integrity" already
> > > being present in Kconfig and possibly other areas. "IMA" is a
> > > specific thing/LSM whereas "integrity" is a property, principle, or
> > > quality. Especially as we move forward with promoting IMA as a full
> > > and proper LSM, we should work towards referring to it as "IMA" and
> > > not "integrity".
> > >
> > > If anything we should be working to support "IMA" in places where we
> > > currently have "integrity" so that we can eventually deprecate
> > > "integrity".
> >
> > Hi Paul
> >
> > I fully understand your argument. However, 'integrity' has been the
> > word to identify the integrity subsystem since long time ago.
> >
> > Reducing the scope to 'ima' would create some confusion since, while
> > 'ima' is associated to integrity, it would not encompass EVM.
>
> Using LSM_ID_IMA to reference the combination of IMA+EVM makes much
> more sense to me than using LSM_ID_INTEGRITY, especially as we move
> towards promoting IMA+EVM and adopting LSM hooks for integrity
> verification, opening the door for other integrity focused LSMs.

+ Mimi, linux-integrity

Ok, just to understand before posting v4, the code looks like this:

+const struct lsm_id integrity_lsmid = {
+ .name = "integrity",
+ .id = LSM_ID_IMA,
+};
+
DEFINE_LSM(integrity) = {
.name = "integrity",
- .init = integrity_iintcache_init,
+ .init = integrity_lsm_init,
.order = LSM_ORDER_LAST,
};

Is it ok?

Thanks

Roberto


2023-10-18 09:33:36

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Tue, 2023-10-17 at 18:07 +0200, Roberto Sassu wrote:
> On Tue, 2023-10-17 at 11:58 -0400, Paul Moore wrote:
> > On Tue, Oct 17, 2023 at 3:01 AM Roberto Sassu
> > <[email protected]> wrote:
> > > On Mon, 2023-10-16 at 11:06 -0400, Paul Moore wrote:
> > > > On Mon, Oct 16, 2023 at 8:05 AM Roberto Sassu
> > > > <[email protected]> wrote:
> > > > >
> > > > > Sorry, I just noticed LSM_ID_IMA. Since we have the 'integrity' LSM, I
> > > > > think it should be LSM_ID_INTEGRITY.
> > > > >
> > > > > Mimi, all, do you agree? If yes, I send a patch shortly.
> > > >
> > > > I believe LSM_ID_IMA is the better option, despite "integrity" already
> > > > being present in Kconfig and possibly other areas. "IMA" is a
> > > > specific thing/LSM whereas "integrity" is a property, principle, or
> > > > quality. Especially as we move forward with promoting IMA as a full
> > > > and proper LSM, we should work towards referring to it as "IMA" and
> > > > not "integrity".
> > > >
> > > > If anything we should be working to support "IMA" in places where we
> > > > currently have "integrity" so that we can eventually deprecate
> > > > "integrity".
> > >
> > > Hi Paul
> > >
> > > I fully understand your argument. However, 'integrity' has been the
> > > word to identify the integrity subsystem since long time ago.
> > >
> > > Reducing the scope to 'ima' would create some confusion since, while
> > > 'ima' is associated to integrity, it would not encompass EVM.
> >
> > Using LSM_ID_IMA to reference the combination of IMA+EVM makes much
> > more sense to me than using LSM_ID_INTEGRITY, especially as we move
> > towards promoting IMA+EVM and adopting LSM hooks for integrity
> > verification, opening the door for other integrity focused LSMs.
>
> + Mimi, linux-integrity
>
> Ok, just to understand before posting v4, the code looks like this:

I worked on a new proposal. Let me know what you think. It is available
here:

https://github.com/robertosassu/linux/tree/ima-evm-lsms-v4-devel-v6


I made IMA and EVM as standalone LSMs and removed 'integrity'. They
maintain the same properties of 'integrity', i.e. they are the last and
always enabled.

During initialization, 'ima' and 'evm' call integrity_iintcache_init(),
so that they can get integrity metadata. I added a check to ensure that
this function is called only once. I also added the lsmid parameter so
that the integrity-specific functions are added under the LSM ID of the
caller.

I added a new LSM ID for EVM, does not look good that IMA and EVM are
represented by LSM_ID_IMA.

Finally, I had to drop the patch to remove the rbtree, because without
the 'integrity' LSM, space in the security blob cannot be reserved.
Since integrity metadata is shared, it cannot be reserved by 'ima' or
'evm'.

An intermediate solution would be to keep the 'integrity' LSM just to
reserve space in the security blob. Or, we remove the rbtree if/when
IMA and EVM use disjoint integrity metadata.

Roberto

2023-10-18 13:35:10

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Wed, 2023-10-18 at 11:31 +0200, Roberto Sassu wrote:
> On Tue, 2023-10-17 at 18:07 +0200, Roberto Sassu wrote:
> > On Tue, 2023-10-17 at 11:58 -0400, Paul Moore wrote:
> > > On Tue, Oct 17, 2023 at 3:01 AM Roberto Sassu
> > > <[email protected]> wrote:
> > > > On Mon, 2023-10-16 at 11:06 -0400, Paul Moore wrote:
> > > > > On Mon, Oct 16, 2023 at 8:05 AM Roberto Sassu
> > > > > <[email protected]> wrote:
> > > > > >
> > > > > > Sorry, I just noticed LSM_ID_IMA. Since we have the 'integrity' LSM, I
> > > > > > think it should be LSM_ID_INTEGRITY.
> > > > > >
> > > > > > Mimi, all, do you agree? If yes, I send a patch shortly.
> > > > >
> > > > > I believe LSM_ID_IMA is the better option, despite "integrity" already
> > > > > being present in Kconfig and possibly other areas. "IMA" is a
> > > > > specific thing/LSM whereas "integrity" is a property, principle, or
> > > > > quality. Especially as we move forward with promoting IMA as a full
> > > > > and proper LSM, we should work towards referring to it as "IMA" and
> > > > > not "integrity".
> > > > >
> > > > > If anything we should be working to support "IMA" in places where we
> > > > > currently have "integrity" so that we can eventually deprecate
> > > > > "integrity".
> > > >
> > > > Hi Paul
> > > >
> > > > I fully understand your argument. However, 'integrity' has been the
> > > > word to identify the integrity subsystem since long time ago.
> > > >
> > > > Reducing the scope to 'ima' would create some confusion since, while
> > > > 'ima' is associated to integrity, it would not encompass EVM.
> > >
> > > Using LSM_ID_IMA to reference the combination of IMA+EVM makes much
> > > more sense to me than using LSM_ID_INTEGRITY, especially as we move
> > > towards promoting IMA+EVM and adopting LSM hooks for integrity
> > > verification, opening the door for other integrity focused LSMs.
> >
> > + Mimi, linux-integrity
> >
> > Ok, just to understand before posting v4, the code looks like this:
>
> I worked on a new proposal. Let me know what you think. It is available
> here:
>
> https://github.com/robertosassu/linux/tree/ima-evm-lsms-v4-devel-v6
>
>
> I made IMA and EVM as standalone LSMs and removed 'integrity'. They
> maintain the same properties of 'integrity', i.e. they are the last and
> always enabled.
>
> During initialization, 'ima' and 'evm' call integrity_iintcache_init(),
> so that they can get integrity metadata. I added a check to ensure that
> this function is called only once. I also added the lsmid parameter so
> that the integrity-specific functions are added under the LSM ID of the
> caller.
>
> I added a new LSM ID for EVM, does not look good that IMA and EVM are
> represented by LSM_ID_IMA.
>
> Finally, I had to drop the patch to remove the rbtree, because without
> the 'integrity' LSM, space in the security blob cannot be reserved.
> Since integrity metadata is shared, it cannot be reserved by 'ima' or
> 'evm'.
>
> An intermediate solution would be to keep the 'integrity' LSM just to
> reserve space in the security blob. Or, we remove the rbtree if/when
> IMA and EVM use disjoint integrity metadata.

One of the major benefits for making IMA and EVM LSMs was removing the
rbtree and replacing it with the ability of using i_security.

I agree with Roberto. All three should be defined: LSM_ID_INTEGRITY,
LSM_ID_IMA, LSM_ID_EVM.

--
thanks,

Mimi

2023-10-18 14:17:43

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On 10/18/2023 3:09 PM, Mimi Zohar wrote:
> On Wed, 2023-10-18 at 11:31 +0200, Roberto Sassu wrote:
>> On Tue, 2023-10-17 at 18:07 +0200, Roberto Sassu wrote:
>>> On Tue, 2023-10-17 at 11:58 -0400, Paul Moore wrote:
>>>> On Tue, Oct 17, 2023 at 3:01 AM Roberto Sassu
>>>> <[email protected]> wrote:
>>>>> On Mon, 2023-10-16 at 11:06 -0400, Paul Moore wrote:
>>>>>> On Mon, Oct 16, 2023 at 8:05 AM Roberto Sassu
>>>>>> <[email protected]> wrote:
>>>>>>>
>>>>>>> Sorry, I just noticed LSM_ID_IMA. Since we have the 'integrity' LSM, I
>>>>>>> think it should be LSM_ID_INTEGRITY.
>>>>>>>
>>>>>>> Mimi, all, do you agree? If yes, I send a patch shortly.
>>>>>>
>>>>>> I believe LSM_ID_IMA is the better option, despite "integrity" already
>>>>>> being present in Kconfig and possibly other areas. "IMA" is a
>>>>>> specific thing/LSM whereas "integrity" is a property, principle, or
>>>>>> quality. Especially as we move forward with promoting IMA as a full
>>>>>> and proper LSM, we should work towards referring to it as "IMA" and
>>>>>> not "integrity".
>>>>>>
>>>>>> If anything we should be working to support "IMA" in places where we
>>>>>> currently have "integrity" so that we can eventually deprecate
>>>>>> "integrity".
>>>>>
>>>>> Hi Paul
>>>>>
>>>>> I fully understand your argument. However, 'integrity' has been the
>>>>> word to identify the integrity subsystem since long time ago.
>>>>>
>>>>> Reducing the scope to 'ima' would create some confusion since, while
>>>>> 'ima' is associated to integrity, it would not encompass EVM.
>>>>
>>>> Using LSM_ID_IMA to reference the combination of IMA+EVM makes much
>>>> more sense to me than using LSM_ID_INTEGRITY, especially as we move
>>>> towards promoting IMA+EVM and adopting LSM hooks for integrity
>>>> verification, opening the door for other integrity focused LSMs.
>>>
>>> + Mimi, linux-integrity
>>>
>>> Ok, just to understand before posting v4, the code looks like this:
>>
>> I worked on a new proposal. Let me know what you think. It is available
>> here:
>>
>> https://github.com/robertosassu/linux/tree/ima-evm-lsms-v4-devel-v6
>>
>>
>> I made IMA and EVM as standalone LSMs and removed 'integrity'. They
>> maintain the same properties of 'integrity', i.e. they are the last and
>> always enabled.
>>
>> During initialization, 'ima' and 'evm' call integrity_iintcache_init(),
>> so that they can get integrity metadata. I added a check to ensure that
>> this function is called only once. I also added the lsmid parameter so
>> that the integrity-specific functions are added under the LSM ID of the
>> caller.
>>
>> I added a new LSM ID for EVM, does not look good that IMA and EVM are
>> represented by LSM_ID_IMA.
>>
>> Finally, I had to drop the patch to remove the rbtree, because without
>> the 'integrity' LSM, space in the security blob cannot be reserved.
>> Since integrity metadata is shared, it cannot be reserved by 'ima' or
>> 'evm'.
>>
>> An intermediate solution would be to keep the 'integrity' LSM just to
>> reserve space in the security blob. Or, we remove the rbtree if/when
>> IMA and EVM use disjoint integrity metadata.
>
> One of the major benefits for making IMA and EVM LSMs was removing the
> rbtree and replacing it with the ability of using i_security.
>
> I agree with Roberto. All three should be defined: LSM_ID_INTEGRITY,
> LSM_ID_IMA, LSM_ID_EVM.

I did not try yet, but the 'integrity' LSM does not need an LSM ID. With
the last version adding hooks to 'ima' or 'evm', it should be sufficient
to keep DEFINE_LSM(integrity) with the request to store a pointer in the
security blob (even the init function can be a dummy function).

Roberto

2023-10-18 16:36:12

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Wed, Oct 18, 2023 at 10:15 AM Roberto Sassu
<[email protected]> wrote:
> On 10/18/2023 3:09 PM, Mimi Zohar wrote:

...

> > I agree with Roberto. All three should be defined: LSM_ID_INTEGRITY,
> > LSM_ID_IMA, LSM_ID_EVM.
>
> I did not try yet, but the 'integrity' LSM does not need an LSM ID. With
> the last version adding hooks to 'ima' or 'evm', it should be sufficient
> to keep DEFINE_LSM(integrity) with the request to store a pointer in the
> security blob (even the init function can be a dummy function).

First off, this *really* should have been brought up way, way, *way*
before now. This patchset has been discussed for months, and bringing
up concerns in the eleventh hour is borderline rude.

At least we haven't shipped this in a tagged release from Linus yet,
so there is that.

If you want to add a unique LSM ID for both IMA and EVM, I'm okay with
that, but if we do that I don't see the need for a dedicated ID for
"integrity". Roberto, Mimi, one of you please send me a patch on top
of lsm/next-queue that updates the LSM ID to look like the following
(I believe EVM was added between AppArmor and Yama, yes?):

#define LSM_ID_UNDEF 0
#define LSM_ID_CAPABILITY 100
#define LSM_ID_SELINUX 101
#define LSM_ID_SMACK 102
#define LSM_ID_TOMOYO 103
#define LSM_ID_IMA 104
#define LSM_ID_APPARMOR 105
#define LSM_ID_EVM 106
#define LSM_ID_YAMA 107
#define LSM_ID_LOADPIN 108
#define LSM_ID_SAFESETID 109
#define LSM_ID_LOCKDOWN 110
#define LSM_ID_BPF 111
#define LSM_ID_LANDLOCK 112

... and also update the LSM registration code for IMA/EVM/etc. to do
the right thing.

Also, just to be clear, you should get this patch out ASAP.

--
paul-moore.com

2023-10-18 20:23:28

by Mimi Zohar

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Wed, 2023-10-18 at 12:35 -0400, Paul Moore wrote:
> On Wed, Oct 18, 2023 at 10:15 AM Roberto Sassu
> <[email protected]> wrote:
> > On 10/18/2023 3:09 PM, Mimi Zohar wrote:
>
> ...
>
> > > I agree with Roberto. All three should be defined: LSM_ID_INTEGRITY,
> > > LSM_ID_IMA, LSM_ID_EVM.
> >
> > I did not try yet, but the 'integrity' LSM does not need an LSM ID. With
> > the last version adding hooks to 'ima' or 'evm', it should be sufficient
> > to keep DEFINE_LSM(integrity) with the request to store a pointer in the
> > security blob (even the init function can be a dummy function).
>
> First off, this *really* should have been brought up way, way, *way*
> before now. This patchset has been discussed for months, and bringing
> up concerns in the eleventh hour is borderline rude.

As everyone knows IMA and EVM are not LSMs at this point.

So the only thing that is "rude" is the way you're responding in this
thread.

>
> At least we haven't shipped this in a tagged release from Linus yet,
> so there is that.

What does that have to do with anything?! Code changes.

Mimi

2023-10-18 20:40:56

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Wed, Oct 18, 2023 at 4:23 PM Mimi Zohar <[email protected]> wrote:
> On Wed, 2023-10-18 at 12:35 -0400, Paul Moore wrote:
> > On Wed, Oct 18, 2023 at 10:15 AM Roberto Sassu
> > <[email protected]> wrote:
> > > On 10/18/2023 3:09 PM, Mimi Zohar wrote:
> >
> > ...
> >
> > > > I agree with Roberto. All three should be defined: LSM_ID_INTEGRITY,
> > > > LSM_ID_IMA, LSM_ID_EVM.
> > >
> > > I did not try yet, but the 'integrity' LSM does not need an LSM ID. With
> > > the last version adding hooks to 'ima' or 'evm', it should be sufficient
> > > to keep DEFINE_LSM(integrity) with the request to store a pointer in the
> > > security blob (even the init function can be a dummy function).
> >
> > First off, this *really* should have been brought up way, way, *way*
> > before now. This patchset has been discussed for months, and bringing
> > up concerns in the eleventh hour is borderline rude.
>
> As everyone knows IMA and EVM are not LSMs at this point.

Considering all the work Roberto has been doing to make that happen,
not to mention the discussions we've had on this topic, that's an
awfully small technicality to use as the basis of an argument.

> So the only thing that is "rude" is the way you're responding in this
> thread.

Agree to disagree.

> > At least we haven't shipped this in a tagged release from Linus yet,
> > so there is that.
>
> What does that have to do with anything?! Code changes.

Code can change, Linux kernel APIs should not change.

--
paul-moore.com

2023-10-19 07:46:13

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Wed, 2023-10-18 at 16:40 -0400, Paul Moore wrote:
> On Wed, Oct 18, 2023 at 4:23 PM Mimi Zohar <[email protected]> wrote:
> > On Wed, 2023-10-18 at 12:35 -0400, Paul Moore wrote:
> > > On Wed, Oct 18, 2023 at 10:15 AM Roberto Sassu
> > > <[email protected]> wrote:
> > > > On 10/18/2023 3:09 PM, Mimi Zohar wrote:
> > >
> > > ...
> > >
> > > > > I agree with Roberto. All three should be defined: LSM_ID_INTEGRITY,
> > > > > LSM_ID_IMA, LSM_ID_EVM.
> > > >
> > > > I did not try yet, but the 'integrity' LSM does not need an LSM ID. With
> > > > the last version adding hooks to 'ima' or 'evm', it should be sufficient
> > > > to keep DEFINE_LSM(integrity) with the request to store a pointer in the
> > > > security blob (even the init function can be a dummy function).
> > >
> > > First off, this *really* should have been brought up way, way, *way*
> > > before now. This patchset has been discussed for months, and bringing
> > > up concerns in the eleventh hour is borderline rude.
> >
> > As everyone knows IMA and EVM are not LSMs at this point.
>
> Considering all the work Roberto has been doing to make that happen,
> not to mention the discussions we've had on this topic, that's an
> awfully small technicality to use as the basis of an argument.

Sorry Paul, but I've been working on this patch set for a long time and
you were also involved in the prerequisites (like making the
'integrity' LSM as the last).

I thought it was clear at this point that we were going to add the
hooks to the 'integrity' LSM.

I really have no problem to rebase my work on top of other work, but I
was very surprised to see LSM_ID_IMA instead of LSM_ID_INTEGRITY, and
at minimum this should have been agreed with Mimi. And also, I was not
convinced with the argument that LSM_ID_IMA should represent IMA+EVM.

Roberto

2023-10-19 08:50:12

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On Wed, 2023-10-18 at 16:14 +0200, Roberto Sassu wrote:
> On 10/18/2023 3:09 PM, Mimi Zohar wrote:
> > On Wed, 2023-10-18 at 11:31 +0200, Roberto Sassu wrote:
> > > On Tue, 2023-10-17 at 18:07 +0200, Roberto Sassu wrote:
> > > > On Tue, 2023-10-17 at 11:58 -0400, Paul Moore wrote:
> > > > > On Tue, Oct 17, 2023 at 3:01 AM Roberto Sassu
> > > > > <[email protected]> wrote:
> > > > > > On Mon, 2023-10-16 at 11:06 -0400, Paul Moore wrote:
> > > > > > > On Mon, Oct 16, 2023 at 8:05 AM Roberto Sassu
> > > > > > > <[email protected]> wrote:
> > > > > > > >
> > > > > > > > Sorry, I just noticed LSM_ID_IMA. Since we have the 'integrity' LSM, I
> > > > > > > > think it should be LSM_ID_INTEGRITY.
> > > > > > > >
> > > > > > > > Mimi, all, do you agree? If yes, I send a patch shortly.
> > > > > > >
> > > > > > > I believe LSM_ID_IMA is the better option, despite "integrity" already
> > > > > > > being present in Kconfig and possibly other areas. "IMA" is a
> > > > > > > specific thing/LSM whereas "integrity" is a property, principle, or
> > > > > > > quality. Especially as we move forward with promoting IMA as a full
> > > > > > > and proper LSM, we should work towards referring to it as "IMA" and
> > > > > > > not "integrity".
> > > > > > >
> > > > > > > If anything we should be working to support "IMA" in places where we
> > > > > > > currently have "integrity" so that we can eventually deprecate
> > > > > > > "integrity".
> > > > > >
> > > > > > Hi Paul
> > > > > >
> > > > > > I fully understand your argument. However, 'integrity' has been the
> > > > > > word to identify the integrity subsystem since long time ago.
> > > > > >
> > > > > > Reducing the scope to 'ima' would create some confusion since, while
> > > > > > 'ima' is associated to integrity, it would not encompass EVM.
> > > > >
> > > > > Using LSM_ID_IMA to reference the combination of IMA+EVM makes much
> > > > > more sense to me than using LSM_ID_INTEGRITY, especially as we move
> > > > > towards promoting IMA+EVM and adopting LSM hooks for integrity
> > > > > verification, opening the door for other integrity focused LSMs.
> > > >
> > > > + Mimi, linux-integrity
> > > >
> > > > Ok, just to understand before posting v4, the code looks like this:
> > >
> > > I worked on a new proposal. Let me know what you think. It is available
> > > here:
> > >
> > > https://github.com/robertosassu/linux/tree/ima-evm-lsms-v4-devel-v6
> > >
> > >
> > > I made IMA and EVM as standalone LSMs and removed 'integrity'. They
> > > maintain the same properties of 'integrity', i.e. they are the last and
> > > always enabled.
> > >
> > > During initialization, 'ima' and 'evm' call integrity_iintcache_init(),
> > > so that they can get integrity metadata. I added a check to ensure that
> > > this function is called only once. I also added the lsmid parameter so
> > > that the integrity-specific functions are added under the LSM ID of the
> > > caller.
> > >
> > > I added a new LSM ID for EVM, does not look good that IMA and EVM are
> > > represented by LSM_ID_IMA.
> > >
> > > Finally, I had to drop the patch to remove the rbtree, because without
> > > the 'integrity' LSM, space in the security blob cannot be reserved.
> > > Since integrity metadata is shared, it cannot be reserved by 'ima' or
> > > 'evm'.
> > >
> > > An intermediate solution would be to keep the 'integrity' LSM just to
> > > reserve space in the security blob. Or, we remove the rbtree if/when
> > > IMA and EVM use disjoint integrity metadata.
> >
> > One of the major benefits for making IMA and EVM LSMs was removing the
> > rbtree and replacing it with the ability of using i_security.
> >
> > I agree with Roberto. All three should be defined: LSM_ID_INTEGRITY,
> > LSM_ID_IMA, LSM_ID_EVM.
>
> I did not try yet, but the 'integrity' LSM does not need an LSM ID. With
> the last version adding hooks to 'ima' or 'evm', it should be sufficient
> to keep DEFINE_LSM(integrity) with the request to store a pointer in the
> security blob (even the init function can be a dummy function).

Ok, I rebased on top of Paul's 'lsm: drop LSM_ID_IMA', made IMA and EVM
as standalone LSMs, and assigned LSM IDs to them in the correct
chronological order.

Still left DEFINE_LSM(integrity) to reserve space for the
integrity_iint_cache pointer, but it does not register any LSM hook,
then no LSM ID required.

In the future, we might be able to make IMA and EVM use disjoint
metadata, so they will reserve space in the security blob and register
appropriate hooks for the metadata management.

With this intermediate solution, I can keep the rbtree patch, which
will provide performance improvements due to searching metadata in
constant time.

If you want to have a look before I send the patch set, the code is
available here:

https://github.com/robertosassu/linux/commits/ima-evm-lsms-v4-devel-v7

It passes all IMA tests:

https://github.com/robertosassu/ima-evm-utils/actions/runs/6571587570

Roberto

2023-10-20 16:37:54

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 00/11] LSM: Three basic syscalls

On 10/19/2023 12:45 AM, Roberto Sassu wrote:
> On Wed, 2023-10-18 at 16:40 -0400, Paul Moore wrote:
>> On Wed, Oct 18, 2023 at 4:23 PM Mimi Zohar <[email protected]> wrote:
>>> On Wed, 2023-10-18 at 12:35 -0400, Paul Moore wrote:
>>>> On Wed, Oct 18, 2023 at 10:15 AM Roberto Sassu
>>>> <[email protected]> wrote:
>>>>> On 10/18/2023 3:09 PM, Mimi Zohar wrote:
>>>> ...
>>>>
>>>>>> I agree with Roberto. All three should be defined: LSM_ID_INTEGRITY,
>>>>>> LSM_ID_IMA, LSM_ID_EVM.
>>>>> I did not try yet, but the 'integrity' LSM does not need an LSM ID. With
>>>>> the last version adding hooks to 'ima' or 'evm', it should be sufficient
>>>>> to keep DEFINE_LSM(integrity) with the request to store a pointer in the
>>>>> security blob (even the init function can be a dummy function).
>>>> First off, this *really* should have been brought up way, way, *way*
>>>> before now. This patchset has been discussed for months, and bringing
>>>> up concerns in the eleventh hour is borderline rude.
>>> As everyone knows IMA and EVM are not LSMs at this point.
>> Considering all the work Roberto has been doing to make that happen,
>> not to mention the discussions we've had on this topic, that's an
>> awfully small technicality to use as the basis of an argument.
> Sorry Paul, but I've been working on this patch set for a long time and
> you were also involved in the prerequisites (like making the
> 'integrity' LSM as the last).
>
> I thought it was clear at this point that we were going to add the
> hooks to the 'integrity' LSM.

There's a chicken/egg issue here. You can hold up the syscalls patch
forever if you insist on it accommodating every patch set that's in the
pipeline. I understand that you've been working on the integrity rework
for some time. I understand that it's frustrating when things change out
from under you. Believe me, I do.

>
> I really have no problem to rebase my work on top of other work, but I
> was very surprised to see LSM_ID_IMA instead of LSM_ID_INTEGRITY, and
> at minimum this should have been agreed with Mimi. And also, I was not
> convinced with the argument that LSM_ID_IMA should represent IMA+EVM.
>
> Roberto
>

2023-10-20 19:40:25

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 08/11] Smack: implement setselfattr and getselfattr hooks



On 10/3/2023 7:28 AM, Mickaël Salaün wrote:
> On Tue, Sep 12, 2023 at 01:56:53PM -0700, Casey Schaufler wrote:
>> Implement Smack support for security_[gs]etselfattr.
>> Refactor the setprocattr hook to avoid code duplication.
>>
>> Signed-off-by: Casey Schaufler <[email protected]>
>> Reviewed-by: John Johansen <[email protected]>
>> ---
>> security/smack/smack_lsm.c | 95 ++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 90 insertions(+), 5 deletions(-)
>>
>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>> index f73f9a2834eb..12160d060cc1 100644
>> --- a/security/smack/smack_lsm.c
>> +++ b/security/smack/smack_lsm.c
>> @@ -3626,6 +3626,46 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
>> return;
>> }
>>
>> +/**
>> + * smack_getselfattr - Smack current process attribute
>> + * @attr: which attribute to fetch
>> + * @ctx: buffer to receive the result
>> + * @size: available size in, actual size out
>> + * @flags: unused
>> + *
>> + * Fill the passed user space @ctx with the details of the requested
>> + * attribute.
>> + *
>> + * Returns the number of attributes on success, an error code otherwise.
>> + * There will only ever be one attribute.
>> + */
>> +static int smack_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
>> + size_t *size, u32 flags)
>> +{
>> + struct smack_known *skp = smk_of_current();
>> + int total;
>> + int slen;
>> + int rc;
>> +
>> + if (attr != LSM_ATTR_CURRENT)
>> + return -EOPNOTSUPP;
>> +
>> + slen = strlen(skp->smk_known) + 1;
>
>> + total = ALIGN(slen + sizeof(*ctx), 8);
>> + if (total > *size)
>> + rc = -E2BIG;
>> + else if (ctx)
>> + rc = lsm_fill_user_ctx(ctx, skp->smk_known, slen, LSM_ID_SMACK,
>> + 0);
>> + else
>> + rc = 1;
> Can we move these checks into lsm_fill_user_ctx()? They are similar for
> AppArmor and SELinux.
>
>> +
>> + *size = total;
>> + if (rc >= 0)
>> + return 1;
>> + return rc;
>> +}

2023-10-20 19:43:03

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 08/11] Smack: implement setselfattr and getselfattr hooks

On 10/3/2023 7:28 AM, Mickaël Salaün wrote:
> On Tue, Sep 12, 2023 at 01:56:53PM -0700, Casey Schaufler wrote:
>> Implement Smack support for security_[gs]etselfattr.
>> Refactor the setprocattr hook to avoid code duplication.
>>
>> Signed-off-by: Casey Schaufler <[email protected]>
>> Reviewed-by: John Johansen <[email protected]>
>> ---
>> security/smack/smack_lsm.c | 95 ++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 90 insertions(+), 5 deletions(-)
>>
>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>> index f73f9a2834eb..12160d060cc1 100644
>> --- a/security/smack/smack_lsm.c
>> +++ b/security/smack/smack_lsm.c
>> @@ -3626,6 +3626,46 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
>> return;
>> }
>>
>> +/**
>> + * smack_getselfattr - Smack current process attribute
>> + * @attr: which attribute to fetch
>> + * @ctx: buffer to receive the result
>> + * @size: available size in, actual size out
>> + * @flags: unused
>> + *
>> + * Fill the passed user space @ctx with the details of the requested
>> + * attribute.
>> + *
>> + * Returns the number of attributes on success, an error code otherwise.
>> + * There will only ever be one attribute.
>> + */
>> +static int smack_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
>> + size_t *size, u32 flags)
>> +{
>> + struct smack_known *skp = smk_of_current();
>> + int total;
>> + int slen;
>> + int rc;
>> +
>> + if (attr != LSM_ATTR_CURRENT)
>> + return -EOPNOTSUPP;
>> +
>> + slen = strlen(skp->smk_known) + 1;
>
>> + total = ALIGN(slen + sizeof(*ctx), 8);
>> + if (total > *size)
>> + rc = -E2BIG;
>> + else if (ctx)
>> + rc = lsm_fill_user_ctx(ctx, skp->smk_known, slen, LSM_ID_SMACK,
>> + 0);
>> + else
>> + rc = 1;
> Can we move these checks into lsm_fill_user_ctx()? They are similar for
> AppArmor and SELinux.

Possibly, but that would make lsm_fill_user_ctx() into lsm_validiate_and_fill_user_ctx(),
and I don't want to do that.

>
>> +
>> + *size = total;
>> + if (rc >= 0)
>> + return 1;
>> + return rc;
>> +}

2023-10-20 19:53:12

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 10/5/2023 5:58 AM, Tetsuo Handa wrote:
> On 2023/09/13 5:56, Casey Schaufler wrote:
>> Create a struct lsm_id to contain identifying information about Linux
>> Security Modules (LSMs). At inception this contains the name of the
>> module and an identifier associated with the security module. Change
>> the security_add_hooks() interface to use this structure. Change the
>> individual modules to maintain their own struct lsm_id and pass it to
>> security_add_hooks().
> I came to worry about what purpose does the LSM ID value (or more precisely,
> "struct lsm_id") is used for. If the LSM ID value is used for only switch
> {reading,writing} /proc/self/attr/ of specific LSM module's information, only
> LSM modules that use /proc/self/attr/ will need the LSM ID value.
>
> But this series uses "struct lsm_id" as one of arguments for security_add_hooks(),
> and might be reused for different purposes.
>
> Then, BPF-based LSMs (which are not considered as in-tree LSM modules, for
> only BPF hook is considered as in-tree LSM module) might receive unfavorable
> treatment than non BPF-based LSMs?
>
> [PATCH v15 05/11] says
>
> Create a system call to report the list of Linux Security Modules
> that are active on the system. The list is provided as an array
> of LSM ID numbers.
>
> The calling application can use this list determine what LSM
> specific actions it might take. That might include choosing an
> output format, determining required privilege or bypassing
> security module specific behavior.
>
> but, at least, name of BPF-based LSMs won't be shown up in lsm_list_modules()
> compared to non BPF-based LSMs? Then, the calling application can't use this
> list determine what BPF-based LSM specific actions it might take?

That is correct. Just as knowing that your system is using SELinux won't
tell you whether a specific action might be permitted because that's driven
by the loaded policy, so too knowing that your system is using BPF won't
tell you whether a specific action might be permitted because that's driven
by the eBPF programs in place.

I wish we could stop people from saying "BPF-based LSM". BPF is the LSM. The
eBPF programs that implement a "policy" are NOT a LSM. There needs to be a
name for that, but LSM is not it.

2023-10-21 12:22:01

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 2023/10/21 4:52, Casey Schaufler wrote:
> On 10/5/2023 5:58 AM, Tetsuo Handa wrote:
>> On 2023/09/13 5:56, Casey Schaufler wrote:
>>> Create a struct lsm_id to contain identifying information about Linux
>>> Security Modules (LSMs). At inception this contains the name of the
>>> module and an identifier associated with the security module. Change
>>> the security_add_hooks() interface to use this structure. Change the
>>> individual modules to maintain their own struct lsm_id and pass it to
>>> security_add_hooks().
>> I came to worry about what purpose does the LSM ID value (or more precisely,
>> "struct lsm_id") is used for. If the LSM ID value is used for only switch
>> {reading,writing} /proc/self/attr/ of specific LSM module's information, only
>> LSM modules that use /proc/self/attr/ will need the LSM ID value.
>>
>> But this series uses "struct lsm_id" as one of arguments for security_add_hooks(),
>> and might be reused for different purposes.
>>
>> Then, BPF-based LSMs (which are not considered as in-tree LSM modules, for
>> only BPF hook is considered as in-tree LSM module) might receive unfavorable
>> treatment than non BPF-based LSMs?
>>
>> [PATCH v15 05/11] says
>>
>> Create a system call to report the list of Linux Security Modules
>> that are active on the system. The list is provided as an array
>> of LSM ID numbers.
>>
>> The calling application can use this list determine what LSM
>> specific actions it might take. That might include choosing an
>> output format, determining required privilege or bypassing
>> security module specific behavior.
>>
>> but, at least, name of BPF-based LSMs won't be shown up in lsm_list_modules()
>> compared to non BPF-based LSMs? Then, the calling application can't use this
>> list determine what BPF-based LSM specific actions it might take?
>
> That is correct. Just as knowing that your system is using SELinux won't
> tell you whether a specific action might be permitted because that's driven
> by the loaded policy, so too knowing that your system is using BPF won't
> tell you whether a specific action might be permitted because that's driven
> by the eBPF programs in place.

If the system call returning LSM ID value for SELinux but does not tell
the caller of that system call whether a specific action might be permitted,
what information does LSM ID value tell?

The patch description lacks relationship between LSM ID value and data.
In other words, why LSM ID values are needed (and are useful for doing what).
If the only information the caller can know from the LSM ID value were
what LSMs are enabled (i.e. the content of /sys/kernel/security/lsm ), why
bother to use LSM ID values? (Yes, integer comparison is faster than string
comparison. But that is not enough justification for not allowing out-of-tree
LSMs and eBPF-based access control mechanisms to have stable LSM ID values.)

What does "choosing an output format", "determining required privilege",
"bypassing security module specific behavior" mean? How can they choose
meaningful output format, determine appropriate privilege, bypass security
module specific behavior (if the only information the caller can know from
the LSM ID value were what LSMs are enabled) ?



> I wish we could stop people from saying "BPF-based LSM". BPF is the LSM. The
> eBPF programs that implement a "policy" are NOT a LSM. There needs to be a
> name for that, but LSM is not it.

My understanding is that "BPF is not an LSM module but infrastructure for using
LSM hooks".

Say, an access control implementation consists of two parts; "code" and "data".
The "code" is written by developers and is determined at compile time and is
interpreted by CPU, and the "data" is written by administrators and is interpreted
by "code". The "data" part can be either built-in (determined at compile time) or
loadable (configurable at run-time).

eBPF-based access control implementations (which can be loaded via bpf() system
call after boot) consists of "code" and "data". BPF will remain no-op unless
eBPF-based access control implementations are loaded via bpf() system call.
Thus, I believe that an eBPF-based access control implementation should be
considered as an LSM module (like SELinux etc.)

2023-10-21 14:12:33

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 10/21/2023 5:20 AM, Tetsuo Handa wrote:
> On 2023/10/21 4:52, Casey Schaufler wrote:
>> On 10/5/2023 5:58 AM, Tetsuo Handa wrote:
>>> On 2023/09/13 5:56, Casey Schaufler wrote:
>>>> Create a struct lsm_id to contain identifying information about Linux
>>>> Security Modules (LSMs). At inception this contains the name of the
>>>> module and an identifier associated with the security module. Change
>>>> the security_add_hooks() interface to use this structure. Change the
>>>> individual modules to maintain their own struct lsm_id and pass it to
>>>> security_add_hooks().
>>> I came to worry about what purpose does the LSM ID value (or more precisely,
>>> "struct lsm_id") is used for. If the LSM ID value is used for only switch
>>> {reading,writing} /proc/self/attr/ of specific LSM module's information, only
>>> LSM modules that use /proc/self/attr/ will need the LSM ID value.
>>>
>>> But this series uses "struct lsm_id" as one of arguments for security_add_hooks(),
>>> and might be reused for different purposes.
>>>
>>> Then, BPF-based LSMs (which are not considered as in-tree LSM modules, for
>>> only BPF hook is considered as in-tree LSM module) might receive unfavorable
>>> treatment than non BPF-based LSMs?
>>>
>>> [PATCH v15 05/11] says
>>>
>>> Create a system call to report the list of Linux Security Modules
>>> that are active on the system. The list is provided as an array
>>> of LSM ID numbers.
>>>
>>> The calling application can use this list determine what LSM
>>> specific actions it might take. That might include choosing an
>>> output format, determining required privilege or bypassing
>>> security module specific behavior.
>>>
>>> but, at least, name of BPF-based LSMs won't be shown up in lsm_list_modules()
>>> compared to non BPF-based LSMs? Then, the calling application can't use this
>>> list determine what BPF-based LSM specific actions it might take?
>> That is correct. Just as knowing that your system is using SELinux won't
>> tell you whether a specific action might be permitted because that's driven
>> by the loaded policy, so too knowing that your system is using BPF won't
>> tell you whether a specific action might be permitted because that's driven
>> by the eBPF programs in place.
> If the system call returning LSM ID value for SELinux but does not tell
> the caller of that system call whether a specific action might be permitted,
> what information does LSM ID value tell?

It tells the caller that the LSM is active on the system. That's it.
Just like reading /sys/kernel/security/lsm.

>
> The patch description lacks relationship between LSM ID value and data.
> In other words, why LSM ID values are needed (and are useful for doing what).
> If the only information the caller can know from the LSM ID value were
> what LSMs are enabled (i.e. the content of /sys/kernel/security/lsm ), why
> bother to use LSM ID values? (Yes, integer comparison is faster than string
> comparison. But that is not enough justification for not allowing out-of-tree
> LSMs and eBPF-based access control mechanisms to have stable LSM ID values.)
>
> What does "choosing an output format", "determining required privilege",
> "bypassing security module specific behavior" mean? How can they choose
> meaningful output format, determine appropriate privilege, bypass security
> module specific behavior (if the only information the caller can know from
> the LSM ID value were what LSMs are enabled) ?

If Smack and SELinux not enabled on the system there is no point in
setting up a netlabel configuration, for example.

>> I wish we could stop people from saying "BPF-based LSM". BPF is the LSM. The
>> eBPF programs that implement a "policy" are NOT a LSM. There needs to be a
>> name for that, but LSM is not it.
> My understanding is that "BPF is not an LSM module but infrastructure for using
> LSM hooks".

As BPF is implemented as a LSM I suggest your statement is incorrect.

> Say, an access control implementation consists of two parts; "code" and "data".
> The "code" is written by developers and is determined at compile time and is
> interpreted by CPU, and the "data" is written by administrators and is interpreted
> by "code". The "data" part can be either built-in (determined at compile time) or
> loadable (configurable at run-time).
>
> eBPF-based access control implementations (which can be loaded via bpf() system
> call after boot) consists of "code" and "data". BPF will remain no-op unless
> eBPF-based access control implementations are loaded via bpf() system call.
> Thus, I believe that an eBPF-based access control implementation should be
> considered as an LSM module (like SELinux etc.)

And I say you're wrong. Your arguments are gibberish.

https://www.youtube.com/watch?v=-7cUnID7vFs

2023-10-29 10:59:07

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 2023/10/21 23:11, Casey Schaufler wrote:
>> If the system call returning LSM ID value for SELinux but does not tell
>> the caller of that system call whether a specific action might be permitted,
>> what information does LSM ID value tell?
>
> It tells the caller that the LSM is active on the system. That's it.
> Just like reading /sys/kernel/security/lsm.

Then, the

The calling application can use this list determine what LSM
specific actions it might take. That might include choosing an
output format, determining required privilege or bypassing
security module specific behavior.

part should be removed from the description. Instead, the description should
emphasis that the numeric LSM ID values are there in order to allow
identifying what LSM modules are active without interpreting string LSM names
in /sys/kernel/security/lsm .



>> What does "choosing an output format", "determining required privilege",
>> "bypassing security module specific behavior" mean? How can they choose
>> meaningful output format, determine appropriate privilege, bypass security
>> module specific behavior (if the only information the caller can know from
>> the LSM ID value were what LSMs are enabled) ?
>
> If Smack and SELinux not enabled on the system there is no point in
> setting up a netlabel configuration, for example.

I know nothing about netlabel. But can userspace make such assumption from
this granularity? For example, if TOMOYO and AppArmor start supporting
netlabel configuration, your assumption

If Smack and SELinux not enabled on the system there is no point in
setting up a netlabel configuration

becomes no longer true. It is also possible that a new LSM implementation
obtains an LSM ID for that LSM, and starts supporting netlabel configuration
some timer later. I don't know if we come to the point where we can enable
SELinux and Smack at the same time. But when it becomes possible to enable
SELinux and Smack at the same time, the userspace might have already written
code based on current situation that netlabel configuration are exclusive. Then,
someday starting to return both LSM ID for SELinux and LSM ID for Smack might
confuse userspace.

Thus, it might be safe to determine what LSMs are active from the LSM ID values
returned from the system call. But it is not safe to assume what functionality
is active (e.g. netlabel configuration is interpreted) from the LSM ID values
returned from the system call.

If you want to allow userspace to make such assumption using the system call,
the granularity the system call returns needs to be what access control mechanism
(not only LSM modules but also eBPF-based access control mechanisms) hooks which
LSM hooks. More information than interpreting string LSM names in
/sys/kernel/security/lsm will be needed.

>
>>> I wish we could stop people from saying "BPF-based LSM". BPF is the LSM. The
>>> eBPF programs that implement a "policy" are NOT a LSM. There needs to be a
>>> name for that, but LSM is not it.
>> My understanding is that "BPF is not an LSM module but infrastructure for using
>> LSM hooks".
>
> As BPF is implemented as a LSM I suggest your statement is incorrect.

Enumerating only LSM modules are not useful. "ID for access control mechanisms
that can be controlled via LSM hooks" will be needed.

>
>>
>> The patch description lacks relationship between LSM ID value and data.
>> In other words, why LSM ID values are needed (and are useful for doing what).
>> If the only information the caller can know from the LSM ID value were
>> what LSMs are enabled (i.e. the content of /sys/kernel/security/lsm ), why
>> bother to use LSM ID values? (Yes, integer comparison is faster than string
>> comparison. But that is not enough justification for not allowing out-of-tree
>> LSMs and eBPF-based access control mechanisms to have stable LSM ID values.)
>>

I conclude that LSM ID values are pointless and are NOT needed.

2023-10-29 18:01:13

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 01/11] LSM: Identify modules by more than name

On 10/29/2023 3:57 AM, Tetsuo Handa wrote:
> On 2023/10/21 23:11, Casey Schaufler wrote:
>>> If the system call returning LSM ID value for SELinux but does not tell
>>> the caller of that system call whether a specific action might be permitted,
>>> what information does LSM ID value tell?
>> It tells the caller that the LSM is active on the system. That's it.
>> Just like reading /sys/kernel/security/lsm.
> Then, the
>
> The calling application can use this list determine what LSM
> specific actions it might take. That might include choosing an
> output format, determining required privilege or bypassing
> security module specific behavior.
>
> part should be removed from the description. Instead, the description should
> emphasis that the numeric LSM ID values are there in order to allow
> identifying what LSM modules are active without interpreting string LSM names
> in /sys/kernel/security/lsm .

No, I stand by the description as written.

>>> What does "choosing an output format", "determining required privilege",
>>> "bypassing security module specific behavior" mean? How can they choose
>>> meaningful output format, determine appropriate privilege, bypass security
>>> module specific behavior (if the only information the caller can know from
>>> the LSM ID value were what LSMs are enabled) ?
>> If Smack and SELinux not enabled on the system there is no point in
>> setting up a netlabel configuration, for example.
> I know nothing about netlabel. But can userspace make such assumption from
> this granularity? For example, if TOMOYO and AppArmor start supporting
> netlabel configuration, your assumption
>
> If Smack and SELinux not enabled on the system there is no point in
> setting up a netlabel configuration
>
> becomes no longer true.

You are correct. If I thought there was the remotest possibility
of that, I wouldn't have used it as an example.

If Smack isn't enabled there's no point in running the Smack testsuite.
If SELinux isn't enabled there's no point in running the SELinux testsuite.
If SELinux isn't enabled there's no reason to invoke SELinux userspace features.

> It is also possible that a new LSM implementation
> obtains an LSM ID for that LSM, and starts supporting netlabel configuration
> some timer later. I don't know if we come to the point where we can enable
> SELinux and Smack at the same time. But when it becomes possible to enable
> SELinux and Smack at the same time, the userspace might have already written
> code based on current situation that netlabel configuration are exclusive. Then,
> someday starting to return both LSM ID for SELinux and LSM ID for Smack might
> confuse userspace.

Believe me, that's way down on the list of userspace issues with using Smack and
SELinux together in a meaningful way.

>
> Thus, it might be safe to determine what LSMs are active from the LSM ID values
> returned from the system call. But it is not safe to assume what functionality
> is active (e.g. netlabel configuration is interpreted) from the LSM ID values
> returned from the system call.

That is correct.

> If you want to allow userspace to make such assumption using the system call,
> the granularity the system call returns needs to be what access control mechanism
> (not only LSM modules but also eBPF-based access control mechanisms) hooks which
> LSM hooks. More information than interpreting string LSM names in
> /sys/kernel/security/lsm will be needed.

That's already true. You have to understand all sorts of factors, like SELinux policy,
Smack rule sets and AppArmor policy definitions. Then there's netfilter configuration.


>>>> I wish we could stop people from saying "BPF-based LSM". BPF is the LSM. The
>>>> eBPF programs that implement a "policy" are NOT a LSM. There needs to be a
>>>> name for that, but LSM is not it.
>>> My understanding is that "BPF is not an LSM module but infrastructure for using
>>> LSM hooks".
>> As BPF is implemented as a LSM I suggest your statement is incorrect.
> Enumerating only LSM modules are not useful. "ID for access control mechanisms
> that can be controlled via LSM hooks" will be needed.

The BPF program set is no different from the SELinux policy in this regard.
It's completely user defined, and out of the kernel's control. I seriously
doubt that you want an ID for "SELinux reference policy 4.3.2 with Infiniband"



>>> The patch description lacks relationship between LSM ID value and data.
>>> In other words, why LSM ID values are needed (and are useful for doing what).
>>> If the only information the caller can know from the LSM ID value were
>>> what LSMs are enabled (i.e. the content of /sys/kernel/security/lsm ), why
>>> bother to use LSM ID values? (Yes, integer comparison is faster than string
>>> comparison. But that is not enough justification for not allowing out-of-tree
>>> LSMs and eBPF-based access control mechanisms to have stable LSM ID values.)
>>>
> I conclude that LSM ID values are pointless and are NOT needed.

OK.

2024-03-12 10:16:51

by Dmitry V. Levin

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

Hi,

On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
[...]
> --- a/security/lsm_syscalls.c
> +++ b/security/lsm_syscalls.c
> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
> {
> return security_getselfattr(attr, ctx, size, flags);
> }
> +
> +/**
> + * sys_lsm_list_modules - Return a list of the active security modules
> + * @ids: the LSM module ids
> + * @size: pointer to size of @ids, updated on return
> + * @flags: reserved for future use, must be zero
> + *
> + * Returns a list of the active LSM ids. On success this function
> + * returns the number of @ids array elements. This value may be zero
> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
> + u32, flags)

I'm sorry but the size of userspace size_t is different from the kernel one
on 32-bit compat architectures.

Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ...)
now. Other two added lsm syscalls also have this issue.


--
ldv

2024-03-12 13:26:51

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <[email protected]> wrote:
> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
> [...]
> > --- a/security/lsm_syscalls.c
> > +++ b/security/lsm_syscalls.c
> > @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
> > {
> > return security_getselfattr(attr, ctx, size, flags);
> > }
> > +
> > +/**
> > + * sys_lsm_list_modules - Return a list of the active security modules
> > + * @ids: the LSM module ids
> > + * @size: pointer to size of @ids, updated on return
> > + * @flags: reserved for future use, must be zero
> > + *
> > + * Returns a list of the active LSM ids. On success this function
> > + * returns the number of @ids array elements. This value may be zero
> > + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
> > + u32, flags)
>
> I'm sorry but the size of userspace size_t is different from the kernel one
> on 32-bit compat architectures.

D'oh, yes, thanks for pointing that out. It would have been nice to
have caught that before v6.8 was released, but I guess it's better
than later.

> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ...)
> now. Other two added lsm syscalls also have this issue.

Considering that Linux v6.8, and by extension these syscalls, are only
a few days old, I think I'd rather see us just modify the syscalls and
avoid the compat baggage. I'm going to be shocked if anyone has
shifted to using the new syscalls yet, and even if they have (!!),
moving from a "size_t" type to a "u64" should be mostly transparent
for the majority of native 64-bit systems. Those running the absolute
latest kernels on 32-bit systems with custom or bleeding edge
userspace *may* see a slight hiccup, but I think that user count is in
the single digits, if not zero.

Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
compat shim if we can.

Casey, do you have time to put together a patch for this (you should
fix the call chains below the syscalls too)? If not, please let me
know and I'll get a patch out ASAP.

Thanks all.

--
paul-moore.com

2024-03-12 16:46:54

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On 3/12/2024 6:25 AM, Paul Moore wrote:
> On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <[email protected]> wrote:
>> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
>> [...]
>>> --- a/security/lsm_syscalls.c
>>> +++ b/security/lsm_syscalls.c
>>> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
>>> {
>>> return security_getselfattr(attr, ctx, size, flags);
>>> }
>>> +
>>> +/**
>>> + * sys_lsm_list_modules - Return a list of the active security modules
>>> + * @ids: the LSM module ids
>>> + * @size: pointer to size of @ids, updated on return
>>> + * @flags: reserved for future use, must be zero
>>> + *
>>> + * Returns a list of the active LSM ids. On success this function
>>> + * returns the number of @ids array elements. This value may be zero
>>> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
>>> + u32, flags)
>> I'm sorry but the size of userspace size_t is different from the kernel one
>> on 32-bit compat architectures.
> D'oh, yes, thanks for pointing that out. It would have been nice to
> have caught that before v6.8 was released, but I guess it's better
> than later.
>
>> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ...)
>> now. Other two added lsm syscalls also have this issue.
> Considering that Linux v6.8, and by extension these syscalls, are only
> a few days old, I think I'd rather see us just modify the syscalls and
> avoid the compat baggage. I'm going to be shocked if anyone has
> shifted to using the new syscalls yet, and even if they have (!!),
> moving from a "size_t" type to a "u64" should be mostly transparent
> for the majority of native 64-bit systems. Those running the absolute
> latest kernels on 32-bit systems with custom or bleeding edge
> userspace *may* see a slight hiccup, but I think that user count is in
> the single digits, if not zero.
>
> Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
> compat shim if we can.
>
> Casey, do you have time to put together a patch for this (you should
> fix the call chains below the syscalls too)? If not, please let me
> know and I'll get a patch out ASAP.

Grumble. Yes, I'll get right on it.

>
> Thanks all.
>

2024-03-12 17:09:44

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On Tue, Mar 12, 2024 at 11:27 AM Casey Schaufler <[email protected]> wrote:
> On 3/12/2024 6:25 AM, Paul Moore wrote:
> > On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <[email protected]> wrote:
> >> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
> >> [...]
> >>> --- a/security/lsm_syscalls.c
> >>> +++ b/security/lsm_syscalls.c
> >>> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
> >>> {
> >>> return security_getselfattr(attr, ctx, size, flags);
> >>> }
> >>> +
> >>> +/**
> >>> + * sys_lsm_list_modules - Return a list of the active security modules
> >>> + * @ids: the LSM module ids
> >>> + * @size: pointer to size of @ids, updated on return
> >>> + * @flags: reserved for future use, must be zero
> >>> + *
> >>> + * Returns a list of the active LSM ids. On success this function
> >>> + * returns the number of @ids array elements. This value may be zero
> >>> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
> >>> + u32, flags)
> >> I'm sorry but the size of userspace size_t is different from the kernel one
> >> on 32-bit compat architectures.
> > D'oh, yes, thanks for pointing that out. It would have been nice to
> > have caught that before v6.8 was released, but I guess it's better
> > than later.
> >
> >> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ..)
> >> now. Other two added lsm syscalls also have this issue.
> > Considering that Linux v6.8, and by extension these syscalls, are only
> > a few days old, I think I'd rather see us just modify the syscalls and
> > avoid the compat baggage. I'm going to be shocked if anyone has
> > shifted to using the new syscalls yet, and even if they have (!!),
> > moving from a "size_t" type to a "u64" should be mostly transparent
> > for the majority of native 64-bit systems. Those running the absolute
> > latest kernels on 32-bit systems with custom or bleeding edge
> > userspace *may* see a slight hiccup, but I think that user count is in
> > the single digits, if not zero.
> >
> > Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
> > compat shim if we can.
> >
> > Casey, do you have time to put together a patch for this (you should
> > fix the call chains below the syscalls too)? If not, please let me
> > know and I'll get a patch out ASAP.
>
> Grumble. Yes, I'll get right on it.

Great, thanks Casey.

--
paul-moore.com

2024-03-12 18:11:51

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On Tue, Mar 12, 2024 at 1:44 PM Casey Schaufler <casey@schaufler-cacom> wrote:
> On 3/12/2024 10:06 AM, Paul Moore wrote:
> > On Tue, Mar 12, 2024 at 11:27 AM Casey Schaufler <[email protected]> wrote:
> >> On 3/12/2024 6:25 AM, Paul Moore wrote:
> >>> On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <[email protected]> wrote:
> >>>> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
> >>>> [...]
> >>>>> --- a/security/lsm_syscalls.c
> >>>>> +++ b/security/lsm_syscalls.c
> >>>>> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
> >>>>> {
> >>>>> return security_getselfattr(attr, ctx, size, flags);
> >>>>> }
> >>>>> +
> >>>>> +/**
> >>>>> + * sys_lsm_list_modules - Return a list of the active security modules
> >>>>> + * @ids: the LSM module ids
> >>>>> + * @size: pointer to size of @ids, updated on return
> >>>>> + * @flags: reserved for future use, must be zero
> >>>>> + *
> >>>>> + * Returns a list of the active LSM ids. On success this function
> >>>>> + * returns the number of @ids array elements. This value may be zero
> >>>>> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
> >>>>> + u32, flags)
> >>>> I'm sorry but the size of userspace size_t is different from the kernel one
> >>>> on 32-bit compat architectures.
> >>> D'oh, yes, thanks for pointing that out. It would have been nice to
> >>> have caught that before v6.8 was released, but I guess it's better
> >>> than later.
> >>>
> >>>> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ..)
> >>>> now. Other two added lsm syscalls also have this issue.
> >>> Considering that Linux v6.8, and by extension these syscalls, are only
> >>> a few days old, I think I'd rather see us just modify the syscalls and
> >>> avoid the compat baggage. I'm going to be shocked if anyone has
> >>> shifted to using the new syscalls yet, and even if they have (!!),
> >>> moving from a "size_t" type to a "u64" should be mostly transparent
> >>> for the majority of native 64-bit systems. Those running the absolute
> >>> latest kernels on 32-bit systems with custom or bleeding edge
> >>> userspace *may* see a slight hiccup, but I think that user count is in
> >>> the single digits, if not zero.
> >>>
> >>> Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
> >>> compat shim if we can.
> >>>
> >>> Casey, do you have time to put together a patch for this (you should
> >>> fix the call chains below the syscalls too)? If not, please let me
> >>> know and I'll get a patch out ASAP.
> >> Grumble. Yes, I'll get right on it.
> > Great, thanks Casey.
>
> Look like lsm_get_self_attr() needs the same change. lsm_set_self_attr()
> doesn't, need it, but I'm tempted to change it as well for consistency.
> Thoughts?

I'd suggest changing both.

--
paul-moore.com

2024-03-12 18:28:36

by Dmitry V. Levin

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On Tue, Mar 12, 2024 at 10:44:38AM -0700, Casey Schaufler wrote:
> On 3/12/2024 10:06 AM, Paul Moore wrote:
> > On Tue, Mar 12, 2024 at 11:27 AM Casey Schaufler <[email protected]> wrote:
> >> On 3/12/2024 6:25 AM, Paul Moore wrote:
> >>> On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <[email protected]> wrote:
> >>>> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
> >>>> [...]
> >>>>> --- a/security/lsm_syscalls.c
> >>>>> +++ b/security/lsm_syscalls.c
> >>>>> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
> >>>>> {
> >>>>> return security_getselfattr(attr, ctx, size, flags);
> >>>>> }
> >>>>> +
> >>>>> +/**
> >>>>> + * sys_lsm_list_modules - Return a list of the active security modules
> >>>>> + * @ids: the LSM module ids
> >>>>> + * @size: pointer to size of @ids, updated on return
> >>>>> + * @flags: reserved for future use, must be zero
> >>>>> + *
> >>>>> + * Returns a list of the active LSM ids. On success this function
> >>>>> + * returns the number of @ids array elements. This value may be zero
> >>>>> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
> >>>>> + u32, flags)
> >>>> I'm sorry but the size of userspace size_t is different from the kernel one
> >>>> on 32-bit compat architectures.
> >>> D'oh, yes, thanks for pointing that out. It would have been nice to
> >>> have caught that before v6.8 was released, but I guess it's better
> >>> than later.
> >>>
> >>>> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ..)
> >>>> now. Other two added lsm syscalls also have this issue.
> >>> Considering that Linux v6.8, and by extension these syscalls, are only
> >>> a few days old, I think I'd rather see us just modify the syscalls and
> >>> avoid the compat baggage. I'm going to be shocked if anyone has
> >>> shifted to using the new syscalls yet, and even if they have (!!),
> >>> moving from a "size_t" type to a "u64" should be mostly transparent
> >>> for the majority of native 64-bit systems. Those running the absolute
> >>> latest kernels on 32-bit systems with custom or bleeding edge
> >>> userspace *may* see a slight hiccup, but I think that user count is in
> >>> the single digits, if not zero.
> >>>
> >>> Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
> >>> compat shim if we can.
> >>>
> >>> Casey, do you have time to put together a patch for this (you should
> >>> fix the call chains below the syscalls too)? If not, please let me
> >>> know and I'll get a patch out ASAP.
> >> Grumble. Yes, I'll get right on it.
> > Great, thanks Casey.
>
> Look like lsm_get_self_attr() needs the same change. lsm_set_self_attr()
> doesn't, need it, but I'm tempted to change it as well for consistency.
> Thoughts?

As lsm_get_self_attr() has the same issue, it needs the same treatment.

lsm_set_self_attr() could be left unchanged. In fact, changing the type
of syscall arguments from size_t to an explicit 64-bit type would be
problematic because 32-bit syscalls cannot have 64-bit arguments.


--
ldv

2024-03-12 20:11:22

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On 3/12/2024 10:06 AM, Paul Moore wrote:
> On Tue, Mar 12, 2024 at 11:27 AM Casey Schaufler <[email protected]> wrote:
>> On 3/12/2024 6:25 AM, Paul Moore wrote:
>>> On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <[email protected]> wrote:
>>>> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
>>>> [...]
>>>>> --- a/security/lsm_syscalls.c
>>>>> +++ b/security/lsm_syscalls.c
>>>>> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
>>>>> {
>>>>> return security_getselfattr(attr, ctx, size, flags);
>>>>> }
>>>>> +
>>>>> +/**
>>>>> + * sys_lsm_list_modules - Return a list of the active security modules
>>>>> + * @ids: the LSM module ids
>>>>> + * @size: pointer to size of @ids, updated on return
>>>>> + * @flags: reserved for future use, must be zero
>>>>> + *
>>>>> + * Returns a list of the active LSM ids. On success this function
>>>>> + * returns the number of @ids array elements. This value may be zero
>>>>> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
>>>>> + u32, flags)
>>>> I'm sorry but the size of userspace size_t is different from the kernel one
>>>> on 32-bit compat architectures.
>>> D'oh, yes, thanks for pointing that out. It would have been nice to
>>> have caught that before v6.8 was released, but I guess it's better
>>> than later.
>>>
>>>> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ..)
>>>> now. Other two added lsm syscalls also have this issue.
>>> Considering that Linux v6.8, and by extension these syscalls, are only
>>> a few days old, I think I'd rather see us just modify the syscalls and
>>> avoid the compat baggage. I'm going to be shocked if anyone has
>>> shifted to using the new syscalls yet, and even if they have (!!),
>>> moving from a "size_t" type to a "u64" should be mostly transparent
>>> for the majority of native 64-bit systems. Those running the absolute
>>> latest kernels on 32-bit systems with custom or bleeding edge
>>> userspace *may* see a slight hiccup, but I think that user count is in
>>> the single digits, if not zero.
>>>
>>> Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
>>> compat shim if we can.
>>>
>>> Casey, do you have time to put together a patch for this (you should
>>> fix the call chains below the syscalls too)? If not, please let me
>>> know and I'll get a patch out ASAP.
>> Grumble. Yes, I'll get right on it.
> Great, thanks Casey.

Look like lsm_get_self_attr() needs the same change. lsm_set_self_attr()
doesn't, need it, but I'm tempted to change it as well for consistency.
Thoughts?

>

2024-03-12 21:50:19

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On Tue, Mar 12, 2024 at 08:28:20PM +0200, Dmitry V. Levin wrote:
> On Tue, Mar 12, 2024 at 10:44:38AM -0700, Casey Schaufler wrote:
> > On 3/12/2024 10:06 AM, Paul Moore wrote:
> > > On Tue, Mar 12, 2024 at 11:27 AM Casey Schaufler <[email protected]> wrote:
> > >> On 3/12/2024 6:25 AM, Paul Moore wrote:
> > >>> On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <[email protected]> wrote:
> > >>>> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
> > >>>> [...]
> > >>>>> --- a/security/lsm_syscalls.c
> > >>>>> +++ b/security/lsm_syscalls.c
> > >>>>> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
> > >>>>> {
> > >>>>> return security_getselfattr(attr, ctx, size, flags);
> > >>>>> }
> > >>>>> +
> > >>>>> +/**
> > >>>>> + * sys_lsm_list_modules - Return a list of the active security modules
> > >>>>> + * @ids: the LSM module ids
> > >>>>> + * @size: pointer to size of @ids, updated on return
> > >>>>> + * @flags: reserved for future use, must be zero
> > >>>>> + *
> > >>>>> + * Returns a list of the active LSM ids. On success this function
> > >>>>> + * returns the number of @ids array elements. This value may be zero
> > >>>>> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
> > >>>>> + u32, flags)
> > >>>> I'm sorry but the size of userspace size_t is different from the kernel one
> > >>>> on 32-bit compat architectures.
> > >>> D'oh, yes, thanks for pointing that out. It would have been nice to
> > >>> have caught that before v6.8 was released, but I guess it's better
> > >>> than later.
> > >>>
> > >>>> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ..)
> > >>>> now. Other two added lsm syscalls also have this issue.
> > >>> Considering that Linux v6.8, and by extension these syscalls, are only
> > >>> a few days old, I think I'd rather see us just modify the syscalls and
> > >>> avoid the compat baggage. I'm going to be shocked if anyone has
> > >>> shifted to using the new syscalls yet, and even if they have (!!),
> > >>> moving from a "size_t" type to a "u64" should be mostly transparent
> > >>> for the majority of native 64-bit systems. Those running the absolute
> > >>> latest kernels on 32-bit systems with custom or bleeding edge
> > >>> userspace *may* see a slight hiccup, but I think that user count is in
> > >>> the single digits, if not zero.
> > >>>
> > >>> Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
> > >>> compat shim if we can.
> > >>>
> > >>> Casey, do you have time to put together a patch for this (you should
> > >>> fix the call chains below the syscalls too)? If not, please let me
> > >>> know and I'll get a patch out ASAP.
> > >> Grumble. Yes, I'll get right on it.
> > > Great, thanks Casey.
> >
> > Look like lsm_get_self_attr() needs the same change. lsm_set_self_attr()
> > doesn't, need it, but I'm tempted to change it as well for consistency.
> > Thoughts?
>
> As lsm_get_self_attr() has the same issue, it needs the same treatment.
>
> lsm_set_self_attr() could be left unchanged. In fact, changing the type
> of syscall arguments from size_t to an explicit 64-bit type would be
> problematic because 32-bit syscalls cannot have 64-bit arguments.

Using u32 should be totally fine for both. Nearly ever kernel internal
limits sizes to INT_MAX anyway. :)

--
Kees Cook

2024-03-12 22:06:59

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On Tue, Mar 12, 2024 at 2:28 PM Dmitry V. Levin <[email protected]> wrote:
> On Tue, Mar 12, 2024 at 10:44:38AM -0700, Casey Schaufler wrote:
> > On 3/12/2024 10:06 AM, Paul Moore wrote:
> > > On Tue, Mar 12, 2024 at 11:27 AM Casey Schaufler <[email protected]> wrote:
> > >> On 3/12/2024 6:25 AM, Paul Moore wrote:
> > >>> On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <ldv@straceio> wrote:
> > >>>> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
> > >>>> [...]
> > >>>>> --- a/security/lsm_syscalls.c
> > >>>>> +++ b/security/lsm_syscalls.c
> > >>>>> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
> > >>>>> {
> > >>>>> return security_getselfattr(attr, ctx, size, flags);
> > >>>>> }
> > >>>>> +
> > >>>>> +/**
> > >>>>> + * sys_lsm_list_modules - Return a list of the active security modules
> > >>>>> + * @ids: the LSM module ids
> > >>>>> + * @size: pointer to size of @ids, updated on return
> > >>>>> + * @flags: reserved for future use, must be zero
> > >>>>> + *
> > >>>>> + * Returns a list of the active LSM ids. On success this function
> > >>>>> + * returns the number of @ids array elements. This value may be zero
> > >>>>> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
> > >>>>> + u32, flags)
> > >>>> I'm sorry but the size of userspace size_t is different from the kernel one
> > >>>> on 32-bit compat architectures.
> > >>> D'oh, yes, thanks for pointing that out. It would have been nice to
> > >>> have caught that before v6.8 was released, but I guess it's better
> > >>> than later.
> > >>>
> > >>>> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ..)
> > >>>> now. Other two added lsm syscalls also have this issue.
> > >>> Considering that Linux v6.8, and by extension these syscalls, are only
> > >>> a few days old, I think I'd rather see us just modify the syscalls and
> > >>> avoid the compat baggage. I'm going to be shocked if anyone has
> > >>> shifted to using the new syscalls yet, and even if they have (!!),
> > >>> moving from a "size_t" type to a "u64" should be mostly transparent
> > >>> for the majority of native 64-bit systems. Those running the absolute
> > >>> latest kernels on 32-bit systems with custom or bleeding edge
> > >>> userspace *may* see a slight hiccup, but I think that user count is in
> > >>> the single digits, if not zero.
> > >>>
> > >>> Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
> > >>> compat shim if we can.
> > >>>
> > >>> Casey, do you have time to put together a patch for this (you should
> > >>> fix the call chains below the syscalls too)? If not, please let me
> > >>> know and I'll get a patch out ASAP.
> > >> Grumble. Yes, I'll get right on it.
> > > Great, thanks Casey.
> >
> > Look like lsm_get_self_attr() needs the same change. lsm_set_self_attr()
> > doesn't, need it, but I'm tempted to change it as well for consistency.
> > Thoughts?
>
> As lsm_get_self_attr() has the same issue, it needs the same treatment.
>
> lsm_set_self_attr() could be left unchanged. In fact, changing the type
> of syscall arguments from size_t to an explicit 64-bit type would be
> problematic because 32-bit syscalls cannot have 64-bit arguments.

You might as well convert all of the size_t parameters, pointers or
otherwise, in the three syscalls to u32 Casey.

I'd leave the lsm_ctx struct alone, the individual fields are nicely
aligned on both 32-bit and 64-bit systems and worst case we have some
unused bits.

The 64-bit LSM IDs are perhaps a bit more problematic, but I believe
we are okay and I don't think we should change that. With one of the
primary motivations behind the LSM syscalls being support for multiple
LSMs, I suspect any future LSMs will use an array of LSM IDs (the u64
is hidden behind a pointer) as we do in lsm_list_modules() or the LSM
ID will be part of a larger struct like lsm_ctx.

--
paul-moore.com

2024-03-12 23:17:39

by Paul Moore

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On Tue, Mar 12, 2024 at 6:18 PM Casey Schaufler <casey@schaufler-cacom> wrote:
> On 3/12/2024 3:06 PM, Paul Moore wrote:
> > On Tue, Mar 12, 2024 at 2:28 PM Dmitry V. Levin <[email protected]> wrote:
> >> On Tue, Mar 12, 2024 at 10:44:38AM -0700, Casey Schaufler wrote:
> >>> On 3/12/2024 10:06 AM, Paul Moore wrote:
> >>>> On Tue, Mar 12, 2024 at 11:27 AM Casey Schaufler <[email protected]> wrote:
> >>>>> On 3/12/2024 6:25 AM, Paul Moore wrote:
> >>>>>> On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <[email protected]> wrote:
> >>>>>>> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
> >>>>>>> [...]
> >>>>>>>> --- a/security/lsm_syscalls.c
> >>>>>>>> +++ b/security/lsm_syscalls.c
> >>>>>>>> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
> >>>>>>>> {
> >>>>>>>> return security_getselfattr(attr, ctx, size, flags);
> >>>>>>>> }
> >>>>>>>> +
> >>>>>>>> +/**
> >>>>>>>> + * sys_lsm_list_modules - Return a list of the active security modules
> >>>>>>>> + * @ids: the LSM module ids
> >>>>>>>> + * @size: pointer to size of @ids, updated on return
> >>>>>>>> + * @flags: reserved for future use, must be zero
> >>>>>>>> + *
> >>>>>>>> + * Returns a list of the active LSM ids. On success this function
> >>>>>>>> + * returns the number of @ids array elements. This value may be zero
> >>>>>>>> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
> >>>>>>>> + u32, flags)
> >>>>>>> I'm sorry but the size of userspace size_t is different from the kernel one
> >>>>>>> on 32-bit compat architectures.
> >>>>>> D'oh, yes, thanks for pointing that out. It would have been nice to
> >>>>>> have caught that before v6.8 was released, but I guess it's better
> >>>>>> than later.
> >>>>>>
> >>>>>>> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ..)
> >>>>>>> now. Other two added lsm syscalls also have this issue.
> >>>>>> Considering that Linux v6.8, and by extension these syscalls, are only
> >>>>>> a few days old, I think I'd rather see us just modify the syscalls and
> >>>>>> avoid the compat baggage. I'm going to be shocked if anyone has
> >>>>>> shifted to using the new syscalls yet, and even if they have (!!),
> >>>>>> moving from a "size_t" type to a "u64" should be mostly transparent
> >>>>>> for the majority of native 64-bit systems. Those running the absolute
> >>>>>> latest kernels on 32-bit systems with custom or bleeding edge
> >>>>>> userspace *may* see a slight hiccup, but I think that user count is in
> >>>>>> the single digits, if not zero.
> >>>>>>
> >>>>>> Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
> >>>>>> compat shim if we can.
> >>>>>>
> >>>>>> Casey, do you have time to put together a patch for this (you should
> >>>>>> fix the call chains below the syscalls too)? If not, please let me
> >>>>>> know and I'll get a patch out ASAP.
> >>>>> Grumble. Yes, I'll get right on it.
> >>>> Great, thanks Casey.
> >>> Look like lsm_get_self_attr() needs the same change. lsm_set_self_attr()
> >>> doesn't, need it, but I'm tempted to change it as well for consistency.
> >>> Thoughts?
> >> As lsm_get_self_attr() has the same issue, it needs the same treatment.
> >>
> >> lsm_set_self_attr() could be left unchanged. In fact, changing the type
> >> of syscall arguments from size_t to an explicit 64-bit type would be
> >> problematic because 32-bit syscalls cannot have 64-bit arguments.
> > You might as well convert all of the size_t parameters, pointers or
> > otherwise, in the three syscalls to u32 Casey.
>
> Well, nuts. So much for that coin flip. V2 coming real soon.

Yeah, sorry for the false starts today ...

--
paul-moore.com

2024-03-12 23:25:14

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On 3/12/2024 3:06 PM, Paul Moore wrote:
> On Tue, Mar 12, 2024 at 2:28 PM Dmitry V. Levin <[email protected]> wrote:
>> On Tue, Mar 12, 2024 at 10:44:38AM -0700, Casey Schaufler wrote:
>>> On 3/12/2024 10:06 AM, Paul Moore wrote:
>>>> On Tue, Mar 12, 2024 at 11:27 AM Casey Schaufler <[email protected]> wrote:
>>>>> On 3/12/2024 6:25 AM, Paul Moore wrote:
>>>>>> On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <[email protected]> wrote:
>>>>>>> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
>>>>>>> [...]
>>>>>>>> --- a/security/lsm_syscalls.c
>>>>>>>> +++ b/security/lsm_syscalls.c
>>>>>>>> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
>>>>>>>> {
>>>>>>>> return security_getselfattr(attr, ctx, size, flags);
>>>>>>>> }
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * sys_lsm_list_modules - Return a list of the active security modules
>>>>>>>> + * @ids: the LSM module ids
>>>>>>>> + * @size: pointer to size of @ids, updated on return
>>>>>>>> + * @flags: reserved for future use, must be zero
>>>>>>>> + *
>>>>>>>> + * Returns a list of the active LSM ids. On success this function
>>>>>>>> + * returns the number of @ids array elements. This value may be zero
>>>>>>>> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
>>>>>>>> + u32, flags)
>>>>>>> I'm sorry but the size of userspace size_t is different from the kernel one
>>>>>>> on 32-bit compat architectures.
>>>>>> D'oh, yes, thanks for pointing that out. It would have been nice to
>>>>>> have caught that before v6.8 was released, but I guess it's better
>>>>>> than later.
>>>>>>
>>>>>>> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ..)
>>>>>>> now. Other two added lsm syscalls also have this issue.
>>>>>> Considering that Linux v6.8, and by extension these syscalls, are only
>>>>>> a few days old, I think I'd rather see us just modify the syscalls and
>>>>>> avoid the compat baggage. I'm going to be shocked if anyone has
>>>>>> shifted to using the new syscalls yet, and even if they have (!!),
>>>>>> moving from a "size_t" type to a "u64" should be mostly transparent
>>>>>> for the majority of native 64-bit systems. Those running the absolute
>>>>>> latest kernels on 32-bit systems with custom or bleeding edge
>>>>>> userspace *may* see a slight hiccup, but I think that user count is in
>>>>>> the single digits, if not zero.
>>>>>>
>>>>>> Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
>>>>>> compat shim if we can.
>>>>>>
>>>>>> Casey, do you have time to put together a patch for this (you should
>>>>>> fix the call chains below the syscalls too)? If not, please let me
>>>>>> know and I'll get a patch out ASAP.
>>>>> Grumble. Yes, I'll get right on it.
>>>> Great, thanks Casey.
>>> Look like lsm_get_self_attr() needs the same change. lsm_set_self_attr()
>>> doesn't, need it, but I'm tempted to change it as well for consistency.
>>> Thoughts?
>> As lsm_get_self_attr() has the same issue, it needs the same treatment.
>>
>> lsm_set_self_attr() could be left unchanged. In fact, changing the type
>> of syscall arguments from size_t to an explicit 64-bit type would be
>> problematic because 32-bit syscalls cannot have 64-bit arguments.
> You might as well convert all of the size_t parameters, pointers or
> otherwise, in the three syscalls to u32 Casey.

Well, nuts. So much for that coin flip. V2 coming real soon.


2024-03-13 02:15:13

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v15 05/11] LSM: Create lsm_list_modules system call

On 3/12/2024 2:50 PM, Kees Cook wrote:
> On Tue, Mar 12, 2024 at 08:28:20PM +0200, Dmitry V. Levin wrote:
>> On Tue, Mar 12, 2024 at 10:44:38AM -0700, Casey Schaufler wrote:
>>> On 3/12/2024 10:06 AM, Paul Moore wrote:
>>>> On Tue, Mar 12, 2024 at 11:27 AM Casey Schaufler <[email protected]> wrote:
>>>>> On 3/12/2024 6:25 AM, Paul Moore wrote:
>>>>>> On Tue, Mar 12, 2024 at 6:16 AM Dmitry V. Levin <[email protected]> wrote:
>>>>>>> On Tue, Sep 12, 2023 at 01:56:50PM -0700, Casey Schaufler wrote:
>>>>>>> [...]
>>>>>>>> --- a/security/lsm_syscalls.c
>>>>>>>> +++ b/security/lsm_syscalls.c
>>>>>>>> @@ -55,3 +55,42 @@ SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
>>>>>>>> {
>>>>>>>> return security_getselfattr(attr, ctx, size, flags);
>>>>>>>> }
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * sys_lsm_list_modules - Return a list of the active security modules
>>>>>>>> + * @ids: the LSM module ids
>>>>>>>> + * @size: pointer to size of @ids, updated on return
>>>>>>>> + * @flags: reserved for future use, must be zero
>>>>>>>> + *
>>>>>>>> + * Returns a list of the active LSM ids. On success this function
>>>>>>>> + * returns the number of @ids array elements. This value may be zero
>>>>>>>> + * if there are no LSMs active. 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_list_modules, u64 __user *, ids, size_t __user *, size,
>>>>>>>> + u32, flags)
>>>>>>> I'm sorry but the size of userspace size_t is different from the kernel one
>>>>>>> on 32-bit compat architectures.
>>>>>> D'oh, yes, thanks for pointing that out. It would have been nice to
>>>>>> have caught that before v6.8 was released, but I guess it's better
>>>>>> than later.
>>>>>>
>>>>>>> Looks like there has to be a COMPAT_SYSCALL_DEFINE3(lsm_list_modules, ..)
>>>>>>> now. Other two added lsm syscalls also have this issue.
>>>>>> Considering that Linux v6.8, and by extension these syscalls, are only
>>>>>> a few days old, I think I'd rather see us just modify the syscalls and
>>>>>> avoid the compat baggage. I'm going to be shocked if anyone has
>>>>>> shifted to using the new syscalls yet, and even if they have (!!),
>>>>>> moving from a "size_t" type to a "u64" should be mostly transparent
>>>>>> for the majority of native 64-bit systems. Those running the absolute
>>>>>> latest kernels on 32-bit systems with custom or bleeding edge
>>>>>> userspace *may* see a slight hiccup, but I think that user count is in
>>>>>> the single digits, if not zero.
>>>>>>
>>>>>> Let's fix this quickly with /size_t/u64/ in v6.8.1 and avoid the
>>>>>> compat shim if we can.
>>>>>>
>>>>>> Casey, do you have time to put together a patch for this (you should
>>>>>> fix the call chains below the syscalls too)? If not, please let me
>>>>>> know and I'll get a patch out ASAP.
>>>>> Grumble. Yes, I'll get right on it.
>>>> Great, thanks Casey.
>>> Look like lsm_get_self_attr() needs the same change. lsm_set_self_attr()
>>> doesn't, need it, but I'm tempted to change it as well for consistency.
>>> Thoughts?
>> As lsm_get_self_attr() has the same issue, it needs the same treatment.
>>
>> lsm_set_self_attr() could be left unchanged. In fact, changing the type
>> of syscall arguments from size_t to an explicit 64-bit type would be
>> problematic because 32-bit syscalls cannot have 64-bit arguments.
> Using u32 should be totally fine for both. Nearly ever kernel internal
> limits sizes to INT_MAX anyway. :)

My initial patch changes the size_t pointers in lsm_list_modules()
and lsm_get_self_attr() to __u64 pointers. I could change them to
__u32 pointers and include lsm_set_self_attr() as well. Let's see
who screams how loudly.