All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v13 00/11] LSM: Three basic syscalls
       [not found] <20230802174435.11928-1-casey.ref@schaufler-ca.com>
@ 2023-08-02 17:44 ` Casey Schaufler
  2023-08-02 17:44   ` [PATCH v13 01/11] LSM: Identify modules by more than name Casey Schaufler
                     ` (11 more replies)
  0 siblings, 12 replies; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic

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#lsm-syscalls-6.4-v12

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                       | 118 +++++++++
 security/safesetid/lsm.c                      |   9 +-
 security/security.c                           | 226 ++++++++++++++++-
 security/selinux/hooks.c                      | 145 +++++++++--
 security/smack/smack_lsm.c                    | 102 +++++++-
 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/Makefile          |  19 ++
 tools/testing/selftests/lsm/common.c          |  81 ++++++
 tools/testing/selftests/lsm/common.h          |  33 +++
 tools/testing/selftests/lsm/config            |   3 +
 .../selftests/lsm/lsm_get_self_attr_test.c    | 240 ++++++++++++++++++
 .../selftests/lsm/lsm_list_modules_test.c     | 140 ++++++++++
 .../selftests/lsm/lsm_set_self_attr_test.c    |  74 ++++++
 62 files changed, 1624 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/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


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v13 01/11] LSM: Identify modules by more than name
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-10 15:54     ` John Johansen
  2023-08-18 18:00     ` Mickaël Salaün
  2023-08-02 17:44   ` [PATCH v13 02/11] LSM: Maintain a table of LSM attribute data Casey Schaufler
                     ` (10 subsequent siblings)
  11 siblings, 2 replies; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic

Create a struct lsm_id to contain identifying information
about Linux Security Modules (LSMs). At inception this contains
the name of the module, an identifier associated with the security
module and an integer member "attrs" which identifies the API
related data associated with each security module. The initial set
of features maps to information that has traditionaly been available
in /proc/self/attr. They are documented in a new userspace-api file.
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 <casey@schaufler-ca.com>
Cc: linux-security-module <linux-security-module@vger.kernel.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Reviewed-by: Mickael Salaun <mic@digikod.net>
---
 Documentation/userspace-api/index.rst |  1 +
 MAINTAINERS                           |  1 +
 include/linux/lsm_hooks.h             | 16 ++++++++++++++--
 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 +++++++-
 19 files changed, 107 insertions(+), 21 deletions(-)

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 d516295978a4..aca4db11dd02 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19156,6 +19156,7 @@ L:	linux-security-module@vger.kernel.org (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 ab2b2fafa4a4..5f7d8caacc00 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -41,6 +41,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.
@@ -49,7 +61,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;
 
 /*
@@ -84,7 +96,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/security/apparmor/lsm.c b/security/apparmor/lsm.c
index c9463bd0307d..bfd049c3fd22 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),
 };
 
+static 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..57b9ffd53c98 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),
 };
 
+static 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 ab5742ab4362..4e94075656e9 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
 
+static 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 ebae964f7cc9..9fbc90f0e65b 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);
 }
 
+static 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..f2bdbd55aa2b 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),
 };
 
+static 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..1ba564f097f5 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;
 }
 
+static 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 b720424ca37d..feaae09581dc 100644
--- a/security/security.c
+++ b/security/security.c
@@ -512,17 +512,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);
 	}
 
@@ -531,7 +531,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__);
 	}
 }
@@ -3778,7 +3778,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);
 	}
@@ -3803,7 +3803,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 d06e350fedee..c900813fc8f7 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"
@@ -6929,6 +6930,11 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
 }
 #endif /* CONFIG_IO_URING */
 
+static 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,
@@ -7250,7 +7256,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 6e270cf3fd30..f3e4b26c8a87 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"
@@ -4871,6 +4872,11 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
 	.lbs_superblock = sizeof(struct superblock_smack),
 };
 
+static 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),
@@ -5077,7 +5083,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..9dc8e64890bc 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)
 	}
 }
 
+static 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..49dc52b454ef 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;
 }
 
+static 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


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v13 02/11] LSM: Maintain a table of LSM attribute data
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
  2023-08-02 17:44   ` [PATCH v13 01/11] LSM: Identify modules by more than name Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-10 15:54     ` John Johansen
  2023-08-18 17:58     ` Mickaël Salaün
  2023-08-02 17:44   ` [PATCH v13 03/11] proc: Use lsmids instead of lsm names for attrs Casey Schaufler
                     ` (9 subsequent siblings)
  11 siblings, 2 replies; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic

As LSMs are registered add their lsm_id pointers to a table.
This will be used later for attribute reporting.

Determine the number of possible security modules based on
their respective CONFIG options. This allows the number to be
known at build time. This allows data structures and tables
to use the constant.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
---
 include/linux/security.h |  2 ++
 security/security.c      | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index 32828502f09e..a20a4ceda6d9 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -138,6 +138,8 @@ enum lockdown_reason {
 };
 
 extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
+extern u32 lsm_active_cnt;
+extern const struct lsm_id *lsm_idlist[];
 
 /* These functions are in security/commoncap.c */
 extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
diff --git a/security/security.c b/security/security.c
index feaae09581dc..87b70a55a028 100644
--- a/security/security.c
+++ b/security/security.c
@@ -36,6 +36,25 @@
 /* How many LSMs were built into the kernel? */
 #define LSM_COUNT (__end_lsm_info - __start_lsm_info)
 
