Skip to content

Commit

Permalink
LSM: Identify modules by more than name
Browse files Browse the repository at this point in the history
Create a struct lsm_id to contain identifying information about Linux
Security Modules (LSMs). At inception this contains the name of the
module and an identifier associated with the security module.  Change
the security_add_hooks() interface to use this structure.  Change the
individual modules to maintain their own struct lsm_id and pass it to
security_add_hooks().

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

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

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

Cc: linux-security-module <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: Serge Hallyn <[email protected]>
Reviewed-by: Mickael Salaun <[email protected]>
Reviewed-by: John Johansen <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
Nacked-by: Tetsuo Handa <[email protected]>
[PM: forward ported beyond v6.6 due merge window changes]
Signed-off-by: Paul Moore <[email protected]>
  • Loading branch information
cschaufler authored and pcmoore committed Nov 13, 2023
1 parent b85ea95 commit f3b8788
Show file tree
Hide file tree
Showing 21 changed files with 162 additions and 22 deletions.
1 change: 1 addition & 0 deletions Documentation/userspace-api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ place where this information is gathered.
sysfs-platform_profile
vduse
futex2
lsm

.. only:: subproject and html

Expand Down
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -19511,6 +19511,7 @@ L: [email protected] (suggested Cc:)
S: Supported
W: http://kernsec.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git
F: include/uapi/linux/lsm.h
F: security/
X: security/selinux/

Expand Down
16 changes: 14 additions & 2 deletions include/linux/lsm_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ struct security_hook_heads {
#undef LSM_HOOK
} __randomize_layout;

/**
* struct lsm_id - Identify a Linux Security Module.
* @lsm: name of the LSM, must be approved by the LSM maintainers
* @id: LSM ID number from uapi/linux/lsm.h
*
* Contains the information that identifies the LSM.
*/
struct lsm_id {
const char *name;
u64 id;
};

/*
* Security module hook list structure.
* For use with generic list macros for common operations.
Expand All @@ -50,7 +62,7 @@ struct security_hook_list {
struct hlist_node list;
struct hlist_head *head;
union security_list_options hook;
const char *lsm;
const struct lsm_id *lsmid;
} __randomize_layout;

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

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

#define LSM_FLAG_LEGACY_MAJOR BIT(0)
#define LSM_FLAG_EXCLUSIVE BIT(1)
Expand Down
54 changes: 54 additions & 0 deletions include/uapi/linux/lsm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Linux Security Modules (LSM) - User space API
*
* Copyright (C) 2022 Casey Schaufler <[email protected]>
* Copyright (C) 2022 Intel Corporation
*/

#ifndef _UAPI_LINUX_LSM_H
#define _UAPI_LINUX_LSM_H

/*
* ID tokens to identify Linux Security Modules (LSMs)
*
* These token values are used to uniquely identify specific LSMs
* in the kernel as well as in the kernel's LSM userspace API.
*
* A value of zero/0 is considered undefined and should not be used
* outside the kernel. Values 1-99 are reserved for potential
* future use.
*/
#define LSM_ID_UNDEF 0
#define LSM_ID_CAPABILITY 100
#define LSM_ID_SELINUX 101
#define LSM_ID_SMACK 102
#define LSM_ID_TOMOYO 103
#define LSM_ID_IMA 104
#define LSM_ID_APPARMOR 105
#define LSM_ID_YAMA 106
#define LSM_ID_LOADPIN 107
#define LSM_ID_SAFESETID 108
#define LSM_ID_LOCKDOWN 109
#define LSM_ID_BPF 110
#define LSM_ID_LANDLOCK 111

/*
* LSM_ATTR_XXX definitions identify different LSM attributes
* which are used in the kernel's LSM userspace API. Support
* for these attributes vary across the different LSMs. None
* are required.
*
* A value of zero/0 is considered undefined and should not be used
* outside the kernel. Values 1-99 are reserved for potential
* future use.
*/
#define LSM_ATTR_UNDEF 0
#define LSM_ATTR_CURRENT 100
#define LSM_ATTR_EXEC 101
#define LSM_ATTR_FSCREATE 102
#define LSM_ATTR_KEYCREATE 103
#define LSM_ATTR_PREV 104
#define LSM_ATTR_SOCKCREATE 105

