2023-04-11 16:05:48

by Casey Schaufler

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

Add three system calls for the Linux Security Module ABI.

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

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

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

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

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

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

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

https://github.com/cschaufler/lsm-stacking.git#lsm-syscalls-6.3-rc2-a

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 an 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 | 1 +
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 | 25 +-
include/linux/security.h | 45 ++-
include/linux/syscalls.h | 6 +
include/uapi/asm-generic/unistd.h | 11 +-
include/uapi/linux/lsm.h | 84 ++++++
kernel/sys_ni.c | 5 +
security/Makefile | 1 +
security/apparmor/include/procattr.h | 2 +-
security/apparmor/lsm.c | 104 ++++++-
security/apparmor/procattr.c | 11 +-
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 | 208 ++++++++++++--
security/selinux/hooks.c | 162 +++++++++--
security/smack/smack_lsm.c | 113 +++++++-
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 | 12 +
tools/testing/selftests/lsm/config | 2 +
.../selftests/lsm/lsm_get_self_attr_test.c | 268 ++++++++++++++++++
.../selftests/lsm/lsm_list_modules_test.c | 149 ++++++++++
.../selftests/lsm/lsm_set_self_attr_test.c | 70 +++++
60 files changed, 1547 insertions(+), 101 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/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.39.2


2023-04-11 16:06:01

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v8 06/11] LSM: wireup Linux Security Module syscalls

Wireup lsm_get_self_attr, lsm_set_self_attr and lsm_list_modules
system calls.

Signed-off-by: Casey Schaufler <[email protected]>
Acked-by: Geert Uytterhoeven <[email protected]>
Acked-by: Arnd Bergmann <[email protected]>
Cc: [email protected]
---
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 | 11 ++++++++++-
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, 77 insertions(+), 2 deletions(-)

diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl
index 8ebacf37a8cf..178e2792c251 100644
--- a/arch/alpha/kernel/syscalls/syscall.tbl
+++ b/arch/alpha/kernel/syscalls/syscall.tbl
@@ -490,3 +490,6 @@
558 common process_mrelease sys_process_mrelease
559 common futex_waitv sys_futex_waitv
560 common set_mempolicy_home_node sys_ni_syscall
+561 common lsm_get_self_attr sys_lsm_get_self_attr
+562 common lsm_list_modules sys_lsm_list_modules
+563 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl
index ac964612d8b0..9cda144f9631 100644
--- a/arch/arm/tools/syscall.tbl
+++ b/arch/arm/tools/syscall.tbl
@@ -464,3 +464,6 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 037feba03a51..6a28fb91b85d 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 451
+#define __NR_compat_syscalls 454
#endif

#define __ARCH_WANT_SYS_CLONE
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h
index 604a2053d006..72022ffd5faa 100644
--- a/arch/arm64/include/asm/unistd32.h
+++ b/arch/arm64/include/asm/unistd32.h
@@ -907,6 +907,12 @@ __SYSCALL(__NR_process_mrelease, sys_process_mrelease)
__SYSCALL(__NR_futex_waitv, sys_futex_waitv)
#define __NR_set_mempolicy_home_node 450
__SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)
+#define __NR_lsm_get_self_attr 451
+__SYSCALL(__NR_lsm_get_self_attr, sys_lsm_get_self_attr)
+#define __NR_lsm_list_modules 452
+__SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules)
+#define __NR_lsm_set_self_attr 453
+__SYSCALL(__NR_lsm_set_self_attr, sys_lsm_set_self_attr)