+/*
+ * How many LSMs are built into the kernel as determined at
+ * build time. Used to determine fixed array sizes.
+ * The capability module is accounted for by CONFIG_SECURITY
+ */
+#define LSM_CONFIG_COUNT ( \
+	(IS_ENABLED(CONFIG_SECURITY) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_SECURITY_SELINUX) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_SECURITY_SMACK) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_SECURITY_TOMOYO) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_SECURITY_APPARMOR) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_SECURITY_YAMA) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_SECURITY_LOADPIN) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \
+	(IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0))
+
 /*
  * These are descriptions of the reasons that can be passed to the
  * security_locked_down() LSM hook. Placing this array here allows
@@ -245,6 +264,12 @@ static void __init initialize_lsm(struct lsm_info *lsm)
 	}
 }
 
+/*
+ * Current index to use while initializing the lsm id list.
+ */
+u32 lsm_active_cnt __ro_after_init;
+const struct lsm_id *lsm_idlist[LSM_CONFIG_COUNT] __ro_after_init;
+
 /* Populate ordered LSMs list from comma-separated LSM name list. */
 static void __init ordered_lsm_parse(const char *order, const char *origin)
 {
@@ -521,6 +546,18 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
 {
 	int i;
 
+	/*
+	 * A security module may call security_add_hooks() more
+	 * than once during initialization, and LSM initialization
+	 * is serialized. Landlock is one such case.
+	 * Look at the previous entry, if there is one, for duplication.
+	 */
+	if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
+		if (lsm_active_cnt >= LSM_CONFIG_COUNT)
+			panic("%s Too many LSMs registered.\n", __func__);
+		lsm_idlist[lsm_active_cnt++] = lsmid;
+	}
+
 	for (i = 0; i < count; i++) {
 		hooks[i].lsmid = lsmid;
 		hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v13 03/11] proc: Use lsmids instead of lsm names for attrs
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
  2023-08-02 17:44   ` [PATCH v13 01/11] LSM: Identify modules by more than name Casey Schaufler
  2023-08-02 17:44   ` [PATCH v13 02/11] LSM: Maintain a table of LSM attribute data Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-10 15:54     ` John Johansen
  2023-08-02 17:44   ` [PATCH v13 04/11] LSM: syscalls for current process attributes Casey Schaufler
                     ` (8 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic,
	linux-fsdevel

Use the LSM ID number instead of the LSM name to identify which
security module's attibute data should be shown in /proc/self/attr.
The security_[gs]etprocattr() functions have been changed to expect
the LSM ID. The change from a string comparison to an integer comparison
in these functions will provide a minor performance improvement.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Reviewed-by: Mickael Salaun <mic@digikod.net>
Cc: linux-fsdevel@vger.kernel.org
---
 fs/proc/base.c           | 29 +++++++++++++++--------------
 fs/proc/internal.h       |  2 +-
 include/linux/security.h | 11 +++++------
 security/security.c      | 15 +++++++--------
 4 files changed, 28 insertions(+), 29 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 05452c3b9872..f999bb5c497b 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -97,6 +97,7 @@
 #include <linux/resctrl.h>
 #include <linux/cn_proc.h>
 #include <linux/ksm.h>
+#include <uapi/linux/lsm.h>
 #include <trace/events/oom.h>
 #include "internal.h"
 #include "fd.h"
@@ -146,10 +147,10 @@ struct pid_entry {
 	NOD(NAME, (S_IFREG|(MODE)),			\
 		NULL, &proc_single_file_operations,	\
 		{ .proc_show = show } )
-#define ATTR(LSM, NAME, MODE)				\
+#define ATTR(LSMID, NAME, MODE)				\
 	NOD(NAME, (S_IFREG|(MODE)),			\
 		NULL, &proc_pid_attr_operations,	\
-		{ .lsm = LSM })
+		{ .lsmid = LSMID })
 
 /*
  * Count the number of hardlinks for the pid_entry table, excluding the .
@@ -2730,7 +2731,7 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
 	if (!task)
 		return -ESRCH;
 
-	length = security_getprocattr(task, PROC_I(inode)->op.lsm,
+	length = security_getprocattr(task, PROC_I(inode)->op.lsmid,
 				      file->f_path.dentry->d_name.name,
 				      &p);
 	put_task_struct(task);
@@ -2788,7 +2789,7 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
 	if (rv < 0)
 		goto out_free;
 
-	rv = security_setprocattr(PROC_I(inode)->op.lsm,
+	rv = security_setprocattr(PROC_I(inode)->op.lsmid,
 				  file->f_path.dentry->d_name.name, page,
 				  count);
 	mutex_unlock(&current->signal->cred_guard_mutex);
@@ -2837,27 +2838,27 @@ static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \
 
 #ifdef CONFIG_SECURITY_SMACK
 static const struct pid_entry smack_attr_dir_stuff[] = {
-	ATTR("smack", "current",	0666),
+	ATTR(LSM_ID_SMACK, "current",	0666),
 };
 LSM_DIR_OPS(smack);
 #endif
 
 #ifdef CONFIG_SECURITY_APPARMOR
 static const struct pid_entry apparmor_attr_dir_stuff[] = {
-	ATTR("apparmor", "current",	0666),
-	ATTR("apparmor", "prev",	0444),
-	ATTR("apparmor", "exec",	0666),
+	ATTR(LSM_ID_APPARMOR, "current",	0666),
+	ATTR(LSM_ID_APPARMOR, "prev",		0444),
+	ATTR(LSM_ID_APPARMOR, "exec",		0666),
 };
 LSM_DIR_OPS(apparmor);
 #endif
 
 static const struct pid_entry attr_dir_stuff[] = {
-	ATTR(NULL, "current",		0666),
-	ATTR(NULL, "prev",		0444),
-	ATTR(NULL, "exec",		0666),
-	ATTR(NULL, "fscreate",		0666),
-	ATTR(NULL, "keycreate",		0666),
-	ATTR(NULL, "sockcreate",	0666),
+	ATTR(LSM_ID_UNDEF, "current",	0666),
+	ATTR(LSM_ID_UNDEF, "prev",		0444),
+	ATTR(LSM_ID_UNDEF, "exec",		0666),
+	ATTR(LSM_ID_UNDEF, "fscreate",	0666),
+	ATTR(LSM_ID_UNDEF, "keycreate",	0666),
+	ATTR(LSM_ID_UNDEF, "sockcreate",	0666),
 #ifdef CONFIG_SECURITY_SMACK
 	DIR("smack",			0555,
 	    proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 9dda7e54b2d0..a889d9ef9584 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -92,7 +92,7 @@ union proc_op {
 	int (*proc_show)(struct seq_file *m,
 		struct pid_namespace *ns, struct pid *pid,
 		struct task_struct *task);
-	const char *lsm;
+	int lsmid;
 };
 
 struct proc_inode {
diff --git a/include/linux/security.h b/include/linux/security.h
index a20a4ceda6d9..b5fd3f7f4cd3 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -470,10 +470,9 @@ 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_getprocattr(struct task_struct *p, const char *lsm, const char *name,
+int security_getprocattr(struct task_struct *p, int lsmid, const char *name,
 			 char **value);
-int security_setprocattr(const char *lsm, const char *name, void *value,
-			 size_t size);
+int security_setprocattr(int lsmid, const char *name, void *value, size_t size);
 int security_netlink_send(struct sock *sk, struct sk_buff *skb);
 int security_ismaclabel(const char *name);
 int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
@@ -1332,14 +1331,14 @@ static inline void security_d_instantiate(struct dentry *dentry,
 					  struct inode *inode)
 { }
 
-static inline int security_getprocattr(struct task_struct *p, const char *lsm,
+static inline int security_getprocattr(struct task_struct *p, int lsmid,
 				       const char *name, char **value)
 {
 	return -EINVAL;
 }
 
-static inline int security_setprocattr(const char *lsm, char *name,
-				       void *value, size_t size)
+static inline int security_setprocattr(int lsmid, char *name, void *value,
+				       size_t size)
 {
 	return -EINVAL;
 }
diff --git a/security/security.c b/security/security.c
index 87b70a55a028..5e9cd548dd95 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3801,7 +3801,7 @@ EXPORT_SYMBOL(security_d_instantiate);
 /**
  * security_getprocattr() - Read an attribute for a task
  * @p: the task
- * @lsm: LSM name
+ * @lsmid: LSM identification
  * @name: attribute name
  * @value: attribute value
  *
@@ -3809,13 +3809,13 @@ EXPORT_SYMBOL(security_d_instantiate);
  *
  * Return: Returns the length of @value on success, a negative value otherwise.
  */
-int security_getprocattr(struct task_struct *p, const char *lsm,
-			 const char *name, char **value)
+int security_getprocattr(struct task_struct *p, int lsmid, const char *name,
+			 char **value)
 {
 	struct security_hook_list *hp;
 
 	hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
-		if (lsm != NULL && strcmp(lsm, hp->lsmid->name))
+		if (lsmid != 0 && lsmid != hp->lsmid->id)
 			continue;
 		return hp->hook.getprocattr(p, name, value);
 	}
@@ -3824,7 +3824,7 @@ int security_getprocattr(struct task_struct *p, const char *lsm,
 
 /**
  * security_setprocattr() - Set an attribute for a task
- * @lsm: LSM name
+ * @lsmid: LSM identification
  * @name: attribute name
  * @value: attribute value
  * @size: attribute value size
@@ -3834,13 +3834,12 @@ int security_getprocattr(struct task_struct *p, const char *lsm,
  *
  * Return: Returns bytes written on success, a negative value otherwise.
  */
-int security_setprocattr(const char *lsm, const char *name, void *value,
-			 size_t size)
+int security_setprocattr(int lsmid, const char *name, void *value, size_t size)
 {
 	struct security_hook_list *hp;
 
 	hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
-		if (lsm != NULL && strcmp(lsm, hp->lsmid->name))
+		if (lsmid != 0 && lsmid != hp->lsmid->id)
 			continue;
 		return hp->hook.setprocattr(name, value, size);
 	}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v13 04/11] LSM: syscalls for current process attributes
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
                     ` (2 preceding siblings ...)
  2023-08-02 17:44   ` [PATCH v13 03/11] proc: Use lsmids instead of lsm names for attrs Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-10 15:55     ` John Johansen
                       ` (3 more replies)
  2023-08-02 17:44   ` [PATCH v13 05/11] LSM: Create lsm_list_modules system call Casey Schaufler
                     ` (7 subsequent siblings)
  11 siblings, 4 replies; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic

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 <casey@schaufler-ca.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
---
 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            |  90 ++++++++++++++++++++
 kernel/sys_ni.c                     |   2 +
 security/Makefile                   |   1 +
 security/lsm_syscalls.c             |  55 ++++++++++++
 security/security.c                 | 125 ++++++++++++++++++++++++++++
 10 files changed, 372 insertions(+)
 create mode 100644 Documentation/userspace-api/lsm.rst
 create mode 100644 include/uapi/linux/lsm.h
 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 <casey@schaufler-ca.com>
+.. 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 7308a1a7599b..6dffac59dfe3 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -261,6 +261,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 5f7d8caacc00..0662e5c2cd06 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 b5fd3f7f4cd3..0d882cb221f4 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
@@ -470,6 +471,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);
@@ -1331,6 +1336,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 03e3d0121d5e..a3938850752a 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;
@@ -953,6 +954,10 @@ asmlinkage long sys_set_mempolicy_home_node(unsigned long start, unsigned long l
 asmlinkage long sys_cachestat(unsigned int fd,
 		struct cachestat_range __user *cstat_range,
 		struct cachestat __user *cstat, 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
new file mode 100644
index 000000000000..eeda59a77c02
--- /dev/null
+++ b/include/uapi/linux/lsm.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Linux Security Modules (LSM) - User space API
+ *
+ * Copyright (C) 2022 Casey Schaufler <casey@schaufler-ca.com>
+ * Copyright (C) 2022 Intel Corporation
+ */
+
+#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)
+ *
+ * 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
+
+/*
+ * 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 781de7cc6a4e..8b96cd01b485 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..ee3881159241
--- /dev/null
+++ b/security/lsm_syscalls.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * System calls implementing the Linux Security Module API.
+ *
+ *  Copyright (C) 2022 Casey Schaufler <casey@schaufler-ca.com>
+ *  Copyright (C) 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 set
+ * @ctx: the LSM contexts
+ * @size: size of @ctx, updated on return
+ * @flags: reserved for future use
+ *
+ * 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 5e9cd548dd95..cde7f3a13e7c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3798,6 +3798,131 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
 }
 EXPORT_SYMBOL(security_d_instantiate);
 
+/**
+ * security_getselfattr - Read an LSM attribute of the current process.
+ * @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
+ *
+ * A NULL value for @ctx 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 *ctx,
+			 size_t __user *size, u32 flags)
+{
+	struct security_hook_list *hp;
+	struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
+	u8 __user *base = (u8 __user *)ctx;
+	size_t total = 0;
+	size_t entrysize;
+	size_t left;
+	bool toobig = 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 & LSM_FLAG_SINGLE) == LSM_FLAG_SINGLE) {
+		if (!ctx)
+			return -EINVAL;
+		if (copy_struct_from_user(&lctx, sizeof(lctx), ctx, left))
+			return -EFAULT;
+		if (lctx.id == LSM_ID_UNDEF)
+			return -EINVAL;
+	} else if (flags) {
+		return -EINVAL;
+	}
+
+	hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
+		if (lctx.id != LSM_ID_UNDEF && lctx.id != hp->lsmid->id)
+			continue;
+		entrysize = left;
+		if (base)
+			ctx = (struct lsm_ctx __user *)(base + total);
+		rc = hp->hook.getselfattr(attr, ctx, &entrysize, flags);
+		if (rc == -EOPNOTSUPP) {
+			rc = 0;
+			continue;
+		}
+		if (rc == -E2BIG) {
+			toobig = true;
+			left = 0;
+			continue;
+		}
+		if (rc < 0)
+			return rc;
+
+		left -= entrysize;
+		total += entrysize;
+		count += rc;
+	}
+	if (put_user(total, size))
+		return -EFAULT;
+	if (toobig)
+		return -E2BIG;
+	if (count == 0)
+		return LSM_RET_DEFAULT(getselfattr);
+	return count;
+}
+
+/**
+ * security_setselfattr - Set an LSM attribute on the current process.
+ * @attr: which attribute to set
+ * @ctx: 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 @ctx.
+ *
+ * Returns 0 on success, -EINVAL if the input is inconsistent, -EFAULT
+ * if the user buffer is inaccessible or an LSM specific failure.
+ */
+int security_setselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
+			 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(*ctx))
+		return -EINVAL;
+
+	lctx = kmalloc(size, GFP_KERNEL);
+	if (lctx == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(&lctx, ctx, size))
+		return -EFAULT;
+
+	if (size < lctx->len || size < lctx->ctx_len + sizeof(ctx) ||
+	    lctx->len < lctx->ctx_len + sizeof(ctx))
+		return -EINVAL;
+
+	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;
+		}
+
+	kfree(lctx);
+	return rc;
+}
+
 /**
  * security_getprocattr() - Read an attribute for a task
  * @p: the task
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v13 05/11] LSM: Create lsm_list_modules system call
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
                     ` (3 preceding siblings ...)
  2023-08-02 17:44   ` [PATCH v13 04/11] LSM: syscalls for current process attributes Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-10 15:55     ` John Johansen
  2023-08-02 17:44   ` [PATCH v13 06/11] LSM: wireup Linux Security Module syscalls Casey Schaufler
                     ` (6 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic

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 <casey@schaufler-ca.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
---
 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 a3938850752a..4e1596b5c300 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -958,6 +958,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 8b96cd01b485..7663ef16c07e 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 ee3881159241..f03f2d17ab49 100644
--- a/security/lsm_syscalls.c
+++ b/security/lsm_syscalls.c
@@ -53,3 +53,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


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v13 06/11] LSM: wireup Linux Security Module syscalls
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
                     ` (4 preceding siblings ...)
  2023-08-02 17:44   ` [PATCH v13 05/11] LSM: Create lsm_list_modules system call Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-10 15:56     ` John Johansen
  2023-08-02 17:44   ` [PATCH v13 07/11] LSM: Helpers for attribute names and filling lsm_ctx Casey Schaufler
                     ` (5 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic,
	Geert Uytterhoeven, Arnd Bergmann

Wireup lsm_get_self_attr, lsm_set_self_attr and lsm_list_modules
system calls.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Cc: linux-api@vger.kernel.org
---
 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 +++
 include/uapi/asm-generic/unistd.h                   | 9 ++++++++-
 tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl | 3 +++
 tools/perf/arch/powerpc/entry/syscalls/syscall.tbl  | 3 +++
 tools/perf/arch/s390/entry/syscalls/syscall.tbl     | 3 +++
 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl   | 3 +++
 23 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl
index 1f13995d00d7..bb00aecf1dc4 100644
--- a/arch/alpha/kernel/syscalls/syscall.tbl
+++ b/arch/alpha/kernel/syscalls/syscall.tbl
@@ -491,3 +491,6 @@
 559	common  futex_waitv                     sys_futex_waitv
 560	common	set_mempolicy_home_node		sys_ni_syscall
 561	common	cachestat			sys_cachestat
+562	common	lsm_get_self_attr		sys_lsm_get_self_attr
+563	common	lsm_set_self_attr		sys_lsm_set_self_attr
+564	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl
index 8ebed8a13874..a148e71905a7 100644
--- a/arch/arm/tools/syscall.tbl
+++ b/arch/arm/tools/syscall.tbl
@@ -465,3 +465,6 @@
 449	common	futex_waitv			sys_futex_waitv
 450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	common	cachestat			sys_cachestat
+452	common	lsm_get_self_attr		sys_lsm_get_self_attr
+453	common	lsm_set_self_attr		sys_lsm_set_self_attr
+454	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 64a514f90131..63a8a9c4abc1 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -39,7 +39,7 @@
 #define __ARM_NR_compat_set_tls		(__ARM_NR_COMPAT_BASE + 5)
 #define __ARM_NR_COMPAT_END		(__ARM_NR_COMPAT_BASE + 0x800)
 
-#define __NR_compat_syscalls		452
+#define __NR_compat_syscalls		455
 #endif
 
 #define __ARCH_WANT_SYS_CLONE
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h
index d952a28463e0..df214b7ec5dd 100644
--- a/arch/arm64/include/asm/unistd32.h
+++ b/arch/arm64/include/asm/unistd32.h
@@ -909,6 +909,12 @@ __SYSCALL(__NR_futex_waitv, sys_futex_waitv)
 __SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)
 #define __NR_cachestat 451
 __SYSCALL(__NR_cachestat, sys_cachestat)
+#define __NR_lsm_get_self_attr 452
+__SYSCALL(__NR_lsm_get_self_attr, sys_lsm_get_self_attr)
+#define __NR_lsm_set_self_attr 453
+__SYSCALL(__NR_lsm_set_self_attr, sys_lsm_set_self_attr)
+#define __NR_lsm_list_modules 454
+__SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules)
 
 /*
  * Please add new compat syscalls above this comment and update
diff --git a/arch/ia64/kernel/syscalls/syscall.tbl b/arch/ia64/kernel/syscalls/syscall.tbl
index f8c74ffeeefb..1b53f9d28514 100644
--- a/arch/ia64/kernel/syscalls/syscall.tbl
+++ b/arch/ia64/kernel/syscalls/syscall.tbl
@@ -372,3 +372,6 @@
 449	common  futex_waitv                     sys_futex_waitv
 450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	common	cachestat			sys_cachestat
+452	common	lsm_get_self_attr		sys_lsm_get_self_attr
+453	common	lsm_set_self_attr		sys_lsm_set_self_attr
+454	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl
index 4f504783371f..f7a91d458f0c 100644
--- a/arch/m68k/kernel/syscalls/syscall.tbl
+++ b/arch/m68k/kernel/syscalls/syscall.tbl
@@ -451,3 +451,6 @@
 449	common  futex_waitv                     sys_futex_waitv
 450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	common	cachestat			sys_cachestat
+452	common	lsm_get_self_attr		sys_lsm_get_self_attr
+453	common	lsm_set_self_attr		sys_lsm_set_self_attr
+454	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl
index 858d22bf275c..2b24b19a9bec 100644
--- a/arch/microblaze/kernel/syscalls/syscall.tbl
+++ b/arch/microblaze/kernel/syscalls/syscall.tbl
@@ -457,3 +457,6 @@
 449	common  futex_waitv                     sys_futex_waitv
 450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	common	cachestat			sys_cachestat
+452	common	lsm_get_self_attr		sys_lsm_get_self_attr
+453	common	lsm_set_self_attr		sys_lsm_set_self_attr
+454	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl
index 1976317d4e8b..0ff4072ed024 100644
--- a/arch/mips/kernel/syscalls/syscall_n32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n32.tbl
@@ -390,3 +390,6 @@
 449	n32	futex_waitv			sys_futex_waitv
 450	n32	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	n32	cachestat			sys_cachestat
+452	n32	lsm_get_self_attr		sys_lsm_get_self_attr
+453	n32	lsm_set_self_attr		sys_lsm_set_self_attr
+454	n32	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl b/arch/mips/kernel/syscalls/syscall_n64.tbl
index cfda2511badf..9c38818dd9f9 100644
--- a/arch/mips/kernel/syscalls/syscall_n64.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n64.tbl
@@ -366,3 +366,6 @@
 449	n64	futex_waitv			sys_futex_waitv
 450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	n64	cachestat			sys_cachestat
+452	n64	lsm_get_self_attr		sys_lsm_get_self_attr
+453	n64	lsm_set_self_attr		sys_lsm_set_self_attr
+454	n64	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl b/arch/mips/kernel/syscalls/syscall_o32.tbl
index 7692234c3768..a07e1ba91511 100644
--- a/arch/mips/kernel/syscalls/syscall_o32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_o32.tbl
@@ -439,3 +439,6 @@
 449	o32	futex_waitv			sys_futex_waitv
 450	o32	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	o32	cachestat			sys_cachestat
+452	o32	lsm_get_self_attr		sys_lsm_get_self_attr
+453	032	lsm_set_self_attr		sys_lsm_set_self_attr
+454	o32	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl
index a0a9145b6dd4..36cc0130ee1d 100644
--- a/arch/parisc/kernel/syscalls/syscall.tbl
+++ b/arch/parisc/kernel/syscalls/syscall.tbl
@@ -450,3 +450,6 @@
 449	common	futex_waitv			sys_futex_waitv
 450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	common	cachestat			sys_cachestat
+452	common	lsm_get_self_attr		sys_lsm_get_self_attr
+453	common	lsm_set_self_attr		sys_lsm_set_self_attr
+454	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl
index 8c0b08b7a80e..fe2ba9e8a413 100644
--- a/arch/powerpc/kernel/syscalls/syscall.tbl
+++ b/arch/powerpc/kernel/syscalls/syscall.tbl
@@ -538,3 +538,6 @@
 449	common  futex_waitv                     sys_futex_waitv
 450 	nospu	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	common	cachestat			sys_cachestat
+452	common	lsm_get_self_attr		sys_lsm_get_self_attr
+453	common	lsm_set_self_attr		sys_lsm_set_self_attr
+454	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl
index a6935af2235c..fe3fc23697b0 100644
--- a/arch/s390/kernel/syscalls/syscall.tbl
+++ b/arch/s390/kernel/syscalls/syscall.tbl
@@ -454,3 +454,6 @@
 449  common	futex_waitv		sys_futex_waitv			sys_futex_waitv
 450  common	set_mempolicy_home_node	sys_set_mempolicy_home_node	sys_set_mempolicy_home_node
 451  common	cachestat		sys_cachestat			sys_cachestat
+452  common	lsm_get_self_attr	sys_lsm_get_self_attr		sys_lsm_get_self_attr
+453  common	lsm_set_self_attr	sys_lsm_set_self_attr		sys_lsm_set_self_attr
+454  common	lsm_list_modules	sys_lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl
index 97377e8c5025..319968dccde9 100644
--- a/arch/sh/kernel/syscalls/syscall.tbl
+++ b/arch/sh/kernel/syscalls/syscall.tbl
@@ -454,3 +454,6 @@
 449	common  futex_waitv                     sys_futex_waitv
 450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	common	cachestat			sys_cachestat
+452	common	lsm_get_self_attr		sys_lsm_get_self_attr
+453	common	lsm_set_self_attr		sys_lsm_set_self_attr
+454	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl
index faa835f3c54a..9ca3fb4c05de 100644
--- a/arch/sparc/kernel/syscalls/syscall.tbl
+++ b/arch/sparc/kernel/syscalls/syscall.tbl
@@ -497,3 +497,6 @@
 449	common  futex_waitv                     sys_futex_waitv
 450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	common	cachestat			sys_cachestat
+452	common	lsm_get_self_attr		sys_lsm_get_self_attr
+453	common	lsm_set_self_attr		sys_lsm_set_self_attr
+454	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index bc0a3c941b35..4caa3c415528 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -456,3 +456,6 @@
 449	i386	futex_waitv		sys_futex_waitv
 450	i386	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	i386	cachestat		sys_cachestat
+452	i386	lsm_get_self_attr	sys_lsm_get_self_attr
+453	i386	lsm_set_self_attr	sys_lsm_set_self_attr
+454	i386	lsm_list_modules	sys_lsm_list_modules
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 227538b0ce80..c5f85f93e80b 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -373,6 +373,9 @@
 449	common	futex_waitv		sys_futex_waitv
 450	common	set_mempolicy_home_node	sys_set_mempolicy_home_node
 451	common	cachestat		sys_cachestat
+452	common	lsm_get_self_attr	sys_lsm_get_self_attr
+453	common	lsm_set_self_attr	sys_lsm_set_self_attr
+454	common	lsm_list_modules	sys_lsm_list_modules
 
 #
 # Due to a historical design error, certain syscalls are numbered differently
diff --git a/arch/xtensa/kernel/syscalls/syscall.tbl b/arch/xtensa/kernel/syscalls/syscall.tbl
index 2b69c3c035b6..509379512c27 100644
--- a/arch/xtensa/kernel/syscalls/syscall.tbl
+++ b/arch/xtensa/kernel/syscalls/syscall.tbl
@@ -422,3 +422,6 @@
 449	common  futex_waitv                     sys_futex_waitv
 450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	common	cachestat			sys_cachestat
+452	common	lsm_get_self_attr		sys_lsm_get_self_attr
+453	common	lsm_set_self_attr		sys_lsm_set_self_attr
+454	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index fd6c1cb585db..b5588efc0933 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -820,8 +820,15 @@ __SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)
 #define __NR_cachestat 451
 __SYSCALL(__NR_cachestat, sys_cachestat)
 
+#define __NR_lsm_get_self_attr 452
+__SYSCALL(__NR_lsm_get_self_attr, sys_lsm_get_self_attr)
+#define __NR_lsm_set_self_attr 453
+__SYSCALL(__NR_lsm_set_self_attr, sys_lsm_set_self_attr)
+#define __NR_lsm_list_modules 454
+__SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules)
+
 #undef __NR_syscalls
-#define __NR_syscalls 452
+#define __NR_syscalls 455
 
 /*
  * 32 bit systems traditionally used different
diff --git a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl
index cfda2511badf..9c38818dd9f9 100644
--- a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl
+++ b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl
@@ -366,3 +366,6 @@
 449	n64	futex_waitv			sys_futex_waitv
 450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	n64	cachestat			sys_cachestat
+452	n64	lsm_get_self_attr		sys_lsm_get_self_attr
+453	n64	lsm_set_self_attr		sys_lsm_set_self_attr
+454	n64	lsm_list_modules		sys_lsm_list_modules
diff --git a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
index 8c0b08b7a80e..fe2ba9e8a413 100644
--- a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
+++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
@@ -538,3 +538,6 @@
 449	common  futex_waitv                     sys_futex_waitv
 450 	nospu	set_mempolicy_home_node		sys_set_mempolicy_home_node
 451	common	cachestat			sys_cachestat
+452	common	lsm_get_self_attr		sys_lsm_get_self_attr
+453	common	lsm_set_self_attr		sys_lsm_set_self_attr
+454	common	lsm_list_modules		sys_lsm_list_modules
diff --git a/tools/perf/arch/s390/entry/syscalls/syscall.tbl b/tools/perf/arch/s390/entry/syscalls/syscall.tbl
index a6935af2235c..a18e9d7cf92b 100644
--- a/tools/perf/arch/s390/entry/syscalls/syscall.tbl
+++ b/tools/perf/arch/s390/entry/syscalls/syscall.tbl
@@ -454,3 +454,6 @@
 449  common	futex_waitv		sys_futex_waitv			sys_futex_waitv
 450  common	set_mempolicy_home_node	sys_set_mempolicy_home_node	sys_set_mempolicy_home_node
 451  common	cachestat		sys_cachestat			sys_cachestat
+452  common	lsm_get_self_attr	sys_lsm_get_self_attr	sys_lsm_get_self_attr
+453  common	lsm_set_self_attr	sys_lsm_set_self_attr	sys_lsm_set_self_attr
+454  common	lsm_list_modules	sys_lsm_list_modules	sys_lsm_list_modules
diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
index 227538b0ce80..c5f85f93e80b 100644
--- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
@@ -373,6 +373,9 @@
 449	common	futex_waitv		sys_futex_waitv
 450	common	set_mempolicy_home_node	sys_set_mempolicy_home_node
 451	common	cachestat		sys_cachestat
+452	common	lsm_get_self_attr	sys_lsm_get_self_attr
+453	common	lsm_set_self_attr	sys_lsm_set_self_attr
+454	common	lsm_list_modules	sys_lsm_list_modules
 
 #
 # Due to a historical design error, certain syscalls are numbered differently
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v13 07/11] LSM: Helpers for attribute names and filling lsm_ctx
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
                     ` (5 preceding siblings ...)
  2023-08-02 17:44   ` [PATCH v13 06/11] LSM: wireup Linux Security Module syscalls Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-10 15:57     ` John Johansen
  2023-08-02 17:44   ` [PATCH v13 08/11] Smack: implement setselfattr and getselfattr hooks Casey Schaufler
                     ` (4 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic

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 <casey@schaufler-ca.com>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
---
 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 0d882cb221f4..817cf28dbf8a 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;
@@ -263,6 +264,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);
@@ -488,6 +490,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)
@@ -505,6 +509,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)
 {
 }
