summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-12-03 09:53:48 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2025-12-03 09:53:48 -0800
commit121cc35cfb55ab0bcf04c8ba6b364a0990eb2449 (patch)
tree323e2b393e0c49692ff45e03c5767b6dc54848e0
parent7fc2cd2e4b398c57c9cf961cfea05eadbf34c05c (diff)
parent9a948eefad594c42717f29824dd40d6dc0b7aa13 (diff)
Merge tag 'lsm-pr-20251201' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm
Pull LSM updates from Paul Moore: - Rework the LSM initialization code What started as a "quick" patch to enable a notification event once all of the individual LSMs were initialized, snowballed a bit into a 30+ patch patchset when everything was done. Most of the patches, and diffstat, is due to splitting out the initialization code into security/lsm_init.c and cleaning up some of the mess that was there. While not strictly necessary, it does cleanup the code signficantly, and hopefully makes the upkeep a bit easier in the future. Aside from the new LSM_STARTED_ALL notification, these changes also ensure that individual LSM initcalls are only called when the LSM is enabled at boot time. There should be a minor reduction in boot times for those who build multiple LSMs into their kernels, but only enable a subset at boot. It is worth mentioning that nothing at present makes use of the LSM_STARTED_ALL notification, but there is work in progress which is dependent upon LSM_STARTED_ALL. - Make better use of the seq_put*() helpers in device_cgroup * tag 'lsm-pr-20251201' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm: (36 commits) lsm: use unrcu_pointer() for current->cred in security_init() device_cgroup: Refactor devcgroup_seq_show to use seq_put* helpers lsm: add a LSM_STARTED_ALL notification event lsm: consolidate all of the LSM framework initcalls selinux: move initcalls to the LSM framework ima,evm: move initcalls to the LSM framework lockdown: move initcalls to the LSM framework apparmor: move initcalls to the LSM framework safesetid: move initcalls to the LSM framework tomoyo: move initcalls to the LSM framework smack: move initcalls to the LSM framework ipe: move initcalls to the LSM framework loadpin: move initcalls to the LSM framework lsm: introduce an initcall mechanism into the LSM framework lsm: group lsm_order_parse() with the other lsm_order_*() functions lsm: output available LSMs when debugging lsm: cleanup the debug and console output in lsm_init.c lsm: add/tweak function header comment blocks in lsm_init.c lsm: fold lsm_init_ordered() into security_init() lsm: cleanup initialize_lsm() and rename to lsm_init_single() ...
-rw-r--r--include/linux/lsm_hooks.h73
-rw-r--r--include/linux/security.h3
-rw-r--r--security/Makefile2
-rw-r--r--security/apparmor/apparmorfs.c4
-rw-r--r--security/apparmor/crypto.c3
-rw-r--r--security/apparmor/include/apparmorfs.h2
-rw-r--r--security/apparmor/include/crypto.h1
-rw-r--r--security/apparmor/lsm.c11
-rw-r--r--security/bpf/hooks.c2
-rw-r--r--security/commoncap.c2
-rw-r--r--security/device_cgroup.c56
-rw-r--r--security/inode.c46
-rw-r--r--security/integrity/evm/evm_main.c5
-rw-r--r--security/integrity/evm/evm_secfs.c11
-rw-r--r--security/integrity/iint.c14
-rw-r--r--security/integrity/ima/ima_fs.c11
-rw-r--r--security/integrity/ima/ima_main.c6
-rw-r--r--security/integrity/integrity.h2
-rw-r--r--security/ipe/fs.c4
-rw-r--r--security/ipe/ipe.c3
-rw-r--r--security/ipe/ipe.h2
-rw-r--r--security/landlock/setup.c2
-rw-r--r--security/loadpin/loadpin.c13
-rw-r--r--security/lockdown/lockdown.c5
-rw-r--r--security/lsm.h58
-rw-r--r--security/lsm_init.c564
-rw-r--r--security/lsm_notifier.c31
-rw-r--r--security/lsm_syscalls.c2
-rw-r--r--security/min_addr.c5
-rw-r--r--security/safesetid/lsm.c3
-rw-r--r--security/safesetid/lsm.h2
-rw-r--r--security/safesetid/securityfs.c3
-rw-r--r--security/security.c623
-rw-r--r--security/selinux/Makefile2
-rw-r--r--security/selinux/hooks.c11
-rw-r--r--security/selinux/ibpkey.c5
-rw-r--r--security/selinux/include/audit.h9
-rw-r--r--security/selinux/include/initcalls.h19
-rw-r--r--security/selinux/initcalls.c52
-rw-r--r--security/selinux/netif.c5
-rw-r--r--security/selinux/netlink.c5
-rw-r--r--security/selinux/netnode.c5
-rw-r--r--security/selinux/netport.c5
-rw-r--r--security/selinux/selinuxfs.c5
-rw-r--r--security/selinux/ss/services.c26
-rw-r--r--security/smack/smack.h14
-rw-r--r--security/smack/smack_lsm.c11
-rw-r--r--security/smack/smack_netfilter.c4
-rw-r--r--security/smack/smackfs.c4
-rw-r--r--security/tomoyo/common.h2
-rw-r--r--security/tomoyo/securityfs_if.c4
-rw-r--r--security/tomoyo/tomoyo.c3
-rw-r--r--security/yama/yama_lsm.c2
53 files changed, 1025 insertions, 742 deletions
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 79ec5a2bdcca..b92008641242 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -102,23 +102,23 @@ struct security_hook_list {
* Security blob size or offset data.
*/
struct lsm_blob_sizes {
- int lbs_cred;
- int lbs_file;
- int lbs_ib;
- int lbs_inode;
- int lbs_sock;
- int lbs_superblock;
- int lbs_ipc;
- int lbs_key;
- int lbs_msg_msg;
- int lbs_perf_event;
- int lbs_task;
- int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
- int lbs_tun_dev;
- int lbs_bdev;
- int lbs_bpf_map;
- int lbs_bpf_prog;
- int lbs_bpf_token;
+ unsigned int lbs_cred;
+ unsigned int lbs_file;
+ unsigned int lbs_ib;
+ unsigned int lbs_inode;
+ unsigned int lbs_sock;
+ unsigned int lbs_superblock;
+ unsigned int lbs_ipc;
+ unsigned int lbs_key;
+ unsigned int lbs_msg_msg;
+ unsigned int lbs_perf_event;
+ unsigned int lbs_task;
+ unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
+ unsigned int lbs_tun_dev;
+ unsigned int lbs_bdev;
+ unsigned int lbs_bpf_map;
+ unsigned int lbs_bpf_prog;
+ unsigned int lbs_bpf_token;
};
/*
@@ -151,13 +151,36 @@ enum lsm_order {
LSM_ORDER_LAST = 1, /* This is only for integrity. */
};
+/**
+ * struct lsm_info - Define an individual LSM for the LSM framework.
+ * @id: LSM name/ID info
+ * @order: ordering with respect to other LSMs, optional
+ * @flags: descriptive flags, optional
+ * @blobs: LSM blob sharing, optional
+ * @enabled: controlled by CONFIG_LSM, optional
+ * @init: LSM specific initialization routine
+ * @initcall_pure: LSM callback for initcall_pure() setup, optional
+ * @initcall_early: LSM callback for early_initcall setup, optional
+ * @initcall_core: LSM callback for core_initcall() setup, optional
+ * @initcall_subsys: LSM callback for subsys_initcall() setup, optional
+ * @initcall_fs: LSM callback for fs_initcall setup, optional
+ * @nitcall_device: LSM callback for device_initcall() setup, optional
+ * @initcall_late: LSM callback for late_initcall() setup, optional
+ */
struct lsm_info {
- const char *name; /* Required. */
- enum lsm_order order; /* Optional: default is LSM_ORDER_MUTABLE */
- unsigned long flags; /* Optional: flags describing LSM */
- int *enabled; /* Optional: controlled by CONFIG_LSM */
- int (*init)(void); /* Required. */
- struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
+ const struct lsm_id *id;
+ enum lsm_order order;
+ unsigned long flags;
+ struct lsm_blob_sizes *blobs;
+ int *enabled;
+ int (*init)(void);
+ int (*initcall_pure)(void);
+ int (*initcall_early)(void);
+ int (*initcall_core)(void);
+ int (*initcall_subsys)(void);
+ int (*initcall_fs)(void);
+ int (*initcall_device)(void);
+ int (*initcall_late)(void);
};
#define DEFINE_LSM(lsm) \
@@ -170,11 +193,9 @@ struct lsm_info {
__used __section(".early_lsm_info.init") \
__aligned(sizeof(unsigned long))
+
/* DO NOT tamper with these variables outside of the LSM framework */
-extern char *lsm_names;
extern struct lsm_static_calls_table static_calls_table __ro_after_init;
-extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
-extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
/**
* lsm_get_xattr_slot - Return the next available slot and increment the index
diff --git a/include/linux/security.h b/include/linux/security.h
index 92ac3f27b973..eb36451ce41f 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -85,6 +85,7 @@ struct timezone;
enum lsm_event {
LSM_POLICY_CHANGE,
+ LSM_STARTED_ALL,
};
struct dm_verity_digest {
@@ -167,8 +168,6 @@ struct lsm_prop {
};
extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
-extern u32 lsm_active_cnt;
-extern const struct lsm_id *lsm_idlist[];
/* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
diff --git a/security/Makefile b/security/Makefile
index 22ff4c8bd8ce..4601230ba442 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_SECURITY) += lsm_syscalls.o
obj-$(CONFIG_MMU) += min_addr.o
# Object file lists
-obj-$(CONFIG_SECURITY) += security.o
+obj-$(CONFIG_SECURITY) += security.o lsm_notifier.o lsm_init.o
obj-$(CONFIG_SECURITYFS) += inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
obj-$(CONFIG_SECURITY_SMACK) += smack/
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 9d08d103f142..e4114aa1e04f 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -2649,7 +2649,7 @@ static const struct inode_operations policy_link_iops = {
*
* Returns: error on failure
*/
-static int __init aa_create_aafs(void)
+int __init aa_create_aafs(void)
{
struct dentry *dent;
int error;
@@ -2728,5 +2728,3 @@ error:
AA_ERROR("Error creating AppArmor securityfs\n");
return error;
}
-
-fs_initcall(aa_create_aafs);
diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c
index 227d47c14907..d8a7bde94d79 100644
--- a/security/apparmor/crypto.c
+++ b/security/apparmor/crypto.c
@@ -53,10 +53,9 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
return 0;
}
-static int __init init_profile_hash(void)
+int __init init_profile_hash(void)
{
if (apparmor_initialized)
aa_info_message("AppArmor sha256 policy hashing enabled");
return 0;
}
-late_initcall(init_profile_hash);
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
index 1e94904f68d9..dd580594dfb7 100644
--- a/security/apparmor/include/apparmorfs.h
+++ b/security/apparmor/include/apparmorfs.h
@@ -104,6 +104,8 @@ enum aafs_prof_type {
#define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
#define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
+int aa_create_aafs(void);
+
void __aa_bump_ns_revision(struct aa_ns *ns);
void __aafs_profile_rmdir(struct aa_profile *profile);
void __aafs_profile_migrate_dents(struct aa_profile *old,
diff --git a/security/apparmor/include/crypto.h b/security/apparmor/include/crypto.h
index 636a04e20d91..f3ffd388cc58 100644
--- a/security/apparmor/include/crypto.h
+++ b/security/apparmor/include/crypto.h
@@ -13,6 +13,7 @@
#include "policy.h"
#ifdef CONFIG_SECURITY_APPARMOR_HASH
+int init_profile_hash(void);
unsigned int aa_hash_size(void);
char *aa_calc_hash(void *data, size_t len);
int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index b3f7a3258a2c..a87cd60ed206 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -32,6 +32,7 @@
#include "include/audit.h"
#include "include/capability.h"
#include "include/cred.h"
+#include "include/crypto.h"
#include "include/file.h"
#include "include/ipc.h"
#include "include/net.h"
@@ -2426,7 +2427,6 @@ static int __init apparmor_nf_ip_init(void)
return 0;
}
-__initcall(apparmor_nf_ip_init);
#endif
static char nulldfa_src[] __aligned(8) = {
@@ -2555,9 +2555,16 @@ alloc_out:
}
DEFINE_LSM(apparmor) = {
- .name = "apparmor",
+ .id = &apparmor_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &apparmor_enabled,
.blobs = &apparmor_blob_sizes,
.init = apparmor_init,
+ .initcall_fs = aa_create_aafs,
+#if defined(CONFIG_NETFILTER) && defined(CONFIG_NETWORK_SECMARK)
+ .initcall_device = apparmor_nf_ip_init,
+#endif
+#ifdef CONFIG_SECURITY_APPARMOR_HASH
+ .initcall_late = init_profile_hash,
+#endif
};
diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
index db759025abe1..40efde233f3a 100644
--- a/security/bpf/hooks.c
+++ b/security/bpf/hooks.c
@@ -33,7 +33,7 @@ struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
};
DEFINE_LSM(bpf) = {
- .name = "bpf",
+ .id = &bpf_lsmid,
.init = bpf_lsm_init,
.blobs = &bpf_lsm_blob_sizes
};
diff --git a/security/commoncap.c b/security/commoncap.c
index 6bd4adeb4795..b50479bd0286 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1505,7 +1505,7 @@ static int __init capability_init(void)
}
DEFINE_LSM(capability) = {
- .name = "capability",
+ .id = &capability_lsmid,
.order = LSM_ORDER_FIRST,
.init = capability_init,
};
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index dc4df7475081..7fec575d32d6 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -244,45 +244,40 @@ static void devcgroup_css_free(struct cgroup_subsys_state *css)
#define DEVCG_DENY 2
#define DEVCG_LIST 3
-#define MAJMINLEN 13
-#define ACCLEN 4
-
-static void set_access(char *acc, short access)
+static void seq_putaccess(struct seq_file *m, short access)
{
- int idx = 0;
- memset(acc, 0, ACCLEN);
if (access & DEVCG_ACC_READ)
- acc[idx++] = 'r';
+ seq_putc(m, 'r');
if (access & DEVCG_ACC_WRITE)
- acc[idx++] = 'w';
+ seq_putc(m, 'w');
if (access & DEVCG_ACC_MKNOD)
- acc[idx++] = 'm';
+ seq_putc(m, 'm');
}
-static char type_to_char(short type)
+static void seq_puttype(struct seq_file *m, short type)
{
if (type == DEVCG_DEV_ALL)
- return 'a';
- if (type == DEVCG_DEV_CHAR)
- return 'c';
- if (type == DEVCG_DEV_BLOCK)
- return 'b';
- return 'X';
+ seq_putc(m, 'a');
+ else if (type == DEVCG_DEV_CHAR)
+ seq_putc(m, 'c');
+ else if (type == DEVCG_DEV_BLOCK)
+ seq_putc(m, 'b');
+ else
+ seq_putc(m, 'X');
}
-static void set_majmin(char *str, unsigned m)
+static void seq_putversion(struct seq_file *m, unsigned int version)
{
- if (m == ~0)
- strcpy(str, "*");
+ if (version == ~0)
+ seq_putc(m, '*');
else
- sprintf(str, "%u", m);
+ seq_printf(m, "%u", version);
}
static int devcgroup_seq_show(struct seq_file *m, void *v)
{
struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m));
struct dev_exception_item *ex;
- char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
rcu_read_lock();
/*
@@ -292,18 +287,17 @@ static int devcgroup_seq_show(struct seq_file *m, void *v)
* This way, the file remains as a "whitelist of devices"
*/
if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
- set_access(acc, DEVCG_ACC_MASK);
- set_majmin(maj, ~0);
- set_majmin(min, ~0);
- seq_printf(m, "%c %s:%s %s\n", type_to_char(DEVCG_DEV_ALL),
- maj, min, acc);
+ seq_puts(m, "a *:* rwm\n");
} else {
list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) {
- set_access(acc, ex->access);
- set_majmin(maj, ex->major);
- set_majmin(min, ex->minor);
- seq_printf(m, "%c %s:%s %s\n", type_to_char(ex->type),
- maj, min, acc);
+ seq_puttype(m, ex->type);
+ seq_putc(m, ' ');
+ seq_putversion(m, ex->major);
+ seq_putc(m, ':');
+ seq_putversion(m, ex->minor);
+ seq_putc(m, ' ');
+ seq_putaccess(m, ex->access);
+ seq_putc(m, '\n');
}
}
rcu_read_unlock();
diff --git a/security/inode.c b/security/inode.c
index 43382ef8896e..ab8d6a2acadb 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -22,6 +22,8 @@
#include <linux/lsm_hooks.h>
#include <linux/magic.h>
+#include "lsm.h"
+
static struct vfsmount *mount;
static int mount_count;
@@ -315,12 +317,49 @@ void securityfs_remove(struct dentry *dentry)
EXPORT_SYMBOL_GPL(securityfs_remove);
#ifdef CONFIG_SECURITY
+#include <linux/spinlock.h>
+
static struct dentry *lsm_dentry;
+
static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
loff_t *ppos)
{
- return simple_read_from_buffer(buf, count, ppos, lsm_names,
- strlen(lsm_names));
+ int i;
+ static char *str;
+ static size_t len;
+ static DEFINE_SPINLOCK(lock);
+
+ /* NOTE: we never free or modify the string once it is set */
+
+ if (unlikely(!str || !len)) {
+ char *str_tmp;
+ size_t len_tmp = 0;
+
+ for (i = 0; i < lsm_active_cnt; i++)
+ /* the '+ 1' accounts for either a comma or a NUL */
+ len_tmp += strlen(lsm_idlist[i]->name) + 1;
+
+ str_tmp = kmalloc(len_tmp, GFP_KERNEL);
+ if (!str_tmp)
+ return -ENOMEM;
+ str_tmp[0] = '\0';
+
+ for (i = 0; i < lsm_active_cnt; i++) {
+ if (i > 0)
+ strcat(str_tmp, ",");
+ strcat(str_tmp, lsm_idlist[i]->name);
+ }
+
+ spin_lock(&lock);
+ if (!str) {
+ str = str_tmp;
+ len = len_tmp - 1;
+ } else
+ kfree(str_tmp);
+ spin_unlock(&lock);
+ }
+
+ return simple_read_from_buffer(buf, count, ppos, str, len);
}
static const struct file_operations lsm_ops = {
@@ -329,7 +368,7 @@ static const struct file_operations lsm_ops = {
};
#endif
-static int __init securityfs_init(void)
+int __init securityfs_init(void)
{
int retval;
@@ -348,4 +387,3 @@ static int __init securityfs_init(void)
#endif
return 0;
}
-core_initcall(securityfs_init);
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 0add782e73ba..73d500a375cb 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -1175,10 +1175,9 @@ struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
};
DEFINE_LSM(evm) = {
- .name = "evm",
+ .id = &evm_lsmid,
.init = init_evm_lsm,
.order = LSM_ORDER_LAST,
.blobs = &evm_blob_sizes,
+ .initcall_late = init_evm,
};
-
-late_initcall(init_evm);
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
index b0d2aad27850..c26724690cec 100644
--- a/security/integrity/evm/evm_secfs.c
+++ b/security/integrity/evm/evm_secfs.c
@@ -302,10 +302,16 @@ int __init evm_init_secfs(void)
int error = 0;
struct dentry *dentry;
- evm_dir = securityfs_create_dir("evm", integrity_dir);
- if (IS_ERR(evm_dir))
+ error = integrity_fs_init();
+ if (error < 0)
return -EFAULT;
+ evm_dir = securityfs_create_dir("evm", integrity_dir);
+ if (IS_ERR(evm_dir)) {
+ error = -EFAULT;
+ goto out;
+ }
+
dentry = securityfs_create_file("evm", 0660,
evm_dir, NULL, &evm_key_ops);
if (IS_ERR(dentry)) {
@@ -329,5 +335,6 @@ int __init evm_init_secfs(void)
out:
securityfs_remove(evm_symlink);
securityfs_remove(evm_dir);
+ integrity_fs_fini();
return error;
}
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 068ac6c2ae1e..8ec1a3436a71 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -42,8 +42,11 @@ void __init integrity_load_keys(void)
evm_load_x509();
}
-static int __init integrity_fs_init(void)
+int __init integrity_fs_init(void)
{
+ if (integrity_dir)
+ return 0;
+
integrity_dir = securityfs_create_dir("integrity", NULL);
if (IS_ERR(integrity_dir)) {
int ret = PTR_ERR(integrity_dir);
@@ -58,4 +61,11 @@ static int __init integrity_fs_init(void)
return 0;
}
-late_initcall(integrity_fs_init)
+void __init integrity_fs_fini(void)
+{
+ if (!integrity_dir || !simple_empty(integrity_dir))
+ return;
+
+ securityfs_remove(integrity_dir);
+ integrity_dir = NULL;
+}
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 87045b09f120..012a58959ff0 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -499,9 +499,15 @@ int __init ima_fs_init(void)
struct dentry *dentry;
int ret;
+ ret = integrity_fs_init();
+ if (ret < 0)
+ return ret;
+
ima_dir = securityfs_create_dir("ima", integrity_dir);
- if (IS_ERR(ima_dir))
- return PTR_ERR(ima_dir);
+ if (IS_ERR(ima_dir)) {
+ ret = PTR_ERR(ima_dir);
+ goto out;
+ }
ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima",
NULL);
@@ -555,6 +561,7 @@ int __init ima_fs_init(void)
out:
securityfs_remove(ima_symlink);
securityfs_remove(ima_dir);
+ integrity_fs_fini();
return ret;
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index cdd225f65a62..b703bfc2f470 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1279,10 +1279,10 @@ struct lsm_blob_sizes ima_blob_sizes __ro_after_init = {
};
DEFINE_LSM(ima) = {
- .name = "ima",
+ .id = &ima_lsmid,
.init = init_ima_lsm,
.order = LSM_ORDER_LAST,
.blobs = &ima_blob_sizes,
+ /* Start IMA after the TPM is available */
+ .initcall_late = init_ima,
};
-
-late_initcall(init_ima); /* Start IMA after the TPM is available */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index c2c2da691123..7b388b66cf80 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -114,6 +114,8 @@ struct ima_file_id {
int integrity_kernel_read(struct file *file, loff_t offset,
void *addr, unsigned long count);
+int __init integrity_fs_init(void);
+void __init integrity_fs_fini(void);
#define INTEGRITY_KEYRING_EVM 0
#define INTEGRITY_KEYRING_IMA 1
diff --git a/security/ipe/fs.c b/security/ipe/fs.c
index 0bb9468b8026..076c111c85c8 100644
--- a/security/ipe/fs.c
+++ b/security/ipe/fs.c
@@ -193,7 +193,7 @@ static const struct file_operations enforce_fops = {
* Return: %0 on success. If an error occurs, the function will return
* the -errno.
*/
-static int __init ipe_init_securityfs(void)
+int __init ipe_init_securityfs(void)
{
int rc = 0;
struct ipe_policy *ap;
@@ -244,5 +244,3 @@ err:
securityfs_remove(root);
return rc;
}
-
-fs_initcall(ipe_init_securityfs);
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 4317134cb0da..71644748ed56 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -92,7 +92,8 @@ static int __init ipe_init(void)
}
DEFINE_LSM(ipe) = {
- .name = "ipe",
+ .id = &ipe_lsmid,
.init = ipe_init,
.blobs = &ipe_blobs,
+ .initcall_fs = ipe_init_securityfs,
};
diff --git a/security/ipe/ipe.h b/security/ipe/ipe.h
index fb37513812dd..25cfdb8f0c20 100644
--- a/security/ipe/ipe.h
+++ b/security/ipe/ipe.h
@@ -23,4 +23,6 @@ struct ipe_bdev *ipe_bdev(struct block_device *b);
struct ipe_inode *ipe_inode(const struct inode *inode);
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+int ipe_init_securityfs(void);
+
#endif /* _IPE_H */
diff --git a/security/landlock/setup.c b/security/landlock/setup.c
index bd53c7a56ab9..47dac1736f10 100644
--- a/security/landlock/setup.c
+++ b/security/landlock/setup.c
@@ -75,7 +75,7 @@ static int __init landlock_init(void)
}
DEFINE_LSM(LANDLOCK_NAME) = {
- .name = LANDLOCK_NAME,
+ .id = &landlock_lsmid,
.init = landlock_init,
.blobs = &landlock_blob_sizes,
};
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index 68252452b66c..273ffbd6defe 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -270,11 +270,6 @@ static int __init loadpin_init(void)
return 0;
}
-DEFINE_LSM(loadpin) = {
- .name = "loadpin",
- .init = loadpin_init,
-};
-
#ifdef CONFIG_SECURITY_LOADPIN_VERITY
enum loadpin_securityfs_interface_index {
@@ -434,9 +429,15 @@ static int __init init_loadpin_securityfs(void)
return 0;
}
-fs_initcall(init_loadpin_securityfs);
+#endif /* CONFIG_SECURITY_LOADPIN_VERITY */
+DEFINE_LSM(loadpin) = {
+ .id = &loadpin_lsmid,
+ .init = loadpin_init,
+#ifdef CONFIG_SECURITY_LOADPIN_VERITY
+ .initcall_fs = init_loadpin_securityfs,
#endif /* CONFIG_SECURITY_LOADPIN_VERITY */
+};
/* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
module_param(enforce, int, 0);
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
index cf83afa1d879..8d46886d2cca 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -161,13 +161,12 @@ static int __init lockdown_secfs_init(void)
return PTR_ERR_OR_ZERO(dentry);
}
-core_initcall(lockdown_secfs_init);
-
#ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
DEFINE_EARLY_LSM(lockdown) = {
#else
DEFINE_LSM(lockdown) = {
#endif
- .name = "lockdown",
+ .id = &lockdown_lsmid,
.init = lockdown_lsm_init,
+ .initcall_core = lockdown_secfs_init,
};
diff --git a/security/lsm.h b/security/lsm.h
new file mode 100644
index 000000000000..81aadbc61685
--- /dev/null
+++ b/security/lsm.h
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LSM functions
+ */
+
+#ifndef _LSM_H_
+#define _LSM_H_
+
+#include <linux/printk.h>
+#include <linux/lsm_hooks.h>
+#include <linux/lsm_count.h>
+
+/* LSM debugging */
+extern bool lsm_debug;
+#define lsm_pr(...) pr_info(__VA_ARGS__)
+#define lsm_pr_cont(...) pr_cont(__VA_ARGS__)
+#define lsm_pr_dbg(...) \
+ do { \
+ if (lsm_debug) \
+ pr_info(__VA_ARGS__); \
+ } while (0)
+
+/* List of configured LSMs */
+extern unsigned int lsm_active_cnt;
+extern const struct lsm_id *lsm_idlist[];
+
+/* LSM blob configuration */
+extern struct lsm_blob_sizes blob_sizes;
+
+/* LSM blob caches */
+extern struct kmem_cache *lsm_file_cache;
+extern struct kmem_cache *lsm_inode_cache;
+
+/* LSM blob allocators */
+int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
+int lsm_task_alloc(struct task_struct *task);
+
+/* LSM framework initializers */
+
+#ifdef CONFIG_MMU
+int min_addr_init(void);
+#else
+static inline int min_addr_init(void)
+{
+ return 0;
+}
+#endif /* CONFIG_MMU */
+
+#ifdef CONFIG_SECURITYFS
+int securityfs_init(void);
+#else
+static inline int securityfs_init(void)
+{
+ return 0;
+}
+#endif /* CONFIG_SECURITYFS */
+
+#endif /* _LSM_H_ */
diff --git a/security/lsm_init.c b/security/lsm_init.c
new file mode 100644
index 000000000000..05bd52e6b1f2
--- /dev/null
+++ b/security/lsm_init.c
@@ -0,0 +1,564 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LSM initialization functions
+ */
+
+#define pr_fmt(fmt) "LSM: " fmt
+
+#include <linux/init.h>
+#include <linux/lsm_hooks.h>
+
+#include "lsm.h"
+
+/* LSM enabled constants. */
+static __initdata int lsm_enabled_true = 1;
+static __initdata int lsm_enabled_false = 0;
+
+/* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
+extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
+extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
+
+/* Number of "early" LSMs */
+static __initdata unsigned int lsm_count_early;
+
+/* Build and boot-time LSM ordering. */
+static __initconst const char *const lsm_order_builtin = CONFIG_LSM;
+static __initdata const char *lsm_order_cmdline;
+static __initdata const char *lsm_order_legacy;
+
+/* Ordered list of LSMs to initialize. */
+static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
+static __initdata struct lsm_info *lsm_exclusive;
+
+#define lsm_order_for_each(iter) \
+ for ((iter) = lsm_order; *(iter); (iter)++)
+#define lsm_for_each_raw(iter) \
+ for ((iter) = __start_lsm_info; \
+ (iter) < __end_lsm_info; (iter)++)
+#define lsm_early_for_each_raw(iter) \
+ for ((iter) = __start_early_lsm_info; \
+ (iter) < __end_early_lsm_info; (iter)++)
+
+#define lsm_initcall(level) \
+ ({ \
+ int _r, _rc = 0; \
+ struct lsm_info **_lp, *_l; \
+ lsm_order_for_each(_lp) { \
+ _l = *_lp; \
+ if (!_l->initcall_##level) \
+ continue; \
+ lsm_pr_dbg("running %s %s initcall", \
+ _l->id->name, #level); \
+ _r = _l->initcall_##level(); \
+ if (_r) { \
+ pr_warn("failed LSM %s %s initcall with errno %d\n", \
+ _l->id->name, #level, _r); \
+ if (!_rc) \
+ _rc = _r; \
+ } \
+ } \
+ _rc; \
+ })
+
+/**
+ * lsm_choose_security - Legacy "major" LSM selection
+ * @str: kernel command line parameter
+ */
+static int __init lsm_choose_security(char *str)
+{
+ lsm_order_legacy = str;
+ return 1;
+}
+__setup("security=", lsm_choose_security);
+
+/**
+ * lsm_choose_lsm - Modern LSM selection
+ * @str: kernel command line parameter
+ */
+static int __init lsm_choose_lsm(char *str)
+{
+ lsm_order_cmdline = str;
+ return 1;
+}
+__setup("lsm=", lsm_choose_lsm);
+
+/**
+ * lsm_debug_enable - Enable LSM framework debugging
+ * @str: kernel command line parameter
+ *
+ * Currently we only provide debug info during LSM initialization, but we may
+ * want to expand this in the future.
+ */
+static int __init lsm_debug_enable(char *str)
+{
+ lsm_debug = true;
+ return 1;
+}
+__setup("lsm.debug", lsm_debug_enable);
+
+/**
+ * lsm_enabled_set - Mark a LSM as enabled
+ * @lsm: LSM definition
+ * @enabled: enabled flag
+ */
+static void __init lsm_enabled_set(struct lsm_info *lsm, bool enabled)
+{
+ /*
+ * When an LSM hasn't configured an enable variable, we can use
+ * a hard-coded location for storing the default enabled state.
+ */
+ if (!lsm->enabled ||
+ lsm->enabled == &lsm_enabled_true ||
+ lsm->enabled == &lsm_enabled_false) {
+ lsm->enabled = enabled ? &lsm_enabled_true : &lsm_enabled_false;
+ } else {
+ *lsm->enabled = enabled;
+ }
+}
+
+/**
+ * lsm_is_enabled - Determine if a LSM is enabled
+ * @lsm: LSM definition
+ */
+static inline bool lsm_is_enabled(struct lsm_info *lsm)
+{
+ return (lsm->enabled ? *lsm->enabled : false);
+}
+
+/**
+ * lsm_order_exists - Determine if a LSM exists in the ordered list
+ * @lsm: LSM definition
+ */
+static bool __init lsm_order_exists(struct lsm_info *lsm)
+{
+ struct lsm_info **check;
+
+ lsm_order_for_each(check) {
+ if (*check == lsm)
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * lsm_order_append - Append a LSM to the ordered list
+ * @lsm: LSM definition
+ * @src: source of the addition
+ *
+ * Append @lsm to the enabled LSM array after ensuring that it hasn't been
+ * explicitly disabled, is a duplicate entry, or would run afoul of the
+ * LSM_FLAG_EXCLUSIVE logic.
+ */
+static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
+{
+ /* Ignore duplicate selections. */
+ if (lsm_order_exists(lsm))
+ return;
+
+ /* Skip explicitly disabled LSMs. */
+ if (lsm->enabled && !lsm_is_enabled(lsm)) {
+ lsm_pr_dbg("skip previously disabled LSM %s:%s\n",
+ src, lsm->id->name);
+ return;
+ }
+
+ if (lsm_active_cnt == MAX_LSM_COUNT) {
+ pr_warn("exceeded maximum LSM count on %s:%s\n",
+ src, lsm->id->name);
+ lsm_enabled_set(lsm, false);
+ return;
+ }
+
+ if (lsm->flags & LSM_FLAG_EXCLUSIVE) {
+ if (lsm_exclusive) {
+ lsm_pr_dbg("skip exclusive LSM conflict %s:%s\n",
+ src, lsm->id->name);
+ lsm_enabled_set(lsm, false);
+ return;
+ } else {
+ lsm_pr_dbg("select exclusive LSM %s:%s\n",
+ src, lsm->id->name);
+ lsm_exclusive = lsm;
+ }
+ }
+
+ lsm_enabled_set(lsm, true);
+ lsm_order[lsm_active_cnt] = lsm;
+ lsm_idlist[lsm_active_cnt++] = lsm->id;
+
+ lsm_pr_dbg("enabling LSM %s:%s\n", src, lsm->id->name);
+}
+
+/**
+ * lsm_order_parse - Parse the comma delimited LSM list
+ * @list: LSM list
+ * @src: source of the list
+ */
+static void __init lsm_order_parse(const char *list, const char *src)
+{
+ struct lsm_info *lsm;
+ char *sep, *name, *next;
+
+ /* Handle any Legacy LSM exclusions if one was specified. */
+ if (lsm_order_legacy) {
+ /*
+ * To match the original "security=" behavior, this explicitly
+ * does NOT fallback to another Legacy Major if the selected
+ * one was separately disabled: disable all non-matching
+ * Legacy Major LSMs.
+ */
+ lsm_for_each_raw(lsm) {
+ if ((lsm->flags & LSM_FLAG_LEGACY_MAJOR) &&
+ strcmp(lsm->id->name, lsm_order_legacy)) {
+ lsm_enabled_set(lsm, false);
+ lsm_pr_dbg("skip legacy LSM conflict %s:%s\n",
+ src, lsm->id->name);
+ }
+ }
+ }
+
+ /* LSM_ORDER_FIRST */
+ lsm_for_each_raw(lsm) {
+ if (lsm->order == LSM_ORDER_FIRST)
+ lsm_order_append(lsm, "first");
+ }
+
+ /* Normal or "mutable" LSMs */
+ sep = kstrdup(list, GFP_KERNEL);
+ next = sep;
+ /* Walk the list, looking for matching LSMs. */
+ while ((name = strsep(&next, ",")) != NULL) {
+ lsm_for_each_raw(lsm) {
+ if (!strcmp(lsm->id->name, name) &&
+ lsm->order == LSM_ORDER_MUTABLE)
+ lsm_order_append(lsm, src);
+ }
+ }
+ kfree(sep);
+
+ /* Legacy LSM if specified. */
+ if (lsm_order_legacy) {
+ lsm_for_each_raw(lsm) {
+ if (!strcmp(lsm->id->name, lsm_order_legacy))
+ lsm_order_append(lsm, src);
+ }
+ }
+
+ /* LSM_ORDER_LAST */
+ lsm_for_each_raw(lsm) {
+ if (lsm->order == LSM_ORDER_LAST)
+ lsm_order_append(lsm, "last");
+ }
+
+ /* Disable all LSMs not previously enabled. */
+ lsm_for_each_raw(lsm) {
+ if (lsm_order_exists(lsm))
+ continue;
+ lsm_enabled_set(lsm, false);
+ lsm_pr_dbg("skip disabled LSM %s:%s\n", src, lsm->id->name);
+ }
+}
+
+/**
+ * lsm_blob_size_update - Update the LSM blob size and offset information
+ * @sz_req: the requested additional blob size
+ * @sz_cur: the existing blob size
+ */
+static void __init lsm_blob_size_update(unsigned int *sz_req,
+ unsigned int *sz_cur)
+{
+ unsigned int offset;
+
+ if (*sz_req == 0)
+ return;
+
+ offset = ALIGN(*sz_cur, sizeof(void *));
+ *sz_cur = offset + *sz_req;
+ *sz_req = offset;
+}
+
+/**
+ * lsm_prepare - Prepare the LSM framework for a new LSM
+ * @lsm: LSM definition
+ */
+static void __init lsm_prepare(struct lsm_info *lsm)
+{
+ struct lsm_blob_sizes *blobs = lsm->blobs;
+
+ if (!blobs)
+ return;
+
+ /* Register the LSM blob sizes. */
+ blobs = lsm->blobs;
+ lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
+ lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
+ lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib);
+ /* inode blob gets an rcu_head in addition to LSM blobs. */
+ if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
+ blob_sizes.lbs_inode = sizeof(struct rcu_head);
+ lsm_blob_size_update(&blobs->lbs_inode, &blob_sizes.lbs_inode);
+ lsm_blob_size_update(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
+ lsm_blob_size_update(&blobs->lbs_key, &blob_sizes.lbs_key);
+ lsm_blob_size_update(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+ lsm_blob_size_update(&blobs->lbs_perf_event,
+ &blob_sizes.lbs_perf_event);
+ lsm_blob_size_update(&blobs->lbs_sock, &blob_sizes.lbs_sock);
+ lsm_blob_size_update(&blobs->lbs_superblock,
+ &blob_sizes.lbs_superblock);
+ lsm_blob_size_update(&blobs->lbs_task, &blob_sizes.lbs_task);
+ lsm_blob_size_update(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
+ lsm_blob_size_update(&blobs->lbs_xattr_count,
+ &blob_sizes.lbs_xattr_count);
+ lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
+ lsm_blob_size_update(&blobs->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
+ lsm_blob_size_update(&blobs->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
+ lsm_blob_size_update(&blobs->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
+}
+
+/**
+ * lsm_init_single - Initialize a given LSM
+ * @lsm: LSM definition
+ */
+static void __init lsm_init_single(struct lsm_info *lsm)
+{
+ int ret;
+
+ if (!lsm_is_enabled(lsm))
+ return;
+
+ lsm_pr_dbg("initializing %s\n", lsm->id->name);
+ ret = lsm->init();
+ WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
+}
+
+/**
+ * lsm_static_call_init - Initialize a LSM's static calls
+ * @hl: LSM hook list
+ */
+static int __init lsm_static_call_init(struct security_hook_list *hl)
+{
+ struct lsm_static_call *scall = hl->scalls;
+ int i;
+
+ for (i = 0; i < MAX_LSM_COUNT; i++) {
+ /* Update the first static call that is not used yet */
+ if (!scall->hl) {
+ __static_call_update(scall->key, scall->trampoline,
+ hl->hook.lsm_func_addr);
+ scall->hl = hl;
+ static_branch_enable(scall->active);
+ return 0;
+ }
+ scall++;
+ }
+
+ return -ENOSPC;
+}
+
+/**
+ * security_add_hooks - Add a LSM's hooks to the LSM framework's hook lists
+ * @hooks: LSM hooks to add
+ * @count: number of hooks to add
+ * @lsmid: identification information for the LSM
+ *
+ * Each LSM has to register its hooks with the LSM framework.
+ */
+void __init security_add_hooks(struct security_hook_list *hooks, int count,
+ const struct lsm_id *lsmid)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ hooks[i].lsmid = lsmid;
+ if (lsm_static_call_init(&hooks[i]))
+ panic("exhausted LSM callback slots with LSM %s\n",
+ lsmid->name);
+ }
+}
+
+/**
+ * early_security_init - Initialize the early LSMs
+ */
+int __init early_security_init(void)
+{
+ struct lsm_info *lsm;
+
+ /* NOTE: lsm_pr_dbg() doesn't work here as lsm_debug is not yet set */
+
+ lsm_early_for_each_raw(lsm) {
+ lsm_enabled_set(lsm, true);
+ lsm_order_append(lsm, "early");
+ lsm_prepare(lsm);
+ lsm_init_single(lsm);
+ lsm_count_early++;
+ }
+
+ return 0;
+}
+
+/**
+ * security_init - Initializes the LSM framework
+ *
+ * This should be called early in the kernel initialization sequence.
+ */
+int __init security_init(void)
+{
+ unsigned int cnt;
+ struct lsm_info **lsm;
+
+ if (lsm_debug) {
+ struct lsm_info *i;
+
+ cnt = 0;
+ lsm_pr("available LSMs: ");
+ lsm_early_for_each_raw(i)
+ lsm_pr_cont("%s%s(E)", (cnt++ ? "," : ""), i->id->name);
+ lsm_for_each_raw(i)
+ lsm_pr_cont("%s%s", (cnt++ ? "," : ""), i->id->name);
+ lsm_pr_cont("\n");
+
+ lsm_pr("built-in LSM config: %s\n", lsm_order_builtin);
+
+ lsm_pr("legacy LSM parameter: %s\n", lsm_order_legacy);
+ lsm_pr("boot LSM parameter: %s\n", lsm_order_cmdline);
+
+ /* see the note about lsm_pr_dbg() in early_security_init() */
+ lsm_early_for_each_raw(i)
+ lsm_pr("enabled LSM early:%s\n", i->id->name);
+ }
+
+ if (lsm_order_cmdline) {
+ if (lsm_order_legacy)
+ lsm_order_legacy = NULL;
+ lsm_order_parse(lsm_order_cmdline, "cmdline");
+ } else
+ lsm_order_parse(lsm_order_builtin, "builtin");
+
+ lsm_order_for_each(lsm)
+ lsm_prepare(*lsm);
+
+ if (lsm_debug) {
+ lsm_pr("blob(cred) size %d\n", blob_sizes.lbs_cred);
+ lsm_pr("blob(file) size %d\n", blob_sizes.lbs_file);
+ lsm_pr("blob(ib) size %d\n", blob_sizes.lbs_ib);
+ lsm_pr("blob(inode) size %d\n", blob_sizes.lbs_inode);
+ lsm_pr("blob(ipc) size %d\n", blob_sizes.lbs_ipc);
+ lsm_pr("blob(key) size %d\n", blob_sizes.lbs_key);
+ lsm_pr("blob(msg_msg)_size %d\n", blob_sizes.lbs_msg_msg);
+ lsm_pr("blob(sock) size %d\n", blob_sizes.lbs_sock);
+ lsm_pr("blob(superblock) size %d\n", blob_sizes.lbs_superblock);
+ lsm_pr("blob(perf_event) size %d\n", blob_sizes.lbs_perf_event);
+ lsm_pr("blob(task) size %d\n", blob_sizes.lbs_task);
+ lsm_pr("blob(tun_dev) size %d\n", blob_sizes.lbs_tun_dev);
+ lsm_pr("blob(xattr) count %d\n", blob_sizes.lbs_xattr_count);
+ lsm_pr("blob(bdev) size %d\n", blob_sizes.lbs_bdev);
+ lsm_pr("blob(bpf_map) size %d\n", blob_sizes.lbs_bpf_map);
+ lsm_pr("blob(bpf_prog) size %d\n", blob_sizes.lbs_bpf_prog);
+ lsm_pr("blob(bpf_token) size %d\n", blob_sizes.lbs_bpf_token);
+ }
+
+ if (blob_sizes.lbs_file)
+ lsm_file_cache = kmem_cache_create("lsm_file_cache",
+ blob_sizes.lbs_file, 0,
+ SLAB_PANIC, NULL);
+ if (blob_sizes.lbs_inode)
+ lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
+ blob_sizes.lbs_inode, 0,
+ SLAB_PANIC, NULL);
+
+ if (lsm_cred_alloc((struct cred *)unrcu_pointer(current->cred),
+ GFP_KERNEL))
+ panic("early LSM cred alloc failed\n");
+ if (lsm_task_alloc(current))
+ panic("early LSM task alloc failed\n");
+
+ cnt = 0;
+ lsm_order_for_each(lsm) {
+ /* skip the "early" LSMs as they have already been setup */
+ if (cnt++ < lsm_count_early)
+ continue;
+ lsm_init_single(*lsm);
+ }
+
+ return 0;
+}
+
+/**
+ * security_initcall_pure - Run the LSM pure initcalls
+ */
+static int __init security_initcall_pure(void)
+{
+ int rc_adr, rc_lsm;
+
+ rc_adr = min_addr_init();
+ rc_lsm = lsm_initcall(pure);
+
+ return (rc_adr ? rc_adr : rc_lsm);
+}
+pure_initcall(security_initcall_pure);
+
+/**
+ * security_initcall_early - Run the LSM early initcalls
+ */
+static int __init security_initcall_early(void)
+{
+ return lsm_initcall(early);
+}
+early_initcall(security_initcall_early);
+
+/**
+ * security_initcall_core - Run the LSM core initcalls
+ */
+static int __init security_initcall_core(void)
+{
+ int rc_sfs, rc_lsm;
+
+ rc_sfs = securityfs_init();
+ rc_lsm = lsm_initcall(core);
+
+ return (rc_sfs ? rc_sfs : rc_lsm);
+}
+core_initcall(security_initcall_core);
+
+/**
+ * security_initcall_subsys - Run the LSM subsys initcalls
+ */
+static int __init security_initcall_subsys(void)
+{
+ return lsm_initcall(subsys);
+}
+subsys_initcall(security_initcall_subsys);
+
+/**
+ * security_initcall_fs - Run the LSM fs initcalls
+ */
+static int __init security_initcall_fs(void)
+{
+ return lsm_initcall(fs);
+}
+fs_initcall(security_initcall_fs);
+
+/**
+ * security_initcall_device - Run the LSM device initcalls
+ */
+static int __init security_initcall_device(void)
+{
+ return lsm_initcall(device);
+}
+device_initcall(security_initcall_device);
+
+/**
+ * security_initcall_late - Run the LSM late initcalls
+ */
+static int __init security_initcall_late(void)
+{
+ int rc;
+
+ rc = lsm_initcall(late);
+ lsm_pr_dbg("all enabled LSMs fully activated\n");
+ call_blocking_lsm_notifier(LSM_STARTED_ALL, NULL);
+
+ return rc;
+}
+late_initcall(security_initcall_late);
diff --git a/security/lsm_notifier.c b/security/lsm_notifier.c
new file mode 100644
index 000000000000..c92fad5d57d4
--- /dev/null
+++ b/security/lsm_notifier.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * LSM notifier functions
+ *
+ */
+
+#include <linux/notifier.h>
+#include <linux/security.h>
+
+static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
+
+int call_blocking_lsm_notifier(enum lsm_event event, void *data)
+{
+ return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
+ event, data);
+}
+EXPORT_SYMBOL(call_blocking_lsm_notifier);
+
+int register_blocking_lsm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
+ nb);
+}
+EXPORT_SYMBOL(register_blocking_lsm_notifier);
+
+int unregister_blocking_lsm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
+ nb);
+}
+EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
index 8440948a690c..5648b1f0ce9c 100644
--- a/security/lsm_syscalls.c
+++ b/security/lsm_syscalls.c
@@ -17,6 +17,8 @@
#include <linux/lsm_hooks.h>
#include <uapi/linux/lsm.h>
+#include "lsm.h"
+
/**
* lsm_name_to_attr - map an LSM attribute name to its ID
* @name: name of the attribute
diff --git a/security/min_addr.c b/security/min_addr.c
index c55bb84b8632..0fde5ec9abc8 100644
--- a/security/min_addr.c
+++ b/security/min_addr.c
@@ -5,6 +5,8 @@
#include <linux/sysctl.h>
#include <linux/minmax.h>
+#include "lsm.h"
+
/* amount of vm to protect from userspace access by both DAC and the LSM*/
unsigned long mmap_min_addr;
/* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */
@@ -52,11 +54,10 @@ static const struct ctl_table min_addr_sysctl_table[] = {
},
};
-static int __init init_mmap_min_addr(void)
+int __init min_addr_init(void)
{
register_sysctl_init("vm", min_addr_sysctl_table);
update_mmap_min_addr();
return 0;
}
-pure_initcall(init_mmap_min_addr);
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
index 1ba564f097f5..d5fb949050dd 100644
--- a/security/safesetid/lsm.c
+++ b/security/safesetid/lsm.c
@@ -287,6 +287,7 @@ static int __init safesetid_security_init(void)
}
DEFINE_LSM(safesetid_security_init) = {
+ .id = &safesetid_lsmid,
.init = safesetid_security_init,
- .name = "safesetid",
+ .initcall_fs = safesetid_init_securityfs,
};
diff --git a/security/safesetid/lsm.h b/security/safesetid/lsm.h
index d346f4849cea..bf5172e2c3f7 100644
--- a/security/safesetid/lsm.h
+++ b/security/safesetid/lsm.h
@@ -70,4 +70,6 @@ enum sid_policy_type _setid_policy_lookup(struct setid_ruleset *policy,
extern struct setid_ruleset __rcu *safesetid_setuid_rules;
extern struct setid_ruleset __rcu *safesetid_setgid_rules;
+int safesetid_init_securityfs(void);
+
#endif /* _SAFESETID_H */
diff --git a/security/safesetid/securityfs.c b/security/safesetid/securityfs.c
index 8e1ffd70b18a..ece259f75b0d 100644
--- a/security/safesetid/securityfs.c
+++ b/security/safesetid/securityfs.c
@@ -308,7 +308,7 @@ static const struct file_operations safesetid_gid_file_fops = {
.write = safesetid_gid_file_write,
};
-static int __init safesetid_init_securityfs(void)
+int __init safesetid_init_securityfs(void)
{
int ret;
struct dentry *policy_dir;
@@ -345,4 +345,3 @@ error:
securityfs_remove(policy_dir);
return ret;
}
-fs_initcall(safesetid_init_securityfs);
diff --git a/security/security.c b/security/security.c
index 4d3c03a4524c..31a688650601 100644
--- a/security/security.c
+++ b/security/security.c
@@ -32,24 +32,7 @@
#include <net/flow.h>
#include <net/sock.h>
-#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
-
-/*
- * Identifier for the LSM static calls.
- * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
- * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
- */
-#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
-
-/*
- * Call the macro M for each LSM hook MAX_LSM_COUNT times.
- */
-#define LSM_LOOP_UNROLL(M, ...) \
-do { \
- UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__) \
-} while (0)
-
-#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
+#include "lsm.h"
/*
* These are descriptions of the reasons that can be passed to the
@@ -90,23 +73,34 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
};
-static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
+bool lsm_debug __ro_after_init;
-static struct kmem_cache *lsm_file_cache;
-static struct kmem_cache *lsm_inode_cache;
+unsigned int lsm_active_cnt __ro_after_init;
+const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
-char *lsm_names;
-static struct lsm_blob_sizes blob_sizes __ro_after_init;
+struct lsm_blob_sizes blob_sizes;
-/* Boot-time LSM user choice */
-static __initdata const char *chosen_lsm_order;
-static __initdata const char *chosen_major_lsm;
+struct kmem_cache *lsm_file_cache;
+struct kmem_cache *lsm_inode_cache;
-static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
+#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
-/* Ordered list of LSMs to initialize. */
-static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
-static __initdata struct lsm_info *exclusive;
+/*
+ * Identifier for the LSM static calls.
+ * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
+ * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
+ */
+#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
+
+/*
+ * Call the macro M for each LSM hook MAX_LSM_COUNT times.
+ */
+#define LSM_LOOP_UNROLL(M, ...) \
+do { \
+ UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__) \
+} while (0)
+
+#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
#ifdef CONFIG_HAVE_STATIC_CALL
#define LSM_HOOK_TRAMP(NAME, NUM) \
@@ -157,518 +151,26 @@ struct lsm_static_calls_table
#undef INIT_LSM_STATIC_CALL
};
-static __initdata bool debug;
-#define init_debug(...) \
- do { \
- if (debug) \
- pr_info(__VA_ARGS__); \
- } while (0)
-
-static bool __init is_enabled(struct lsm_info *lsm)
-{
- if (!lsm->enabled)
- return false;
-
- return *lsm->enabled;
-}
-
-/* Mark an LSM's enabled flag. */
-static int lsm_enabled_true __initdata = 1;
-static int lsm_enabled_false __initdata = 0;
-static void __init set_enabled(struct lsm_info *lsm, bool enabled)
-{
- /*
- * When an LSM hasn't configured an enable variable, we can use
- * a hard-coded location for storing the default enabled state.
- */
- if (!lsm->enabled) {
- if (enabled)
- lsm->enabled = &lsm_enabled_true;
- else
- lsm->enabled = &lsm_enabled_false;
- } else if (lsm->enabled == &lsm_enabled_true) {
- if (!enabled)
- lsm->enabled = &lsm_enabled_false;
- } else if (lsm->enabled == &lsm_enabled_false) {
- if (enabled)
- lsm->enabled = &lsm_enabled_true;
- } else {
- *lsm->enabled = enabled;
- }
-}
-
-/* Is an LSM already listed in the ordered LSMs list? */
-static bool __init exists_ordered_lsm(struct lsm_info *lsm)
-{
- struct lsm_info **check;
-
- for (check = ordered_lsms; *check; check++)
- if (*check == lsm)
- return true;
-
- return false;
-}
-
-/* Append an LSM to the list of ordered LSMs to initialize. */
-static int last_lsm __initdata;
-static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
-{
- /* Ignore duplicate selections. */
- if (exists_ordered_lsm(lsm))
- return;
-
- if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
- return;
-
- /* Enable this LSM, if it is not already set. */
- if (!lsm->enabled)
- lsm->enabled = &lsm_enabled_true;
- ordered_lsms[last_lsm++] = lsm;
-
- init_debug("%s ordered: %s (%s)\n", from, lsm->name,
- is_enabled(lsm) ? "enabled" : "disabled");
-}
-
-/* Is an LSM allowed to be initialized? */
-static bool __init lsm_allowed(struct lsm_info *lsm)
-{
- /* Skip if the LSM is disabled. */
- if (!is_enabled(lsm))
- return false;
-
- /* Not allowed if another exclusive LSM already initialized. */
- if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
- init_debug("exclusive disabled: %s\n", lsm->name);
- return false;
- }
-
- return true;
-}
-
-static void __init lsm_set_blob_size(int *need, int *lbs)
-{
- int offset;
-
- if (*need <= 0)
- return;
-
- offset = ALIGN(*lbs, sizeof(void *));
- *lbs = offset + *need;
- *need = offset;
-}
-
-static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
-{
- if (!needed)
- return;
-
- lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
- lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
- lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
- /*
- * The inode blob gets an rcu_head in addition to
- * what the modules might need.
- */
- if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
- blob_sizes.lbs_inode = sizeof(struct rcu_head);
- lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
- lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
- lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
- lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
- lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
- lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
- lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
- lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
- lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
- lsm_set_blob_size(&needed->lbs_xattr_count,
- &blob_sizes.lbs_xattr_count);
- lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
- lsm_set_blob_size(&needed->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
- lsm_set_blob_size(&needed->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
- lsm_set_blob_size(&needed->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
-}
-
-/* Prepare LSM for initialization. */
-static void __init prepare_lsm(struct lsm_info *lsm)
-{
- int enabled = lsm_allowed(lsm);
-
- /* Record enablement (to handle any following exclusive LSMs). */
- set_enabled(lsm, enabled);
-
- /* If enabled, do pre-initialization work. */
- if (enabled) {
- if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
- exclusive = lsm;
- init_debug("exclusive chosen: %s\n", lsm->name);
- }
-
- lsm_set_blob_sizes(lsm->blobs);
- }
-}
-
-/* Initialize a given LSM, if it is enabled. */
-static void __init initialize_lsm(struct lsm_info *lsm)
-{
- if (is_enabled(lsm)) {
- int ret;
-
- init_debug("initializing %s\n", lsm->name);
- ret = lsm->init();
- WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
- }
-}
-
-/*
- * Current index to use while initializing the lsm id list.
- */
-u32 lsm_active_cnt __ro_after_init;
-const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
-
-/* Populate ordered LSMs list from comma-separated LSM name list. */
-static void __init ordered_lsm_parse(const char *order, const char *origin)
-{
- struct lsm_info *lsm;
- char *sep, *name, *next;
-
- /* LSM_ORDER_FIRST is always first. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
- if (lsm->order == LSM_ORDER_FIRST)
- append_ordered_lsm(lsm, " first");
- }
-
- /* Process "security=", if given. */
- if (chosen_major_lsm) {
- struct lsm_info *major;
-
- /*
- * To match the original "security=" behavior, this
- * explicitly does NOT fallback to another Legacy Major
- * if the selected one was separately disabled: disable
- * all non-matching Legacy Major LSMs.
- */
- for (major = __start_lsm_info; major < __end_lsm_info;
- major++) {
- if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
- strcmp(major->name, chosen_major_lsm) != 0) {
- set_enabled(major, false);
- init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
- chosen_major_lsm, major->name);
- }
- }
- }
-
- sep = kstrdup(order, GFP_KERNEL);
- next = sep;
- /* Walk the list, looking for matching LSMs. */
- while ((name = strsep(&next, ",")) != NULL) {
- bool found = false;
-
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
- if (strcmp(lsm->name, name) == 0) {
- if (lsm->order == LSM_ORDER_MUTABLE)
- append_ordered_lsm(lsm, origin);
- found = true;
- }
- }
-
- if (!found)
- init_debug("%s ignored: %s (not built into kernel)\n",
- origin, name);
- }
-
- /* Process "security=", if given. */
- if (chosen_major_lsm) {
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
- if (exists_ordered_lsm(lsm))
- continue;
- if (strcmp(lsm->name, chosen_major_lsm) == 0)
- append_ordered_lsm(lsm, "security=");
- }
- }
-
- /* LSM_ORDER_LAST is always last. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
- if (lsm->order == LSM_ORDER_LAST)
- append_ordered_lsm(lsm, " last");
- }
-
- /* Disable all LSMs not in the ordered list. */
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
- if (exists_ordered_lsm(lsm))
- continue;
- set_enabled(lsm, false);
- init_debug("%s skipped: %s (not in requested order)\n",
- origin, lsm->name);
- }
-
- kfree(sep);
-}
-
-static void __init lsm_static_call_init(struct security_hook_list *hl)
-{
- struct lsm_static_call *scall = hl->scalls;
- int i;
-
- for (i = 0; i < MAX_LSM_COUNT; i++) {
- /* Update the first static call that is not used yet */
- if (!scall->hl) {
- __static_call_update(scall->key, scall->trampoline,
- hl->hook.lsm_func_addr);
- scall->hl = hl;
- static_branch_enable(scall->active);
- return;
- }
- scall++;
- }
- panic("%s - Ran out of static slots.\n", __func__);
-}
-
-static void __init lsm_early_cred(struct cred *cred);
-static void __init lsm_early_task(struct task_struct *task);
-
-static int lsm_append(const char *new, char **result);
-
-static void __init report_lsm_order(void)
-{
- struct lsm_info **lsm, *early;
- int first = 0;
-
- pr_info("initializing lsm=");
-
- /* Report each enabled LSM name, comma separated. */
- for (early = __start_early_lsm_info;
- early < __end_early_lsm_info; early++)
- if (is_enabled(early))
- pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
- for (lsm = ordered_lsms; *lsm; lsm++)
- if (is_enabled(*lsm))
- pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
-
- pr_cont("\n");
-}
-
-static void __init ordered_lsm_init(void)
-{
- struct lsm_info **lsm;
-
- if (chosen_lsm_order) {
- if (chosen_major_lsm) {
- pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
- chosen_major_lsm, chosen_lsm_order);
- chosen_major_lsm = NULL;
- }
- ordered_lsm_parse(chosen_lsm_order, "cmdline");
- } else
- ordered_lsm_parse(builtin_lsm_order, "builtin");
-
- for (lsm = ordered_lsms; *lsm; lsm++)
- prepare_lsm(*lsm);
-
- report_lsm_order();
-
- init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
- init_debug("file blob size = %d\n", blob_sizes.lbs_file);
- init_debug("ib blob size = %d\n", blob_sizes.lbs_ib);
- init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
- init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
-#ifdef CONFIG_KEYS
- init_debug("key blob size = %d\n", blob_sizes.lbs_key);
-#endif /* CONFIG_KEYS */
- init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
- init_debug("sock blob size = %d\n", blob_sizes.lbs_sock);
- init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
- init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
- init_debug("task blob size = %d\n", blob_sizes.lbs_task);
- init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
- init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
- init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);
- init_debug("bpf map blob size = %d\n", blob_sizes.lbs_bpf_map);
- init_debug("bpf prog blob size = %d\n", blob_sizes.lbs_bpf_prog);
- init_debug("bpf token blob size = %d\n", blob_sizes.lbs_bpf_token);
-
- /*
- * Create any kmem_caches needed for blobs
- */
- if (blob_sizes.lbs_file)
- lsm_file_cache = kmem_cache_create("lsm_file_cache",
- blob_sizes.lbs_file, 0,
- SLAB_PANIC, NULL);
- if (blob_sizes.lbs_inode)
- lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
- blob_sizes.lbs_inode, 0,
- SLAB_PANIC, NULL);
-
- lsm_early_cred((struct cred *) current->cred);
- lsm_early_task(current);
- for (lsm = ordered_lsms; *lsm; lsm++)
- initialize_lsm(*lsm);
-}
-
-int __init early_security_init(void)
-{
- struct lsm_info *lsm;
-
- for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
- if (!lsm->enabled)
- lsm->enabled = &lsm_enabled_true;
- prepare_lsm(lsm);
- initialize_lsm(lsm);
- }
-
- return 0;
-}
-
/**
- * security_init - initializes the security framework
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
*
- * This should be called early in the kernel initialization sequence.
- */
-int __init security_init(void)
-{
- struct lsm_info *lsm;
-
- init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
- init_debug(" CONFIG_LSM=%s\n", builtin_lsm_order);
- init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
-
- /*
- * Append the names of the early LSM modules now that kmalloc() is
- * available
- */
- for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
- init_debug(" early started: %s (%s)\n", lsm->name,
- is_enabled(lsm) ? "enabled" : "disabled");
- if (lsm->enabled)
- lsm_append(lsm->name, &lsm_names);
- }
-
- /* Load LSMs in specified order. */
- ordered_lsm_init();
-
- return 0;
-}
-
-/* Save user chosen LSM */
-static int __init choose_major_lsm(char *str)
-{
- chosen_major_lsm = str;
- return 1;
-}
-__setup("security=", choose_major_lsm);
-
-/* Explicitly choose LSM initialization order. */
-static int __init choose_lsm_order(char *str)
-{
- chosen_lsm_order = str;
- return 1;
-}
-__setup("lsm=", choose_lsm_order);
-
-/* Enable LSM order debugging. */
-static int __init enable_debug(char *str)
-{
- debug = true;
- return 1;
-}
-__setup("lsm.debug", enable_debug);
-
-static bool match_last_lsm(const char *list, const char *lsm)
-{
- const char *last;
-
- if (WARN_ON(!list || !lsm))
- return false;
- last = strrchr(list, ',');
- if (last)
- /* Pass the comma, strcmp() will check for '\0' */
- last++;
- else
- last = list;
- return !strcmp(last, lsm);
-}
-
-static int lsm_append(const char *new, char **result)
-{
- char *cp;
-
- if (*result == NULL) {
- *result = kstrdup(new, GFP_KERNEL);
- if (*result == NULL)
- return -ENOMEM;
- } else {
- /* Check if it is the last registered name */
- if (match_last_lsm(*result, new))
- return 0;
- cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
- if (cp == NULL)
- return -ENOMEM;
- kfree(*result);
- *result = cp;
- }
- return 0;
-}
-
-/**
- * security_add_hooks - Add a modules hooks to the hook lists.
- * @hooks: the hooks to add
- * @count: the number of hooks to add
- * @lsmid: the identification information for the security module
+ * Allocate the file blob for all the modules
*
- * Each LSM has to register its hooks with the infrastructure.
+ * Returns 0, or -ENOMEM if memory can't be allocated.
*/
-void __init security_add_hooks(struct security_hook_list *hooks, int count,
- const struct lsm_id *lsmid)
+static int lsm_file_alloc(struct file *file)
{
- 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 >= MAX_LSM_COUNT)
- panic("%s Too many LSMs registered.\n", __func__);
- lsm_idlist[lsm_active_cnt++] = lsmid;
- }
-
- for (i = 0; i < count; i++) {
- hooks[i].lsmid = lsmid;
- lsm_static_call_init(&hooks[i]);
- }
-
- /*
- * Don't try to append during early_security_init(), we'll come back
- * and fix this up afterwards.
- */
- if (slab_is_available()) {
- if (lsm_append(lsmid->name, &lsm_names) < 0)
- panic("%s - Cannot get early memory.\n", __func__);
+ if (!lsm_file_cache) {
+ file->f_security = NULL;
+ return 0;
}
-}
-
-int call_blocking_lsm_notifier(enum lsm_event event, void *data)
-{
- return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
- event, data);
-}
-EXPORT_SYMBOL(call_blocking_lsm_notifier);
-
-int register_blocking_lsm_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
- nb);
-}
-EXPORT_SYMBOL(register_blocking_lsm_notifier);
-int unregister_blocking_lsm_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
- nb);
+ file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
+ if (file->f_security == NULL)
+ return -ENOMEM;
+ return 0;
}
-EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
/**
* lsm_blob_alloc - allocate a composite blob
@@ -702,47 +204,12 @@ static int lsm_blob_alloc(void **dest, size_t size, gfp_t gfp)
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
-static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
+int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
{
return lsm_blob_alloc(&cred->security, blob_sizes.lbs_cred, gfp);
}
/**
- * lsm_early_cred - during initialization allocate a composite cred blob
- * @cred: the cred that needs a blob
- *
- * Allocate the cred blob for all the modules
- */
-static void __init lsm_early_cred(struct cred *cred)
-{
- int rc = lsm_cred_alloc(cred, GFP_KERNEL);
-
- if (rc)
- panic("%s: Early cred alloc failed.\n", __func__);
-}
-
-/**
- * lsm_file_alloc - allocate a composite file blob
- * @file: the file that needs a blob
- *
- * Allocate the file blob for all the modules
- *
- * Returns 0, or -ENOMEM if memory can't be allocated.
- */
-static int lsm_file_alloc(struct file *file)
-{
- if (!lsm_file_cache) {
- file->f_security = NULL;
- return 0;
- }
-
- file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
- if (file->f_security == NULL)
- return -ENOMEM;
- return 0;
-}
-
-/**
* lsm_inode_alloc - allocate a composite inode blob
* @inode: the inode that needs a blob
* @gfp: allocation flags
@@ -772,7 +239,7 @@ static int lsm_inode_alloc(struct inode *inode, gfp_t gfp)
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
-static int lsm_task_alloc(struct task_struct *task)
+int lsm_task_alloc(struct task_struct *task)
{
return lsm_blob_alloc(&task->security, blob_sizes.lbs_task, GFP_KERNEL);
}
@@ -875,20 +342,6 @@ static int lsm_bpf_token_alloc(struct bpf_token *token)
#endif /* CONFIG_BPF_SYSCALL */
/**
- * lsm_early_task - during initialization allocate a composite task blob
- * @task: the task that needs a blob
- *
- * Allocate the task blob for all the modules
- */
-static void __init lsm_early_task(struct task_struct *task)
-{
- int rc = lsm_task_alloc(task);
-
- if (rc)
- panic("%s: Early task alloc failed.\n", __func__);
-}
-
-/**
* lsm_superblock_alloc - allocate a composite superblock blob
* @sb: the superblock that needs a blob
*
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index 66e56e9011df..72d3baf7900c 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -15,7 +15,7 @@ ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
- netnode.o netport.o status.o \
+ netnode.o netport.o status.o initcalls.o \
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/context.o
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e713291db873..139df920f582 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -94,6 +94,7 @@
#include <linux/io_uring/cmd.h>
#include <uapi/linux/lsm.h>
+#include "initcalls.h"
#include "avc.h"
#include "objsec.h"
#include "netif.h"
@@ -7617,6 +7618,10 @@ static __init int selinux_init(void)
if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET))
panic("SELinux: Unable to register AVC LSM notifier callback\n");
+ if (avc_add_callback(selinux_audit_rule_avc_callback,
+ AVC_CALLBACK_RESET))
+ panic("SELinux: Unable to register AVC audit callback\n");
+
if (selinux_enforcing_boot)
pr_debug("SELinux: Starting in enforcing mode\n");
else
@@ -7644,11 +7649,12 @@ void selinux_complete_init(void)
/* SELinux requires early initialization in order to label
all processes and objects when they are created. */
DEFINE_LSM(selinux) = {
- .name = "selinux",
+ .id = &selinux_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &selinux_enabled_boot,
.blobs = &selinux_blob_sizes,
.init = selinux_init,
+ .initcall_device = selinux_initcall,
};
#if defined(CONFIG_NETFILTER)
@@ -7710,7 +7716,7 @@ static struct pernet_operations selinux_net_ops = {
.exit = selinux_nf_unregister,
};
-static int __init selinux_nf_ip_init(void)
+int __init selinux_nf_ip_init(void)
{
int err;
@@ -7725,5 +7731,4 @@ static int __init selinux_nf_ip_init(void)
return 0;
}
-__initcall(selinux_nf_ip_init);
#endif /* CONFIG_NETFILTER */
diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c
index 470481cfe0e8..ea1d9b2c7d2b 100644
--- a/security/selinux/ibpkey.c
+++ b/security/selinux/ibpkey.c
@@ -23,6 +23,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
+#include "initcalls.h"
#include "ibpkey.h"
#include "objsec.h"
@@ -218,7 +219,7 @@ void sel_ib_pkey_flush(void)
spin_unlock_irqrestore(&sel_ib_pkey_lock, flags);
}
-static __init int sel_ib_pkey_init(void)
+int __init sel_ib_pkey_init(void)
{
int iter;
@@ -232,5 +233,3 @@ static __init int sel_ib_pkey_init(void)
return 0;
}
-
-subsys_initcall(sel_ib_pkey_init);
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index d5b0425055e4..85a531ac737b 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -16,6 +16,15 @@
#include <linux/types.h>
/**
+ * selinux_audit_rule_avc_callback - update the audit LSM rules on AVC events.
+ * @event: the AVC event
+ *
+ * Update any audit LSM rules based on the AVC event specified in @event.
+ * Returns 0 on success, negative values otherwise.
+ */
+int selinux_audit_rule_avc_callback(u32 event);
+
+/**
* selinux_audit_rule_init - alloc/init an selinux audit rule structure.
* @field: the field this rule refers to
* @op: the operator the rule uses
diff --git a/security/selinux/include/initcalls.h b/security/selinux/include/initcalls.h
new file mode 100644
index 000000000000..6674cf489473
--- /dev/null
+++ b/security/selinux/include/initcalls.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SELinux initcalls
+ */
+
+#ifndef _SELINUX_INITCALLS_H
+#define _SELINUX_INITCALLS_H
+
+int init_sel_fs(void);
+int sel_netport_init(void);
+int sel_netnode_init(void);
+int sel_netif_init(void);
+int sel_netlink_init(void);
+int sel_ib_pkey_init(void);
+int selinux_nf_ip_init(void);
+
+int selinux_initcall(void);
+
+#endif
diff --git a/security/selinux/initcalls.c b/security/selinux/initcalls.c
new file mode 100644
index 000000000000..f6716a1d38c1
--- /dev/null
+++ b/security/selinux/initcalls.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SELinux initcalls
+ */
+
+#include <linux/init.h>
+
+#include "initcalls.h"
+
+/**
+ * selinux_initcall - Perform the SELinux initcalls
+ *
+ * Used as a device initcall in the SELinux LSM definition.
+ */
+int __init selinux_initcall(void)
+{
+ int rc = 0, rc_tmp = 0;
+
+ rc_tmp = init_sel_fs();
+ if (!rc && rc_tmp)
+ rc = rc_tmp;
+
+ rc_tmp = sel_netport_init();
+ if (!rc && rc_tmp)
+ rc = rc_tmp;
+
+ rc_tmp = sel_netnode_init();
+ if (!rc && rc_tmp)
+ rc = rc_tmp;
+
+ rc_tmp = sel_netif_init();
+ if (!rc && rc_tmp)
+ rc = rc_tmp;
+
+ rc_tmp = sel_netlink_init();
+ if (!rc && rc_tmp)
+ rc = rc_tmp;
+
+#if defined(CONFIG_SECURITY_INFINIBAND)
+ rc_tmp = sel_ib_pkey_init();
+ if (!rc && rc_tmp)
+ rc = rc_tmp;
+#endif
+
+#if defined(CONFIG_NETFILTER)
+ rc_tmp = selinux_nf_ip_init();
+ if (!rc && rc_tmp)
+ rc = rc_tmp;
+#endif
+
+ return rc;
+}
diff --git a/security/selinux/netif.c b/security/selinux/netif.c
index 78afbecdbe57..e24b2cba28ea 100644
--- a/security/selinux/netif.c
+++ b/security/selinux/netif.c
@@ -22,6 +22,7 @@
#include <linux/rcupdate.h>
#include <net/net_namespace.h>
+#include "initcalls.h"
#include "security.h"
#include "objsec.h"
#include "netif.h"
@@ -265,7 +266,7 @@ static struct notifier_block sel_netif_netdev_notifier = {
.notifier_call = sel_netif_netdev_notifier_handler,
};
-static __init int sel_netif_init(void)
+int __init sel_netif_init(void)
{
int i;
@@ -280,5 +281,3 @@ static __init int sel_netif_init(void)
return 0;
}
-__initcall(sel_netif_init);
-
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
index 1760aee712fd..eb40e4603475 100644
--- a/security/selinux/netlink.c
+++ b/security/selinux/netlink.c
@@ -17,6 +17,7 @@
#include <net/net_namespace.h>
#include <net/netlink.h>
+#include "initcalls.h"
#include "security.h"
static struct sock *selnl __ro_after_init;
@@ -105,7 +106,7 @@ void selnl_notify_policyload(u32 seqno)
selnl_notify(SELNL_MSG_POLICYLOAD, &seqno);
}
-static int __init selnl_init(void)
+int __init sel_netlink_init(void)
{
struct netlink_kernel_cfg cfg = {
.groups = SELNLGRP_MAX,
@@ -117,5 +118,3 @@ static int __init selnl_init(void)
panic("SELinux: Cannot create netlink socket.");
return 0;
}
-
-__initcall(selnl_init);
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 5d0ed08d46e5..9b3da5ce8d39 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -30,6 +30,7 @@
#include <net/ip.h>
#include <net/ipv6.h>
+#include "initcalls.h"
#include "netnode.h"
#include "objsec.h"
@@ -290,7 +291,7 @@ void sel_netnode_flush(void)
spin_unlock_bh(&sel_netnode_lock);
}
-static __init int sel_netnode_init(void)
+int __init sel_netnode_init(void)
{
int iter;
@@ -304,5 +305,3 @@ static __init int sel_netnode_init(void)
return 0;
}
-
-__initcall(sel_netnode_init);
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 6fd7da4b3576..9e62f7285e81 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -29,6 +29,7 @@
#include <net/ip.h>
#include <net/ipv6.h>
+#include "initcalls.h"
#include "netport.h"
#include "objsec.h"
@@ -218,7 +219,7 @@ void sel_netport_flush(void)
spin_unlock_bh(&sel_netport_lock);
}
-static __init int sel_netport_init(void)
+int __init sel_netport_init(void)
{
int iter;
@@ -232,5 +233,3 @@ static __init int sel_netport_init(void)
return 0;
}
-
-__initcall(sel_netport_init);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 404e08bf60ba..d98fbc4d068f 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -35,6 +35,7 @@
/* selinuxfs pseudo filesystem for exporting the security policy API.
Based on the proc code and the fs/nfsd/nfsctl.c code. */
+#include "initcalls.h"
#include "flask.h"
#include "avc.h"
#include "avc_ss.h"
@@ -2133,7 +2134,7 @@ static struct file_system_type sel_fs_type = {
struct path selinux_null __ro_after_init;
-static int __init init_sel_fs(void)
+int __init init_sel_fs(void)
{
struct qstr null_name = QSTR_INIT(NULL_FILE_NAME,
sizeof(NULL_FILE_NAME)-1);
@@ -2177,5 +2178,3 @@ static int __init init_sel_fs(void)
return err;
}
-
-__initcall(init_sel_fs);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 713130bd43c4..13fc712d5923 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -3570,6 +3570,13 @@ struct selinux_audit_rule {
struct context au_ctxt;
};
+int selinux_audit_rule_avc_callback(u32 event)
+{
+ if (event == AVC_CALLBACK_RESET)
+ return audit_update_lsm_rules();
+ return 0;
+}
+
void selinux_audit_rule_free(void *vrule)
{
struct selinux_audit_rule *rule = vrule;
@@ -3820,25 +3827,6 @@ out:
return match;
}
-static int aurule_avc_callback(u32 event)
-{
- if (event == AVC_CALLBACK_RESET)
- return audit_update_lsm_rules();
- return 0;
-}
-
-static int __init aurule_init(void)
-{
- int err;
-
- err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
- if (err)
- panic("avc_add_callback() failed, error %d\n", err);
-
- return err;
-}
-__initcall(aurule_init);
-
#ifdef CONFIG_NETLABEL
/**
* security_netlbl_cache_add - Add an entry to the NetLabel cache
diff --git a/security/smack/smack.h b/security/smack/smack.h
index bf6a6ed3946c..c56e1e876f7c 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -276,6 +276,20 @@ struct smk_audit_info {
};
/*
+ * Initialization
+ */
+#if defined(CONFIG_SECURITY_SMACK_NETFILTER)
+int smack_nf_ip_init(void);
+#else
+static inline int smack_nf_ip_init(void)
+{
+ return 0;
+}
+#endif
+int init_smk_fs(void);
+int smack_initcall(void);
+
+/*
* These functions are in smack_access.c
*/
int smk_access_entry(char *, char *, struct list_head *);
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index af986587841d..23ee1c0c07b7 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5275,13 +5275,22 @@ static __init int smack_init(void)
return 0;
}
+int __init smack_initcall(void)
+{
+ int rc_fs = init_smk_fs();
+ int rc_nf = smack_nf_ip_init();
+
+ return rc_fs ? rc_fs : rc_nf;
+}
+
/*
* Smack requires early initialization in order to label
* all processes and objects when they are created.
*/
DEFINE_LSM(smack) = {
- .name = "smack",
+ .id = &smack_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.blobs = &smack_blob_sizes,
.init = smack_init,
+ .initcall_device = smack_initcall,
};
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index 8fd747b3653a..17ba578b1308 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -68,7 +68,7 @@ static struct pernet_operations smack_net_ops = {
.exit = smack_nf_unregister,
};
-static int __init smack_nf_ip_init(void)
+int __init smack_nf_ip_init(void)
{
if (smack_enabled == 0)
return 0;
@@ -76,5 +76,3 @@ static int __init smack_nf_ip_init(void)
printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
return register_pernet_subsys(&smack_net_ops);
}
-
-__initcall(smack_nf_ip_init);
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index b1e5e62f5cbd..405ace6db109 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -2978,7 +2978,7 @@ static struct vfsmount *smackfs_mount;
* Returns true if we were not chosen on boot or if
* we were chosen and filesystem registration succeeded.
*/
-static int __init init_smk_fs(void)
+int __init init_smk_fs(void)
{
int err;
int rc;
@@ -3021,5 +3021,3 @@ static int __init init_smk_fs(void)
return err;
}
-
-__initcall(init_smk_fs);
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 0e8e2e959aef..3b2a97d10a5d 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -924,6 +924,8 @@ struct tomoyo_task {
/********** Function prototypes. **********/
+int tomoyo_interface_init(void);
+
bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
const struct tomoyo_group *group);
bool tomoyo_compare_number_union(const unsigned long value,
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
index 7e69747b2f77..33933645f5b9 100644
--- a/security/tomoyo/securityfs_if.c
+++ b/security/tomoyo/securityfs_if.c
@@ -233,7 +233,7 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode,
*
* Returns 0.
*/
-static int __init tomoyo_interface_init(void)
+int __init tomoyo_interface_init(void)
{
struct tomoyo_domain_info *domain;
struct dentry *tomoyo_dir;
@@ -269,5 +269,3 @@ static int __init tomoyo_interface_init(void)
tomoyo_load_builtin_policy();
return 0;
}
-
-fs_initcall(tomoyo_interface_init);
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 48fc59d38ab2..c66e02ed8ee3 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -612,9 +612,10 @@ static int __init tomoyo_init(void)
}
DEFINE_LSM(tomoyo) = {
- .name = "tomoyo",
+ .id = &tomoyo_lsmid,
.enabled = &tomoyo_enabled,
.flags = LSM_FLAG_LEGACY_MAJOR,
.blobs = &tomoyo_blob_sizes,
.init = tomoyo_init,
+ .initcall_fs = tomoyo_interface_init,
};
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 3d064dd4e03f..38b21ee0c560 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -476,6 +476,6 @@ static int __init yama_init(void)
}
DEFINE_LSM(yama) = {
- .name = "yama",
+ .id = &yama_lsmid,
.init = yama_init,
};