/*
* 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 72c929d9902b..c52e9d87f47d 100644
--- a/arch/ia64/kernel/syscalls/syscall.tbl
+++ b/arch/ia64/kernel/syscalls/syscall.tbl
@@ -371,3 +371,6 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl
index b1f3940bc298..31eac3c99d84 100644
--- a/arch/m68k/kernel/syscalls/syscall.tbl
+++ b/arch/m68k/kernel/syscalls/syscall.tbl
@@ -450,3 +450,6 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl
index 820145e47350..5037fa1f74b8 100644
--- a/arch/microblaze/kernel/syscalls/syscall.tbl
+++ b/arch/microblaze/kernel/syscalls/syscall.tbl
@@ -456,3 +456,6 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl
index 253ff994ed2e..29545b3ec587 100644
--- a/arch/mips/kernel/syscalls/syscall_n32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n32.tbl
@@ -389,3 +389,6 @@
448 n32 process_mrelease sys_process_mrelease
449 n32 futex_waitv sys_futex_waitv
450 n32 set_mempolicy_home_node sys_set_mempolicy_home_node
+451 n32 lsm_get_self_attr sys_lsm_get_self_attr
+452 n32 lsm_list_modules sys_lsm_list_modules
+453 n32 lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl b/arch/mips/kernel/syscalls/syscall_n64.tbl
index 3f1886ad9d80..8492aa4a771f 100644
--- a/arch/mips/kernel/syscalls/syscall_n64.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n64.tbl
@@ -365,3 +365,6 @@
448 n64 process_mrelease sys_process_mrelease
449 n64 futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 n64 lsm_get_self_attr sys_lsm_get_self_attr
+452 n64 lsm_list_modules sys_lsm_list_modules
+453 n64 lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl b/arch/mips/kernel/syscalls/syscall_o32.tbl
index 8f243e35a7b2..d74fd86de2a2 100644
--- a/arch/mips/kernel/syscalls/syscall_o32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_o32.tbl
@@ -438,3 +438,6 @@
448 o32 process_mrelease sys_process_mrelease
449 o32 futex_waitv sys_futex_waitv
450 o32 set_mempolicy_home_node sys_set_mempolicy_home_node
+451 o32 lsm_get_self_attr sys_lsm_get_self_attr
+452 o32 lsm_list_modules sys_lsm_list_modules
+453 032 lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl
index 0e42fceb2d5e..d1a5f3120d6c 100644
--- a/arch/parisc/kernel/syscalls/syscall.tbl
+++ b/arch/parisc/kernel/syscalls/syscall.tbl
@@ -448,3 +448,6 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl
index a0be127475b1..a414fe8c069b 100644
--- a/arch/powerpc/kernel/syscalls/syscall.tbl
+++ b/arch/powerpc/kernel/syscalls/syscall.tbl
@@ -537,3 +537,6 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 nospu set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl
index 799147658dee..96b7e6b72747 100644
--- a/arch/s390/kernel/syscalls/syscall.tbl
+++ b/arch/s390/kernel/syscalls/syscall.tbl
@@ -453,3 +453,6 @@
448 common process_mrelease sys_process_mrelease sys_process_mrelease
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 lsm_get_self_attr sys_lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl
index 2de85c977f54..1a75a599bb55 100644
--- a/arch/sh/kernel/syscalls/syscall.tbl
+++ b/arch/sh/kernel/syscalls/syscall.tbl
@@ -453,3 +453,6 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl
index 4398cc6fb68d..80b165091f6f 100644
--- a/arch/sparc/kernel/syscalls/syscall.tbl
+++ b/arch/sparc/kernel/syscalls/syscall.tbl
@@ -496,3 +496,6 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 320480a8db4f..130f9feb9eb9 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -455,3 +455,6 @@
448 i386 process_mrelease sys_process_mrelease
449 i386 futex_waitv sys_futex_waitv
450 i386 set_mempolicy_home_node sys_set_mempolicy_home_node
+451 i386 lsm_get_self_attr sys_lsm_get_self_attr
+452 i386 lsm_list_modules sys_lsm_list_modules
+453 i386 lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index c84d12608cd2..96dd45bc5988 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -372,6 +372,9 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr

#
# 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 52c94ab5c205..2610aba19802 100644
--- a/arch/xtensa/kernel/syscalls/syscall.tbl
+++ b/arch/xtensa/kernel/syscalls/syscall.tbl
@@ -421,3 +421,6 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 45fa180cc56a..93f89fb06ef5 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -886,8 +886,17 @@ __SYSCALL(__NR_futex_waitv, sys_futex_waitv)
#define __NR_set_mempolicy_home_node 450
__SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)

+#define __NR_lsm_get_self_attr 451
+__SYSCALL(__NR_lsm_get_self_attr, sys_lsm_get_self_attr)
+
+#define __NR_lsm_list_modules 452
+__SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules)
+
+#define __NR_lsm_set_self_attr 453
+__SYSCALL(__NR_lsm_set_self_attr, sys_lsm_set_self_attr)
+
#undef __NR_syscalls
-#define __NR_syscalls 451
+#define __NR_syscalls 454

/*
* 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 3f1886ad9d80..8492aa4a771f 100644
--- a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl
+++ b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl
@@ -365,3 +365,6 @@
448 n64 process_mrelease sys_process_mrelease
449 n64 futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 n64 lsm_get_self_attr sys_lsm_get_self_attr
+452 n64 lsm_list_modules sys_lsm_list_modules
+453 n64 lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
index a0be127475b1..a414fe8c069b 100644
--- a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
+++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
@@ -537,3 +537,6 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 nospu set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/tools/perf/arch/s390/entry/syscalls/syscall.tbl b/tools/perf/arch/s390/entry/syscalls/syscall.tbl
index 799147658dee..f9257e040109 100644
--- a/tools/perf/arch/s390/entry/syscalls/syscall.tbl
+++ b/tools/perf/arch/s390/entry/syscalls/syscall.tbl
@@ -453,3 +453,6 @@
448 common process_mrelease sys_process_mrelease sys_process_mrelease
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 lsm_get_self_attr sys_lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr
diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
index c84d12608cd2..96dd45bc5988 100644
--- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
@@ -372,6 +372,9 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common lsm_get_self_attr sys_lsm_get_self_attr
+452 common lsm_list_modules sys_lsm_list_modules
+453 common lsm_set_self_attr sys_lsm_set_self_attr

#
# Due to a historical design error, certain syscalls are numbered differently
--
2.39.2

2023-04-11 16:06:02

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v8 02/11] LSM: Maintain a table of LSM attribute data

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 <[email protected]>
---
include/linux/security.h | 2 ++
security/security.c | 43 ++++++++++++++++++++++++++++++++--------
2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 5984d0d550b4..e70fc863b04a 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 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 58828a326024..3f98e5171176 100644
--- a/security/security.c
+++ b/security/security.c
@@ -28,12 +28,29 @@
#include <linux/backing-dev.h>
#include <linux/string.h>
#include <linux/msg.h>
+#include <uapi/linux/lsm.h>
#include <net/flow.h>

#define MAX_LSM_EVM_XATTR 2

-/* 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_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
@@ -90,7 +107,7 @@ static __initdata const char *chosen_major_lsm;
static __initconst const char * const builtin_lsm_order = CONFIG_LSM;

/* Ordered list of LSMs to initialize. */
-static __initdata struct lsm_info **ordered_lsms;
+static __initdata struct lsm_info *ordered_lsms[LSM_COUNT + 1];
static __initdata struct lsm_info *exclusive;