@@ -1408,6 +1417,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 f03f2d17ab49..bc22f05e2d8c 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 cde7f3a13e7c..f1038686ebd0 100644
--- a/security/security.c
+++ b/security/security.c
@@ -770,6 +770,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


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v13 08/11] Smack: implement setselfattr and getselfattr hooks
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
                     ` (6 preceding siblings ...)
  2023-08-02 17:44   ` [PATCH v13 07/11] LSM: Helpers for attribute names and filling lsm_ctx Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-10 15:57     ` John Johansen
  2023-08-18 15:14     ` Serge Hallyn
  2023-08-02 17:44   ` [PATCH v13 09/11] AppArmor: Add selfattr hooks Casey Schaufler
                     ` (3 subsequent siblings)
  11 siblings, 2 replies; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic

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

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/smack/smack_lsm.c | 94 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 89 insertions(+), 5 deletions(-)

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index f3e4b26c8a87..71c773fff971 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3565,6 +3565,45 @@ 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 1, the number of attributes, on success, an error code otherwise.
+ */
+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
@@ -3594,8 +3633,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
  *
@@ -3604,7 +3643,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;
@@ -3618,8 +3657,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))
@@ -3658,6 +3697,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
@@ -4970,6 +5052,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


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v13 09/11] AppArmor: Add selfattr hooks
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
                     ` (7 preceding siblings ...)
  2023-08-02 17:44   ` [PATCH v13 08/11] Smack: implement setselfattr and getselfattr hooks Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-10 15:53     ` John Johansen
  2023-08-02 17:44   ` [PATCH v13 10/11] SELinux: " Casey Schaufler
                     ` (2 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic

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 <casey@schaufler-ca.com>
Cc: John Johansen <john.johansen@canonical.com>
---
 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 bfd049c3fd22..cd54e5ecb46a 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


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v13 10/11] SELinux: Add selfattr hooks
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
                     ` (8 preceding siblings ...)
  2023-08-02 17:44   ` [PATCH v13 09/11] AppArmor: Add selfattr hooks Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-10 22:24     ` Paul Moore
  2023-08-25 15:00     ` Mickaël Salaün
  2023-08-02 17:44   ` [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls Casey Schaufler
  2023-08-10 22:32   ` [PATCH v13 00/11] LSM: Three basic syscalls Paul Moore
  11 siblings, 2 replies; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic, selinux

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 <casey@schaufler-ca.com>
Cc: selinux@vger.kernel.org
Cc: Paul Moore <paul@paul-moore.com>
---
 security/selinux/hooks.c | 136 +++++++++++++++++++++++++++++++--------
 1 file changed, 109 insertions(+), 27 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c900813fc8f7..f66a28f672b2 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6265,8 +6265,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;
@@ -6283,20 +6283,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();
@@ -6314,7 +6321,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;
@@ -6325,23 +6332,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;
 
@@ -6353,13 +6368,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
@@ -6370,7 +6386,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;
@@ -6393,11 +6410,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);
@@ -6405,9 +6422,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;
@@ -6449,6 +6466,69 @@ 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;
+
+	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);
+	else
+		rc = 1;
+
+	kfree(value);
+	*size = total_len;
+	if (rc < 0)
+		return rc;
+	return 1;
+}
+
+static int selinux_setselfattr(unsigned int __user attr, struct lsm_ctx *ctx,
+			       size_t __user size, u32 __user 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);
@@ -7080,6 +7160,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


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
                     ` (9 preceding siblings ...)
  2023-08-02 17:44   ` [PATCH v13 10/11] SELinux: " Casey Schaufler
@ 2023-08-02 17:44   ` Casey Schaufler
  2023-08-18 15:53     ` Serge Hallyn
                       ` (2 more replies)
  2023-08-10 22:32   ` [PATCH v13 00/11] LSM: Three basic syscalls Paul Moore
  11 siblings, 3 replies; 38+ messages in thread
From: Casey Schaufler @ 2023-08-02 17:44 UTC (permalink / raw)
  To: casey, paul, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic

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 <casey@schaufler-ca.com>
---
 MAINTAINERS                                   |   1 +
 tools/testing/selftests/Makefile              |   1 +
 tools/testing/selftests/lsm/Makefile          |  19 ++
 tools/testing/selftests/lsm/common.c          |  81 ++++++
 tools/testing/selftests/lsm/common.h          |  33 +++
 tools/testing/selftests/lsm/config            |   3 +
 .../selftests/lsm/lsm_get_self_attr_test.c    | 240 ++++++++++++++++++
 .../selftests/lsm/lsm_list_modules_test.c     | 140 ++++++++++
 .../selftests/lsm/lsm_set_self_attr_test.c    |  74 ++++++
 9 files changed, 592 insertions(+)
 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 aca4db11dd02..c96f1c388d22 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19158,6 +19158,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 666b56f22a41..bde7c217b23f 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -39,6 +39,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/Makefile b/tools/testing/selftests/lsm/Makefile
new file mode 100644
index 000000000000..bae6c1e3bba4
--- /dev/null
+++ b/tools/testing/selftests/lsm/Makefile
@@ -0,0 +1,19 @@
+# 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
+
+$(TEST_GEN_PROGS):
+
+$(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..db9af9375238
--- /dev/null
+++ b/tools/testing/selftests/lsm/common.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Security Module infrastructure tests
+ *
+ * Copyright © 2023 Casey Schaufler <casey@schaufler-ca.com>
+ */
+
+#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);
+	if (len <= 0)
+		return -1;
+	close(fd);
+
+	path = strchr(value, '\n');
+	if (path)
+		*path = '\0';
+
+	return 0;
+}
+
+int read_sysfs_lsms(char *lsms, size_t size)
+{
+	FILE *fp;
+
+	fp = fopen("/sys/kernel/security/lsm", "r");
+	if (fp == NULL)
+		return -1;
+	if (fread(lsms, 1, size, fp) <= 0)
+		return -1;
+	fclose(fp);
+	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..cd0214a3eeb2
--- /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 <casey@schaufler-ca.com>
+ */
+
+#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..74c65aae1fcc
--- /dev/null
+++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Security Module infrastructure tests
+ * Tests for the lsm_get_self_attr system call
+ *
+ * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com>
+ */
+
+#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);
+	size_t size = page_size;
+
+	ASSERT_NE(NULL, ctx);
+	errno = 0;
+	ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, 1));
+	ASSERT_EQ(EINVAL, errno);
+	ASSERT_EQ(page_size, size);
+
+	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 = page_size;
+
+	ASSERT_NE(NULL, ctx);
+	errno = 0;
+	ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx,
+					&size, 0));
+	ASSERT_EQ(EOPNOTSUPP, 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 <casey@schaufler-ca.com>
+ */
+
+#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..d0f5b776c548
--- /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 <casey@schaufler-ca.com>
+ */
+
+#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


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 09/11] AppArmor: Add selfattr hooks
  2023-08-02 17:44   ` [PATCH v13 09/11] AppArmor: Add selfattr hooks Casey Schaufler
@ 2023-08-10 15:53     ` John Johansen
  0 siblings, 0 replies; 38+ messages in thread
From: John Johansen @ 2023-08-10 15:53 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module
  Cc: jmorris, serge, keescook, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, mic

On 8/2/23 10:44, Casey Schaufler wrote:
> 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 <casey@schaufler-ca.com>
> Cc: John Johansen <john.johansen@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>

> ---
>   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 bfd049c3fd22..cd54e5ecb46a 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;
>   }
>   
>   /**


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 01/11] LSM: Identify modules by more than name
  2023-08-02 17:44   ` [PATCH v13 01/11] LSM: Identify modules by more than name Casey Schaufler
@ 2023-08-10 15:54     ` John Johansen
  2023-08-18 18:00     ` Mickaël Salaün
  1 sibling, 0 replies; 38+ messages in thread
From: John Johansen @ 2023-08-10 15:54 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module
  Cc: jmorris, serge, keescook, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, mic

On 8/2/23 10:44, 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, an identifier associated with the security
> module and an integer member "attrs" which identifies the API
> related data associated with each security module. The initial set
> of features maps to information that has traditionaly been available
> in /proc/self/attr. They are documented in a new userspace-api file.
> 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 <casey@schaufler-ca.com>
> Cc: linux-security-module <linux-security-module@vger.kernel.org>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>
> Reviewed-by: Mickael Salaun <mic@digikod.net>
Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   Documentation/userspace-api/index.rst |  1 +
>   MAINTAINERS                           |  1 +
>   include/linux/lsm_hooks.h             | 16 ++++++++++++++--
>   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 +++++++-
>   19 files changed, 107 insertions(+), 21 deletions(-)
> 
> 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 d516295978a4..aca4db11dd02 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19156,6 +19156,7 @@ L:	linux-security-module@vger.kernel.org (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 ab2b2fafa4a4..5f7d8caacc00 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -41,6 +41,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.
> @@ -49,7 +61,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;
>   
>   /*
> @@ -84,7 +96,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/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index c9463bd0307d..bfd049c3fd22 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),
>   };
>   
> +static 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..57b9ffd53c98 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),
>   };
>   
> +static 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 ab5742ab4362..4e94075656e9 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
>   
> +static 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 ebae964f7cc9..9fbc90f0e65b 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);
>   }
>   
> +static 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..f2bdbd55aa2b 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),
>   };
>   
> +static 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..1ba564f097f5 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;
>   }
>   
> +static 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 b720424ca37d..feaae09581dc 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -512,17 +512,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);
>   	}
>   
> @@ -531,7 +531,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__);
>   	}
>   }
> @@ -3778,7 +3778,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);
>   	}
> @@ -3803,7 +3803,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 d06e350fedee..c900813fc8f7 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"
> @@ -6929,6 +6930,11 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
>   }
>   #endif /* CONFIG_IO_URING */
>   
> +static 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,
> @@ -7250,7 +7256,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 6e270cf3fd30..f3e4b26c8a87 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"
> @@ -4871,6 +4872,11 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
>   	.lbs_superblock = sizeof(struct superblock_smack),
>   };
>   
> +static 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),
> @@ -5077,7 +5083,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..9dc8e64890bc 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)
>   	}
>   }
>   
> +static 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..49dc52b454ef 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;
>   }
>   
> +static 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;
>   }


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 02/11] LSM: Maintain a table of LSM attribute data
  2023-08-02 17:44   ` [PATCH v13 02/11] LSM: Maintain a table of LSM attribute data Casey Schaufler
@ 2023-08-10 15:54     ` John Johansen
  2023-08-18 17:58     ` Mickaël Salaün
  1 sibling, 0 replies; 38+ messages in thread
From: John Johansen @ 2023-08-10 15:54 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module
  Cc: jmorris, serge, keescook, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, mic

On 8/2/23 10:44, Casey Schaufler wrote:
> As LSMs are registered add their lsm_id pointers to a table.
> This will be used later for attribute reporting.
> 
> Determine the number of possible security modules based on
> their respective CONFIG options. This allows the number to be
> known at build time. This allows data structures and tables
> to use the constant.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   include/linux/security.h |  2 ++
>   security/security.c      | 37 +++++++++++++++++++++++++++++++++++++
>   2 files changed, 39 insertions(+)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 32828502f09e..a20a4ceda6d9 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -138,6 +138,8 @@ enum lockdown_reason {
>   };
>   
>   extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
> +extern u32 lsm_active_cnt;
> +extern const struct lsm_id *lsm_idlist[];
>   
>   /* These functions are in security/commoncap.c */
>   extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
> diff --git a/security/security.c b/security/security.c
> index feaae09581dc..87b70a55a028 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -36,6 +36,25 @@
>   /* How many LSMs were built into the kernel? */
>   #define LSM_COUNT (__end_lsm_info - __start_lsm_info)
>   
> +/*
> + * How many LSMs are built into the kernel as determined at
> + * build time. Used to determine fixed array sizes.
> + * The capability module is accounted for by CONFIG_SECURITY
> + */
> +#define LSM_CONFIG_COUNT ( \
> +	(IS_ENABLED(CONFIG_SECURITY) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_SELINUX) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_SMACK) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_TOMOYO) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_APPARMOR) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_YAMA) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_LOADPIN) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0))
> +
>   /*
>    * These are descriptions of the reasons that can be passed to the
>    * security_locked_down() LSM hook. Placing this array here allows
> @@ -245,6 +264,12 @@ static void __init initialize_lsm(struct lsm_info *lsm)
>   	}
>   }
>   
> +/*
> + * Current index to use while initializing the lsm id list.
> + */
> +u32 lsm_active_cnt __ro_after_init;
> +const struct lsm_id *lsm_idlist[LSM_CONFIG_COUNT] __ro_after_init;
> +
>   /* Populate ordered LSMs list from comma-separated LSM name list. */
>   static void __init ordered_lsm_parse(const char *order, const char *origin)
>   {
> @@ -521,6 +546,18 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
>   {
>   	int i;
>   
> +	/*
> +	 * A security module may call security_add_hooks() more
> +	 * than once during initialization, and LSM initialization
> +	 * is serialized. Landlock is one such case.
> +	 * Look at the previous entry, if there is one, for duplication.
> +	 */
> +	if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
> +		if (lsm_active_cnt >= LSM_CONFIG_COUNT)
> +			panic("%s Too many LSMs registered.\n", __func__);
> +		lsm_idlist[lsm_active_cnt++] = lsmid;
> +	}
> +
>   	for (i = 0; i < count; i++) {
>   		hooks[i].lsmid = lsmid;
>   		hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 03/11] proc: Use lsmids instead of lsm names for attrs
  2023-08-02 17:44   ` [PATCH v13 03/11] proc: Use lsmids instead of lsm names for attrs Casey Schaufler
