lsm/stable-6.8 PR 20240105

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCAAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAmWYKUIUHHBhdWxAcGF1
 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXNyHw/+IKnqL1MZ5QS+/HtSzi4jCL47N9yZ
 OHLol6XswyEGHH9myKPPGnT5lVA93v98v4ty2mws7EJUSGZQQUntYBPbU9Gi40+B
 XDzYSRocoj96sdlKeOJMgaWo3NBRD9HYSoGPDNWZixy6m+bLPk/Dqhn3FabKf1lo
 2qQSmstvChFRmVNkmgaQnBCAtWVqla4EJEL0EKX6cspHbuzRNTeJdTPn6Q/zOUVL
 O2znOZuEtSVpYS7yg3uJT0hHD8H0GnIciAcDAhyPSBL5Uk5l6gwJiACcdRfLRbgp
 QM5Z4qUFdKljV5XBCzYnfhhrx1df08h1SG84El8UK8HgTTfOZfYmawByJRWNJSQE
 TdCmtyyvEbfb61CKBFVwD7Tzb9/y8WgcY5N3Un8uCQqRzFIO+6cghHri5NrVhifp
 nPFlP4klxLHh3d7ZVekLmCMHbpaacRyJKwLy+f/nwbBEID47jpPkvZFIpbalat+r
 QaKRBNWdTeV+GZ+Yu0uWsI029aQnpcO1kAnGg09fl6b/dsmxeKOVWebir25AzQ++
 a702S8HRmj80X+VnXHU9a64XeGtBH7Nq0vu0lGHQPgwhSx/9P6/qICEPwsIriRjR
 I9OulWt4OBPDtlsonHFgDs+lbnd0Z0GJUwYT8e9pjRDMxijVO9lhAXyglVRmuNR8
 to2ByKP5BO+Vh8Y=
 =Py+n
 -----END PGP SIGNATURE-----

Merge tag 'lsm-pr-20240105' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm

Pull security module updates from Paul Moore:

 - Add three new syscalls: lsm_list_modules(), lsm_get_self_attr(), and
   lsm_set_self_attr().

   The first syscall simply lists the LSMs enabled, while the second and
   third get and set the current process' LSM attributes. Yes, these
   syscalls may provide similar functionality to what can be found under
   /proc or /sys, but they were designed to support multiple,
   simultaneaous (stacked) LSMs from the start as opposed to the current
   /proc based solutions which were created at a time when only one LSM
   was allowed to be active at a given time.

   We have spent considerable time discussing ways to extend the
   existing /proc interfaces to support multiple, simultaneaous LSMs and
   even our best ideas have been far too ugly to support as a kernel
   API; after +20 years in the kernel, I felt the LSM layer had
   established itself enough to justify a handful of syscalls.

   Support amongst the individual LSM developers has been nearly
   unanimous, with a single objection coming from Tetsuo (TOMOYO) as he
   is worried that the LSM_ID_XXX token concept will make it more
   difficult for out-of-tree LSMs to survive. Several members of the LSM
   community have demonstrated the ability for out-of-tree LSMs to
   continue to exist by picking high/unused LSM_ID values as well as
   pointing out that many kernel APIs rely on integer identifiers, e.g.
   syscalls (!), but unfortunately Tetsuo's objections remain.

   My personal opinion is that while I have no interest in penalizing
   out-of-tree LSMs, I'm not going to penalize in-tree development to
   support out-of-tree development, and I view this as a necessary step
   forward to support the push for expanded LSM stacking and reduce our
   reliance on /proc and /sys which has occassionally been problematic
   for some container users. Finally, we have included the linux-api
   folks on (all?) recent revisions of the patchset and addressed all of
   their concerns.

 - Add a new security_file_ioctl_compat() LSM hook to handle the 32-bit
   ioctls on 64-bit systems problem.

   This patch includes support for all of the existing LSMs which
   provide ioctl hooks, although it turns out only SELinux actually
   cares about the individual ioctls. It is worth noting that while
   Casey (Smack) and Tetsuo (TOMOYO) did not give explicit ACKs to this
   patch, they did both indicate they are okay with the changes.

 - Fix a potential memory leak in the CALIPSO code when IPv6 is disabled
   at boot.

   While it's good that we are fixing this, I doubt this is something
   users are seeing in the wild as you need to both disable IPv6 and
   then attempt to configure IPv6 labeled networking via
   NetLabel/CALIPSO; that just doesn't make much sense.

   Normally this would go through netdev, but Jakub asked me to take
   this patch and of all the trees I maintain, the LSM tree seemed like
   the best fit.

 - Update the LSM MAINTAINERS entry with additional information about
   our process docs, patchwork, bug reporting, etc.

   I also noticed that the Lockdown LSM is missing a dedicated
   MAINTAINERS entry so I've added that to the pull request. I've been
   working with one of the major Lockdown authors/contributors to see if
   they are willing to step up and assume a Lockdown maintainer role;
   hopefully that will happen soon, but in the meantime I'll continue to
   look after it.

 - Add a handful of mailmap entries for Serge Hallyn and myself.

* tag 'lsm-pr-20240105' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm: (27 commits)
  lsm: new security_file_ioctl_compat() hook
  lsm: Add a __counted_by() annotation to lsm_ctx.ctx
  calipso: fix memory leak in netlbl_calipso_add_pass()
  selftests: remove the LSM_ID_IMA check in lsm/lsm_list_modules_test
  MAINTAINERS: add an entry for the lockdown LSM
  MAINTAINERS: update the LSM entry
  mailmap: add entries for Serge Hallyn's dead accounts
  mailmap: update/replace my old email addresses
  lsm: mark the lsm_id variables are marked as static
  lsm: convert security_setselfattr() to use memdup_user()
  lsm: align based on pointer length in lsm_fill_user_ctx()
  lsm: consolidate buffer size handling into lsm_fill_user_ctx()
  lsm: correct error codes in security_getselfattr()
  lsm: cleanup the size counters in security_getselfattr()
  lsm: don't yet account for IMA in LSM_CONFIG_COUNT calculation
  lsm: drop LSM_ID_IMA
  LSM: selftests for Linux Security Module syscalls
  SELinux: Add selfattr hooks
  AppArmor: Add selfattr hooks
  Smack: implement setselfattr and getselfattr hooks
  ...