static __initdata bool debug;
@@ -341,13 +358,16 @@ static void __init report_lsm_order(void)
pr_cont("\n");
}

+/*
+ * Current index to use while initializing the lsm id list.
+ */
+u32 lsm_active_cnt __lsm_ro_after_init;
+struct lsm_id *lsm_idlist[LSM_COUNT] __lsm_ro_after_init;
+
static void __init ordered_lsm_init(void)
{
struct lsm_info **lsm;

- ordered_lsms = kcalloc(LSM_COUNT + 1, sizeof(*ordered_lsms),
- GFP_KERNEL);
-
if (chosen_lsm_order) {
if (chosen_major_lsm) {
pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
@@ -387,8 +407,6 @@ static void __init ordered_lsm_init(void)
lsm_early_task(current);
for (lsm = ordered_lsms; *lsm; lsm++)
initialize_lsm(*lsm);
-
- kfree(ordered_lsms);
}

int __init early_security_init(void)
@@ -513,6 +531,15 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
{
int i;

+ if (lsm_active_cnt >= LSM_COUNT)
+ panic("%s Too many LSMs registered.\n", __func__);
+ /*
+ * A security module may call security_add_hooks() more
+ * than once. Landlock is one such case.
+ */
+ if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid)
+ 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.39.2

2023-04-11 16:06:53

by Casey Schaufler

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

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

Signed-off-by: Casey Schaufler <[email protected]>
Cc: John Johansen <[email protected]>
---
security/apparmor/include/procattr.h | 2 +-
security/apparmor/lsm.c | 96 ++++++++++++++++++++++++++--
security/apparmor/procattr.c | 11 +++-
3 files changed, 99 insertions(+), 10 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 ce6ccb7e06ec..16ae61cec26a 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -630,6 +630,45 @@ static int apparmor_sb_pivotroot(const struct path *old_path,
return error;
}

+static int apparmor_getselfattr(unsigned int __user attr,
+ struct lsm_ctx __user *lx, size_t *size,
+ u32 __user flags)
+{
+ int error = -ENOENT;
+ struct aa_task_ctx *ctx = task_ctx(current);
+ struct aa_label *label = NULL;
+ size_t total_len;
+ char *value;
+
+ if (attr == LSM_ATTR_CURRENT)
+ label = aa_get_newest_label(cred_label(current_cred()));
+ else if (attr == LSM_ATTR_PREV && ctx->previous)
+ label = aa_get_newest_label(ctx->previous);
+ else if (attr == LSM_ATTR_EXEC && ctx->onexec)
+ label = aa_get_newest_label(ctx->onexec);
+ else
+ error = -EOPNOTSUPP;
+
+ if (label) {
+ error = aa_getprocattr(label, &value, false);
+ if (error > 0) {
+ total_len = error + sizeof(*ctx);
+ if (total_len > *size)
+ error = -E2BIG;
+ else
+ lsm_fill_user_ctx(lx, value, error,
+ LSM_ID_APPARMOR, 0);
+ }
+ }
+
+ aa_put_label(label);
+
+ *size = total_len;
+ if (error > 0)
+ return 1;
+ return error;
+}
+
static int apparmor_getprocattr(struct task_struct *task, const char *name,
char **value)
{
@@ -649,7 +688,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 +696,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 +727,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 +742,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 +762,57 @@ 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 __user attr,
+ struct lsm_ctx __user *ctx, size_t __user size,
+ u32 __user flags)
+{
+ struct lsm_ctx *lctx;
+ void *context;
+ int rc;
+
+ if (attr != LSM_ATTR_CURRENT && attr != LSM_ATTR_EXEC)
+ return -EOPNOTSUPP;
+
+ context = kmalloc(size, GFP_KERNEL);
+ if (context == NULL)
+ return -ENOMEM;
+
+ lctx = (struct lsm_ctx *)context;
+ if (copy_from_user(context, ctx, size))
+ rc = -EFAULT;
+ else if (lctx->ctx_len > size)
+ rc = -EINVAL;
+ else
+ rc = do_setattr(attr, lctx + 1, lctx->ctx_len);
+
+ kfree(context);
+ 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 +1335,8 @@ static struct security_hook_list apparmor_hooks[] __lsm_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..196f319aa3b2 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,10 +58,14 @@ 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);
+
+ if (newline)
+ return len;
return len + 1;
}

--
2.39.2

2023-04-11 16:07:04

by Casey Schaufler

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

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

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

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9403aee75981..beb1d6f5e000 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6348,8 +6348,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;
@@ -6367,20 +6367,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();
@@ -6398,7 +6405,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;
@@ -6409,28 +6416,36 @@ 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_CURRENT:
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
+ PROCESS__SETCURRENT, NULL);
+ break;
+ case LSM_ATTR_EXEC:
error = avc_has_perm(&selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETEXEC, NULL);
- else if (!strcmp(name, "fscreate"))
+ break;
+ case LSM_ATTR_FSCREATE:
error = avc_has_perm(&selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETFSCREATE, NULL);
- else if (!strcmp(name, "keycreate"))
+ break;
+ case LSM_ATTR_KEYCREATE:
error = avc_has_perm(&selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETKEYCREATE, NULL);
- else if (!strcmp(name, "sockcreate"))
+ break;
+ case LSM_ATTR_SOCKCREATE:
error = avc_has_perm(&selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETSOCKCREATE, NULL);
- else if (!strcmp(name, "current"))
- error = avc_has_perm(&selinux_state,
- mysid, mysid, SECCLASS_PROCESS,
- PROCESS__SETCURRENT, NULL);
- else
- error = -EINVAL;
+ break;
+ default:
+ error = -EOPNOTSUPP;
+ break;
+ }
if (error)
return error;