@ 2023-08-10 15:54     ` John Johansen
  0 siblings, 0 replies; 38+ messages in thread
From: John Johansen @ 2023-08-10 15:54 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module
  Cc: jmorris, serge, keescook, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, mic, linux-fsdevel

On 8/2/23 10:44, Casey Schaufler wrote:
> Use the LSM ID number instead of the LSM name to identify which
> security module's attibute data should be shown in /proc/self/attr.
> The security_[gs]etprocattr() functions have been changed to expect
> the LSM ID. The change from a string comparison to an integer comparison
> in these functions will provide a minor performance improvement.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>
> Reviewed-by: Mickael Salaun <mic@digikod.net>
> Cc: linux-fsdevel@vger.kernel.org

Reviewed-by: John Johansen <john.johansen@canonical.com>


> ---
>   fs/proc/base.c           | 29 +++++++++++++++--------------
>   fs/proc/internal.h       |  2 +-
>   include/linux/security.h | 11 +++++------
>   security/security.c      | 15 +++++++--------
>   4 files changed, 28 insertions(+), 29 deletions(-)
> 
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index 05452c3b9872..f999bb5c497b 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -97,6 +97,7 @@
>   #include <linux/resctrl.h>
>   #include <linux/cn_proc.h>
>   #include <linux/ksm.h>
> +#include <uapi/linux/lsm.h>
>   #include <trace/events/oom.h>
>   #include "internal.h"
>   #include "fd.h"
> @@ -146,10 +147,10 @@ struct pid_entry {
>   	NOD(NAME, (S_IFREG|(MODE)),			\
>   		NULL, &proc_single_file_operations,	\
>   		{ .proc_show = show } )
> -#define ATTR(LSM, NAME, MODE)				\
> +#define ATTR(LSMID, NAME, MODE)				\
>   	NOD(NAME, (S_IFREG|(MODE)),			\
>   		NULL, &proc_pid_attr_operations,	\
> -		{ .lsm = LSM })
> +		{ .lsmid = LSMID })
>   
>   /*
>    * Count the number of hardlinks for the pid_entry table, excluding the .
> @@ -2730,7 +2731,7 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
>   	if (!task)
>   		return -ESRCH;
>   
> -	length = security_getprocattr(task, PROC_I(inode)->op.lsm,
> +	length = security_getprocattr(task, PROC_I(inode)->op.lsmid,
>   				      file->f_path.dentry->d_name.name,
>   				      &p);
>   	put_task_struct(task);
> @@ -2788,7 +2789,7 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
>   	if (rv < 0)
>   		goto out_free;
>   
> -	rv = security_setprocattr(PROC_I(inode)->op.lsm,
> +	rv = security_setprocattr(PROC_I(inode)->op.lsmid,
>   				  file->f_path.dentry->d_name.name, page,
>   				  count);
>   	mutex_unlock(&current->signal->cred_guard_mutex);
> @@ -2837,27 +2838,27 @@ static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \
>   
>   #ifdef CONFIG_SECURITY_SMACK
>   static const struct pid_entry smack_attr_dir_stuff[] = {
> -	ATTR("smack", "current",	0666),
> +	ATTR(LSM_ID_SMACK, "current",	0666),
>   };
>   LSM_DIR_OPS(smack);
>   #endif
>   
>   #ifdef CONFIG_SECURITY_APPARMOR
>   static const struct pid_entry apparmor_attr_dir_stuff[] = {
> -	ATTR("apparmor", "current",	0666),
> -	ATTR("apparmor", "prev",	0444),
> -	ATTR("apparmor", "exec",	0666),
> +	ATTR(LSM_ID_APPARMOR, "current",	0666),
> +	ATTR(LSM_ID_APPARMOR, "prev",		0444),
> +	ATTR(LSM_ID_APPARMOR, "exec",		0666),
>   };
>   LSM_DIR_OPS(apparmor);
>   #endif
>   
>   static const struct pid_entry attr_dir_stuff[] = {
> -	ATTR(NULL, "current",		0666),
> -	ATTR(NULL, "prev",		0444),
> -	ATTR(NULL, "exec",		0666),
> -	ATTR(NULL, "fscreate",		0666),
> -	ATTR(NULL, "keycreate",		0666),
> -	ATTR(NULL, "sockcreate",	0666),
> +	ATTR(LSM_ID_UNDEF, "current",	0666),
> +	ATTR(LSM_ID_UNDEF, "prev",		0444),
> +	ATTR(LSM_ID_UNDEF, "exec",		0666),
> +	ATTR(LSM_ID_UNDEF, "fscreate",	0666),
> +	ATTR(LSM_ID_UNDEF, "keycreate",	0666),
> +	ATTR(LSM_ID_UNDEF, "sockcreate",	0666),
>   #ifdef CONFIG_SECURITY_SMACK
>   	DIR("smack",			0555,
>   	    proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
> diff --git a/fs/proc/internal.h b/fs/proc/internal.h
> index 9dda7e54b2d0..a889d9ef9584 100644
> --- a/fs/proc/internal.h
> +++ b/fs/proc/internal.h
> @@ -92,7 +92,7 @@ union proc_op {
>   	int (*proc_show)(struct seq_file *m,
>   		struct pid_namespace *ns, struct pid *pid,
>   		struct task_struct *task);
> -	const char *lsm;
> +	int lsmid;
>   };
>   
>   struct proc_inode {
> diff --git a/include/linux/security.h b/include/linux/security.h
> index a20a4ceda6d9..b5fd3f7f4cd3 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -470,10 +470,9 @@ 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_getprocattr(struct task_struct *p, const char *lsm, const char *name,
> +int security_getprocattr(struct task_struct *p, int lsmid, const char *name,
>   			 char **value);
> -int security_setprocattr(const char *lsm, const char *name, void *value,
> -			 size_t size);
> +int security_setprocattr(int lsmid, const char *name, void *value, size_t size);
>   int security_netlink_send(struct sock *sk, struct sk_buff *skb);
>   int security_ismaclabel(const char *name);
>   int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
> @@ -1332,14 +1331,14 @@ static inline void security_d_instantiate(struct dentry *dentry,
>   					  struct inode *inode)
>   { }
>   
> -static inline int security_getprocattr(struct task_struct *p, const char *lsm,
> +static inline int security_getprocattr(struct task_struct *p, int lsmid,
>   				       const char *name, char **value)
>   {
>   	return -EINVAL;
>   }
>   
> -static inline int security_setprocattr(const char *lsm, char *name,
> -				       void *value, size_t size)
> +static inline int security_setprocattr(int lsmid, char *name, void *value,
> +				       size_t size)
>   {
>   	return -EINVAL;
>   }
> diff --git a/security/security.c b/security/security.c
> index 87b70a55a028..5e9cd548dd95 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -3801,7 +3801,7 @@ EXPORT_SYMBOL(security_d_instantiate);
>   /**
>    * security_getprocattr() - Read an attribute for a task
>    * @p: the task
> - * @lsm: LSM name
> + * @lsmid: LSM identification
>    * @name: attribute name
>    * @value: attribute value
>    *
> @@ -3809,13 +3809,13 @@ EXPORT_SYMBOL(security_d_instantiate);
>    *
>    * Return: Returns the length of @value on success, a negative value otherwise.
>    */
> -int security_getprocattr(struct task_struct *p, const char *lsm,
> -			 const char *name, char **value)
> +int security_getprocattr(struct task_struct *p, int lsmid, const char *name,
> +			 char **value)
>   {
>   	struct security_hook_list *hp;
>   
>   	hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
> -		if (lsm != NULL && strcmp(lsm, hp->lsmid->name))
> +		if (lsmid != 0 && lsmid != hp->lsmid->id)
>   			continue;
>   		return hp->hook.getprocattr(p, name, value);
>   	}
> @@ -3824,7 +3824,7 @@ int security_getprocattr(struct task_struct *p, const char *lsm,
>   
>   /**
>    * security_setprocattr() - Set an attribute for a task
> - * @lsm: LSM name
> + * @lsmid: LSM identification
>    * @name: attribute name
>    * @value: attribute value
>    * @size: attribute value size
> @@ -3834,13 +3834,12 @@ int security_getprocattr(struct task_struct *p, const char *lsm,
>    *
>    * Return: Returns bytes written on success, a negative value otherwise.
>    */
> -int security_setprocattr(const char *lsm, const char *name, void *value,
> -			 size_t size)
> +int security_setprocattr(int lsmid, const char *name, void *value, size_t size)
>   {
>   	struct security_hook_list *hp;
>   
>   	hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
> -		if (lsm != NULL && strcmp(lsm, hp->lsmid->name))
> +		if (lsmid != 0 && lsmid != hp->lsmid->id)
>   			continue;
>   		return hp->hook.setprocattr(name, value, size);
>   	}


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 04/11] LSM: syscalls for current process attributes
  2023-08-02 17:44   ` [PATCH v13 04/11] LSM: syscalls for current process attributes Casey Schaufler
@ 2023-08-10 15:55     ` John Johansen
  2023-08-23 17:27     ` Mickaël Salaün
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 38+ messages in thread
From: John Johansen @ 2023-08-10 15:55 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module
  Cc: jmorris, serge, keescook, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, mic

On 8/2/23 10:44, 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 <casey@schaufler-ca.com>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>