This commit is contained in:
Linus Torvalds 2024-01-09 12:57:46 -08:00
commit 063a7ce32d
66 changed files with 1784 additions and 122 deletions

View File

@ -478,6 +478,8 @@ Paul E. McKenney <paulmck@kernel.org> <paulmck@linux.vnet.ibm.com>
Paul E. McKenney <paulmck@kernel.org> <paulmck@us.ibm.com>
Paul Mackerras <paulus@ozlabs.org> <paulus@samba.org>
Paul Mackerras <paulus@ozlabs.org> <paulus@au1.ibm.com>
Paul Moore <paul@paul-moore.com> <paul.moore@hp.com>
Paul Moore <paul@paul-moore.com> <pmoore@redhat.com>
Pavankumar Kondeti <quic_pkondeti@quicinc.com> <pkondeti@codeaurora.org>
Peter A Jonsson <pj@ludd.ltu.se>
Peter Oruba <peter.oruba@amd.com>
@ -542,6 +544,8 @@ Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk>
Sebastian Reichel <sre@kernel.org> <sre@debian.org>
Sedat Dilek <sedat.dilek@gmail.com> <sedat.dilek@credativ.de>
Senthilkumar N L <quic_snlakshm@quicinc.com> <snlakshm@codeaurora.org>
Serge Hallyn <sergeh@kernel.org> <serge.hallyn@canonical.com>
Serge Hallyn <sergeh@kernel.org> <serue@us.ibm.com>
Seth Forshee <sforshee@kernel.org> <seth.forshee@canonical.com>
Shannon Nelson <shannon.nelson@amd.com> <snelson@pensando.io>
Shannon Nelson <shannon.nelson@amd.com> <shannon.nelson@intel.com>

View File

@ -33,6 +33,7 @@ place where this information is gathered.
sysfs-platform_profile
vduse
futex2
lsm
.. only:: subproject and html

View File

@ -0,0 +1,73 @@
.. 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
.. kernel-doc:: security/lsm_syscalls.c
:identifiers: sys_lsm_list_modules
Additional documentation
========================
* Documentation/security/lsm.rst
* Documentation/security/lsm-development.rst

View File

@ -12417,6 +12417,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/har
F: Documentation/admin-guide/LSM/LoadPin.rst
F: security/loadpin/
LOCKDOWN SECURITY MODULE
L: linux-security-module@vger.kernel.org
S: Odd Fixes
T: git https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git
F: security/lockdown/
LOCKING PRIMITIVES
M: Peter Zijlstra <peterz@infradead.org>
M: Ingo Molnar <mingo@redhat.com>
@ -19455,12 +19461,17 @@ SECURITY SUBSYSTEM
M: Paul Moore <paul@paul-moore.com>
M: James Morris <jmorris@namei.org>
M: "Serge E. Hallyn" <serge@hallyn.com>
L: linux-security-module@vger.kernel.org (suggested Cc:)
L: linux-security-module@vger.kernel.org
S: Supported
W: http://kernsec.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git
Q: https://patchwork.kernel.org/project/linux-security-module/list
B: mailto:linux-security-module@vger.kernel.org
P: https://github.com/LinuxSecurityModule/kernel/blob/main/README.md
T: git https://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/
K: \bsecurity_[a-z_0-9]\+\b
SELINUX SECURITY MODULE
M: Paul Moore <paul@paul-moore.com>

View File

@ -498,3 +498,6 @@
566 common futex_requeue sys_futex_requeue
567 common statmount sys_statmount
568 common listmount sys_listmount
569 common lsm_get_self_attr sys_lsm_get_self_attr
570 common lsm_set_self_attr sys_lsm_set_self_attr
571 common lsm_list_modules sys_lsm_list_modules

View File

@ -472,3 +472,6 @@
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules

View File

@ -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 459
#define __NR_compat_syscalls 462
#endif
#define __ARCH_WANT_SYS_CLONE

View File