#endif /* _UAPI_LINUX_LSM_H */
8 changes: 7 additions & 1 deletion security/apparmor/lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1385,6 +1386,11 @@ struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
.lbs_task = sizeof(struct aa_task_ctx),
};

const struct lsm_id apparmor_lsmid = {
.name = "apparmor",
.id = LSM_ID_APPARMOR,
};

static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
Expand Down Expand Up @@ -2202,7 +2208,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;
Expand Down
9 changes: 8 additions & 1 deletion security/bpf/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, ...) \
Expand All @@ -15,9 +16,15 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
LSM_HOOK_INIT(task_free, bpf_task_storage_free),
};

const struct lsm_id bpf_lsmid = {
.name = "bpf",
.id = LSM_ID_BPF,
};

static int __init bpf_lsm_init(void)
{
security_add_hooks(bpf_lsm_hooks, ARRAY_SIZE(bpf_lsm_hooks), "bpf");
security_add_hooks(bpf_lsm_hooks, ARRAY_SIZE(bpf_lsm_hooks),
&bpf_lsmid);
pr_info("LSM support for eBPF active\n");
return 0;
}
Expand Down
8 changes: 7 additions & 1 deletion security/commoncap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1440,6 +1441,11 @@ int cap_mmap_file(struct file *file, unsigned long reqprot,

#ifdef CONFIG_SECURITY

const struct lsm_id capability_lsmid = {
.name = "capability",
.id = LSM_ID_CAPABILITY,
};

static struct security_hook_list capability_hooks[] __ro_after_init = {
LSM_HOOK_INIT(capable, cap_capable),
LSM_HOOK_INIT(settime, cap_settime),
Expand All @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion security/landlock/cred.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 1 addition & 1 deletion security/landlock/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 1 addition & 1 deletion security/landlock/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 1 addition & 1 deletion security/landlock/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
6 changes: 6 additions & 0 deletions security/landlock/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

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

#include "common.h"
#include "cred.h"
Expand All @@ -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();
Expand Down
1 change: 1 addition & 0 deletions security/landlock/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
9 changes: 8 additions & 1 deletion security/loadpin/loadpin.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

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

const struct lsm_id loadpin_lsmid = {
.name = "loadpin",
.id = LSM_ID_LOADPIN,
};

static struct security_hook_list loadpin_hooks[] __ro_after_init = {
LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security),
LSM_HOOK_INIT(kernel_read_file, loadpin_read_file),
Expand Down Expand Up @@ -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;
}
Expand Down
8 changes: 7 additions & 1 deletion security/lockdown/lockdown.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down
9 changes: 8 additions & 1 deletion security/safesetid/lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -261,6 +262,11 @@ static int safesetid_task_fix_setgroups(struct cred *new, const struct cred *old
return 0;
}

const struct lsm_id safesetid_lsmid = {
.name = "safesetid",
.id = LSM_ID_SAFESETID,
};

static struct security_hook_list safesetid_security_hooks[] = {
LSM_HOOK_INIT(task_fix_setuid, safesetid_task_fix_setuid),
LSM_HOOK_INIT(task_fix_setgid, safesetid_task_fix_setgid),
Expand All @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions security/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,17 +513,17 @@ static int lsm_append(const char *new, char **result)
* security_add_hooks - Add a modules hooks to the hook lists.
* @hooks: the hooks to add
* @count: the number of hooks to add
* @lsm: the name of the security module
* @lsmid: the identification information for the security module
*
* Each LSM has to register its hooks with the infrastructure.
*/
void __init security_add_hooks(struct security_hook_list *hooks, int count,
const char *lsm)
const struct lsm_id *lsmid)
{
int i;

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

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

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

hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
if (lsm != NULL && strcmp(lsm, hp->lsm))
if (lsm != NULL && strcmp(lsm, hp->lsmid->name))
continue;
return hp->hook.setprocattr(name, value, size);
}
Expand Down
Loading

0 comments on commit f3b8788

Please sign in to comment.