[PATCH v4] lockdown,selinux: fix wrong subject in some SELinux lockdown checks

From: Ondrej Mosnacek
Date: Mon Sep 13 2021 - 10:06:30 EST


Commit 59438b46471a ("security,lockdown,selinux: implement SELinux
lockdown") added an implementation of the locked_down LSM hook to
SELinux, with the aim to restrict which domains are allowed to perform
operations that would breach lockdown.

However, in several places the security_locked_down() hook is called in
situations where the current task isn't doing any action that would
directly breach lockdown, leading to SELinux checks that are basically
bogus.

To fix this, add an explicit struct cred pointer argument to
security_lockdown() and define NULL as a special value to pass instead
of current_cred() in such situations. LSMs that take the subject
credentials into account can then fall back to some default or ignore
such calls altogether. In the SELinux lockdown hook implementation, use
SECINITSID_KERNEL in case the cred argument is NULL.

Most of the callers are updated to pass current_cred() as the cred
pointer, thus maintaining the same behavior. The following callers are
modified to pass NULL as the cred pointer instead:
1. arch/powerpc/xmon/xmon.c
Seems to be some interactive debugging facility. It appears that
the lockdown hook is called from interrupt context here, so it
should be more appropriate to request a global lockdown decision.
2. fs/tracefs/inode.c:tracefs_create_file()
Here the call is used to prevent creating new tracefs entries when
the kernel is locked down. Assumes that locking down is one-way -
i.e. if the hook returns non-zero once, it will never return zero
again, thus no point in creating these files. Also, the hook is
often called by a module's init function when it is loaded by
userspace, where it doesn't make much sense to do a check against
the current task's creds, since the task itself doesn't actually
use the tracing functionality (i.e. doesn't breach lockdown), just
indirectly makes some new tracepoints available to whoever is
authorized to use them.
3. net/xfrm/xfrm_user.c:copy_to_user_*()
Here a cryptographic secret is redacted based on the value returned
from the hook. There are two possible actions that may lead here:
a) A netlink message XFRM_MSG_GETSA with NLM_F_DUMP set - here the
task context is relevant, since the dumped data is sent back to
the current task.
b) When adding/deleting/updating an SA via XFRM_MSG_xxxSA, the
dumped SA is broadcasted to tasks subscribed to XFRM events -
here the current task context is not relevant as it doesn't
represent the tasks that could potentially see the secret.
It doesn't seem worth it to try to keep using the current task's
context in the a) case, since the eventual data leak can be
circumvented anyway via b), plus there is no way for the task to
indicate that it doesn't care about the actual key value, so the
check could generate a lot of "false alert" denials with SELinux.
Thus, let's pass NULL instead of current_cred() here faute de
mieux.

Improvements-suggested-by: Casey Schaufler <casey@xxxxxxxxxxxxxxxx>
Improvements-suggested-by: Paul Moore <paul@xxxxxxxxxxxxxx>
Fixes: 59438b46471a ("security,lockdown,selinux: implement SELinux lockdown")
Acked-by: Dan Williams <dan.j.williams@xxxxxxxxx> [cxl]
Acked-by: Steffen Klassert <steffen.klassert@xxxxxxxxxxx> [xfrm]
Signed-off-by: Ondrej Mosnacek <omosnace@xxxxxxxxxx>
---

v4:
- rebase on top of TODO
- fix rebase conflicts:
* drivers/cxl/pci.c
- trivial: the lockdown reason was corrected in mainline
* kernel/bpf/helpers.c, kernel/trace/bpf_trace.c
- trivial: LOCKDOWN_BPF_READ was renamed to LOCKDOWN_BPF_READ_KERNEL
in mainline
* kernel/power/hibernate.c
- trivial: !secretmem_active() was added to the condition in
hibernation_available()
- cover new security_locked_down() call in kernel/bpf/helpers.c
(LOCKDOWN_BPF_WRITE_USER in BPF_FUNC_probe_write_user case)