@ -923,6 +923,12 @@ __SYSCALL(__NR_futex_requeue, sys_futex_requeue)
__SYSCALL(__NR_statmount, sys_statmount)
#define __NR_listmount 458
__SYSCALL(__NR_listmount, sys_listmount)
#define __NR_lsm_get_self_attr 459
__SYSCALL(__NR_lsm_get_self_attr, sys_lsm_get_self_attr)
#define __NR_lsm_set_self_attr 460
__SYSCALL(__NR_lsm_set_self_attr, sys_lsm_set_self_attr)
#define __NR_lsm_list_modules 461
__SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules)
/*
* Please add new compat syscalls above this comment and update

View File

@ -458,3 +458,6 @@
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules

View File

@ -464,3 +464,6 @@
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules

View File

@ -397,3 +397,6 @@
456 n32 futex_requeue sys_futex_requeue
457 n32 statmount sys_statmount
458 n32 listmount sys_listmount
459 n32 lsm_get_self_attr sys_lsm_get_self_attr
460 n32 lsm_set_self_attr sys_lsm_set_self_attr
461 n32 lsm_list_modules sys_lsm_list_modules

View File

@ -373,3 +373,6 @@
456 n64 futex_requeue sys_futex_requeue
457 n64 statmount sys_statmount
458 n64 listmount sys_listmount
459 n64 lsm_get_self_attr sys_lsm_get_self_attr
460 n64 lsm_set_self_attr sys_lsm_set_self_attr
461 n64 lsm_list_modules sys_lsm_list_modules

View File

@ -446,3 +446,6 @@
456 o32 futex_requeue sys_futex_requeue
457 o32 statmount sys_statmount
458 o32 listmount sys_listmount
459 o32 lsm_get_self_attr sys_lsm_get_self_attr
460 o32 lsm_set_self_attr sys_lsm_set_self_attr
461 o32 lsm_list_modules sys_lsm_list_modules

View File

@ -457,3 +457,6 @@
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules

View File

@ -545,3 +545,6 @@
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules

View File

@ -461,3 +461,6 @@
456 common futex_requeue sys_futex_requeue sys_futex_requeue
457 common statmount sys_statmount sys_statmount
458 common listmount sys_listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules

View File

@ -461,3 +461,6 @@
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules

View File

@ -504,3 +504,6 @@
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules

View File

@ -463,3 +463,6 @@
456 i386 futex_requeue sys_futex_requeue
457 i386 statmount sys_statmount
458 i386 listmount sys_listmount
459 i386 lsm_get_self_attr sys_lsm_get_self_attr
460 i386 lsm_set_self_attr sys_lsm_set_self_attr
461 i386 lsm_list_modules sys_lsm_list_modules

View File

@ -380,6 +380,9 @@
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules
#
# Due to a historical design error, certain syscalls are numbered differently

View File

@ -429,3 +429,6 @@
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules

View File

@ -920,8 +920,7 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
if (!f.file)
return -EBADF;
/* RED-PEN how should LSM module know it's handling 32bit? */
error = security_file_ioctl(f.file, cmd, arg);
error = security_file_ioctl_compat(f.file, cmd, arg);
if (error)
goto out;

View File

@ -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 .
@ -2726,7 +2727,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);
@ -2784,7 +2785,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);
@ -2833,27 +2834,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),

View File

@ -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 {

View File

@ -171,6 +171,8 @@ LSM_HOOK(int, 0, file_alloc_security, struct file *file)
LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file)
LSM_HOOK(int, 0, file_ioctl, struct file *file, unsigned int cmd,
unsigned long arg)
LSM_HOOK(int, 0, file_ioctl_compat, struct file *file, unsigned int cmd,
unsigned long arg)
LSM_HOOK(int, 0, mmap_addr, unsigned long addr)
LSM_HOOK(int, 0, mmap_file, struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags)
@ -262,6 +264,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)

View File

@ -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>
@ -42,6 +43,18 @@ struct security_hook_heads {
#undef LSM_HOOK
} __randomize_layout;
/**
* struct lsm_id - Identify a Linux Security Module.
* @lsm: name of the LSM, must be approved by the LSM maintainers
* @id: LSM ID number from uapi/linux/lsm.h
*
* Contains the information that identifies the LSM.
*/
struct lsm_id {
const char *name;
u64 id;
};
/*
* Security module hook list structure.
* For use with generic list macros for common operations.
@ -50,7 +63,7 @@ struct security_hook_list {
struct hlist_node list;
struct hlist_head *head;
union security_list_options hook;
const char *lsm;
const struct lsm_id *lsmid;
} __randomize_layout;
/*
@ -104,7 +117,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)

View File

@ -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;
@ -60,6 +61,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
@ -138,6 +140,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,
@ -261,6 +265,7 @@ int unregister_blocking_lsm_notifier(struct notifier_block *nb);
/* prototypes */
extern int security_init(void);
extern int early_security_init(void);
extern u64 lsm_name_to_attr(const char *name);
/* Security operations */
int security_binder_set_context_mgr(const struct cred *mgr);
@ -389,6 +394,8 @@ int security_file_permission(struct file *file, int mask);
int security_file_alloc(struct file *file);
void security_file_free(struct file *file);
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
int security_file_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg);
int security_mmap_file(struct file *file, unsigned long prot,
unsigned long flags);
int security_mmap_addr(unsigned long addr);
@ -470,10 +477,13 @@ 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_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(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);
@ -484,6 +494,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 *uctx, size_t *uctx_len,
void *val, size_t val_len, u64 id, u64 flags);
#else /* CONFIG_SECURITY */
static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data)
@ -501,6 +513,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)
{
}
@ -987,6 +1004,13 @@ static inline int security_file_ioctl(struct file *file, unsigned int cmd,
return 0;
}
static inline int security_file_ioctl_compat(struct file *file,
unsigned int cmd,
unsigned long arg)
{
return 0;
}
static inline int security_mmap_file(struct file *file, unsigned long prot,
unsigned long flags)
{
@ -1337,14 +1361,28 @@ 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_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)
{
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;
}
@ -1395,6 +1433,12 @@ static inline int security_locked_down(enum lockdown_reason what)
{
return 0;
}
static inline int lsm_fill_user_ctx(struct lsm_ctx __user *uctx,
size_t *uctx_len, void *val, size_t val_len,
u64 id, u64 flags)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_SECURITY */
#if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)

View File

@ -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;
@ -957,6 +958,11 @@ asmlinkage long sys_cachestat(unsigned int fd,
struct cachestat_range __user *cstat_range,
struct cachestat __user *cstat, unsigned int flags);
asmlinkage long sys_map_shadow_stack(unsigned long addr, unsigned long size, unsigned int flags);
asmlinkage long sys_lsm_get_self_attr(unsigned int attr, struct lsm_ctx *ctx,
size_t *size, __u32 flags);
asmlinkage long sys_lsm_set_self_attr(unsigned int attr, struct lsm_ctx *ctx,
size_t size, __u32 flags);
asmlinkage long sys_lsm_list_modules(u64 *ids, size_t *size, u32 flags);
/*
* Architecture-specific system calls

View File

@ -835,8 +835,15 @@ __SYSCALL(__NR_statmount, sys_statmount)
#define __NR_listmount 458
__SYSCALL(__NR_listmount, sys_listmount)
#define __NR_lsm_get_self_attr 459
__SYSCALL(__NR_lsm_get_self_attr, sys_lsm_get_self_attr)
#define __NR_lsm_set_self_attr 460
__SYSCALL(__NR_lsm_set_self_attr, sys_lsm_set_self_attr)
#define __NR_lsm_list_modules 461
__SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules)
#undef __NR_syscalls
#define __NR_syscalls 459
#define __NR_syscalls 462
/*
* 32 bit systems traditionally used different

90
include/uapi/linux/lsm.h Normal file
View File

@ -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/stddef.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[] __counted_by(ctx_len);
};
/*
* 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_APPARMOR 104
#define LSM_ID_YAMA 105
#define LSM_ID_LOADPIN 106
#define LSM_ID_SAFESETID 107
#define LSM_ID_LOCKDOWN 108
#define LSM_ID_BPF 109
#define LSM_ID_LANDLOCK 110
/*
* 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 */