> ---
>   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            |  90 ++++++++++++++++++++
>   kernel/sys_ni.c                     |   2 +
>   security/Makefile                   |   1 +
>   security/lsm_syscalls.c             |  55 ++++++++++++
>   security/security.c                 | 125 ++++++++++++++++++++++++++++
>   10 files changed, 372 insertions(+)
>   create mode 100644 Documentation/userspace-api/lsm.rst
>   create mode 100644 include/uapi/linux/lsm.h
>   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 <casey@schaufler-ca.com>
> +.. 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 7308a1a7599b..6dffac59dfe3 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -261,6 +261,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 5f7d8caacc00..0662e5c2cd06 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 b5fd3f7f4cd3..0d882cb221f4 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
> @@ -470,6 +471,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);
> @@ -1331,6 +1336,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 03e3d0121d5e..a3938850752a 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;
> @@ -953,6 +954,10 @@ asmlinkage long sys_set_mempolicy_home_node(unsigned long start, unsigned long l
>   asmlinkage long sys_cachestat(unsigned int fd,
>   		struct cachestat_range __user *cstat_range,
>   		struct cachestat __user *cstat, 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
> new file mode 100644
> index 000000000000..eeda59a77c02
> --- /dev/null
> +++ b/include/uapi/linux/lsm.h
> @@ -0,0 +1,90 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +/*
> + * Linux Security Modules (LSM) - User space API
> + *
> + * Copyright (C) 2022 Casey Schaufler <casey@schaufler-ca.com>
> + * Copyright (C) 2022 Intel Corporation
> + */
> +
> +#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)
> + *
> + * 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
> +
> +/*
> + * 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 781de7cc6a4e..8b96cd01b485 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..ee3881159241
> --- /dev/null
> +++ b/security/lsm_syscalls.c
> @@ -0,0 +1,55 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * System calls implementing the Linux Security Module API.
> + *
> + *  Copyright (C) 2022 Casey Schaufler <casey@schaufler-ca.com>
> + *  Copyright (C) 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 set
> + * @ctx: the LSM contexts
> + * @size: size of @ctx, updated on return
> + * @flags: reserved for future use
> + *
> + * 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 5e9cd548dd95..cde7f3a13e7c 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -3798,6 +3798,131 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
>   }
>   EXPORT_SYMBOL(security_d_instantiate);
>   
> +/**
> + * security_getselfattr - Read an LSM attribute of the current process.
> + * @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
> + *
> + * A NULL value for @ctx 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 *ctx,
> +			 size_t __user *size, u32 flags)
> +{
> +	struct security_hook_list *hp;
> +	struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
> +	u8 __user *base = (u8 __user *)ctx;
> +	size_t total = 0;
> +	size_t entrysize;
> +	size_t left;
> +	bool toobig = 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 & LSM_FLAG_SINGLE) == LSM_FLAG_SINGLE) {
> +		if (!ctx)
> +			return -EINVAL;
> +		if (copy_struct_from_user(&lctx, sizeof(lctx), ctx, left))
> +			return -EFAULT;
> +		if (lctx.id == LSM_ID_UNDEF)
> +			return -EINVAL;
> +	} else if (flags) {
> +		return -EINVAL;
> +	}
> +
> +	hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
> +		if (lctx.id != LSM_ID_UNDEF && lctx.id != hp->lsmid->id)
> +			continue;
> +		entrysize = left;
> +		if (base)
> +			ctx = (struct lsm_ctx __user *)(base + total);
> +		rc = hp->hook.getselfattr(attr, ctx, &entrysize, flags);
> +		if (rc == -EOPNOTSUPP) {
> +			rc = 0;
> +			continue;
> +		}
> +		if (rc == -E2BIG) {
> +			toobig = true;
> +			left = 0;
> +			continue;
> +		}
> +		if (rc < 0)
> +			return rc;
> +
> +		left -= entrysize;
> +		total += entrysize;
> +		count += rc;
> +	}
> +	if (put_user(total, size))
> +		return -EFAULT;
> +	if (toobig)
> +		return -E2BIG;
> +	if (count == 0)
> +		return LSM_RET_DEFAULT(getselfattr);
> +	return count;
> +}
> +
> +/**
> + * security_setselfattr - Set an LSM attribute on the current process.
> + * @attr: which attribute to set
> + * @ctx: 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 @ctx.
> + *
> + * Returns 0 on success, -EINVAL if the input is inconsistent, -EFAULT
> + * if the user buffer is inaccessible or an LSM specific failure.
> + */
> +int security_setselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
> +			 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(*ctx))
> +		return -EINVAL;
> +
> +	lctx = kmalloc(size, GFP_KERNEL);
> +	if (lctx == NULL)
> +		return -ENOMEM;
> +
> +	if (copy_from_user(&lctx, ctx, size))
> +		return -EFAULT;
> +
> +	if (size < lctx->len || size < lctx->ctx_len + sizeof(ctx) ||
> +	    lctx->len < lctx->ctx_len + sizeof(ctx))
> +		return -EINVAL;
> +
> +	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;
> +		}
> +
> +	kfree(lctx);
> +	return rc;
> +}
> +
>   /**
>    * security_getprocattr() - Read an attribute for a task
>    * @p: the task


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 05/11] LSM: Create lsm_list_modules system call
  2023-08-02 17:44   ` [PATCH v13 05/11] LSM: Create lsm_list_modules system call Casey Schaufler
@ 2023-08-10 15:55     ` John Johansen
  0 siblings, 0 replies; 38+ messages in thread
From: John Johansen @ 2023-08-10 15:55 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module
  Cc: jmorris, serge, keescook, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, mic

On 8/2/23 10:44, 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 <casey@schaufler-ca.com>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>

Reviewed-by: John Johansen <john.johansen@canonical.com>


> ---
>   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 a3938850752a..4e1596b5c300 100644
> --- a/include/linux/syscalls.h
> +++ b/include/linux/syscalls.h
> @@ -958,6 +958,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 8b96cd01b485..7663ef16c07e 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 ee3881159241..f03f2d17ab49 100644
> --- a/security/lsm_syscalls.c
> +++ b/security/lsm_syscalls.c
> @@ -53,3 +53,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;
> +}


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 06/11] LSM: wireup Linux Security Module syscalls
  2023-08-02 17:44   ` [PATCH v13 06/11] LSM: wireup Linux Security Module syscalls Casey Schaufler
@ 2023-08-10 15:56     ` John Johansen
  0 siblings, 0 replies; 38+ messages in thread
From: John Johansen @ 2023-08-10 15:56 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module
  Cc: jmorris, serge, keescook, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, mic, Geert Uytterhoeven, Arnd Bergmann

On 8/2/23 10:44, Casey Schaufler wrote:
> Wireup lsm_get_self_attr, lsm_set_self_attr and lsm_list_modules
> system calls.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
> Acked-by: Arnd Bergmann <arnd@arndb.de>
> Cc: linux-api@vger.kernel.org

Reviewed-by: John Johansen <john.johansen@canonical.com>


> ---
>   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 +++
>   include/uapi/asm-generic/unistd.h                   | 9 ++++++++-
>   tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl | 3 +++
>   tools/perf/arch/powerpc/entry/syscalls/syscall.tbl  | 3 +++
>   tools/perf/arch/s390/entry/syscalls/syscall.tbl     | 3 +++
>   tools/perf/arch/x86/entry/syscalls/syscall_64.tbl   | 3 +++
>   23 files changed, 75 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl
> index 1f13995d00d7..bb00aecf1dc4 100644
> --- a/arch/alpha/kernel/syscalls/syscall.tbl
> +++ b/arch/alpha/kernel/syscalls/syscall.tbl
> @@ -491,3 +491,6 @@
>   559	common  futex_waitv                     sys_futex_waitv
>   560	common	set_mempolicy_home_node		sys_ni_syscall
>   561	common	cachestat			sys_cachestat
> +562	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +563	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +564	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl
> index 8ebed8a13874..a148e71905a7 100644
> --- a/arch/arm/tools/syscall.tbl
> +++ b/arch/arm/tools/syscall.tbl
> @@ -465,3 +465,6 @@
>   449	common	futex_waitv			sys_futex_waitv
>   450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	common	cachestat			sys_cachestat
> +452	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
> index 64a514f90131..63a8a9c4abc1 100644
> --- a/arch/arm64/include/asm/unistd.h
> +++ b/arch/arm64/include/asm/unistd.h
> @@ -39,7 +39,7 @@
>   #define __ARM_NR_compat_set_tls		(__ARM_NR_COMPAT_BASE + 5)
>   #define __ARM_NR_COMPAT_END		(__ARM_NR_COMPAT_BASE + 0x800)
>   
> -#define __NR_compat_syscalls		452
> +#define __NR_compat_syscalls		455
>   #endif
>   
>   #define __ARCH_WANT_SYS_CLONE
> diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h
> index d952a28463e0..df214b7ec5dd 100644
> --- a/arch/arm64/include/asm/unistd32.h
> +++ b/arch/arm64/include/asm/unistd32.h
> @@ -909,6 +909,12 @@ __SYSCALL(__NR_futex_waitv, sys_futex_waitv)
>   __SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)
>   #define __NR_cachestat 451
>   __SYSCALL(__NR_cachestat, sys_cachestat)
> +#define __NR_lsm_get_self_attr 452
> +__SYSCALL(__NR_lsm_get_self_attr, sys_lsm_get_self_attr)
> +#define __NR_lsm_set_self_attr 453
> +__SYSCALL(__NR_lsm_set_self_attr, sys_lsm_set_self_attr)
> +#define __NR_lsm_list_modules 454
> +__SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules)
>   
>   /*
>    * Please add new compat syscalls above this comment and update
> diff --git a/arch/ia64/kernel/syscalls/syscall.tbl b/arch/ia64/kernel/syscalls/syscall.tbl
> index f8c74ffeeefb..1b53f9d28514 100644
> --- a/arch/ia64/kernel/syscalls/syscall.tbl
> +++ b/arch/ia64/kernel/syscalls/syscall.tbl
> @@ -372,3 +372,6 @@
>   449	common  futex_waitv                     sys_futex_waitv
>   450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	common	cachestat			sys_cachestat
> +452	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl
> index 4f504783371f..f7a91d458f0c 100644
> --- a/arch/m68k/kernel/syscalls/syscall.tbl
> +++ b/arch/m68k/kernel/syscalls/syscall.tbl
> @@ -451,3 +451,6 @@
>   449	common  futex_waitv                     sys_futex_waitv
>   450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	common	cachestat			sys_cachestat
> +452	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl
> index 858d22bf275c..2b24b19a9bec 100644
> --- a/arch/microblaze/kernel/syscalls/syscall.tbl
> +++ b/arch/microblaze/kernel/syscalls/syscall.tbl
> @@ -457,3 +457,6 @@
>   449	common  futex_waitv                     sys_futex_waitv
>   450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	common	cachestat			sys_cachestat
> +452	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl
> index 1976317d4e8b..0ff4072ed024 100644
> --- a/arch/mips/kernel/syscalls/syscall_n32.tbl
> +++ b/arch/mips/kernel/syscalls/syscall_n32.tbl
> @@ -390,3 +390,6 @@
>   449	n32	futex_waitv			sys_futex_waitv
>   450	n32	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	n32	cachestat			sys_cachestat
> +452	n32	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	n32	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	n32	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl b/arch/mips/kernel/syscalls/syscall_n64.tbl
> index cfda2511badf..9c38818dd9f9 100644
> --- a/arch/mips/kernel/syscalls/syscall_n64.tbl
> +++ b/arch/mips/kernel/syscalls/syscall_n64.tbl
> @@ -366,3 +366,6 @@
>   449	n64	futex_waitv			sys_futex_waitv
>   450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	n64	cachestat			sys_cachestat
> +452	n64	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	n64	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	n64	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl b/arch/mips/kernel/syscalls/syscall_o32.tbl
> index 7692234c3768..a07e1ba91511 100644
> --- a/arch/mips/kernel/syscalls/syscall_o32.tbl
> +++ b/arch/mips/kernel/syscalls/syscall_o32.tbl
> @@ -439,3 +439,6 @@
>   449	o32	futex_waitv			sys_futex_waitv
>   450	o32	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	o32	cachestat			sys_cachestat
> +452	o32	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	032	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	o32	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl
> index a0a9145b6dd4..36cc0130ee1d 100644
> --- a/arch/parisc/kernel/syscalls/syscall.tbl
> +++ b/arch/parisc/kernel/syscalls/syscall.tbl
> @@ -450,3 +450,6 @@
>   449	common	futex_waitv			sys_futex_waitv
>   450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	common	cachestat			sys_cachestat
> +452	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl
> index 8c0b08b7a80e..fe2ba9e8a413 100644
> --- a/arch/powerpc/kernel/syscalls/syscall.tbl
> +++ b/arch/powerpc/kernel/syscalls/syscall.tbl
> @@ -538,3 +538,6 @@
>   449	common  futex_waitv                     sys_futex_waitv
>   450 	nospu	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	common	cachestat			sys_cachestat
> +452	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl
> index a6935af2235c..fe3fc23697b0 100644
> --- a/arch/s390/kernel/syscalls/syscall.tbl
> +++ b/arch/s390/kernel/syscalls/syscall.tbl
> @@ -454,3 +454,6 @@
>   449  common	futex_waitv		sys_futex_waitv			sys_futex_waitv
>   450  common	set_mempolicy_home_node	sys_set_mempolicy_home_node	sys_set_mempolicy_home_node
>   451  common	cachestat		sys_cachestat			sys_cachestat
> +452  common	lsm_get_self_attr	sys_lsm_get_self_attr		sys_lsm_get_self_attr
> +453  common	lsm_set_self_attr	sys_lsm_set_self_attr		sys_lsm_set_self_attr
> +454  common	lsm_list_modules	sys_lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl
> index 97377e8c5025..319968dccde9 100644
> --- a/arch/sh/kernel/syscalls/syscall.tbl
> +++ b/arch/sh/kernel/syscalls/syscall.tbl
> @@ -454,3 +454,6 @@
>   449	common  futex_waitv                     sys_futex_waitv
>   450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	common	cachestat			sys_cachestat
> +452	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl
> index faa835f3c54a..9ca3fb4c05de 100644
> --- a/arch/sparc/kernel/syscalls/syscall.tbl
> +++ b/arch/sparc/kernel/syscalls/syscall.tbl
> @@ -497,3 +497,6 @@
>   449	common  futex_waitv                     sys_futex_waitv
>   450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	common	cachestat			sys_cachestat
> +452	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
> index bc0a3c941b35..4caa3c415528 100644
> --- a/arch/x86/entry/syscalls/syscall_32.tbl
> +++ b/arch/x86/entry/syscalls/syscall_32.tbl
> @@ -456,3 +456,6 @@
>   449	i386	futex_waitv		sys_futex_waitv
>   450	i386	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	i386	cachestat		sys_cachestat
> +452	i386	lsm_get_self_attr	sys_lsm_get_self_attr
> +453	i386	lsm_set_self_attr	sys_lsm_set_self_attr
> +454	i386	lsm_list_modules	sys_lsm_list_modules
> diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
> index 227538b0ce80..c5f85f93e80b 100644
> --- a/arch/x86/entry/syscalls/syscall_64.tbl
> +++ b/arch/x86/entry/syscalls/syscall_64.tbl
> @@ -373,6 +373,9 @@
>   449	common	futex_waitv		sys_futex_waitv
>   450	common	set_mempolicy_home_node	sys_set_mempolicy_home_node
>   451	common	cachestat		sys_cachestat
> +452	common	lsm_get_self_attr	sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr	sys_lsm_set_self_attr
> +454	common	lsm_list_modules	sys_lsm_list_modules
>   
>   #
>   # Due to a historical design error, certain syscalls are numbered differently
> diff --git a/arch/xtensa/kernel/syscalls/syscall.tbl b/arch/xtensa/kernel/syscalls/syscall.tbl
> index 2b69c3c035b6..509379512c27 100644
> --- a/arch/xtensa/kernel/syscalls/syscall.tbl
> +++ b/arch/xtensa/kernel/syscalls/syscall.tbl
> @@ -422,3 +422,6 @@
>   449	common  futex_waitv                     sys_futex_waitv
>   450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	common	cachestat			sys_cachestat
> +452	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
> index fd6c1cb585db..b5588efc0933 100644
> --- a/include/uapi/asm-generic/unistd.h
> +++ b/include/uapi/asm-generic/unistd.h
> @@ -820,8 +820,15 @@ __SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)
>   #define __NR_cachestat 451
>   __SYSCALL(__NR_cachestat, sys_cachestat)
>   
> +#define __NR_lsm_get_self_attr 452
> +__SYSCALL(__NR_lsm_get_self_attr, sys_lsm_get_self_attr)
> +#define __NR_lsm_set_self_attr 453
> +__SYSCALL(__NR_lsm_set_self_attr, sys_lsm_set_self_attr)
> +#define __NR_lsm_list_modules 454
> +__SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules)
> +
>   #undef __NR_syscalls
> -#define __NR_syscalls 452
> +#define __NR_syscalls 455
>   
>   /*
>    * 32 bit systems traditionally used different
> diff --git a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl
> index cfda2511badf..9c38818dd9f9 100644
> --- a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl
> +++ b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl
> @@ -366,3 +366,6 @@
>   449	n64	futex_waitv			sys_futex_waitv
>   450	common	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	n64	cachestat			sys_cachestat
> +452	n64	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	n64	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	n64	lsm_list_modules		sys_lsm_list_modules
> diff --git a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
> index 8c0b08b7a80e..fe2ba9e8a413 100644
> --- a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
> +++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
> @@ -538,3 +538,6 @@
>   449	common  futex_waitv                     sys_futex_waitv
>   450 	nospu	set_mempolicy_home_node		sys_set_mempolicy_home_node
>   451	common	cachestat			sys_cachestat
> +452	common	lsm_get_self_attr		sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr		sys_lsm_set_self_attr
> +454	common	lsm_list_modules		sys_lsm_list_modules
> diff --git a/tools/perf/arch/s390/entry/syscalls/syscall.tbl b/tools/perf/arch/s390/entry/syscalls/syscall.tbl
> index a6935af2235c..a18e9d7cf92b 100644
> --- a/tools/perf/arch/s390/entry/syscalls/syscall.tbl
> +++ b/tools/perf/arch/s390/entry/syscalls/syscall.tbl
> @@ -454,3 +454,6 @@
>   449  common	futex_waitv		sys_futex_waitv			sys_futex_waitv
>   450  common	set_mempolicy_home_node	sys_set_mempolicy_home_node	sys_set_mempolicy_home_node
>   451  common	cachestat		sys_cachestat			sys_cachestat
> +452  common	lsm_get_self_attr	sys_lsm_get_self_attr	sys_lsm_get_self_attr
> +453  common	lsm_set_self_attr	sys_lsm_set_self_attr	sys_lsm_set_self_attr
> +454  common	lsm_list_modules	sys_lsm_list_modules	sys_lsm_list_modules
> diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
> index 227538b0ce80..c5f85f93e80b 100644
> --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
> +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
> @@ -373,6 +373,9 @@
>   449	common	futex_waitv		sys_futex_waitv
>   450	common	set_mempolicy_home_node	sys_set_mempolicy_home_node
>   451	common	cachestat		sys_cachestat
> +452	common	lsm_get_self_attr	sys_lsm_get_self_attr
> +453	common	lsm_set_self_attr	sys_lsm_set_self_attr
> +454	common	lsm_list_modules	sys_lsm_list_modules
>   
>   #
>   # Due to a historical design error, certain syscalls are numbered differently


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 07/11] LSM: Helpers for attribute names and filling lsm_ctx
  2023-08-02 17:44   ` [PATCH v13 07/11] LSM: Helpers for attribute names and filling lsm_ctx Casey Schaufler
@ 2023-08-10 15:57     ` John Johansen
  0 siblings, 0 replies; 38+ messages in thread
From: John Johansen @ 2023-08-10 15:57 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module
  Cc: jmorris, serge, keescook, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, mic

On 8/2/23 10:44, 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 <casey@schaufler-ca.com>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   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 0d882cb221f4..817cf28dbf8a 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;
> @@ -263,6 +264,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);
> @@ -488,6 +490,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)
> @@ -505,6 +509,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)
>   {
>   }
> @@ -1408,6 +1417,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 f03f2d17ab49..bc22f05e2d8c 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 cde7f3a13e7c..f1038686ebd0 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -770,6 +770,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:


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 08/11] Smack: implement setselfattr and getselfattr hooks
  2023-08-02 17:44   ` [PATCH v13 08/11] Smack: implement setselfattr and getselfattr hooks Casey Schaufler
@ 2023-08-10 15:57     ` John Johansen
  2023-08-18 15:14     ` Serge Hallyn
  1 sibling, 0 replies; 38+ messages in thread
From: John Johansen @ 2023-08-10 15:57 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module
  Cc: jmorris, serge, keescook, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, mic

On 8/2/23 10:44, Casey Schaufler wrote:
> Implement Smack support for security_[gs]etselfattr.
> Refactor the setprocattr hook to avoid code duplication.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   security/smack/smack_lsm.c | 94 ++++++++++++++++++++++++++++++++++++--
>   1 file changed, 89 insertions(+), 5 deletions(-)
> 
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index f3e4b26c8a87..71c773fff971 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -3565,6 +3565,45 @@ 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 1, the number of attributes, on success, an error code otherwise.
> + */
> +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
> @@ -3594,8 +3633,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
>    *
> @@ -3604,7 +3643,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;
> @@ -3618,8 +3657,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))
> @@ -3658,6 +3697,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
> @@ -4970,6 +5052,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),
>   


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 10/11] SELinux: Add selfattr hooks
  2023-08-02 17:44   ` [PATCH v13 10/11] SELinux: " Casey Schaufler
@ 2023-08-10 22:24     ` Paul Moore
  2023-08-25 15:00     ` Mickaël Salaün
  1 sibling, 0 replies; 38+ messages in thread
From: Paul Moore @ 2023-08-10 22:24 UTC (permalink / raw)
  To: Casey Schaufler, casey, linux-security-module
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, linux-api, mic, selinux

On Aug  2, 2023 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> 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 <casey@schaufler-ca.com>
> Cc: selinux@vger.kernel.org
> Cc: Paul Moore <paul@paul-moore.com>
> ---
>  security/selinux/hooks.c | 136 +++++++++++++++++++++++++++++++--------
>  1 file changed, 109 insertions(+), 27 deletions(-)
> 
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index c900813fc8f7..f66a28f672b2 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c

...

> @@ -6449,6 +6466,69 @@ 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;
> +
> +	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);
> +	else
> +		rc = 1;

I'd probably either set rc to zero when at declaration time and drop
this final else, or explicitly set rc to one here to better fit what
lsm_fill_user_ctx() does on success.  However, the end result is the
same so we can just fix that with a follow-up patch once this is
merged into the lsm/next branch.

> +	kfree(value);
> +	*size = total_len;
> +	if (rc < 0)
> +		return rc;
> +	return 1;
> +}

--
paul-moore.com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 00/11] LSM: Three basic syscalls
  2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
                     ` (10 preceding siblings ...)
  2023-08-02 17:44   ` [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls Casey Schaufler
@ 2023-08-10 22:32   ` Paul Moore
  11 siblings, 0 replies; 38+ messages in thread
From: Paul Moore @ 2023-08-10 22:32 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: linux-security-module, jmorris, serge, keescook, john.johansen,
	penguin-kernel, stephen.smalley.work, linux-kernel, linux-api,
	mic

On Wed, Aug 2, 2023 at 1:44 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> Add three system calls for the Linux Security Module ABI ...

I had a small comment on the SELinux patch, but that's oh so very
minor and not worth respinning in my opinion; I can fix that up with a
follow-up patch once the patchset is merged.

I was also happy to see that John had a chance to look everything
over, especially the AppArmor bits, that's good.

Mickaël had a lot of good comments on the selftest patch, and of all
the LSMs I believe he has done the most work with the kernel's
selftest functionality so it would be nice to have him look over the
latest revision in this patchset.  I know he is busy at the moment,
but I'm hopeful he will have an opportunity to look at it in the
second half of next week.

Assuming the selftests look good to Mickaël, and no one else
identifies any problems, I think we're on track to merge this into
lsm/next after the upcoming merge window closes :)  Thanks a lot
Casey, I appreciate all the work you've put into this patchset.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 08/11] Smack: implement setselfattr and getselfattr hooks
  2023-08-02 17:44   ` [PATCH v13 08/11] Smack: implement setselfattr and getselfattr hooks Casey Schaufler
  2023-08-10 15:57     ` John Johansen