v3: https://lore.kernel.org/lkml/20210616085118.1141101-1-omosnace@xxxxxxxxxx/
- add the cred argument to security_locked_down() and adapt all callers
- keep using current_cred() in BPF, as the hook calls have been shifted
to program load time (commit ff40e51043af ("bpf, lockdown, audit: Fix
buggy SELinux lockdown permission checks"))
- in SELinux, don't ignore hook calls where cred == NULL, but use
SECINITSID_KERNEL as the subject instead
- update explanations in the commit message

v2: https://lore.kernel.org/lkml/20210517092006.803332-1-omosnace@xxxxxxxxxx/
- change to a single hook based on suggestions by Casey Schaufler

v1: https://lore.kernel.org/lkml/20210507114048.138933-1-omosnace@xxxxxxxxxx/

arch/powerpc/xmon/xmon.c | 4 ++--
arch/x86/kernel/ioport.c | 4 ++--
arch/x86/kernel/msr.c | 4 ++--
arch/x86/mm/testmmiotrace.c | 2 +-
drivers/acpi/acpi_configfs.c | 2 +-
drivers/acpi/custom_method.c | 2 +-
drivers/acpi/osl.c | 3 ++-
drivers/acpi/tables.c | 2 +-
drivers/char/mem.c | 2 +-
drivers/cxl/pci.c | 2 +-
drivers/firmware/efi/efi.c | 2 +-
drivers/firmware/efi/test/efi_test.c | 2 +-
drivers/pci/pci-sysfs.c | 6 +++---
drivers/pci/proc.c | 6 +++---
drivers/pci/syscall.c | 2 +-
drivers/pcmcia/cistpl.c | 2 +-
drivers/tty/serial/serial_core.c | 2 +-
fs/debugfs/file.c | 2 +-
fs/debugfs/inode.c | 2 +-
fs/proc/kcore.c | 2 +-
fs/tracefs/inode.c | 2 +-
include/linux/lsm_hook_defs.h | 2 +-
include/linux/lsm_hooks.h | 1 +
include/linux/security.h | 4 ++--
kernel/bpf/helpers.c | 10 ++++++----
kernel/events/core.c | 2 +-
kernel/kexec.c | 2 +-
kernel/kexec_file.c | 2 +-
kernel/module.c | 2 +-
kernel/params.c | 2 +-
kernel/power/hibernate.c | 2 +-
kernel/trace/bpf_trace.c | 25 +++++++++++++++----------
kernel/trace/ftrace.c | 4 ++--
kernel/trace/ring_buffer.c | 2 +-
kernel/trace/trace.c | 10 +++++-----
kernel/trace/trace_events.c | 2 +-
kernel/trace/trace_events_hist.c | 4 ++--
kernel/trace/trace_events_synth.c | 2 +-
kernel/trace/trace_events_trigger.c | 2 +-
kernel/trace/trace_kprobe.c | 6 +++---
kernel/trace/trace_printk.c | 2 +-
kernel/trace/trace_stack.c | 2 +-
kernel/trace/trace_stat.c | 2 +-
kernel/trace/trace_uprobe.c | 4 ++--
net/xfrm/xfrm_user.c | 11 +++++++++--
security/lockdown/lockdown.c | 3 ++-
security/security.c | 4 ++--
security/selinux/hooks.c | 7 +++++--
48 files changed, 99 insertions(+), 79 deletions(-)

diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index dd8241c009e5..47464e873749 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -309,7 +309,7 @@ static bool xmon_is_locked_down(void)
static bool lockdown;

if (!lockdown) {
- lockdown = !!security_locked_down(LOCKDOWN_XMON_RW);
+ lockdown = !!security_locked_down(NULL, LOCKDOWN_XMON_RW);
if (lockdown) {
printf("xmon: Disabled due to kernel lockdown\n");
xmon_is_ro = true;
@@ -317,7 +317,7 @@ static bool xmon_is_locked_down(void)
}

if (!xmon_is_ro) {
- xmon_is_ro = !!security_locked_down(LOCKDOWN_XMON_WR);
+ xmon_is_ro = !!security_locked_down(NULL, LOCKDOWN_XMON_WR);
if (xmon_is_ro)
printf("xmon: Read-only due to kernel lockdown\n");
}
diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c
index e2fab3ceb09f..838ba45ecc71 100644
--- a/arch/x86/kernel/ioport.c
+++ b/arch/x86/kernel/ioport.c
@@ -71,7 +71,7 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
return -EINVAL;
if (turn_on && (!capable(CAP_SYS_RAWIO) ||
- security_locked_down(LOCKDOWN_IOPORT)))
+ security_locked_down(current_cred(), LOCKDOWN_IOPORT)))
return -EPERM;

/*
@@ -187,7 +187,7 @@ SYSCALL_DEFINE1(iopl, unsigned int, level)
/* Trying to gain more privileges? */
if (level > old) {
if (!capable(CAP_SYS_RAWIO) ||
- security_locked_down(LOCKDOWN_IOPORT))
+ security_locked_down(current_cred(), LOCKDOWN_IOPORT))
return -EPERM;
}

diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index ed8ac6bcbafb..6a687d91515b 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -116,7 +116,7 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
int err = 0;
ssize_t bytes = 0;

- err = security_locked_down(LOCKDOWN_MSR);
+ err = security_locked_down(current_cred(), LOCKDOWN_MSR);
if (err)
return err;

@@ -179,7 +179,7 @@ static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg)
err = -EFAULT;
break;
}
- err = security_locked_down(LOCKDOWN_MSR);
+ err = security_locked_down(current_cred(), LOCKDOWN_MSR);
if (err)
break;

diff --git a/arch/x86/mm/testmmiotrace.c b/arch/x86/mm/testmmiotrace.c
index bda73cb7a044..c43a13241ae8 100644
--- a/arch/x86/mm/testmmiotrace.c
+++ b/arch/x86/mm/testmmiotrace.c
@@ -116,7 +116,7 @@ static void do_test_bulk_ioremapping(void)
static int __init init(void)
{
unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
- int ret = security_locked_down(LOCKDOWN_MMIOTRACE);
+ int ret = security_locked_down(current_cred(), LOCKDOWN_MMIOTRACE);

if (ret)
return ret;
diff --git a/drivers/acpi/acpi_configfs.c b/drivers/acpi/acpi_configfs.c
index c970792b11a4..17c4e79b596e 100644
--- a/drivers/acpi/acpi_configfs.c
+++ b/drivers/acpi/acpi_configfs.c
@@ -26,7 +26,7 @@ static ssize_t acpi_table_aml_write(struct config_item *cfg,
{
const struct acpi_table_header *header = data;
struct acpi_table *table;
- int ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
+ int ret = security_locked_down(current_cred(), LOCKDOWN_ACPI_TABLES);

if (ret)
return ret;
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c
index d39a9b474727..8cac7f683245 100644
--- a/drivers/acpi/custom_method.c
+++ b/drivers/acpi/custom_method.c
@@ -30,7 +30,7 @@ static ssize_t cm_write(struct file *file, const char __user *user_buf,
acpi_status status;
int ret;

- ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
+ ret = security_locked_down(current_cred(), LOCKDOWN_ACPI_TABLES);
if (ret)
return ret;

diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index a43f1521efe6..11c462788db8 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -198,7 +198,8 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
* specific location (if appropriate) so it can be carried
* over further kexec()s.
*/
- if (acpi_rsdp && !security_locked_down(LOCKDOWN_ACPI_TABLES)) {
+ if (acpi_rsdp && !security_locked_down(current_cred(),
+ LOCKDOWN_ACPI_TABLES)) {
acpi_arch_set_root_pointer(acpi_rsdp);
return acpi_rsdp;
}
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index f9383736fa0f..6569ccacd24b 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -577,7 +577,7 @@ void __init acpi_table_upgrade(void)
if (table_nr == 0)
return;

- if (security_locked_down(LOCKDOWN_ACPI_TABLES)) {
+ if (security_locked_down(current_cred(), LOCKDOWN_ACPI_TABLES)) {
pr_notice("kernel is locked down, ignoring table override\n");
return;
}
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 1c596b5cdb27..330749897cd7 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -617,7 +617,7 @@ static int open_port(struct inode *inode, struct file *filp)
if (!capable(CAP_SYS_RAWIO))
return -EPERM;

- rc = security_locked_down(LOCKDOWN_DEV_MEM);
+ rc = security_locked_down(current_cred(), LOCKDOWN_DEV_MEM);
if (rc)
return rc;

diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 8e45aa07d662..539c91959234 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -575,7 +575,7 @@ static bool cxl_mem_raw_command_allowed(u16 opcode)
if (!IS_ENABLED(CONFIG_CXL_MEM_RAW_COMMANDS))
return false;

- if (security_locked_down(LOCKDOWN_PCI_ACCESS))
+ if (security_locked_down(current_cred(), LOCKDOWN_PCI_ACCESS))
return false;

if (cxl_raw_allow_all)
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 847f33ffc4ae..a885b4c38358 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -200,7 +200,7 @@ static void generic_ops_unregister(void)
static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata;
static int __init efivar_ssdt_setup(char *str)
{
- int ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
+ int ret = security_locked_down(current_cred(), LOCKDOWN_ACPI_TABLES);

if (ret)
return ret;
diff --git a/drivers/firmware/efi/test/efi_test.c b/drivers/firmware/efi/test/efi_test.c
index 47d67bb0a516..942c25843665 100644
--- a/drivers/firmware/efi/test/efi_test.c
+++ b/drivers/firmware/efi/test/efi_test.c
@@ -722,7 +722,7 @@ static long efi_test_ioctl(struct file *file, unsigned int cmd,

static int efi_test_open(struct inode *inode, struct file *file)
{
- int ret = security_locked_down(LOCKDOWN_EFI_TEST);
+ int ret = security_locked_down(current_cred(), LOCKDOWN_EFI_TEST);

if (ret)
return ret;
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 7fb5cd17cc98..b76055dbbb03 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -753,7 +753,7 @@ static ssize_t pci_write_config(struct file *filp, struct kobject *kobj,
u8 *data = (u8 *) buf;
int ret;

- ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_PCI_ACCESS);
if (ret)
return ret;

@@ -1047,7 +1047,7 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
struct resource *res = &pdev->resource[bar];
int ret;

- ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_PCI_ACCESS);
if (ret)
return ret;

@@ -1128,7 +1128,7 @@ static ssize_t pci_write_resource_io(struct file *filp, struct kobject *kobj,
{
int ret;

- ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_PCI_ACCESS);
if (ret)
return ret;

diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index cb18f8a13ab6..1dbdcdf0eff5 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -119,7 +119,7 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
int size = dev->cfg_size;
int cnt, ret;

- ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_PCI_ACCESS);
if (ret)
return ret;

@@ -202,7 +202,7 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
#endif /* HAVE_PCI_MMAP */
int ret = 0;

- ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_PCI_ACCESS);
if (ret)
return ret;

@@ -249,7 +249,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM;

if (!capable(CAP_SYS_RAWIO) ||
- security_locked_down(LOCKDOWN_PCI_ACCESS))
+ security_locked_down(current_cred(), LOCKDOWN_PCI_ACCESS))
return -EPERM;

if (fpriv->mmap_state == pci_mmap_io) {
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
index 61a6fe3cde21..e88cacf8d418 100644
--- a/drivers/pci/syscall.c
+++ b/drivers/pci/syscall.c
@@ -93,7 +93,7 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
int err = 0;

if (!capable(CAP_SYS_ADMIN) ||
- security_locked_down(LOCKDOWN_PCI_ACCESS))
+ security_locked_down(current_cred(), LOCKDOWN_PCI_ACCESS))
return -EPERM;

dev = pci_get_domain_bus_and_slot(0, bus, dfn);
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 948b763dc451..96c96c1cd6da 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -1577,7 +1577,7 @@ static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj,
struct pcmcia_socket *s;
int error;

- error = security_locked_down(LOCKDOWN_PCMCIA_CIS);
+ error = security_locked_down(current_cred(), LOCKDOWN_PCMCIA_CIS);
if (error)
return error;

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 0e2e35ab64c7..7fbec2644b1b 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -840,7 +840,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
}

if (change_irq || change_port) {
- retval = security_locked_down(LOCKDOWN_TIOCSSERIAL);
+ retval = security_locked_down(current_cred(), LOCKDOWN_TIOCSSERIAL);
if (retval)
goto exit;
}
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 7d162b0efbf0..a8e44f3e11d2 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -154,7 +154,7 @@ static int debugfs_locked_down(struct inode *inode,
!real_fops->mmap)
return 0;

- if (security_locked_down(LOCKDOWN_DEBUGFS))
+ if (security_locked_down(current_cred(), LOCKDOWN_DEBUGFS))
return -EPERM;

return 0;
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 8129a430d789..17f6438cc1b5 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -48,7 +48,7 @@ static int debugfs_setattr(struct user_namespace *mnt_userns,
int ret;

if (ia->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) {
- ret = security_locked_down(LOCKDOWN_DEBUGFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_DEBUGFS);
if (ret)
return ret;
}
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 982e694aae77..f386fd373ea6 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -586,7 +586,7 @@ out:

static int open_kcore(struct inode *inode, struct file *filp)
{
- int ret = security_locked_down(LOCKDOWN_KCORE);
+ int ret = security_locked_down(current_cred(), LOCKDOWN_KCORE);

if (!capable(CAP_SYS_RAWIO))
return -EPERM;
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index 1261e8b41edb..9db8dd52d429 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -396,7 +396,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
struct dentry *dentry;
struct inode *inode;

- if (security_locked_down(LOCKDOWN_TRACEFS))
+ if (security_locked_down(NULL, LOCKDOWN_TRACEFS))
return NULL;

if (!(mode & S_IFMT))
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2adeea44c0d5..a83a370cc284 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -393,7 +393,7 @@ LSM_HOOK(int, 0, bpf_prog_alloc_security, struct bpf_prog_aux *aux)
LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free_security, struct bpf_prog_aux *aux)
#endif /* CONFIG_BPF_SYSCALL */

-LSM_HOOK(int, 0, locked_down, enum lockdown_reason what)
+LSM_HOOK(int, 0, locked_down, const struct cred *cred, enum lockdown_reason what)

#ifdef CONFIG_PERF_EVENTS
LSM_HOOK(int, 0, perf_event_open, struct perf_event_attr *attr, int type)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 5c4c5c0602cb..8156f2dbaab7 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1543,6 +1543,7 @@
* Determine whether a kernel feature that potentially enables arbitrary
* code execution in kernel space should be permitted.
*
+ * @cred: credential asociated with the operation, or NULL if not applicable
* @what: kernel feature being accessed
*
* Security hooks for perf events
diff --git a/include/linux/security.h b/include/linux/security.h
index 5b7288521300..a9001c0ed885 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -471,7 +471,7 @@ void security_inode_invalidate_secctx(struct inode *inode);
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 security_locked_down(const struct cred *cred, enum lockdown_reason what);
#else /* CONFIG_SECURITY */

static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data)
@@ -1344,7 +1344,7 @@ static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32
{
return -EOPNOTSUPP;
}
-static inline int security_locked_down(enum lockdown_reason what)
+static inline int security_locked_down(struct cred *cred, enum lockdown_reason what)
{
return 0;
}
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 9aabf84afd4b..61a9645f9b8f 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -1424,13 +1424,15 @@ bpf_base_func_proto(enum bpf_func_id func_id)
case BPF_FUNC_probe_read_user:
return &bpf_probe_read_user_proto;
case BPF_FUNC_probe_read_kernel:
- return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
- NULL : &bpf_probe_read_kernel_proto;
+ if (security_locked_down(current_cred(), LOCKDOWN_BPF_READ_KERNEL) < 0)
+ return NULL;
+ return &bpf_probe_read_kernel_proto;
case BPF_FUNC_probe_read_user_str:
return &bpf_probe_read_user_str_proto;
case BPF_FUNC_probe_read_kernel_str:
- return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
- NULL : &bpf_probe_read_kernel_str_proto;
+ if (security_locked_down(current_cred(), LOCKDOWN_BPF_READ_KERNEL) < 0)
+ return NULL;
+ return &bpf_probe_read_kernel_str_proto;
case BPF_FUNC_snprintf_btf:
return &bpf_snprintf_btf_proto;
case BPF_FUNC_snprintf:
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 744e8726c5b2..d2836e320948 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -12017,7 +12017,7 @@ SYSCALL_DEFINE5(perf_event_open,

/* REGS_INTR can leak data, lockdown must prevent this */
if (attr.sample_type & PERF_SAMPLE_REGS_INTR) {
- err = security_locked_down(LOCKDOWN_PERF);
+ err = security_locked_down(current_cred(), LOCKDOWN_PERF);
if (err)
return err;
}
diff --git a/kernel/kexec.c b/kernel/kexec.c
index b5e40f069768..f908dd7889de 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -208,7 +208,7 @@ static inline int kexec_load_check(unsigned long nr_segments,
* kexec can be used to circumvent module loading restrictions, so
* prevent loading in that case
*/
- result = security_locked_down(LOCKDOWN_KEXEC);
+ result = security_locked_down(current_cred(), LOCKDOWN_KEXEC);
if (result)
return result;

diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 33400ff051a8..add00b325f4f 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -204,7 +204,7 @@ kimage_validate_signature(struct kimage *image)
* down.
*/
if (!ima_appraise_signature(READING_KEXEC_IMAGE) &&
- security_locked_down(LOCKDOWN_KEXEC))
+ security_locked_down(current_cred(), LOCKDOWN_KEXEC))
return -EPERM;

pr_debug("kernel signature verification failed (%d).\n", ret);
diff --git a/kernel/module.c b/kernel/module.c
index 40ec9a030eec..3cad8055d7a2 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2931,7 +2931,7 @@ static int module_sig_check(struct load_info *info, int flags)
return -EKEYREJECTED;
}

- return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
+ return security_locked_down(current_cred(), LOCKDOWN_MODULE_SIGNATURE);
}
#else /* !CONFIG_MODULE_SIG */
static int module_sig_check(struct load_info *info, int flags)
diff --git a/kernel/params.c b/kernel/params.c
index 8299bd764e42..619bf8ad8416 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -100,7 +100,7 @@ bool parameq(const char *a, const char *b)
static bool param_check_unsafe(const struct kernel_param *kp)
{
if (kp->flags & KERNEL_PARAM_FL_HWPARAM &&
- security_locked_down(LOCKDOWN_MODULE_PARAMETERS))
+ security_locked_down(current_cred(), LOCKDOWN_MODULE_PARAMETERS))
return false;

if (kp->flags & KERNEL_PARAM_FL_UNSAFE) {
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 559acef3fddb..2625d531ee0e 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -83,7 +83,7 @@ void hibernate_release(void)
bool hibernation_available(void)
{
return nohibernate == 0 &&
- !security_locked_down(LOCKDOWN_HIBERNATION) &&
+ !security_locked_down(current_cred(), LOCKDOWN_HIBERNATION) &&
!secretmem_active();
}

diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 8e2eb950aa82..51bdbdf75a5c 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -1066,25 +1066,30 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
case BPF_FUNC_get_prandom_u32:
return &bpf_get_prandom_u32_proto;
case BPF_FUNC_probe_write_user:
- return security_locked_down(LOCKDOWN_BPF_WRITE_USER) < 0 ?
- NULL : bpf_get_probe_write_proto();
+ if (security_locked_down(current_cred(), LOCKDOWN_BPF_WRITE_USER) < 0)
+ return NULL;
+ return bpf_get_probe_write_proto();
case BPF_FUNC_probe_read_user:
return &bpf_probe_read_user_proto;
case BPF_FUNC_probe_read_kernel:
- return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
- NULL : &bpf_probe_read_kernel_proto;
+ if (security_locked_down(current_cred(), LOCKDOWN_BPF_READ_KERNEL) < 0)
+ return NULL;
+ return &bpf_probe_read_kernel_proto;
case BPF_FUNC_probe_read_user_str:
return &bpf_probe_read_user_str_proto;
case BPF_FUNC_probe_read_kernel_str:
- return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
- NULL : &bpf_probe_read_kernel_str_proto;
+ if (security_locked_down(current_cred(), LOCKDOWN_BPF_READ_KERNEL) < 0)
+ return NULL;
+ return &bpf_probe_read_kernel_str_proto;
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
case BPF_FUNC_probe_read:
- return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
- NULL : &bpf_probe_read_compat_proto;
+ if (security_locked_down(current_cred(), LOCKDOWN_BPF_READ_KERNEL) < 0)
+ return NULL;
+ return &bpf_probe_read_compat_proto;
case BPF_FUNC_probe_read_str:
- return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
- NULL : &bpf_probe_read_compat_str_proto;
+ if (security_locked_down(current_cred(), LOCKDOWN_BPF_READ_KERNEL) < 0)
+ return NULL;
+ return &bpf_probe_read_compat_str_proto;
#endif
#ifdef CONFIG_CGROUPS
case BPF_FUNC_get_current_cgroup_id:
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 7efbc8aaf7f6..5c1b2681c371 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3694,7 +3694,7 @@ ftrace_avail_open(struct inode *inode, struct file *file)
struct ftrace_iterator *iter;
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

@@ -5822,7 +5822,7 @@ __ftrace_graph_open(struct inode *inode, struct file *file,
int ret;
struct ftrace_hash *new_hash = NULL;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index c5a3fbf19617..13669fcbd466 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -5880,7 +5880,7 @@ static __init int test_ringbuffer(void)
int cpu;
int ret = 0;

- if (security_locked_down(LOCKDOWN_TRACEFS)) {
+ if (security_locked_down(current_cred(), LOCKDOWN_TRACEFS)) {
pr_warn("Lockdown is enabled, skipping ring buffer tests\n");
return 0;
}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 7896d30d90f7..2bac9688ff6a 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -486,7 +486,7 @@ int tracing_check_open_get_tr(struct trace_array *tr)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

@@ -2071,7 +2071,7 @@ int __init register_tracer(struct tracer *type)
return -1;
}

- if (security_locked_down(LOCKDOWN_TRACEFS)) {
+ if (security_locked_down(current_cred(), LOCKDOWN_TRACEFS)) {
pr_warn("Can not register tracer %s due to lockdown\n",
type->name);
return -EPERM;
@@ -9527,7 +9527,7 @@ int tracing_init_dentry(void)
{
struct trace_array *tr = &global_trace;

- if (security_locked_down(LOCKDOWN_TRACEFS)) {
+ if (security_locked_down(current_cred(), LOCKDOWN_TRACEFS)) {
pr_warn("Tracing disabled due to lockdown\n");
return -EPERM;
}
@@ -9989,7 +9989,7 @@ __init static int tracer_alloc_buffers(void)
int ret = -ENOMEM;


- if (security_locked_down(LOCKDOWN_TRACEFS)) {
+ if (security_locked_down(current_cred(), LOCKDOWN_TRACEFS)) {
pr_warn("Tracing disabled due to lockdown\n");
return -EPERM;
}
@@ -10155,7 +10155,7 @@ __init static void tracing_set_default_clock(void)
{
/* sched_clock_stable() is determined in late_initcall */
if (!trace_boot_clock && !sched_clock_stable()) {
- if (security_locked_down(LOCKDOWN_TRACEFS)) {
+ if (security_locked_down(current_cred(), LOCKDOWN_TRACEFS)) {
pr_warn("Can not set tracing clock due to lockdown\n");
return;
}
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 830b3b9940f4..c1e4f7f93c0e 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2130,7 +2130,7 @@ ftrace_event_open(struct inode *inode, struct file *file,
struct seq_file *m;
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index a6061a69aa84..e122f0467421 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -4917,7 +4917,7 @@ static int event_hist_open(struct inode *inode, struct file *file)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

@@ -5189,7 +5189,7 @@ static int event_hist_debug_open(struct inode *inode, struct file *file)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
index d54094b7a9d7..deac45f00f3a 100644
--- a/kernel/trace/trace_events_synth.c
+++ b/kernel/trace/trace_events_synth.c
@@ -2174,7 +2174,7 @@ static int synth_events_open(struct inode *inode, struct file *file)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index 3d5c07239a2a..38226c386f82 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -190,7 +190,7 @@ static int event_trigger_regex_open(struct inode *inode, struct file *file)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 3a64ba4bbad6..9178ad52290e 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -479,7 +479,7 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
{
int i, ret;

- ret = security_locked_down(LOCKDOWN_KPROBES);
+ ret = security_locked_down(current_cred(), LOCKDOWN_KPROBES);
if (ret)
return ret;

@@ -1141,7 +1141,7 @@ static int probes_open(struct inode *inode, struct file *file)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

@@ -1199,7 +1199,7 @@ static int profile_open(struct inode *inode, struct file *file)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index 4b320fe7df70..47c808484cb2 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -362,7 +362,7 @@ ftrace_formats_open(struct inode *inode, struct file *file)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index 63c285042051..63b6ebe7bdce 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -477,7 +477,7 @@ static int stack_trace_open(struct inode *inode, struct file *file)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c
index 8d141c3825a9..2f6ae81ee67e 100644
--- a/kernel/trace/trace_stat.c
+++ b/kernel/trace/trace_stat.c
@@ -236,7 +236,7 @@ static int tracing_stat_open(struct inode *inode, struct file *file)
struct seq_file *m;
struct stat_session *session = inode->i_private;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 225ce569bf8f..4b114e4fe436 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -781,7 +781,7 @@ static int probes_open(struct inode *inode, struct file *file)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

@@ -836,7 +836,7 @@ static int profile_open(struct inode *inode, struct file *file)
{
int ret;

- ret = security_locked_down(LOCKDOWN_TRACEFS);
+ ret = security_locked_down(current_cred(), LOCKDOWN_TRACEFS);
if (ret)
return ret;

diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 03b66d154b2b..ffd560514d8f 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -850,8 +850,15 @@ static int copy_user_offload(struct xfrm_state_offload *xso, struct sk_buff *skb

static bool xfrm_redact(void)
{
- return IS_ENABLED(CONFIG_SECURITY) &&
- security_locked_down(LOCKDOWN_XFRM_SECRET);
+ /* Don't use current_cred() here, since this may be called when
+ * broadcasting a notification that an SA has been created/deleted.
+ * In that case current task is the one triggering the notification,
+ * but the SA key is actually leaked to the event subscribers.
+ * Since we can't easily do the redact decision per-subscriber,
+ * just pass NULL here, indicating to the LSMs that a global lockdown
+ * decision should be made instead.
+ */
+ return security_locked_down(NULL, LOCKDOWN_XFRM_SECRET);
}

static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb)
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
index 87cbdc64d272..2abe92157e82 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -55,7 +55,8 @@ early_param("lockdown", lockdown_param);
* lockdown_is_locked_down - Find out if the kernel is locked down
* @what: Tag to use in notice generated if lockdown is in effect
*/
-static int lockdown_is_locked_down(enum lockdown_reason what)
+static int lockdown_is_locked_down(const struct cred *cred,
+ enum lockdown_reason what)
{
if (WARN(what >= LOCKDOWN_CONFIDENTIALITY_MAX,
"Invalid lockdown reason"))
diff --git a/security/security.c b/security/security.c
index 9ffa9e9c5c55..51245e37b351 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2593,9 +2593,9 @@ void security_bpf_prog_free(struct bpf_prog_aux *aux)
}
#endif /* CONFIG_BPF_SYSCALL */

-int security_locked_down(enum lockdown_reason what)
+int security_locked_down(const struct cred *cred, enum lockdown_reason what)
{
- return call_int_hook(locked_down, 0, what);
+ return call_int_hook(locked_down, 0, cred, what);
}
EXPORT_SYMBOL(security_locked_down);

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6517f221d52c..300bc9e1ffbf 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7013,10 +7013,10 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
}
#endif

-static int selinux_lockdown(enum lockdown_reason what)
+static int selinux_lockdown(const struct cred *cred, enum lockdown_reason what)
{
struct common_audit_data ad;
- u32 sid = current_sid();
+ u32 sid;
int invalid_reason = (what <= LOCKDOWN_NONE) ||
(what == LOCKDOWN_INTEGRITY_MAX) ||
(what >= LOCKDOWN_CONFIDENTIALITY_MAX);
@@ -7028,6 +7028,9 @@ static int selinux_lockdown(enum lockdown_reason what)
return -EINVAL;
}

+ /* Use SECINITSID_KERNEL if there is no relevant cred to check against */
+ sid = cred ? cred_sid(cred) : SECINITSID_KERNEL;
+
ad.type = LSM_AUDIT_DATA_LOCKDOWN;
ad.u.reason = what;

--
2.31.1