View File

@ -171,6 +171,9 @@ 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);
COND_SYSCALL(lsm_list_modules);
/* CONFIG_MMU only */
COND_SYSCALL(swapon);

View File

@ -54,6 +54,28 @@ static const struct nla_policy calipso_genl_policy[NLBL_CALIPSO_A_MAX + 1] = {
[NLBL_CALIPSO_A_MTYPE] = { .type = NLA_U32 },
};
static const struct netlbl_calipso_ops *calipso_ops;
/**
* netlbl_calipso_ops_register - Register the CALIPSO operations
* @ops: ops to register
*
* Description:
* Register the CALIPSO packet engine operations.
*
*/
const struct netlbl_calipso_ops *
netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops)
{
return xchg(&calipso_ops, ops);
}
EXPORT_SYMBOL(netlbl_calipso_ops_register);
static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void)
{
return READ_ONCE(calipso_ops);
}
/* NetLabel Command Handlers
*/
/**
@ -96,15 +118,18 @@ static int netlbl_calipso_add_pass(struct genl_info *info,
*
*/
static int netlbl_calipso_add(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -EINVAL;
struct netlbl_audit audit_info;
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
if (!info->attrs[NLBL_CALIPSO_A_DOI] ||
!info->attrs[NLBL_CALIPSO_A_MTYPE])
return -EINVAL;
if (!ops)
return -EOPNOTSUPP;
netlbl_netlink_auditinfo(&audit_info);
switch (nla_get_u32(info->attrs[NLBL_CALIPSO_A_MTYPE])) {
case CALIPSO_MAP_PASS:
@ -363,28 +388,6 @@ int __init netlbl_calipso_genl_init(void)
return genl_register_family(&netlbl_calipso_gnl_family);
}
static const struct netlbl_calipso_ops *calipso_ops;
/**
* netlbl_calipso_ops_register - Register the CALIPSO operations
* @ops: ops to register
*
* Description:
* Register the CALIPSO packet engine operations.
*
*/
const struct netlbl_calipso_ops *
netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops)
{
return xchg(&calipso_ops, ops);
}
EXPORT_SYMBOL(netlbl_calipso_ops_register);
static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void)
{
return READ_ONCE(calipso_ops);
}
/**
* calipso_doi_add - Add a new DOI to the CALIPSO protocol engine
* @doi_def: the DOI structure

View File

@ -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

View File

@ -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 */

View File

@ -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"
@ -775,6 +776,46 @@ 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;
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)
error = lsm_fill_user_ctx(lx, size, value, error,
LSM_ID_APPARMOR, 0);
kfree(value);
}
aa_put_label(label);
if (error < 0)
return error;
return 1;
}
static int apparmor_getprocattr(struct task_struct *task, const char *name,
char **value)
{
@ -794,7 +835,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);
@ -802,8 +843,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;
@ -834,7 +874,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);
@ -849,7 +889,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)
@ -869,13 +909,42 @@ out:
fail:
ad.subj_label = begin_current_label_crit_section();
ad.info = name;
if (attr == LSM_ATTR_CURRENT)
ad.info = "current";
else if (attr == LSM_ATTR_EXEC)
ad.info = "exec";
else
ad.info = "invalid";
ad.error = error = -EINVAL;
aa_audit_msg(AUDIT_APPARMOR_DENIED, &ad, NULL);
end_current_label_crit_section(ad.subj_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)
@ -1385,6 +1454,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),
@ -1418,6 +1492,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),
@ -2202,7 +2278,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;

View File

@ -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;
}
/**

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -1223,5 +1223,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);
}

View File

@ -196,5 +196,5 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = {
__init void landlock_add_net_hooks(void)
{
security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
LANDLOCK_NAME);
&landlock_lsmid);
}

View File

@ -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);
}

View File

@ -8,6 +8,7 @@
#include <linux/init.h>
#include <linux/lsm_hooks.h>
#include <uapi/linux/lsm.h>
#include "common.h"
#include "cred.h"
@ -25,6 +26,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();

View File

@ -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 */

View File

@ -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;
}

View File

@ -13,6 +13,7 @@
#include <linux/security.h>
#include <linux/export.h>
#include <linux/lsm_hooks.h>
#include <uapi/linux/lsm.h>
static enum lockdown_reason kernel_locked_down;
@ -75,6 +76,11 @@ static struct security_hook_list lockdown_hooks[] __ro_after_init = {
LSM_HOOK_INIT(locked_down, lockdown_is_locked_down),
};
const struct lsm_id lockdown_lsmid = {
.name = "lockdown",
.id = LSM_ID_LOCKDOWN,
};
static int __init lockdown_lsm_init(void)
{
#if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY)
@ -83,7 +89,7 @@ static int __init lockdown_lsm_init(void)
lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY_MAX);
#endif
security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks),
"lockdown");
&lockdown_lsmid);
return 0;
}

120
security/lsm_syscalls.c Normal file
View File