@ 2023-08-18 15:14     ` Serge Hallyn
  1 sibling, 0 replies; 38+ messages in thread
From: Serge Hallyn @ 2023-08-18 15:14 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, keescook, john.johansen,
	penguin-kernel, stephen.smalley.work, linux-kernel, linux-api,
	mic

On Wed, Aug 02, 2023 at 10:44:31AM -0700, Casey Schaufler wrote:
> Implement Smack support for security_[gs]etselfattr.
> Refactor the setprocattr hook to avoid code duplication.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  security/smack/smack_lsm.c | 94 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 89 insertions(+), 5 deletions(-)
> 
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index f3e4b26c8a87..71c773fff971 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -3565,6 +3565,45 @@ 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 1, the number of attributes, on success, an error code otherwise.

This comment is confusing.  is it saying that 1 is always the number
of attributes?  Because the "if (rc >= 0) return 1;" ensure that
it only ever returns 1 or < 0.

> + */
> +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
> @@ -3594,8 +3633,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
>   *
> @@ -3604,7 +3643,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;
> @@ -3618,8 +3657,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))
> @@ -3658,6 +3697,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
> @@ -4970,6 +5052,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
> 
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls
  2023-08-02 17:44   ` [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls Casey Schaufler
@ 2023-08-18 15:53     ` Serge Hallyn
  2023-08-23 19:09       ` Casey Schaufler
  2023-08-23 17:27     ` Mickaël Salaün
  2023-08-25 15:01     ` Mickaël Salaün
  2 siblings, 1 reply; 38+ messages in thread
From: Serge Hallyn @ 2023-08-18 15:53 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, keescook, john.johansen,
	penguin-kernel, stephen.smalley.work, linux-kernel, linux-api,
	mic

On Wed, Aug 02, 2023 at 10:44:34AM -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 <casey@schaufler-ca.com>

I know these are just testcases, but a few things stood out below.

The actual set of tests looks good, though.  Thanks.

> ---
>  MAINTAINERS                                   |   1 +
>  tools/testing/selftests/Makefile              |   1 +
>  tools/testing/selftests/lsm/Makefile          |  19 ++
>  tools/testing/selftests/lsm/common.c          |  81 ++++++
>  tools/testing/selftests/lsm/common.h          |  33 +++
>  tools/testing/selftests/lsm/config            |   3 +
>  .../selftests/lsm/lsm_get_self_attr_test.c    | 240 ++++++++++++++++++
>  .../selftests/lsm/lsm_list_modules_test.c     | 140 ++++++++++
>  .../selftests/lsm/lsm_set_self_attr_test.c    |  74 ++++++
>  9 files changed, 592 insertions(+)
>  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 aca4db11dd02..c96f1c388d22 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19158,6 +19158,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 666b56f22a41..bde7c217b23f 100644
> --- a/tools/testing/selftests/Makefile
> +++ b/tools/testing/selftests/Makefile
> @@ -39,6 +39,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/Makefile b/tools/testing/selftests/lsm/Makefile
> new file mode 100644
> index 000000000000..bae6c1e3bba4
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/Makefile
> @@ -0,0 +1,19 @@
> +# 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
> +
> +$(TEST_GEN_PROGS):
> +
> +$(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..db9af9375238
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/common.c
> @@ -0,0 +1,81 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Linux Security Module infrastructure tests
> + *
> + * Copyright © 2023 Casey Schaufler <casey@schaufler-ca.com>
> + */
> +
> +#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)

not closing fd here

> +		return -1;
> +	len = read(fd, value, size);
> +	if (len <= 0)
> +		return -1;
> +	close(fd);
> +

It would feel cozier if you would ensure a trailing \0 in
value before doing strchr.

> +	path = strchr(value, '\n');
> +	if (path)
> +		*path = '\0';
> +
> +	return 0;
> +}
> +
> +int read_sysfs_lsms(char *lsms, size_t size)
> +{
> +	FILE *fp;
> +
> +	fp = fopen("/sys/kernel/security/lsm", "r");
> +	if (fp == NULL)
> +		return -1;
> +	if (fread(lsms, 1, size, fp) <= 0)

not closing fp

> +		return -1;
> +	fclose(fp);
> +	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;
> +

Again strstr without ensuring \0.  /sys/kernel/security/lsm
is unlikely to be longer than _SC_PAGESIZE, but I *could*
mess with you with a bind mount...

> +	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..cd0214a3eeb2
> --- /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 <casey@schaufler-ca.com>
> + */
> +
> +#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..74c65aae1fcc
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c
> @@ -0,0 +1,240 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Linux Security Module infrastructure tests
> + * Tests for the lsm_get_self_attr system call
> + *
> + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com>
> + */
> +
> +#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);
> +	size_t size = page_size;
> +
> +	ASSERT_NE(NULL, ctx);
> +	errno = 0;
> +	ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, 1));
> +	ASSERT_EQ(EINVAL, errno);
> +	ASSERT_EQ(page_size, size);
> +
> +	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 = page_size;
> +
> +	ASSERT_NE(NULL, ctx);
> +	errno = 0;
> +	ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx,
> +					&size, 0));
> +	ASSERT_EQ(EOPNOTSUPP, 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);

You never verify attr is not NULL

> +	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 <casey@schaufler-ca.com>
> + */
> +
> +#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..d0f5b776c548
> --- /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 <casey@schaufler-ca.com>
> + */
> +
> +#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
> 
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 02/11] LSM: Maintain a table of LSM attribute data
  2023-08-02 17:44   ` [PATCH v13 02/11] LSM: Maintain a table of LSM attribute data Casey Schaufler
  2023-08-10 15:54     ` John Johansen
@ 2023-08-18 17:58     ` Mickaël Salaün
  1 sibling, 0 replies; 38+ messages in thread
From: Mickaël Salaün @ 2023-08-18 17:58 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api

On Wed, Aug 02, 2023 at 10:44:25AM -0700, Casey Schaufler wrote:
> As LSMs are registered add their lsm_id pointers to a table.
> This will be used later for attribute reporting.
> 
> Determine the number of possible security modules based on
> their respective CONFIG options. This allows the number to be
> known at build time. This allows data structures and tables
> to use the constant.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>
> ---
>  include/linux/security.h |  2 ++
>  security/security.c      | 37 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 39 insertions(+)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 32828502f09e..a20a4ceda6d9 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -138,6 +138,8 @@ enum lockdown_reason {
>  };
>  
>  extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
> +extern u32 lsm_active_cnt;
> +extern const struct lsm_id *lsm_idlist[];
>  
>  /* These functions are in security/commoncap.c */
>  extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
> diff --git a/security/security.c b/security/security.c
> index feaae09581dc..87b70a55a028 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -36,6 +36,25 @@
>  /* How many LSMs were built into the kernel? */
>  #define LSM_COUNT (__end_lsm_info - __start_lsm_info)
>  
> +/*
> + * How many LSMs are built into the kernel as determined at
> + * build time. Used to determine fixed array sizes.
> + * The capability module is accounted for by CONFIG_SECURITY
> + */
> +#define LSM_CONFIG_COUNT ( \
> +	(IS_ENABLED(CONFIG_SECURITY) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_SELINUX) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_SMACK) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_TOMOYO) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_APPARMOR) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_YAMA) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_LOADPIN) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \
> +	(IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0))
> +
>  /*
>   * These are descriptions of the reasons that can be passed to the
>   * security_locked_down() LSM hook. Placing this array here allows
> @@ -245,6 +264,12 @@ static void __init initialize_lsm(struct lsm_info *lsm)
>  	}
>  }
>  
> +/*
> + * Current index to use while initializing the lsm id list.
> + */
> +u32 lsm_active_cnt __ro_after_init;
> +const struct lsm_id *lsm_idlist[LSM_CONFIG_COUNT] __ro_after_init;

I guess __ro_after_init is superfluous here.

Reviewed-by: Mickaël Salaün <mic@digikod.net>


> +
>  /* Populate ordered LSMs list from comma-separated LSM name list. */
>  static void __init ordered_lsm_parse(const char *order, const char *origin)
>  {
> @@ -521,6 +546,18 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
>  {
>  	int i;
>  
> +	/*
> +	 * A security module may call security_add_hooks() more
> +	 * than once during initialization, and LSM initialization
> +	 * is serialized. Landlock is one such case.
> +	 * Look at the previous entry, if there is one, for duplication.
> +	 */
> +	if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
> +		if (lsm_active_cnt >= LSM_CONFIG_COUNT)
> +			panic("%s Too many LSMs registered.\n", __func__);
> +		lsm_idlist[lsm_active_cnt++] = lsmid;
> +	}
> +
>  	for (i = 0; i < count; i++) {
>  		hooks[i].lsmid = lsmid;
>  		hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);
> -- 
> 2.41.0
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 01/11] LSM: Identify modules by more than name
  2023-08-02 17:44   ` [PATCH v13 01/11] LSM: Identify modules by more than name Casey Schaufler
  2023-08-10 15:54     ` John Johansen
@ 2023-08-18 18:00     ` Mickaël Salaün
  1 sibling, 0 replies; 38+ messages in thread
From: Mickaël Salaün @ 2023-08-18 18:00 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api

On Wed, Aug 02, 2023 at 10:44:24AM -0700, 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, an identifier associated with the security
> module and an integer member "attrs" which identifies the API
> related data associated with each security module. The initial set
> of features maps to information that has traditionaly been available
> in /proc/self/attr. They are documented in a new userspace-api file.
> 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 <casey@schaufler-ca.com>
> Cc: linux-security-module <linux-security-module@vger.kernel.org>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>
> Reviewed-by: Mickael Salaun <mic@digikod.net>
> ---
>  Documentation/userspace-api/index.rst |  1 +
>  MAINTAINERS                           |  1 +
>  include/linux/lsm_hooks.h             | 16 ++++++++++++++--
>  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 +++++++-
>  19 files changed, 107 insertions(+), 21 deletions(-)
> 
> 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 d516295978a4..aca4db11dd02 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19156,6 +19156,7 @@ L:	linux-security-module@vger.kernel.org (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 ab2b2fafa4a4..5f7d8caacc00 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -41,6 +41,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.
> @@ -49,7 +61,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;
>  
>  /*
> @@ -84,7 +96,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/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index c9463bd0307d..bfd049c3fd22 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),
>  };
>  
> +static const struct lsm_id apparmor_lsmid = {

All these struct "static const" can be simplified to just "const".

Reviewed-by: Mickaël Salaün <mic@digikod.net>


> +	.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..57b9ffd53c98 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),
>  };
>  
> +static 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 ab5742ab4362..4e94075656e9 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
>  
> +static 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 ebae964f7cc9..9fbc90f0e65b 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);
>  }
>  
> +static 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..f2bdbd55aa2b 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),
>  };
>  
> +static 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..1ba564f097f5 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;
>  }
>  
> +static 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 b720424ca37d..feaae09581dc 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -512,17 +512,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);
>  	}
>  
> @@ -531,7 +531,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__);
>  	}
>  }
> @@ -3778,7 +3778,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);
>  	}
> @@ -3803,7 +3803,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 d06e350fedee..c900813fc8f7 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"
> @@ -6929,6 +6930,11 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
>  }
>  #endif /* CONFIG_IO_URING */
>  
> +static 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,
> @@ -7250,7 +7256,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 6e270cf3fd30..f3e4b26c8a87 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"
> @@ -4871,6 +4872,11 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
>  	.lbs_superblock = sizeof(struct superblock_smack),
>  };
>  
> +static 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),
> @@ -5077,7 +5083,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..9dc8e64890bc 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)
>  	}
>  }
>  
> +static 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..49dc52b454ef 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;
>  }
>  
> +static 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
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls
  2023-08-02 17:44   ` [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls Casey Schaufler
  2023-08-18 15:53     ` Serge Hallyn
@ 2023-08-23 17:27     ` Mickaël Salaün
  2023-08-25 15:01     ` Mickaël Salaün
  2 siblings, 0 replies; 38+ messages in thread
From: Mickaël Salaün @ 2023-08-23 17:27 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api

On Wed, Aug 02, 2023 at 10:44:34AM -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 <casey@schaufler-ca.com>
> ---
>  MAINTAINERS                                   |   1 +
>  tools/testing/selftests/Makefile              |   1 +
>  tools/testing/selftests/lsm/Makefile          |  19 ++
>  tools/testing/selftests/lsm/common.c          |  81 ++++++
>  tools/testing/selftests/lsm/common.h          |  33 +++
>  tools/testing/selftests/lsm/config            |   3 +
>  .../selftests/lsm/lsm_get_self_attr_test.c    | 240 ++++++++++++++++++
>  .../selftests/lsm/lsm_list_modules_test.c     | 140 ++++++++++
>  .../selftests/lsm/lsm_set_self_attr_test.c    |  74 ++++++
>  9 files changed, 592 insertions(+)
>  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/tools/testing/selftests/lsm/Makefile b/tools/testing/selftests/lsm/Makefile
> new file mode 100644
> index 000000000000..bae6c1e3bba4
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/Makefile
> @@ -0,0 +1,19 @@
> +# 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

You could use the wildcard approach to avoid explicitly listing output
files here, but it's not a big deal.

> +
> +include ../lib.mk
> +
> +$(TEST_GEN_PROGS):
> +
> +$(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

It would be nice to add /*_test to a .gitignore file

> +
> +EXTRA_CLEAN = $(OUTPUT)/common.o

Anyway, this Makefile works with all kind of test builds (cf. commit
a52540522c9541bfa3e499d2edba7bc0ca73a4ca).

I'll send another review for this file soon.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 04/11] LSM: syscalls for current process attributes
  2023-08-02 17:44   ` [PATCH v13 04/11] LSM: syscalls for current process attributes Casey Schaufler
  2023-08-10 15:55     ` John Johansen
@ 2023-08-23 17:27     ` Mickaël Salaün
  2023-08-25  0:12     ` Mateusz Guzik
  2023-08-25 14:59     ` Mickaël Salaün
  3 siblings, 0 replies; 38+ messages in thread
From: Mickaël Salaün @ 2023-08-23 17:27 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api

On Wed, Aug 02, 2023 at 10:44:27AM -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 <casey@schaufler-ca.com>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>
> ---
>  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            |  90 ++++++++++++++++++++
>  kernel/sys_ni.c                     |   2 +
>  security/Makefile                   |   1 +
>  security/lsm_syscalls.c             |  55 ++++++++++++
>  security/security.c                 | 125 ++++++++++++++++++++++++++++
>  10 files changed, 372 insertions(+)
>  create mode 100644 Documentation/userspace-api/lsm.rst
>  create mode 100644 include/uapi/linux/lsm.h
>  create mode 100644 security/lsm_syscalls.c

> +/**
> + * security_setselfattr - Set an LSM attribute on the current process.
> + * @attr: which attribute to set
> + * @ctx: 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 @ctx.
> + *
> + * Returns 0 on success, -EINVAL if the input is inconsistent, -EFAULT
> + * if the user buffer is inaccessible or an LSM specific failure.
> + */
> +int security_setselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
> +			 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(*ctx))
> +		return -EINVAL;
> +
> +	lctx = kmalloc(size, GFP_KERNEL);
> +	if (lctx == NULL)
> +		return -ENOMEM;
> +
> +	if (copy_from_user(&lctx, ctx, size))

This should be copy_from_user(lctx, ctx, size)

> +		return -EFAULT;
> +
> +	if (size < lctx->len || size < lctx->ctx_len + sizeof(ctx) ||
> +	    lctx->len < lctx->ctx_len + sizeof(ctx))
> +		return -EINVAL;
> +
> +	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;
> +		}
> +
> +	kfree(lctx);
> +	return rc;
> +}
> +
>  /**
>   * security_getprocattr() - Read an attribute for a task
>   * @p: the task
> -- 
> 2.41.0
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls
  2023-08-18 15:53     ` Serge Hallyn
@ 2023-08-23 19:09       ` Casey Schaufler
  2023-08-25  0:36         ` Serge Hallyn
  0 siblings, 1 reply; 38+ messages in thread
From: Casey Schaufler @ 2023-08-23 19:09 UTC (permalink / raw)
  To: Serge Hallyn
  Cc: paul, linux-security-module, jmorris, keescook, john.johansen,
	penguin-kernel, stephen.smalley.work, linux-kernel, linux-api,
	mic, Casey Schaufler

On 8/18/2023 8:53 AM, Serge Hallyn wrote:
> On Wed, Aug 02, 2023 at 10:44:34AM -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 <casey@schaufler-ca.com>
> I know these are just testcases, but a few things stood out below.
>
> The actual set of tests looks good, though.  Thanks.
>
>> ---
>>  MAINTAINERS                                   |   1 +
>>  tools/testing/selftests/Makefile              |   1 +
>>  tools/testing/selftests/lsm/Makefile          |  19 ++
>>  tools/testing/selftests/lsm/common.c          |  81 ++++++
>>  tools/testing/selftests/lsm/common.h          |  33 +++
>>  tools/testing/selftests/lsm/config            |   3 +
>>  .../selftests/lsm/lsm_get_self_attr_test.c    | 240 ++++++++++++++++++
>>  .../selftests/lsm/lsm_list_modules_test.c     | 140 ++++++++++
>>  .../selftests/lsm/lsm_set_self_attr_test.c    |  74 ++++++
>>  9 files changed, 592 insertions(+)
>>  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 aca4db11dd02..c96f1c388d22 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -19158,6 +19158,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 666b56f22a41..bde7c217b23f 100644
>> --- a/tools/testing/selftests/Makefile
>> +++ b/tools/testing/selftests/Makefile
>> @@ -39,6 +39,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/Makefile b/tools/testing/selftests/lsm/Makefile
>> new file mode 100644
>> index 000000000000..bae6c1e3bba4
>> --- /dev/null
>> +++ b/tools/testing/selftests/lsm/Makefile
>> @@ -0,0 +1,19 @@
>> +# 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
>> +
>> +$(TEST_GEN_PROGS):
>> +
>> +$(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..db9af9375238
>> --- /dev/null
>> +++ b/tools/testing/selftests/lsm/common.c
>> @@ -0,0 +1,81 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Linux Security Module infrastructure tests
>> + *
>> + * Copyright © 2023 Casey Schaufler <casey@schaufler-ca.com>
>> + */
>> +
>> +#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)
> not closing fd here