@@ -6442,13 +6457,14 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
}
error = security_context_to_sid(&selinux_state, 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
@@ -6459,7 +6475,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;
@@ -6483,11 +6500,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(&selinux_state, mysid, sid,
SECCLASS_KEY, KEY__CREATE, NULL);
@@ -6495,9 +6512,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;
@@ -6542,6 +6559,80 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
return error;
}

+static int selinux_getselfattr(unsigned int __user attr,
+ struct lsm_ctx __user *ctx, size_t *size,
+ u32 __user flags)
+{
+ char *value;
+ size_t total_len;
+ int len;
+ int rc = 1;
+
+ len = selinux_lsm_getattr(attr, current, &value);
+ if (len < 0)
+ return len;
+
+ total_len = len + sizeof(*ctx);
+
+ if (total_len > *size)
+ rc = -E2BIG;
+ else
+ lsm_fill_user_ctx(ctx, value, len, LSM_ID_SELINUX, 0);
+
+ *size = total_len;
+ return rc;
+}
+
+static int selinux_setselfattr(unsigned int __user attr,
+ struct lsm_ctx __user *ctx, size_t __user size,
+ u32 __user flags)
+{
+ struct lsm_ctx *lctx;
+ void *context;
+ int rc;
+
+ context = kmalloc(size, GFP_KERNEL);
+ if (context == NULL)
+ return -ENOMEM;
+
+ lctx = (struct lsm_ctx *)context;
+ if (copy_from_user(context, ctx, size))
+ rc = -EFAULT;
+ else if (lctx->ctx_len > size)
+ rc = -EINVAL;
+ else
+ rc = selinux_lsm_setattr(attr, lctx + 1, lctx->ctx_len);
+
+ kfree(context);
+ 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);
@@ -7183,6 +7274,8 @@ static struct security_hook_list selinux_hooks[] __lsm_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.39.2

2023-04-11 16:07:21

by Casey Schaufler

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

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

Add lsm_fill_user_ctx(), which fills a struct lsm_ctx, including
the trailing attribute value. The .len value is padded to a multiple
of the size of the structure for alignment.

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

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/security.h | 13 +++++++++++
security/lsm_syscalls.c | 24 ++++++++++++++++++++
security/security.c | 48 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 85 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index f7292890b6a2..c96fb56159e3 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -263,6 +263,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);
@@ -491,6 +492,8 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
int security_locked_down(enum lockdown_reason what);
+int lsm_fill_user_ctx(struct lsm_ctx __user *ctx, void *context,
+ size_t context_size, u64 id, u64 flags);
#else /* CONFIG_SECURITY */

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

+static inline u64 lsm_name_to_attr(const char *name)
+{
+ return 0;
+}
+
static inline void security_free_mnt_opts(void **mnt_opts)
{
}
@@ -1420,6 +1428,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 0;
+}
#endif /* CONFIG_SECURITY */