@ -0,0 +1,120 @@
// 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>
/**
* 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
* @ctx: the LSM contexts
* @size: size of @ctx
* @flags: reserved for future use
*
* Sets the calling task's LSM context. On success this function
* returns 0. If the attribute specified cannot be set a negative
* value indicating the reason for the error is returned.
*/
SYSCALL_DEFINE4(lsm_set_self_attr, unsigned int, attr, struct lsm_ctx __user *,
ctx, size_t, size, u32, flags)
{
return security_setselfattr(attr, ctx, size, flags);
}
/**
* sys_lsm_get_self_attr - Return current task's security module attributes
* @attr: which attribute to return
* @ctx: the user-space destination for the information, or NULL
* @size: pointer to the size of space available to receive the data
* @flags: special handling options. LSM_FLAG_SINGLE indicates that only
* attributes associated with the LSM identified in the passed @ctx be
* reported.
*
* Returns the calling task's LSM contexts. On success this
* function returns the number of @ctx array elements. This value
* may be zero if there are no LSM contexts assigned. If @size is
* insufficient to contain the return data -E2BIG is returned and
* @size is set to the minimum required size. In all other cases
* a negative value indicating the error is returned.
*/
SYSCALL_DEFINE4(lsm_get_self_attr, unsigned int, attr, struct lsm_ctx __user *,
ctx, size_t __user *, size, u32, flags)
{
return security_getselfattr(attr, ctx, size, flags);
}
/**
* 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;
}

View File

@ -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;

View File

@ -34,6 +34,24 @@
/* 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_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 +263,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];
/* Populate ordered LSMs list from comma-separated LSM name list. */
static void __init ordered_lsm_parse(const char *order, const char *origin)
{
@ -513,17 +537,29 @@ 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;
/*
* 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].lsm = lsm;
hooks[i].lsmid = lsmid;
hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);
}
@ -532,7 +568,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__);
}
}
@ -734,6 +770,54 @@ static int lsm_superblock_alloc(struct super_block *sb)
return 0;
}
/**
* lsm_fill_user_ctx - Fill a user space lsm_ctx structure
* @uctx: a userspace LSM context to be filled
* @uctx_len: available uctx size (input), used uctx size (output)
* @val: the new LSM context value
* @val_len: the size of the new LSM context value
* @id: LSM id
* @flags: LSM defined flags
*
* Fill all of the fields in a userspace lsm_ctx structure.
*
* Returns 0 on success, -E2BIG if userspace buffer is not large enough,
* -EFAULT on a copyout error, -ENOMEM if memory can't be allocated.
*/
int lsm_fill_user_ctx(struct lsm_ctx __user *uctx, size_t *uctx_len,
void *val, size_t val_len,
u64 id, u64 flags)
{
struct lsm_ctx *nctx = NULL;
size_t nctx_len;
int rc = 0;
nctx_len = ALIGN(struct_size(nctx, ctx, val_len), sizeof(void *));
if (nctx_len > *uctx_len) {
rc = -E2BIG;
goto out;
}
nctx = kzalloc(nctx_len, GFP_KERNEL);
if (nctx == NULL) {
rc = -ENOMEM;
goto out;
}
nctx->id = id;
nctx->flags = flags;
nctx->len = nctx_len;
nctx->ctx_len = val_len;
memcpy(nctx->ctx, val, val_len);
if (copy_to_user(uctx, nctx, nctx_len))
rc = -EFAULT;
out:
kfree(nctx);
*uctx_len = nctx_len;
return rc;
}
/*
* The default value of the LSM hook is defined in linux/lsm_hook_defs.h and
* can be accessed with:
@ -2642,6 +2726,24 @@ int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
EXPORT_SYMBOL_GPL(security_file_ioctl);
/**
* security_file_ioctl_compat() - Check if an ioctl is allowed in compat mode
* @file: associated file
* @cmd: ioctl cmd
* @arg: ioctl arguments
*
* Compat version of security_file_ioctl() that correctly handles 32-bit
* processes running on 64-bit kernels.
*
* Return: Returns 0 if permission is granted.
*/
int security_file_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
{
return call_int_hook(file_ioctl_compat, 0, file, cmd, arg);
}
EXPORT_SYMBOL_GPL(security_file_ioctl_compat);
static inline unsigned long mmap_prot(struct file *file, unsigned long prot)
{
/*
@ -3794,10 +3896,158 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
}
EXPORT_SYMBOL(security_d_instantiate);
/*
* Please keep this in sync with it's counterpart in security/lsm_syscalls.c
*/
/**
* security_getselfattr - Read an LSM attribute of the current process.
* @attr: which attribute to return
* @uctx: the user-space destination for the information, or NULL
* @size: pointer to the size of space available to receive the data
* @flags: special handling options. LSM_FLAG_SINGLE indicates that only
* attributes associated with the LSM identified in the passed @ctx be
* reported.
*
* A NULL value for @uctx can be used to get both the number of attributes
* and the size of the data.
*
* Returns the number of attributes found on success, negative value
* on error. @size is reset to the total size of the data.
* If @size is insufficient to contain the data -E2BIG is returned.
*/
int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
size_t __user *size, u32 flags)
{
struct security_hook_list *hp;
struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, };
u8 __user *base = (u8 __user *)uctx;
size_t total = 0;
size_t entrysize;
size_t left;
bool toobig = false;
bool single = false;
int count = 0;
int rc;
if (attr == LSM_ATTR_UNDEF)
return -EINVAL;
if (size == NULL)
return -EINVAL;
if (get_user(left, size))
return -EFAULT;
if (flags) {
/*
* Only flag supported is LSM_FLAG_SINGLE
*/
if (flags != LSM_FLAG_SINGLE || !uctx)
return -EINVAL;
if (copy_from_user(&lctx, uctx, sizeof(lctx)))
return -EFAULT;
/*
* If the LSM ID isn't specified it is an error.
*/
if (lctx.id == LSM_ID_UNDEF)
return -EINVAL;
single = true;
}
/*
* In the usual case gather all the data from the LSMs.
* In the single case only get the data from the LSM specified.
*/
hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) {
if (single && lctx.id != hp->lsmid->id)
continue;
entrysize = left;
if (base)
uctx = (struct lsm_ctx __user *)(base + total);
rc = hp->hook.getselfattr(attr, uctx, &entrysize, flags);
if (rc == -EOPNOTSUPP) {
rc = 0;
continue;
}
if (rc == -E2BIG) {
rc = 0;
left = 0;
toobig = true;
} else if (rc < 0)
return rc;
else
left -= entrysize;
total += entrysize;
count += rc;
if (single)
break;
}
if (put_user(total, size))
return -EFAULT;
if (toobig)
return -E2BIG;
if (count == 0)
return LSM_RET_DEFAULT(getselfattr);
return count;
}
/*
* Please keep this in sync with it's counterpart in security/lsm_syscalls.c
*/
/**
* security_setselfattr - Set an LSM attribute on the current process.
* @attr: which attribute to set
* @uctx: the user-space source for the information
* @size: the size of the data
* @flags: reserved for future use, must be 0
*
* Set an LSM attribute for the current process. The LSM, attribute
* and new value are included in @uctx.
*
* Returns 0 on success, -EINVAL if the input is inconsistent, -EFAULT
* if the user buffer is inaccessible, E2BIG if size is too big, or an
* LSM specific failure.
*/
int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
size_t size, u32 flags)
{
struct security_hook_list *hp;
struct lsm_ctx *lctx;
int rc = LSM_RET_DEFAULT(setselfattr);
if (flags)
return -EINVAL;
if (size < sizeof(*lctx))
return -EINVAL;
if (size > PAGE_SIZE)
return -E2BIG;
lctx = memdup_user(uctx, size);
if (IS_ERR(lctx))
return PTR_ERR(lctx);
if (size < lctx->len || size < lctx->ctx_len + sizeof(*lctx) ||
lctx->len < lctx->ctx_len + sizeof(*lctx)) {
rc = -EINVAL;
goto free_out;
}
hlist_for_each_entry(hp, &security_hook_heads.setselfattr, list)
if ((hp->lsmid->id) == lctx->id) {
rc = hp->hook.setselfattr(attr, lctx, size, flags);
break;
}
free_out:
kfree(lctx);
return rc;
}
/**
* security_getprocattr() - Read an attribute for a task
* @p: the task
* @lsm: LSM name
* @lsmid: LSM identification
* @name: attribute name
* @value: attribute value
*
@ -3805,13 +4055,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->lsm))
if (lsmid != 0 && lsmid != hp->lsmid->id)
continue;
return hp->hook.getprocattr(p, name, value);
}
@ -3820,7 +4070,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
@ -3830,13 +4080,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->lsm))
if (lsmid != 0 && lsmid != hp->lsmid->id)
continue;
return hp->hook.setprocattr(name, value, size);
}

View File

@ -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"
@ -3738,6 +3739,33 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
return error;
}
static int selinux_file_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
{
/*
* If we are in a 64-bit kernel running 32-bit userspace, we need to
* make sure we don't compare 32-bit flags to 64-bit flags.
*/
switch (cmd) {
case FS_IOC32_GETFLAGS:
cmd = FS_IOC_GETFLAGS;
break;
case FS_IOC32_SETFLAGS:
cmd = FS_IOC_SETFLAGS;
break;
case FS_IOC32_GETVERSION:
cmd = FS_IOC_GETVERSION;
break;
case FS_IOC32_SETVERSION:
cmd = FS_IOC_SETVERSION;
break;
default:
break;
}
return selinux_file_ioctl(file, cmd, arg);
}
static int default_noexec __ro_after_init;
static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
@ -6313,8 +6341,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;
@ -6331,20 +6359,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();
@ -6362,7 +6397,7 @@ bad:
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;
@ -6373,23 +6408,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;
@ -6401,13 +6444,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
@ -6418,7 +6462,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;
@ -6441,11 +6486,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);
@ -6453,9 +6498,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;
@ -6496,6 +6541,69 @@ abort_change:
return error;
}
/**
* selinux_getselfattr - Get SELinux current task attributes
* @attr: the requested attribute
* @ctx: buffer to receive the result
* @size: buffer size (input), buffer size used (output)
* @flags: unused
*
* Fill the passed user space @ctx with the details of the requested
* attribute.
*
* Returns the number of attributes on success, an error code otherwise.
* There will only ever be one attribute.
*/
static int selinux_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
size_t *size, u32 flags)
{
int rc;
char *val;
int val_len;
val_len = selinux_lsm_getattr(attr, current, &val);
if (val_len < 0)
return val_len;
rc = lsm_fill_user_ctx(ctx, size, val, val_len, LSM_ID_SELINUX, 0);
kfree(val);
return (!rc ? 1 : rc);
}
static int selinux_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
size_t size, u32 flags)
{
int rc;
rc = selinux_lsm_setattr(attr, ctx->ctx, ctx->ctx_len);
if (rc > 0)
return 0;
return rc;
}
static int selinux_getprocattr(struct task_struct *p,
const char *name, char **value)
{
unsigned int attr = lsm_name_to_attr(name);
int rc;
if (attr) {
rc = selinux_lsm_getattr(attr, p, value);
if (rc != -EOPNOTSUPP)
return rc;
}
return -EINVAL;
}
static int selinux_setprocattr(const char *name, void *value, size_t size)
{
int attr = lsm_name_to_attr(name);
if (attr)
return selinux_lsm_setattr(attr, value, size);
return -EINVAL;
}
static int selinux_ismaclabel(const char *name)
{
return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
@ -6978,6 +7086,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,
@ -7064,6 +7177,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(file_permission, selinux_file_permission),
LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat),
LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
@ -7119,6 +7233,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),
@ -7298,7 +7414,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");