The open failed. Nothing to close.

>
>> +		return -1;
>> +	len = read(fd, value, size);
>> +	if (len <= 0)
>> +		return -1;
>> +	close(fd);
>> +
> It would feel cozier if you would ensure a trailing \0 in
> value before doing strchr.

Sure.

>
>> +	path = strchr(value, '\n');
>> +	if (path)
>> +		*path = '\0';
>> +
>> +	return 0;
>> +}
>> +
>> +int read_sysfs_lsms(char *lsms, size_t size)
>> +{
>> +	FILE *fp;
>> +
>> +	fp = fopen("/sys/kernel/security/lsm", "r");
>> +	if (fp == NULL)
>> +		return -1;
>> +	if (fread(lsms, 1, size, fp) <= 0)
> not closing fp

This one does need closing.

>
>> +		return -1;
>> +	fclose(fp);
>> +	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;
>> +
> Again strstr without ensuring \0.  /sys/kernel/security/lsm
> is unlikely to be longer than _SC_PAGESIZE, but I *could*
> mess with you with a bind mount...

Because of your demonstrated cunning I will address this.

>
>> +	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..cd0214a3eeb2
>> --- /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 <casey@schaufler-ca.com>
>> + */
>> +
>> +#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..74c65aae1fcc
>> --- /dev/null
>> +++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c
>> @@ -0,0 +1,240 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Linux Security Module infrastructure tests
>> + * Tests for the lsm_get_self_attr system call
>> + *
>> + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com>
>> + */
>> +
>> +#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);
>> +	size_t size = page_size;
>> +
>> +	ASSERT_NE(NULL, ctx);
>> +	errno = 0;
>> +	ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, 1));
>> +	ASSERT_EQ(EINVAL, errno);
>> +	ASSERT_EQ(page_size, size);
>> +
>> +	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 = page_size;
>> +
>> +	ASSERT_NE(NULL, ctx);
>> +	errno = 0;
>> +	ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx,
>> +					&size, 0));
>> +	ASSERT_EQ(EOPNOTSUPP, 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);
> You never verify attr is not NULL

True. Will fix.

>
>> +	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 <casey@schaufler-ca.com>
>> + */
>> +
>> +#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..d0f5b776c548
>> --- /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 <casey@schaufler-ca.com>
>> + */
>> +
>> +#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
>>
>>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 04/11] LSM: syscalls for current process attributes
  2023-08-02 17:44   ` [PATCH v13 04/11] LSM: syscalls for current process attributes Casey Schaufler
  2023-08-10 15:55     ` John Johansen
  2023-08-23 17:27     ` Mickaël Salaün
@ 2023-08-25  0:12     ` Mateusz Guzik
  2023-08-25 14:59     ` Mickaël Salaün
  3 siblings, 0 replies; 38+ messages in thread
From: Mateusz Guzik @ 2023-08-25  0:12 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, mic

On Wed, Aug 02, 2023 at 10:44:27AM -0700, Casey Schaufler wrote:
> +/**
> + * security_setselfattr - Set an LSM attribute on the current process.
> + * @attr: which attribute to set
> + * @ctx: the user-space source for the information

Would be more idiomatic to name the user arg uctx.

> + * @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 @ctx.
> + *
> + * Returns 0 on success, -EINVAL if the input is inconsistent, -EFAULT
> + * if the user buffer is inaccessible or an LSM specific failure.
> + */
> +int security_setselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
> +			 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(*ctx))
> +		return -EINVAL;
> +

I think it would be cleaner to check against lctx.

But the actual point is that you want an upper bound here.

> +	lctx = kmalloc(size, GFP_KERNEL);
> +	if (lctx == NULL)
> +		return -ENOMEM;
> +
> +	if (copy_from_user(&lctx, ctx, size))
> +		return -EFAULT;
> +

One commenter over already mentioned this should be lctx, not &lctx.

> +	if (size < lctx->len || size < lctx->ctx_len + sizeof(ctx) ||
> +	    lctx->len < lctx->ctx_len + sizeof(ctx))
> +		return -EINVAL;
> +

This leaks lctx.

> +	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;
> +		}
> +
> +	kfree(lctx);
> +	return rc;
> +}
> +

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls
  2023-08-23 19:09       ` Casey Schaufler
@ 2023-08-25  0:36         ` Serge Hallyn
  0 siblings, 0 replies; 38+ messages in thread
From: Serge Hallyn @ 2023-08-25  0:36 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, keescook, john.johansen,
	penguin-kernel, stephen.smalley.work, linux-kernel, linux-api,
	mic

On Wed, Aug 23, 2023 at 12:09:39PM -0700, Casey Schaufler wrote:
> On 8/18/2023 8:53 AM, Serge Hallyn wrote:
> > On Wed, Aug 02, 2023 at 10:44:34AM -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 <casey@schaufler-ca.com>
> > I know these are just testcases, but a few things stood out below.
> >
> > The actual set of tests looks good, though.  Thanks.
> >
> >> ---
> >>  MAINTAINERS                                   |   1 +
> >>  tools/testing/selftests/Makefile              |   1 +
> >>  tools/testing/selftests/lsm/Makefile          |  19 ++
> >>  tools/testing/selftests/lsm/common.c          |  81 ++++++
> >>  tools/testing/selftests/lsm/common.h          |  33 +++
> >>  tools/testing/selftests/lsm/config            |   3 +
> >>  .../selftests/lsm/lsm_get_self_attr_test.c    | 240 ++++++++++++++++++
> >>  .../selftests/lsm/lsm_list_modules_test.c     | 140 ++++++++++
> >>  .../selftests/lsm/lsm_set_self_attr_test.c    |  74 ++++++
> >>  9 files changed, 592 insertions(+)
> >>  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 aca4db11dd02..c96f1c388d22 100644
> >> --- a/MAINTAINERS
> >> +++ b/MAINTAINERS
> >> @@ -19158,6 +19158,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 666b56f22a41..bde7c217b23f 100644
> >> --- a/tools/testing/selftests/Makefile
> >> +++ b/tools/testing/selftests/Makefile
> >> @@ -39,6 +39,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/Makefile b/tools/testing/selftests/lsm/Makefile
> >> new file mode 100644
> >> index 000000000000..bae6c1e3bba4
> >> --- /dev/null
> >> +++ b/tools/testing/selftests/lsm/Makefile
> >> @@ -0,0 +1,19 @@
> >> +# 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
> >> +
> >> +$(TEST_GEN_PROGS):
> >> +
> >> +$(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..db9af9375238
> >> --- /dev/null
> >> +++ b/tools/testing/selftests/lsm/common.c
> >> @@ -0,0 +1,81 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Linux Security Module infrastructure tests
> >> + *
> >> + * Copyright © 2023 Casey Schaufler <casey@schaufler-ca.com>
> >> + */
> >> +
> >> +#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)
> > not closing fd here
> 
> The open failed. Nothing to close.

Lol yes I misplaced my comment.  But after the next read?

> >> +		return -1;
> >> +	len = read(fd, value, size);
> >> +	if (len <= 0)
> >> +		return -1;
> >> +	close(fd);
> >> +
> > It would feel cozier if you would ensure a trailing \0 in
> > value before doing strchr.
> 
> Sure.
> 
> >
> >> +	path = strchr(value, '\n');
> >> +	if (path)
> >> +		*path = '\0';
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +int read_sysfs_lsms(char *lsms, size_t size)
> >> +{
> >> +	FILE *fp;
> >> +
> >> +	fp = fopen("/sys/kernel/security/lsm", "r");
> >> +	if (fp == NULL)
> >> +		return -1;
> >> +	if (fread(lsms, 1, size, fp) <= 0)
> > not closing fp
> 
> This one does need closing.
> 
> >
> >> +		return -1;
> >> +	fclose(fp);
> >> +	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;
> >> +
> > Again strstr without ensuring \0.  /sys/kernel/security/lsm
> > is unlikely to be longer than _SC_PAGESIZE, but I *could*
> > mess with you with a bind mount...
> 
> Because of your demonstrated cunning I will address this.

Victory!

> >> +	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..cd0214a3eeb2
> >> --- /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 <casey@schaufler-ca.com>
> >> + */
> >> +
> >> +#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..74c65aae1fcc
> >> --- /dev/null
> >> +++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c
> >> @@ -0,0 +1,240 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Linux Security Module infrastructure tests
> >> + * Tests for the lsm_get_self_attr system call
> >> + *
> >> + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com>
> >> + */
> >> +
> >> +#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);
> >> +	size_t size = page_size;
> >> +
> >> +	ASSERT_NE(NULL, ctx);
> >> +	errno = 0;
> >> +	ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, 1));
> >> +	ASSERT_EQ(EINVAL, errno);
> >> +	ASSERT_EQ(page_size, size);
> >> +
> >> +	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 = page_size;
> >> +
> >> +	ASSERT_NE(NULL, ctx);
> >> +	errno = 0;
> >> +	ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx,
> >> +					&size, 0));
> >> +	ASSERT_EQ(EOPNOTSUPP, 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);
> > You never verify attr is not NULL
> 
> True. Will fix.
> 
> >
> >> +	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 <casey@schaufler-ca.com>
> >> + */
> >> +
> >> +#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..d0f5b776c548
> >> --- /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 <casey@schaufler-ca.com>
> >> + */
> >> +
> >> +#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
> >>
> >>
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 04/11] LSM: syscalls for current process attributes
  2023-08-02 17:44   ` [PATCH v13 04/11] LSM: syscalls for current process attributes Casey Schaufler
                       ` (2 preceding siblings ...)
  2023-08-25  0:12     ` Mateusz Guzik
@ 2023-08-25 14:59     ` Mickaël Salaün
  2023-08-25 22:23       ` Casey Schaufler
  3 siblings, 1 reply; 38+ messages in thread
From: Mickaël Salaün @ 2023-08-25 14:59 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api

On Wed, Aug 02, 2023 at 10:44:27AM -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 <casey@schaufler-ca.com>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Reviewed-by: Serge Hallyn <serge@hallyn.com>
> ---
>  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            |  90 ++++++++++++++++++++
>  kernel/sys_ni.c                     |   2 +
>  security/Makefile                   |   1 +
>  security/lsm_syscalls.c             |  55 ++++++++++++
>  security/security.c                 | 125 ++++++++++++++++++++++++++++
>  10 files changed, 372 insertions(+)
>  create mode 100644 Documentation/userspace-api/lsm.rst
>  create mode 100644 include/uapi/linux/lsm.h
>  create mode 100644 security/lsm_syscalls.c

> +/**
> + * sys_lsm_get_self_attr - Return current task's security module attributes
> + * @attr: which attribute to set
> + * @ctx: the LSM contexts
> + * @size: size of @ctx, updated on return
> + * @flags: reserved for future use

This documentation is out-of-sync with the LSM hook doc, especially the
flags.

> + *
> + * 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 5e9cd548dd95..cde7f3a13e7c 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -3798,6 +3798,131 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
>  }
>  EXPORT_SYMBOL(security_d_instantiate);
>  
> +/**
> + * security_getselfattr - Read an LSM attribute of the current process.
> + * @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

The final dot is missing.

> + *
> + * A NULL value for @ctx 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 *ctx,
> +			 size_t __user *size, u32 flags)
> +{
> +	struct security_hook_list *hp;
> +	struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
> +	u8 __user *base = (u8 __user *)ctx;
> +	size_t total = 0;
> +	size_t entrysize;
> +	size_t left;
> +	bool toobig = 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 & LSM_FLAG_SINGLE) == LSM_FLAG_SINGLE) {
> +		if (!ctx)

This doesn't fit with the documenation. I guess it should handle NULL
ctx in both cases.

This cases should be tested.

I'm now wondering if this LSM_FLAG_SINGLE makes sense though.

> +			return -EINVAL;
> +		if (copy_struct_from_user(&lctx, sizeof(lctx), ctx, left))

This check looks good but it looks inconsistent with the
non-LSM_FLAG_SINGLE loop which doesn't check that the arrays only
contain zeros.

> +			return -EFAULT;
> +		if (lctx.id == LSM_ID_UNDEF)
> +			return -EINVAL;
> +	} else if (flags) {

This check is not correct. It should test if there is no value other
than LSM_FLAG_SINGLE.

Please add a test with something like this:
lsm_get_self_attr(valid_attr, valid_ctx, valid_size, LSM_FLAG_SINGLE | 1 << 9)

> +		return -EINVAL;
> +	}
> +

Please add a comment to highlight that only LSM_FLAG_SINGLE is handled
for this loop.

> +	hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
> +		if (lctx.id != LSM_ID_UNDEF && lctx.id != hp->lsmid->id)
> +			continue;
> +		entrysize = left;
> +		if (base)
> +			ctx = (struct lsm_ctx __user *)(base + total);

To be consistent with the previous copy_struct_from_user() call, we
should at least check that the ctx arrays contain zeros too.

We should add a test for this case.

> +		rc = hp->hook.getselfattr(attr, ctx, &entrysize, flags);
> +		if (rc == -EOPNOTSUPP) {
> +			rc = 0;
> +			continue;
> +		}
> +		if (rc == -E2BIG) {
> +			toobig = true;
> +			left = 0;
> +			continue;
> +		}
> +		if (rc < 0)
> +			return rc;
> +
> +		left -= entrysize;
> +		total += entrysize;
> +		count += rc;
> +	}
> +	if (put_user(total, size))
> +		return -EFAULT;
> +	if (toobig)
> +		return -E2BIG;
> +	if (count == 0)
> +		return LSM_RET_DEFAULT(getselfattr);
> +	return count;
> +}
> +
> +/**
> + * security_setselfattr - Set an LSM attribute on the current process.
> + * @attr: which attribute to set
> + * @ctx: 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 @ctx.
> + *
> + * Returns 0 on success, -EINVAL if the input is inconsistent, -EFAULT
> + * if the user buffer is inaccessible or an LSM specific failure.
> + */
> +int security_setselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
> +			 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(*ctx))
> +		return -EINVAL;
> +
> +	lctx = kmalloc(size, GFP_KERNEL);

We should not allow user space to allocate arbitrary kernel buffer size.
Limiting to PAGE_SIZE seems reasonable.