#if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
index 6efbe244d304..67106f642422 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 0;
+}
+
/**
* 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 bfe9a1a426b2..453f3ff591ec 100644
--- a/security/security.c
+++ b/security/security.c
@@ -752,6 +752,54 @@ 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.
+ *
+ * The total length is padded to an integral number of lsm_ctx.
+ *
+ * Returns 0 on success, -EFAULT on a copyout error.
+ */
+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;
+ u8 *composite;
+ int rc = 0;
+
+ locallen = sizeof(*ctx);
+ if (context_size)
+ locallen += sizeof(*ctx) * ((context_size / sizeof(*ctx)) + 1);
+
+ composite = kzalloc(locallen, GFP_KERNEL);
+ if (composite == NULL)
+ return -ENOMEM;
+
+ lctx = (struct lsm_ctx *)composite;
+ lctx->id = id;
+ lctx->flags = flags;
+ lctx->ctx_len = context_size;
+ lctx->len = locallen;
+
+ memcpy(composite + sizeof(*lctx), context, context_size);
+
+ if (copy_to_user(ctx, composite, locallen))
+ rc = -EFAULT;
+
+ kfree(composite);
+
+ return rc;
+}
+
/*
* The default value of the LSM hook is defined in linux/lsm_hook_defs.h and
* can be accessed with:
--
2.39.2

2023-04-11 16:07:52

by Casey Schaufler

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

Add selftests for the three system calls supporting the LSM
infrastructure.

Signed-off-by: Casey Schaufler <[email protected]>
---
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/lsm/Makefile | 12 +
tools/testing/selftests/lsm/config | 2 +
.../selftests/lsm/lsm_get_self_attr_test.c | 268 ++++++++++++++++++
.../selftests/lsm/lsm_list_modules_test.c | 149 ++++++++++
.../selftests/lsm/lsm_set_self_attr_test.c | 70 +++++
6 files changed, 502 insertions(+)
create mode 100644 tools/testing/selftests/lsm/Makefile
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/Makefile b/tools/testing/selftests/Makefile
index 13a6837a0c6b..b18d133a1141 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -38,6 +38,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..f39a75212b78
--- /dev/null
+++ b/tools/testing/selftests/lsm/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# First run: make -C ../../../.. headers_install
+
+CFLAGS += -Wall -O2 $(KHDR_INCLUDES)
+
+TEST_GEN_PROGS := lsm_get_self_attr_test lsm_list_modules_test \
+ lsm_set_self_attr_test
+
+include ../lib.mk
+
+$(TEST_GEN_PROGS):
diff --git a/tools/testing/selftests/lsm/config b/tools/testing/selftests/lsm/config
new file mode 100644
index 000000000000..afb887715f64
--- /dev/null
+++ b/tools/testing/selftests/lsm/config
@@ -0,0 +1,2 @@
+CONFIG_SYSFS=y
+CONFIG_SECURITY=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..2c61a1411c54
--- /dev/null
+++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Security Module infrastructure tests
+ * Tests for the lsm_get_self_attr system call
+ *
+ * Copyright © 2022 Casey Schaufler <[email protected]>
+ * Copyright © 2022 Intel Corporation
+ */
+
+#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"
+
+#define PROCATTR "/proc/self/attr/"
+
+static int read_proc_attr(const char *attr, char *value, __kernel_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;
+fprintf(stderr, "len=%d\n", len);
+ close(fd);
+
+ path = strchr(value, '\n');
+ if (path)
+ *path = '\0';
+
+ return 0;
+}
+
+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);
+ char *ctx = calloc(page_size, 1);
+
+ ASSERT_NE(NULL, ctx);
+ ASSERT_EQ(-1, syscall(__NR_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);
+ __kernel_size_t size = page_size;
+
+ ASSERT_NE(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, NULL,
+ &size, 0));
+ ASSERT_NE(1, size);
+}
+
+TEST(size_too_small_lsm_get_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ char *ctx = calloc(page_size, 1);
+ __kernel_size_t size = 1;
+
+ ASSERT_NE(NULL, ctx);
+ ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx,
+ &size, 0));
+ ASSERT_EQ(E2BIG, errno);
+ ASSERT_NE(1, size);
+
+ free(ctx);
+}
+
+TEST(flags_zero_lsm_get_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ char *ctx = calloc(page_size, 1);
+ __kernel_size_t size = page_size;
+
+ ASSERT_NE(NULL, ctx);
+ ASSERT_EQ(-1, syscall(__NR_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);
+ char *ctx = calloc(page_size, 1);
+ __kernel_size_t size = page_size;
+
+ ASSERT_NE(NULL, ctx);
+ ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr,
+ LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx, &size, 0));
+ ASSERT_EQ(EOPNOTSUPP, errno);
+ ASSERT_EQ(page_size, size);
+
+ free(ctx);
+}
+
+TEST(basic_lsm_get_self_attr)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ __kernel_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 = syscall(__NR_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 = syscall(__NR_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 = syscall(__NR_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 = syscall(__NR_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 = syscall(__NR_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 = syscall(__NR_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..3ec814002710
--- /dev/null
+++ b/tools/testing/selftests/lsm/lsm_list_modules_test.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Security Module infrastructure tests
+ * Tests for the lsm_list_modules system call
+ *
+ * Copyright © 2022 Casey Schaufler <[email protected]>
+ * Copyright © 2022 Intel Corporation
+ */
+
+#define _GNU_SOURCE
+#include <linux/lsm.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "../kselftest_harness.h"
+
+static int read_sysfs_lsms(char *lsms, __kernel_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;
+}
+
+TEST(size_null_lsm_list_modules)
+{
+ const long page_size = sysconf(_SC_PAGESIZE);
+ char *syscall_lsms = calloc(page_size, 1);
+
+ ASSERT_NE(NULL, syscall_lsms);
+ ASSERT_EQ(-1, syscall(__NR_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);
+ __kernel_size_t size = page_size;
+
+ ASSERT_EQ(-1, syscall(__NR_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);
+ char *syscall_lsms = calloc(page_size, 1);
+ __kernel_size_t size = 1;
+
+ ASSERT_NE(NULL, syscall_lsms);
+ ASSERT_EQ(-1, syscall(__NR_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);
+ char *syscall_lsms = calloc(page_size, 1);
+ __kernel_size_t size = page_size;
+
+ ASSERT_NE(NULL, syscall_lsms);
+ ASSERT_EQ(-1, syscall(__NR_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);
+ __kernel_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 = syscall(__NR_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..ca538a703168
--- /dev/null
+++ b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Security Module infrastructure tests
+ * Tests for the lsm_set_self_attr system call
+ *
+ * Copyright © 2022 Casey Schaufler <[email protected]>
+ * Copyright © 2022 Intel Corporation
+ */
+
+#define _GNU_SOURCE
+#include <linux/lsm.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "../kselftest_harness.h"
+
+TEST(ctx_null_lsm_set_self_attr)
+{
+ ASSERT_EQ(-1, syscall(__NR_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);
+ __kernel_size_t size = page_size;
+
+ ASSERT_NE(NULL, ctx);
+ ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx,
+ &size, 0));
+ ASSERT_EQ(-1, syscall(__NR_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);
+ char *ctx = calloc(page_size, 1);
+ __kernel_size_t size = page_size;
+
+ ASSERT_NE(NULL, ctx);
+ ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx,
+ &size, 0));
+ ASSERT_EQ(-1, syscall(__NR_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);
+ __kernel_size_t size = page_size;
+ struct lsm_ctx *tctx = (struct lsm_ctx *)ctx;
+
+ ASSERT_NE(NULL, ctx);
+ ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, tctx,
+ &size, 0));
+ ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr,
+ LSM_ATTR_CURRENT | LSM_ATTR_PREV, tctx, size, 0));
+
+ free(ctx);
+}
+
+TEST_HARNESS_MAIN
--
2.39.2

2023-04-11 16:08:16

by Casey Schaufler

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

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

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

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3cf862fcbe08..0068bab21f64 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3552,6 +3552,41 @@ 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 __user attr,
+ struct lsm_ctx __user *ctx, size_t *size,
+ u32 __user flags)
+{
+ struct smack_known *skp = smk_of_current();
+ int total;
+ int slen;
+ int rc = 1;
+
+ if (attr != LSM_ATTR_CURRENT)
+ return -EOPNOTSUPP;
+
+ slen = strlen(skp->smk_known) + 1;
+ total = slen + sizeof(*ctx);
+ if (total > *size)
+ rc = -E2BIG;
+ else
+ lsm_fill_user_ctx(ctx, skp->smk_known, slen, LSM_ID_SMACK, 0);
+
+ *size = total;
+ return rc;
+}
+
/**
* smack_getprocattr - Smack process attribute access
* @p: the object task
@@ -3581,8 +3616,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
*
@@ -3591,7 +3626,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;
@@ -3605,8 +3640,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))
@@ -3645,6 +3680,64 @@ 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 __user attr,
+ struct lsm_ctx __user *ctx, size_t __user size,
+ u32 __user flags)
+{
+ struct lsm_ctx *lctx;
+ void *context;
+ int rc;
+
+ context = kmalloc(size, GFP_KERNEL);
+ if (context == NULL)
+ return -ENOMEM;
+
+ lctx = (struct lsm_ctx *)context;
+ if (copy_from_user(context, ctx, size))
+ rc = -EFAULT;
+ else if (lctx->ctx_len > size)
+ rc = -EINVAL;
+ else
+ rc = do_setattr(attr, lctx + 1, lctx->ctx_len);
+
+ kfree(context);
+ 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)
+ return do_setattr(attr, value, size);
+ return -EINVAL;
+}
+
/**
* smack_unix_stream_connect - Smack access on UDS
* @sock: one sock
@@ -4955,6 +5048,8 @@ static struct security_hook_list smack_hooks[] __lsm_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.39.2

2023-04-18 22:15:57

by Paul Moore

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

On Tue, Apr 11, 2023 at 12:02 PM Casey Schaufler <[email protected]> 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. The .len value is padded to a multiple
> of the size of the structure for alignment.
>
> All are used in module specific components of LSM system calls.
>
> Signed-off-by: Casey Schaufler <[email protected]>
> ---
> include/linux/security.h | 13 +++++++++++
> security/lsm_syscalls.c | 24 ++++++++++++++++++++
> security/security.c | 48 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 85 insertions(+)

...

> diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
> index 6efbe244d304..67106f642422 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 0;
> +}

Thank you :)

> /**
> * 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 bfe9a1a426b2..453f3ff591ec 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -752,6 +752,54 @@ 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.
> + *
> + * The total length is padded to an integral number of lsm_ctx.

Considering that lsm_ctx is variable length I'm not sure that makes a
lot of sense, how about we pad the total length so that the @ctx entry
is a multiple of 64-bits? If needed we can always change this later
as the lsm_ctx struct is inherently variable in length and userspace
will need to deal with the buffer regardless of alignment.

> + * Returns 0 on success, -EFAULT on a copyout error.
> + */
> +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;
> + u8 *composite;
> + int rc = 0;
> +
> + locallen = sizeof(*ctx);
> + if (context_size)
> + locallen += sizeof(*ctx) * ((context_size / sizeof(*ctx)) + 1);

It seems cleaner to use the kernel's ALIGN() macro:

/* ensure the lsm_ctx length is a multiple of 64-bits */
locallen = ALIGN(sizeof(*ctx) + context_size, 8);
lctx = kzalloc(locallen, GFP_KERNEL)
if (!lctx)
return -ENOMEM;

> + composite = kzalloc(locallen, GFP_KERNEL);
> + if (composite == NULL)
> + return -ENOMEM;
> +
> + lctx = (struct lsm_ctx *)composite;
> + lctx->id = id;
> + lctx->flags = flags;
> + lctx->ctx_len = context_size;
> + lctx->len = locallen;
> +
> + memcpy(composite + sizeof(*lctx), context, context_size);

Is there a problem with doing `memcpy(lctx->ctx, context,
context_size)` in place of the memcpy above? That is easier to read
and we can get rid of @composite.

> + if (copy_to_user(ctx, composite, locallen))
> + rc = -EFAULT;
> +
> + kfree(composite);
> +
> + return rc;
> +}

I understand Mickaël asked you to do a single copy_to_user(), but I'm
not sure it is worth it if we have to add a temporary buffer
allocation like that. How about something like below (v7 with some
tweaks/padding)? You could be a bit more clever with the memset if
you want, I was just typing this up quickly ...

int lsm_fill_user_ctx(...)
{
struct lsm_ctx lctx;

/* ensure the lctx length is a multiple of 64-bits */
lctx.len = ALIGN(sizeof(lctx) + context_size, 8);

lctx.id = id;
lctx.flags = flags;
lctx.ctx_len = context_size;

memset(ctx, 0, lctx.len);
if (copy_to_user(ctx, &lctx, sizeof(lctx))
return -EFAULT;
if (copy_to_user(&ctx[1], context, context_size)
return -EFAULT;

return 0;
}

--
paul-moore.com

2023-04-18 22:44:08

by Casey Schaufler

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

On 4/18/2023 2:51 PM, Paul Moore wrote:
> On Tue, Apr 11, 2023 at 12:02 PM Casey Schaufler <[email protected]> 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. The .len value is padded to a multiple
>> of the size of the structure for alignment.
>>
>> All are used in module specific components of LSM system calls.
>>
>> Signed-off-by: Casey Schaufler <[email protected]>
>> ---
>> include/linux/security.h | 13 +++++++++++
>> security/lsm_syscalls.c | 24 ++++++++++++++++++++
>> security/security.c | 48 ++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 85 insertions(+)
> ..
>
>> diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
>> index 6efbe244d304..67106f642422 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 0;
>> +}
> Thank you :)

It didn't hurt all that badly.

>
>> /**
>> * 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 bfe9a1a426b2..453f3ff591ec 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -752,6 +752,54 @@ 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.
>> + *
>> + * The total length is padded to an integral number of lsm_ctx.
> Considering that lsm_ctx is variable length I'm not sure that makes a
> lot of sense, how about we pad the total length so that the @ctx entry
> is a multiple of 64-bits?

64 is fine.

> If needed we can always change this later
> as the lsm_ctx struct is inherently variable in length and userspace
> will need to deal with the buffer regardless of alignment.
>
>> + * Returns 0 on success, -EFAULT on a copyout error.
>> + */
>> +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;
>> + u8 *composite;
>> + int rc = 0;
>> +
>> + locallen = sizeof(*ctx);
>> + if (context_size)
>> + locallen += sizeof(*ctx) * ((context_size / sizeof(*ctx)) + 1);
> It seems cleaner to use the kernel's ALIGN() macro:

Indeed. I'll do it.

>
> /* ensure the lsm_ctx length is a multiple of 64-bits */
> locallen = ALIGN(sizeof(*ctx) + context_size, 8);
> lctx = kzalloc(locallen, GFP_KERNEL)
> if (!lctx)
> return -ENOMEM;
>
>> + composite = kzalloc(locallen, GFP_KERNEL);
>> + if (composite == NULL)
>> + return -ENOMEM;
>> +
>> + lctx = (struct lsm_ctx *)composite;
>> + lctx->id = id;
>> + lctx->flags = flags;
>> + lctx->ctx_len = context_size;
>> + lctx->len = locallen;
>> +
>> + memcpy(composite + sizeof(*lctx), context, context_size);
> Is there a problem with doing `memcpy(lctx->ctx, context,
> context_size)` in place of the memcpy above?

Nope.

> That is easier to read
> and we can get rid of @composite.

Point.

>> + if (copy_to_user(ctx, composite, locallen))
>> + rc = -EFAULT;
>> +
>> + kfree(composite);
>> +
>> + return rc;
>> +}
> I understand Mickaël asked you to do a single copy_to_user(), but I'm
> not sure it is worth it if we have to add a temporary buffer
> allocation like that. How about something like below (v7 with some
> tweaks/padding)? You could be a bit more clever with the memset if
> you want, I was just typing this up quickly ...

I prefer two copies to the allocation myself. I'll incorporate this.

>
> int lsm_fill_user_ctx(...)
> {
> struct lsm_ctx lctx;
>
> /* ensure the lctx length is a multiple of 64-bits */
> lctx.len = ALIGN(sizeof(lctx) + context_size, 8);
>
> lctx.id = id;
> lctx.flags = flags;
> lctx.ctx_len = context_size;
>
> memset(ctx, 0, lctx.len);
> if (copy_to_user(ctx, &lctx, sizeof(lctx))
> return -EFAULT;
> if (copy_to_user(&ctx[1], context, context_size)
> return -EFAULT;
>
> return 0;
> }
>
> --
> paul-moore.com

2023-04-19 22:54:01

by Casey Schaufler

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

On 4/18/2023 3:43 PM, Casey Schaufler wrote:
> On 4/18/2023 2:51 PM, Paul Moore wrote:
>> On Tue, Apr 11, 2023 at 12:02 PM Casey Schaufler <[email protected]> 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. The .len value is padded to a multiple
>>> of the size of the structure for alignment.
>>>
>>> All are used in module specific components of LSM system calls.
>>>
>>> Signed-off-by: Casey Schaufler <[email protected]>
>>> ---
>>> include/linux/security.h | 13 +++++++++++
>>> security/lsm_syscalls.c | 24 ++++++++++++++++++++
>>> security/security.c | 48 ++++++++++++++++++++++++++++++++++++++++
>>> 3 files changed, 85 insertions(+)
>> ..
>>
>>> diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
>>> index 6efbe244d304..67106f642422 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 0;
>>> +}
>> Thank you :)
> It didn't hurt all that badly.
>
>>> /**
>>> * 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 bfe9a1a426b2..453f3ff591ec 100644
>>> --- a/security/security.c
>>> +++ b/security/security.c
>>> @@ -752,6 +752,54 @@ 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.
>>> + *
>>> + * The total length is padded to an integral number of lsm_ctx.
>> Considering that lsm_ctx is variable length I'm not sure that makes a
>> lot of sense, how about we pad the total length so that the @ctx entry
>> is a multiple of 64-bits?
> 64 is fine.
>
>> If needed we can always change this later
>> as the lsm_ctx struct is inherently variable in length and userspace
>> will need to deal with the buffer regardless of alignment.
>>
>>> + * Returns 0 on success, -EFAULT on a copyout error.
>>> + */
>>> +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;
>>> + u8 *composite;
>>> + int rc = 0;
>>> +
>>> + locallen = sizeof(*ctx);
>>> + if (context_size)
>>> + locallen += sizeof(*ctx) * ((context_size / sizeof(*ctx)) + 1);
>> It seems cleaner to use the kernel's ALIGN() macro:
> Indeed. I'll do it.
>
>> /* ensure the lsm_ctx length is a multiple of 64-bits */
>> locallen = ALIGN(sizeof(*ctx) + context_size, 8);
>> lctx = kzalloc(locallen, GFP_KERNEL)
>> if (!lctx)
>> return -ENOMEM;
>>
>>> + composite = kzalloc(locallen, GFP_KERNEL);
>>> + if (composite == NULL)
>>> + return -ENOMEM;
>>> +
>>> + lctx = (struct lsm_ctx *)composite;
>>> + lctx->id = id;
>>> + lctx->flags = flags;
>>> + lctx->ctx_len = context_size;
>>> + lctx->len = locallen;
>>> +
>>> + memcpy(composite + sizeof(*lctx), context, context_size);
>> Is there a problem with doing `memcpy(lctx->ctx, context,
>> context_size)` in place of the memcpy above?
> Nope.
>
>> That is easier to read
>> and we can get rid of @composite.
> Point.
>
>>> + if (copy_to_user(ctx, composite, locallen))
>>> + rc = -EFAULT;
>>> +
>>> + kfree(composite);
>>> +
>>> + return rc;
>>> +}
>> I understand Mickaël asked you to do a single copy_to_user(), but I'm
>> not sure it is worth it if we have to add a temporary buffer
>> allocation like that. How about something like below (v7 with some
>> tweaks/padding)? You could be a bit more clever with the memset if
>> you want, I was just typing this up quickly ...
> I prefer two copies to the allocation myself. I'll incorporate this.

After further review ...

The tweaks required for padding aren't as clean as all that, and memset()
isn't going to work for __user memory. I'm having trouble coming up with a
way to deal with the padding that doesn't require either allocation or a
third copy_to_user(). The inclusion of padding makes the kzalloc() and
single copy_to_user() pretty attractive.

>
>> int lsm_fill_user_ctx(...)
>> {
>> struct lsm_ctx lctx;
>>
>> /* ensure the lctx length is a multiple of 64-bits */
>> lctx.len = ALIGN(sizeof(lctx) + context_size, 8);
>>
>> lctx.id = id;
>> lctx.flags = flags;
>> lctx.ctx_len = context_size;
>>
>> memset(ctx, 0, lctx.len);
>> if (copy_to_user(ctx, &lctx, sizeof(lctx))
>> return -EFAULT;
>> if (copy_to_user(&ctx[1], context, context_size)
>> return -EFAULT;
>>
>> return 0;
>> }
>>
>> --
>> paul-moore.com