View File

@ -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"
@ -3625,6 +3626,35 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
return;
}
/**
* smack_getselfattr - Smack current process attribute
* @attr: which attribute to fetch
* @ctx: buffer to receive the result
* @size: available size in, actual size out
* @flags: unused
*
* Fill the passed user space @ctx with the details of the requested
* attribute.
*
* Returns the number of attributes on success, an error code otherwise.
* There will only ever be one attribute.
*/
static int smack_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
size_t *size, u32 flags)
{
int rc;
struct smack_known *skp;
if (attr != LSM_ATTR_CURRENT)
return -EOPNOTSUPP;
skp = smk_of_current();
rc = lsm_fill_user_ctx(ctx, size,
skp->smk_known, strlen(skp->smk_known) + 1,
LSM_ID_SMACK, 0);
return (!rc ? 1 : rc);
}
/**
* smack_getprocattr - Smack process attribute access
* @p: the object task
@ -3654,8 +3684,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
*
@ -3664,7 +3694,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;
@ -3678,8 +3708,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))
@ -3718,6 +3748,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
@ -4933,6 +5006,11 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
};
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),
@ -4973,6 +5051,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security),
LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
LSM_HOOK_INIT(file_ioctl_compat, smack_file_ioctl),
LSM_HOOK_INIT(file_lock, smack_file_lock),
LSM_HOOK_INIT(file_fcntl, smack_file_fcntl),
LSM_HOOK_INIT(mmap_file, smack_mmap_file),
@ -5027,6 +5106,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),
@ -5140,7 +5221,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");

View File

@ -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.
@ -568,6 +574,7 @@ static struct security_hook_list tomoyo_hooks[] __ro_after_init = {
LSM_HOOK_INIT(path_rename, tomoyo_path_rename),
LSM_HOOK_INIT(inode_getattr, tomoyo_inode_getattr),
LSM_HOOK_INIT(file_ioctl, tomoyo_file_ioctl),
LSM_HOOK_INIT(file_ioctl_compat, tomoyo_file_ioctl),
LSM_HOOK_INIT(path_chmod, tomoyo_path_chmod),
LSM_HOOK_INIT(path_chown, tomoyo_path_chown),
LSM_HOOK_INIT(path_chroot, tomoyo_path_chroot),
@ -595,7 +602,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);

View File

@ -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;
}

View File

@ -371,3 +371,8 @@
454 n64 futex_wake sys_futex_wake
455 n64 futex_wait sys_futex_wait
456 n64 futex_requeue sys_futex_requeue
457 n64 statmount sys_statmount
458 n64 listmount sys_listmount
459 n64 lsm_get_self_attr sys_lsm_get_self_attr
460 n64 lsm_set_self_attr sys_lsm_set_self_attr
461 n64 lsm_list_modules sys_lsm_list_modules

View File

@ -543,3 +543,8 @@
454 common futex_wake sys_futex_wake
455 common futex_wait sys_futex_wait
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules

View File

@ -459,3 +459,8 @@
454 common futex_wake sys_futex_wake sys_futex_wake
455 common futex_wait sys_futex_wait sys_futex_wait
456 common futex_requeue sys_futex_requeue sys_futex_requeue
457 common statmount sys_statmount sys_statmount
458 common listmount sys_listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules

View File

@ -378,6 +378,11 @@
454 common futex_wake sys_futex_wake
455 common futex_wait sys_futex_wait
456 common futex_requeue sys_futex_requeue
457 common statmount sys_statmount
458 common listmount sys_listmount
459 common lsm_get_self_attr sys_lsm_get_self_attr
460 common lsm_set_self_attr sys_lsm_set_self_attr
461 common lsm_list_modules sys_lsm_list_modules
#
# Due to a historical design error, certain syscalls are numbered differently

View File

@ -45,6 +45,7 @@ TARGETS += landlock
TARGETS += lib
TARGETS += livepatch
TARGETS += lkdtm
TARGETS += lsm
TARGETS += membarrier
TARGETS += memfd
TARGETS += memory-hotplug

View File

@ -0,0 +1 @@
/*_test

View File

@ -0,0 +1,17 @@
# SPDX-License-Identifier: GPL-2.0
#
# First run: make -C ../../../.. headers_install
CFLAGS += -Wall -O2 $(KHDR_INCLUDES)
LOCAL_HDRS += common.h
TEST_GEN_PROGS := lsm_get_self_attr_test lsm_list_modules_test \
lsm_set_self_attr_test
include ../lib.mk
$(OUTPUT)/lsm_get_self_attr_test: lsm_get_self_attr_test.c common.c
$(OUTPUT)/lsm_set_self_attr_test: lsm_set_self_attr_test.c common.c
$(OUTPUT)/lsm_list_modules_test: lsm_list_modules_test.c common.c
EXTRA_CLEAN = $(OUTPUT)/common.o

View File

@ -0,0 +1,89 @@
// 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);
close(fd);
/* Ensure value is terminated */
if (len <= 0 || len == size)
return -1;
value[len] = '\0';
path = strchr(value, '\n');
if (path)
*path = '\0';
return 0;
}
int read_sysfs_lsms(char *lsms, size_t size)
{
FILE *fp;
size_t red;
fp = fopen("/sys/kernel/security/lsm", "r");
if (fp == NULL)
return -1;
red = fread(lsms, 1, size, fp);
fclose(fp);
if (red <= 0 || red == size)
return -1;
lsms[red] = '\0';
return 0;
}
int attr_lsm_count(void)
{
char *names = calloc(sysconf(_SC_PAGESIZE), 1);
int count = 0;
if (!names)
return 0;
if (read_sysfs_lsms(names, sysconf(_SC_PAGESIZE)))
return 0;
if (strstr(names, "selinux"))
count++;
if (strstr(names, "smack"))
count++;
if (strstr(names, "apparmor"))
count++;
return count;
}