> +	if (lctx == NULL)
> +		return -ENOMEM;
> +
> +	if (copy_from_user(&lctx, ctx, size))
> +		return -EFAULT;
> +
> +	if (size < lctx->len || size < lctx->ctx_len + sizeof(ctx) ||

Because we only handle one LSM at a time, size should be equal to
lctx->len right?

> +	    lctx->len < lctx->ctx_len + sizeof(ctx))
> +		return -EINVAL;
> +
> +	hlist_for_each_entry(hp, &security_hook_heads.setselfattr, list)
> +		if ((hp->lsmid->id) == lctx->id) {
> +			rc = hp->hook.setselfattr(attr, lctx, size, flags);

It seems that there is no (shared) check that the whole ctx is used. It
would be nice for the LSM hook implementations to return the processed
size and let this code check that there is no remaining data left, or at
least that it only contains zeros.

> +			break;
> +		}
> +
> +	kfree(lctx);
> +	return rc;
> +}
> +
>  /**
>   * security_getprocattr() - Read an attribute for a task
>   * @p: the task
> -- 
> 2.41.0
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 10/11] SELinux: Add selfattr hooks
  2023-08-02 17:44   ` [PATCH v13 10/11] SELinux: " Casey Schaufler
  2023-08-10 22:24     ` Paul Moore
@ 2023-08-25 15:00     ` Mickaël Salaün
  1 sibling, 0 replies; 38+ messages in thread
From: Mickaël Salaün @ 2023-08-25 15:00 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, selinux

On Wed, Aug 02, 2023 at 10:44:33AM -0700, Casey Schaufler wrote:
> 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 <casey@schaufler-ca.com>
> Cc: selinux@vger.kernel.org
> Cc: Paul Moore <paul@paul-moore.com>
> ---
>  security/selinux/hooks.c | 136 +++++++++++++++++++++++++++++++--------
>  1 file changed, 109 insertions(+), 27 deletions(-)

> +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;
> +
> +	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)

It looks a bit weird that size must be greater than all the LSM
attributes even when ctx is NULL. Same for other getselfattr hook
implementations.

> +		rc = -E2BIG;
> +	else if (ctx)
> +		rc = lsm_fill_user_ctx(ctx, value, len, LSM_ID_SELINUX, 0);
> +	else
> +		rc = 1;

Agreed with Paul, we should initialize rc to zero.

> +
> +	kfree(value);
> +	*size = total_len;
> +	if (rc < 0)
> +		return rc;
> +	return 1;
> +}
> +
> +static int selinux_setselfattr(unsigned int __user attr, struct lsm_ctx *ctx,
> +			       size_t __user size, u32 __user flags)

This __user attribute is dedicated to user pointers, not values.

> +{
> +	int rc;
> +

Good to see this refactoring!

> +	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);
> @@ -7080,6 +7160,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
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls
  2023-08-02 17:44   ` [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls Casey Schaufler
  2023-08-18 15:53     ` Serge Hallyn
  2023-08-23 17:27     ` Mickaël Salaün
@ 2023-08-25 15:01     ` Mickaël Salaün
  2023-08-25 18:14       ` Casey Schaufler
  2 siblings, 1 reply; 38+ messages in thread
From: Mickaël Salaün @ 2023-08-25 15:01 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api

These tests look good!

I suggested other tests to add in my previous emails.

I'd suggest to re-run clang-format -i on them though.

On Wed, Aug 02, 2023 at 10:44:34AM -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 <casey@schaufler-ca.com>
> ---
>  MAINTAINERS                                   |   1 +
>  tools/testing/selftests/Makefile              |   1 +
>  tools/testing/selftests/lsm/Makefile          |  19 ++
>  tools/testing/selftests/lsm/common.c          |  81 ++++++
>  tools/testing/selftests/lsm/common.h          |  33 +++
>  tools/testing/selftests/lsm/config            |   3 +
>  .../selftests/lsm/lsm_get_self_attr_test.c    | 240 ++++++++++++++++++
>  .../selftests/lsm/lsm_list_modules_test.c     | 140 ++++++++++
>  .../selftests/lsm/lsm_set_self_attr_test.c    |  74 ++++++
>  9 files changed, 592 insertions(+)
>  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 aca4db11dd02..c96f1c388d22 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19158,6 +19158,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 666b56f22a41..bde7c217b23f 100644
> --- a/tools/testing/selftests/Makefile
> +++ b/tools/testing/selftests/Makefile
> @@ -39,6 +39,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/Makefile b/tools/testing/selftests/lsm/Makefile
> new file mode 100644
> index 000000000000..bae6c1e3bba4
> --- /dev/null
> +++ b/tools/testing/selftests/lsm/Makefile
> @@ -0,0 +1,19 @@
> +# 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
> +
> +$(TEST_GEN_PROGS):

This target can be removed.

> +
> +$(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

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls
  2023-08-25 15:01     ` Mickaël Salaün
@ 2023-08-25 18:14       ` Casey Schaufler
  2023-08-25 18:58         ` Mickaël Salaün
  0 siblings, 1 reply; 38+ messages in thread
From: Casey Schaufler @ 2023-08-25 18:14 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, Casey Schaufler

On 8/25/2023 8:01 AM, Mickaël Salaün wrote:
> These tests look good!
>
> I suggested other tests to add in my previous emails.

Some of the tests you've suggested will be very difficult to implement
in the face of varying LSM configurations. I need to defer them until a
later date.

> I'd suggest to re-run clang-format -i on them though.

I assume you're recommending a set of options to clang-format
beyond just "-i". The result of clang-format -i by itself is
horrific. 

>
> On Wed, Aug 02, 2023 at 10:44:34AM -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 <casey@schaufler-ca.com>
>> ---
>>  MAINTAINERS                                   |   1 +
>>  tools/testing/selftests/Makefile              |   1 +
>>  tools/testing/selftests/lsm/Makefile          |  19 ++
>>  tools/testing/selftests/lsm/common.c          |  81 ++++++
>>  tools/testing/selftests/lsm/common.h          |  33 +++
>>  tools/testing/selftests/lsm/config            |   3 +
>>  .../selftests/lsm/lsm_get_self_attr_test.c    | 240 ++++++++++++++++++
>>  .../selftests/lsm/lsm_list_modules_test.c     | 140 ++++++++++
>>  .../selftests/lsm/lsm_set_self_attr_test.c    |  74 ++++++
>>  9 files changed, 592 insertions(+)
>>  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 aca4db11dd02..c96f1c388d22 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -19158,6 +19158,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 666b56f22a41..bde7c217b23f 100644
>> --- a/tools/testing/selftests/Makefile
>> +++ b/tools/testing/selftests/Makefile
>> @@ -39,6 +39,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/Makefile b/tools/testing/selftests/lsm/Makefile
>> new file mode 100644
>> index 000000000000..bae6c1e3bba4
>> --- /dev/null
>> +++ b/tools/testing/selftests/lsm/Makefile
>> @@ -0,0 +1,19 @@
>> +# 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
>> +
>> +$(TEST_GEN_PROGS):
> This target can be removed.
>
>> +
>> +$(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

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls
  2023-08-25 18:14       ` Casey Schaufler
@ 2023-08-25 18:58         ` Mickaël Salaün
  0 siblings, 0 replies; 38+ messages in thread
From: Mickaël Salaün @ 2023-08-25 18:58 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api

On Fri, Aug 25, 2023 at 11:14:15AM -0700, Casey Schaufler wrote:
> On 8/25/2023 8:01 AM, Mickaël Salaün wrote:
> > These tests look good!
> >
> > I suggested other tests to add in my previous emails.
> 
> Some of the tests you've suggested will be very difficult to implement
> in the face of varying LSM configurations. I need to defer them until a
> later date.

Sure, some might be difficult, but some bound checks (e.g. extra flags)
should be doable.

> 
> > I'd suggest to re-run clang-format -i on them though.
> 
> I assume you're recommending a set of options to clang-format
> beyond just "-i". The result of clang-format -i by itself is
> horrific. 

I just ran clang -i (with the default kernel configuration, which is
taken into account by default). This just add four changes: the PROCATTR
define and three ASSERT*() calls, which are not too uggly IMO.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v13 04/11] LSM: syscalls for current process attributes
  2023-08-25 14:59     ` Mickaël Salaün
@ 2023-08-25 22:23       ` Casey Schaufler
  0 siblings, 0 replies; 38+ messages in thread
From: Casey Schaufler @ 2023-08-25 22:23 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: paul, linux-security-module, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work,
	linux-kernel, linux-api, Casey Schaufler

On 8/25/2023 7:59 AM, Mickaël Salaün wrote:
> On Wed, Aug 02, 2023 at 10:44:27AM -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 <casey@schaufler-ca.com>
>> Reviewed-by: Kees Cook <keescook@chromium.org>
>> Reviewed-by: Serge Hallyn <serge@hallyn.com>
>> ---
>>  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            |  90 ++++++++++++++++++++
>>  kernel/sys_ni.c                     |   2 +
>>  security/Makefile                   |   1 +
>>  security/lsm_syscalls.c             |  55 ++++++++++++
>>  security/security.c                 | 125 ++++++++++++++++++++++++++++
>>  10 files changed, 372 insertions(+)
>>  create mode 100644 Documentation/userspace-api/lsm.rst
>>  create mode 100644 include/uapi/linux/lsm.h
>>  create mode 100644 security/lsm_syscalls.c
>> +/**
>> + * sys_lsm_get_self_attr - Return current task's security module attributes
>> + * @attr: which attribute to set
>> + * @ctx: the LSM contexts
>> + * @size: size of @ctx, updated on return
>> + * @flags: reserved for future use
> This documentation is out-of-sync with the LSM hook doc, especially the
> flags.

You are correct. I will repair it.

>
>> + *
>> + * 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 5e9cd548dd95..cde7f3a13e7c 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -3798,6 +3798,131 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
>>  }
>>  EXPORT_SYMBOL(security_d_instantiate);
>>  
>> +/**
>> + * security_getselfattr - Read an LSM attribute of the current process.
>> + * @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
> The final dot is missing.

Will fix.

>
>> + *
>> + * A NULL value for @ctx 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 *ctx,
>> +			 size_t __user *size, u32 flags)
>> +{
>> +	struct security_hook_list *hp;
>> +	struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
>> +	u8 __user *base = (u8 __user *)ctx;
>> +	size_t total = 0;
>> +	size_t entrysize;
>> +	size_t left;
>> +	bool toobig = 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 & LSM_FLAG_SINGLE) == LSM_FLAG_SINGLE) {
>> +		if (!ctx)
> This doesn't fit with the documenation. I guess it should handle NULL
> ctx in both cases.

It's also not correct. I've reworked the single case logic.

>
> This cases should be tested.
>
> I'm now wondering if this LSM_FLAG_SINGLE makes sense though.

It does if you want to pick up the attributes one at a time in
separate code paths in an application.

>
>> +			return -EINVAL;
>> +		if (copy_struct_from_user(&lctx, sizeof(lctx), ctx, left))
> This check looks good but it looks inconsistent with the
> non-LSM_FLAG_SINGLE loop which doesn't check that the arrays only
> contain zeros.

The single case is the only case where the data is read from user-space.
They're inconsistent because the use of the user-space memory is read+write
in the one case and write-only in the other.

>
>> +			return -EFAULT;
>> +		if (lctx.id == LSM_ID_UNDEF)
>> +			return -EINVAL;
>> +	} else if (flags) {
> This check is not correct. It should test if there is no value other
> than LSM_FLAG_SINGLE.

I've reworked the single logic.

>
> Please add a test with something like this:
> lsm_get_self_attr(valid_attr, valid_ctx, valid_size, LSM_FLAG_SINGLE | 1 << 9)
>
>> +		return -EINVAL;
>> +	}
>> +
> Please add a comment to highlight that only LSM_FLAG_SINGLE is handled
> for this loop.

I don't follow. The loop handles both single and multiple cases.

>
>> +	hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
>> +		if (lctx.id != LSM_ID_UNDEF && lctx.id != hp->lsmid->id)
>> +			continue;
>> +		entrysize = left;
>> +		if (base)
>> +			ctx = (struct lsm_ctx __user *)(base + total);
> To be consistent with the previous copy_struct_from_user() call, we
> should at least check that the ctx arrays contain zeros too.

We don't care because this is the copy-out part. The user-space data
isn't being read here.

>
> We should add a test for this case.
>
>> +		rc = hp->hook.getselfattr(attr, ctx, &entrysize, flags);
>> +		if (rc == -EOPNOTSUPP) {
>> +			rc = 0;
>> +			continue;
>> +		}
>> +		if (rc == -E2BIG) {
>> +			toobig = true;
>> +			left = 0;
>> +			continue;
>> +		}
>> +		if (rc < 0)
>> +			return rc;
>> +
>> +		left -= entrysize;
>> +		total += entrysize;
>> +		count += rc;
>> +	}
>> +	if (put_user(total, size))
>> +		return -EFAULT;
>> +	if (toobig)
>> +		return -E2BIG;
>> +	if (count == 0)
>> +		return LSM_RET_DEFAULT(getselfattr);
>> +	return count;
>> +}
>> +
>> +/**
>> + * security_setselfattr - Set an LSM attribute on the current process.
>> + * @attr: which attribute to set
>> + * @ctx: 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 @ctx.
>> + *
>> + * Returns 0 on success, -EINVAL if the input is inconsistent, -EFAULT
>> + * if the user buffer is inaccessible or an LSM specific failure.
>> + */
>> +int security_setselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
>> +			 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(*ctx))
>> +		return -EINVAL;
>> +
>> +	lctx = kmalloc(size, GFP_KERNEL);
> We should not allow user space to allocate arbitrary kernel buffer size.
> Limiting to PAGE_SIZE seems reasonable.

Quite reasonable.

>
>> +	if (lctx == NULL)
>> +		return -ENOMEM;
>> +
>> +	if (copy_from_user(&lctx, ctx, size))
>> +		return -EFAULT;
>> +
>> +	if (size < lctx->len || size < lctx->ctx_len + sizeof(ctx) ||
> Because we only handle one LSM at a time, size should be equal to
> lctx->len right?

Unless they've done some of the padding Paul's so keen on.

>
>> +	    lctx->len < lctx->ctx_len + sizeof(ctx))
>> +		return -EINVAL;
>> +
>> +	hlist_for_each_entry(hp, &security_hook_heads.setselfattr, list)
>> +		if ((hp->lsmid->id) == lctx->id) {
>> +			rc = hp->hook.setselfattr(attr, lctx, size, flags);
> It seems that there is no (shared) check that the whole ctx is used. It
> would be nice for the LSM hook implementations to return the processed
> size and let this code check that there is no remaining data left, or at
> least that it only contains zeros.

Again, it's the possible padding case.

>
>> +			break;
>> +		}
>> +
>> +	kfree(lctx);
>> +	return rc;
>> +}
>> +
>>  /**
>>   * security_getprocattr() - Read an attribute for a task
>>   * @p: the task
>> -- 
>> 2.41.0
>>

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2023-08-25 22:24 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20230802174435.11928-1-casey.ref@schaufler-ca.com>
2023-08-02 17:44 ` [PATCH v13 00/11] LSM: Three basic syscalls Casey Schaufler
2023-08-02 17:44   ` [PATCH v13 01/11] LSM: Identify modules by more than name Casey Schaufler
2023-08-10 15:54     ` John Johansen
2023-08-18 18:00     ` Mickaël Salaün
2023-08-02 17:44   ` [PATCH v13 02/11] LSM: Maintain a table of LSM attribute data Casey Schaufler
2023-08-10 15:54     ` John Johansen
2023-08-18 17:58     ` Mickaël Salaün
2023-08-02 17:44   ` [PATCH v13 03/11] proc: Use lsmids instead of lsm names for attrs Casey Schaufler
2023-08-10 15:54     ` John Johansen
2023-08-02 17:44   ` [PATCH v13 04/11] LSM: syscalls for current process attributes Casey Schaufler
2023-08-10 15:55     ` John Johansen
2023-08-23 17:27     ` Mickaël Salaün
2023-08-25  0:12     ` Mateusz Guzik
2023-08-25 14:59     ` Mickaël Salaün
2023-08-25 22:23       ` Casey Schaufler
2023-08-02 17:44   ` [PATCH v13 05/11] LSM: Create lsm_list_modules system call Casey Schaufler
2023-08-10 15:55     ` John Johansen
2023-08-02 17:44   ` [PATCH v13 06/11] LSM: wireup Linux Security Module syscalls Casey Schaufler
2023-08-10 15:56     ` John Johansen
2023-08-02 17:44   ` [PATCH v13 07/11] LSM: Helpers for attribute names and filling lsm_ctx Casey Schaufler
2023-08-10 15:57     ` John Johansen
2023-08-02 17:44   ` [PATCH v13 08/11] Smack: implement setselfattr and getselfattr hooks Casey Schaufler
2023-08-10 15:57     ` John Johansen
2023-08-18 15:14     ` Serge Hallyn
2023-08-02 17:44   ` [PATCH v13 09/11] AppArmor: Add selfattr hooks Casey Schaufler
2023-08-10 15:53     ` John Johansen
2023-08-02 17:44   ` [PATCH v13 10/11] SELinux: " Casey Schaufler
2023-08-10 22:24     ` Paul Moore
2023-08-25 15:00     ` Mickaël Salaün
2023-08-02 17:44   ` [PATCH v13 11/11] LSM: selftests for Linux Security Module syscalls Casey Schaufler
2023-08-18 15:53     ` Serge Hallyn
2023-08-23 19:09       ` Casey Schaufler
2023-08-25  0:36         ` Serge Hallyn
2023-08-23 17:27     ` Mickaël Salaün
2023-08-25 15:01     ` Mickaël Salaün
2023-08-25 18:14       ` Casey Schaufler
2023-08-25 18:58         ` Mickaël Salaün
2023-08-10 22:32   ` [PATCH v13 00/11] LSM: Three basic syscalls Paul Moore

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.