View File

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

View File

@ -0,0 +1,3 @@
CONFIG_SYSFS=y
CONFIG_SECURITY=y
CONFIG_SECURITYFS=y

View File

@ -0,0 +1,275 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Linux Security Module infrastructure tests
* Tests for the lsm_get_self_attr system call
*
* Copyright © 2022 Casey Schaufler <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);
__u64 *syscall_lsms = calloc(page_size, 1);
size_t size;
int lsmcount;
int i;
ASSERT_NE(NULL, ctx);
errno = 0;
size = page_size;
ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size,
LSM_FLAG_SINGLE));
ASSERT_EQ(EINVAL, errno);
ASSERT_EQ(page_size, size);
lsmcount = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0);
ASSERT_LE(1, lsmcount);
ASSERT_NE(NULL, syscall_lsms);
for (i = 0; i < lsmcount; i++) {
errno = 0;
size = page_size;
ctx->id = syscall_lsms[i];
if (syscall_lsms[i] == LSM_ID_SELINUX ||
syscall_lsms[i] == LSM_ID_SMACK ||
syscall_lsms[i] == LSM_ID_APPARMOR) {
ASSERT_EQ(1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx,
&size, LSM_FLAG_SINGLE));
} else {
ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx,
&size,
LSM_FLAG_SINGLE));
}
}
free(ctx);
}
TEST(flags_overset_lsm_get_self_attr)
{
const long page_size = sysconf(_SC_PAGESIZE);
struct lsm_ctx *ctx = calloc(page_size, 1);
size_t size;
ASSERT_NE(NULL, ctx);
errno = 0;
size = page_size;
ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx,
&size, 0));
ASSERT_EQ(EOPNOTSUPP, errno);
errno = 0;
size = page_size;
ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size,
LSM_FLAG_SINGLE |
(LSM_FLAG_SINGLE << 1)));
ASSERT_EQ(EINVAL, errno);
free(ctx);
}
TEST(basic_lsm_get_self_attr)
{
const long page_size = sysconf(_SC_PAGESIZE);
size_t size = page_size;
struct lsm_ctx *ctx = calloc(page_size, 1);
struct lsm_ctx *tctx = NULL;
__u64 *syscall_lsms = calloc(page_size, 1);
char *attr = calloc(page_size, 1);
int cnt_current = 0;
int cnt_exec = 0;
int cnt_fscreate = 0;
int cnt_keycreate = 0;
int cnt_prev = 0;
int cnt_sockcreate = 0;
int lsmcount;
int count;
int i;
ASSERT_NE(NULL, ctx);
ASSERT_NE(NULL, syscall_lsms);
lsmcount = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0);
ASSERT_LE(1, lsmcount);
for (i = 0; i < lsmcount; i++) {
switch (syscall_lsms[i]) {
case LSM_ID_SELINUX:
cnt_current++;
cnt_exec++;
cnt_fscreate++;
cnt_keycreate++;
cnt_prev++;
cnt_sockcreate++;
break;
case LSM_ID_SMACK:
cnt_current++;
break;
case LSM_ID_APPARMOR:
cnt_current++;
cnt_exec++;
cnt_prev++;
break;
default:
break;
}
}
if (cnt_current) {
size = page_size;
count = lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, 0);
ASSERT_EQ(cnt_current, count);
tctx = ctx;
ASSERT_EQ(0, read_proc_attr("current", attr, page_size));
ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
for (i = 1; i < count; i++) {
tctx = next_ctx(tctx);
ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
}
}
if (cnt_exec) {
size = page_size;
count = lsm_get_self_attr(LSM_ATTR_EXEC, ctx, &size, 0);
ASSERT_GE(cnt_exec, count);
if (count > 0) {
tctx = ctx;
if (read_proc_attr("exec", attr, page_size) == 0)
ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
}
for (i = 1; i < count; i++) {
tctx = next_ctx(tctx);
ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
}
}
if (cnt_fscreate) {
size = page_size;
count = lsm_get_self_attr(LSM_ATTR_FSCREATE, ctx, &size, 0);
ASSERT_GE(cnt_fscreate, count);
if (count > 0) {
tctx = ctx;
if (read_proc_attr("fscreate", attr, page_size) == 0)
ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
}
for (i = 1; i < count; i++) {
tctx = next_ctx(tctx);
ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
}
}
if (cnt_keycreate) {
size = page_size;
count = lsm_get_self_attr(LSM_ATTR_KEYCREATE, ctx, &size, 0);
ASSERT_GE(cnt_keycreate, count);
if (count > 0) {
tctx = ctx;
if (read_proc_attr("keycreate", attr, page_size) == 0)
ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
}
for (i = 1; i < count; i++) {
tctx = next_ctx(tctx);
ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
}
}
if (cnt_prev) {
size = page_size;
count = lsm_get_self_attr(LSM_ATTR_PREV, ctx, &size, 0);
ASSERT_GE(cnt_prev, count);
if (count > 0) {
tctx = ctx;
ASSERT_EQ(0, read_proc_attr("prev", attr, page_size));
ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
for (i = 1; i < count; i++) {
tctx = next_ctx(tctx);
ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
}
}
}
if (cnt_sockcreate) {
size = page_size;
count = lsm_get_self_attr(LSM_ATTR_SOCKCREATE, ctx, &size, 0);
ASSERT_GE(cnt_sockcreate, count);
if (count > 0) {
tctx = ctx;
if (read_proc_attr("sockcreate", attr, page_size) == 0)
ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr));
}
for (i = 1; i < count; i++) {
tctx = next_ctx(tctx);
ASSERT_NE(0, strcmp((char *)tctx->ctx, attr));
}
}
free(ctx);
free(attr);
free(syscall_lsms);
}
TEST_HARNESS_MAIN

View File

@ -0,0 +1,137 @@
// 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_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

View File

@ -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