mirror of https://github.com/torvalds/linux.git
lsm/stable-6.19 PR 20251201
-----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAmkuALUUHHBhdWxAcGF1 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXOtDg/8DMxvN2XKZrryP31zdknUEHLJOTfz eFCaNKQJK9GpJ1Q/Z4P/q/dH4QUKZHEM7E18N/hjA4Nx6Z7I1eVPK6hvvySkRa9l b5j+GTLteMcANV04i04B8VTn2mtEW5SZp0Y280EFOMoVGvav72zAt4HHWVytDzyy tVzvuC6iPNbe7rw+eUzTjHAq3WWWYe42QmiDfnAttdjWloSnfMx6AIvEoeo6jryc aLGeZQsrgk2wL/ovXXD5kvDo1EQnETGuxQRh8P3W2DzLwEtt6d+BpfAm9PE0FE4k oE5YrqOhvIpmcBm/8DdkvZ0o0gdfe0IrACvoEqJVpWs6w6T6zusiTzwWp7tBzET/ ygqYabUpz+BrAsGNVtXlDD4va37e5OI500PjDntuT4GMwKBGe5JKXLeki0sQeu6d AcZd8hu6sVpYDLWJoWDXplxq1ndJTfafVtONQ5Cw8BHM5j6CIAaZM13KG9rJSOYa uyNOfHxndsjV7dzuQ9S763l4djixiw0oU/PF+XQP4dC/Dyf60yb47mCOlZndRaJj /FqR0Rbp2KonOSrkmzPTteGJOLMgM5bquZsSHNClxC/qeHTv8xKWf0HRWN61ZUe2 /NLcSjL+CIcN6q0c8jx/k7I9N/yQcmQLQIVTnUY6YOi0TkhUUdqSaq0rp8rSDW9z AUvHpfPpC92klcM= =u7yQ -----END PGP SIGNATURE----- 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() ...
This commit is contained in:
commit
121cc35cfb
|
|
@ -102,23 +102,23 @@ struct security_hook_list {
|
||||||
* Security blob size or offset data.
|
* Security blob size or offset data.
|
||||||
*/
|
*/
|
||||||
struct lsm_blob_sizes {
|
struct lsm_blob_sizes {
|
||||||
int lbs_cred;
|
unsigned int lbs_cred;
|
||||||
int lbs_file;
|
unsigned int lbs_file;
|
||||||
int lbs_ib;
|
unsigned int lbs_ib;
|
||||||
int lbs_inode;
|
unsigned int lbs_inode;
|
||||||
int lbs_sock;
|
unsigned int lbs_sock;
|
||||||
int lbs_superblock;
|
unsigned int lbs_superblock;
|
||||||
int lbs_ipc;
|
unsigned int lbs_ipc;
|
||||||
int lbs_key;
|
unsigned int lbs_key;
|
||||||
int lbs_msg_msg;
|
unsigned int lbs_msg_msg;
|
||||||
int lbs_perf_event;
|
unsigned int lbs_perf_event;
|
||||||
int lbs_task;
|
unsigned int lbs_task;
|
||||||
int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
|
unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
|
||||||
int lbs_tun_dev;
|
unsigned int lbs_tun_dev;
|
||||||
int lbs_bdev;
|
unsigned int lbs_bdev;
|
||||||
int lbs_bpf_map;
|
unsigned int lbs_bpf_map;
|
||||||
int lbs_bpf_prog;
|
unsigned int lbs_bpf_prog;
|
||||||
int lbs_bpf_token;
|
unsigned int lbs_bpf_token;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -151,13 +151,36 @@ enum lsm_order {
|
||||||
LSM_ORDER_LAST = 1, /* This is only for integrity. */
|
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 {
|
struct lsm_info {
|
||||||
const char *name; /* Required. */
|
const struct lsm_id *id;
|
||||||
enum lsm_order order; /* Optional: default is LSM_ORDER_MUTABLE */
|
enum lsm_order order;
|
||||||
unsigned long flags; /* Optional: flags describing LSM */
|
unsigned long flags;
|
||||||
int *enabled; /* Optional: controlled by CONFIG_LSM */
|
struct lsm_blob_sizes *blobs;
|
||||||
int (*init)(void); /* Required. */
|
int *enabled;
|
||||||
struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
|
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) \
|
#define DEFINE_LSM(lsm) \
|
||||||
|
|
@ -170,11 +193,9 @@ struct lsm_info {
|
||||||
__used __section(".early_lsm_info.init") \
|
__used __section(".early_lsm_info.init") \
|
||||||
__aligned(sizeof(unsigned long))
|
__aligned(sizeof(unsigned long))
|
||||||
|
|
||||||
|
|
||||||
/* DO NOT tamper with these variables outside of the LSM framework */
|
/* 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_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
|
* lsm_get_xattr_slot - Return the next available slot and increment the index
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ struct timezone;
|
||||||
|
|
||||||
enum lsm_event {
|
enum lsm_event {
|
||||||
LSM_POLICY_CHANGE,
|
LSM_POLICY_CHANGE,
|
||||||
|
LSM_STARTED_ALL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dm_verity_digest {
|
struct dm_verity_digest {
|
||||||
|
|
@ -167,8 +168,6 @@ struct lsm_prop {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
|
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 */
|
/* These functions are in security/commoncap.c */
|
||||||
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
|
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ obj-$(CONFIG_SECURITY) += lsm_syscalls.o
|
||||||
obj-$(CONFIG_MMU) += min_addr.o
|
obj-$(CONFIG_MMU) += min_addr.o
|
||||||
|
|
||||||
# Object file lists
|
# 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_SECURITYFS) += inode.o
|
||||||
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
|
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
|
||||||
obj-$(CONFIG_SECURITY_SMACK) += smack/
|
obj-$(CONFIG_SECURITY_SMACK) += smack/
|
||||||
|
|
|
||||||
|
|
@ -2649,7 +2649,7 @@ static const struct inode_operations policy_link_iops = {
|
||||||
*
|
*
|
||||||
* Returns: error on failure
|
* Returns: error on failure
|
||||||
*/
|
*/
|
||||||
static int __init aa_create_aafs(void)
|
int __init aa_create_aafs(void)
|
||||||
{
|
{
|
||||||
struct dentry *dent;
|
struct dentry *dent;
|
||||||
int error;
|
int error;
|
||||||
|
|
@ -2728,5 +2728,3 @@ static int __init aa_create_aafs(void)
|
||||||
AA_ERROR("Error creating AppArmor securityfs\n");
|
AA_ERROR("Error creating AppArmor securityfs\n");
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_initcall(aa_create_aafs);
|
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,9 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init init_profile_hash(void)
|
int __init init_profile_hash(void)
|
||||||
{
|
{
|
||||||
if (apparmor_initialized)
|
if (apparmor_initialized)
|
||||||
aa_info_message("AppArmor sha256 policy hashing enabled");
|
aa_info_message("AppArmor sha256 policy hashing enabled");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
late_initcall(init_profile_hash);
|
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,8 @@ enum aafs_prof_type {
|
||||||
#define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
|
#define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
|
||||||
#define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
|
#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 __aa_bump_ns_revision(struct aa_ns *ns);
|
||||||
void __aafs_profile_rmdir(struct aa_profile *profile);
|
void __aafs_profile_rmdir(struct aa_profile *profile);
|
||||||
void __aafs_profile_migrate_dents(struct aa_profile *old,
|
void __aafs_profile_migrate_dents(struct aa_profile *old,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "policy.h"
|
#include "policy.h"
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_APPARMOR_HASH
|
#ifdef CONFIG_SECURITY_APPARMOR_HASH
|
||||||
|
int init_profile_hash(void);
|
||||||
unsigned int aa_hash_size(void);
|
unsigned int aa_hash_size(void);
|
||||||
char *aa_calc_hash(void *data, size_t len);
|
char *aa_calc_hash(void *data, size_t len);
|
||||||
int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
|
int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include "include/audit.h"
|
#include "include/audit.h"
|
||||||
#include "include/capability.h"
|
#include "include/capability.h"
|
||||||
#include "include/cred.h"
|
#include "include/cred.h"
|
||||||
|
#include "include/crypto.h"
|
||||||
#include "include/file.h"
|
#include "include/file.h"
|
||||||
#include "include/ipc.h"
|
#include "include/ipc.h"
|
||||||
#include "include/net.h"
|
#include "include/net.h"
|
||||||
|
|
@ -2426,7 +2427,6 @@ static int __init apparmor_nf_ip_init(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
__initcall(apparmor_nf_ip_init);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static char nulldfa_src[] __aligned(8) = {
|
static char nulldfa_src[] __aligned(8) = {
|
||||||
|
|
@ -2555,9 +2555,16 @@ static int __init apparmor_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_LSM(apparmor) = {
|
DEFINE_LSM(apparmor) = {
|
||||||
.name = "apparmor",
|
.id = &apparmor_lsmid,
|
||||||
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
|
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
|
||||||
.enabled = &apparmor_enabled,
|
.enabled = &apparmor_enabled,
|
||||||
.blobs = &apparmor_blob_sizes,
|
.blobs = &apparmor_blob_sizes,
|
||||||
.init = apparmor_init,
|
.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
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_LSM(bpf) = {
|
DEFINE_LSM(bpf) = {
|
||||||
.name = "bpf",
|
.id = &bpf_lsmid,
|
||||||
.init = bpf_lsm_init,
|
.init = bpf_lsm_init,
|
||||||
.blobs = &bpf_lsm_blob_sizes
|
.blobs = &bpf_lsm_blob_sizes
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1505,7 +1505,7 @@ static int __init capability_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_LSM(capability) = {
|
DEFINE_LSM(capability) = {
|
||||||
.name = "capability",
|
.id = &capability_lsmid,
|
||||||
.order = LSM_ORDER_FIRST,
|
.order = LSM_ORDER_FIRST,
|
||||||
.init = capability_init,
|
.init = capability_init,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -244,45 +244,40 @@ static void devcgroup_css_free(struct cgroup_subsys_state *css)
|
||||||
#define DEVCG_DENY 2
|
#define DEVCG_DENY 2
|
||||||
#define DEVCG_LIST 3
|
#define DEVCG_LIST 3
|
||||||
|
|
||||||
#define MAJMINLEN 13
|
static void seq_putaccess(struct seq_file *m, short access)
|
||||||
#define ACCLEN 4
|
|
||||||
|
|
||||||
static void set_access(char *acc, short access)
|
|
||||||
{
|
{
|
||||||
int idx = 0;
|
|
||||||
memset(acc, 0, ACCLEN);
|
|
||||||
if (access & DEVCG_ACC_READ)
|
if (access & DEVCG_ACC_READ)
|
||||||
acc[idx++] = 'r';
|
seq_putc(m, 'r');
|
||||||
if (access & DEVCG_ACC_WRITE)
|
if (access & DEVCG_ACC_WRITE)
|
||||||
acc[idx++] = 'w';
|
seq_putc(m, 'w');
|
||||||
if (access & DEVCG_ACC_MKNOD)
|
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)
|
if (type == DEVCG_DEV_ALL)
|
||||||
return 'a';
|
seq_putc(m, 'a');
|
||||||
if (type == DEVCG_DEV_CHAR)
|
else if (type == DEVCG_DEV_CHAR)
|
||||||
return 'c';
|
seq_putc(m, 'c');
|
||||||
if (type == DEVCG_DEV_BLOCK)
|
else if (type == DEVCG_DEV_BLOCK)
|
||||||
return 'b';
|
seq_putc(m, 'b');
|
||||||
return 'X';
|
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)
|
if (version == ~0)
|
||||||
strcpy(str, "*");
|
seq_putc(m, '*');
|
||||||
else
|
else
|
||||||
sprintf(str, "%u", m);
|
seq_printf(m, "%u", version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int devcgroup_seq_show(struct seq_file *m, void *v)
|
static int devcgroup_seq_show(struct seq_file *m, void *v)
|
||||||
{
|
{
|
||||||
struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m));
|
struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m));
|
||||||
struct dev_exception_item *ex;
|
struct dev_exception_item *ex;
|
||||||
char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
|
|
||||||
|
|
||||||
rcu_read_lock();
|
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"
|
* This way, the file remains as a "whitelist of devices"
|
||||||
*/
|
*/
|
||||||
if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
|
if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
|
||||||
set_access(acc, DEVCG_ACC_MASK);
|
seq_puts(m, "a *:* rwm\n");
|
||||||
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);
|
|
||||||
} else {
|
} else {
|
||||||
list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) {
|
list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) {
|
||||||
set_access(acc, ex->access);
|
seq_puttype(m, ex->type);
|
||||||
set_majmin(maj, ex->major);
|
seq_putc(m, ' ');
|
||||||
set_majmin(min, ex->minor);
|
seq_putversion(m, ex->major);
|
||||||
seq_printf(m, "%c %s:%s %s\n", type_to_char(ex->type),
|
seq_putc(m, ':');
|
||||||
maj, min, acc);
|
seq_putversion(m, ex->minor);
|
||||||
|
seq_putc(m, ' ');
|
||||||
|
seq_putaccess(m, ex->access);
|
||||||
|
seq_putc(m, '\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@
|
||||||
#include <linux/lsm_hooks.h>
|
#include <linux/lsm_hooks.h>
|
||||||
#include <linux/magic.h>
|
#include <linux/magic.h>
|
||||||
|
|
||||||
|
#include "lsm.h"
|
||||||
|
|
||||||
static struct vfsmount *mount;
|
static struct vfsmount *mount;
|
||||||
static int mount_count;
|
static int mount_count;
|
||||||
|
|
||||||
|
|
@ -315,12 +317,49 @@ void securityfs_remove(struct dentry *dentry)
|
||||||
EXPORT_SYMBOL_GPL(securityfs_remove);
|
EXPORT_SYMBOL_GPL(securityfs_remove);
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY
|
#ifdef CONFIG_SECURITY
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
static struct dentry *lsm_dentry;
|
static struct dentry *lsm_dentry;
|
||||||
|
|
||||||
static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
|
static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
|
||||||
loff_t *ppos)
|
loff_t *ppos)
|
||||||
{
|
{
|
||||||
return simple_read_from_buffer(buf, count, ppos, lsm_names,
|
int i;
|
||||||
strlen(lsm_names));
|
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 = {
|
static const struct file_operations lsm_ops = {
|
||||||
|
|
@ -329,7 +368,7 @@ static const struct file_operations lsm_ops = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int __init securityfs_init(void)
|
int __init securityfs_init(void)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
|
@ -348,4 +387,3 @@ static int __init securityfs_init(void)
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
core_initcall(securityfs_init);
|
|
||||||
|
|
|
||||||
|
|
@ -1175,10 +1175,9 @@ struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_LSM(evm) = {
|
DEFINE_LSM(evm) = {
|
||||||
.name = "evm",
|
.id = &evm_lsmid,
|
||||||
.init = init_evm_lsm,
|
.init = init_evm_lsm,
|
||||||
.order = LSM_ORDER_LAST,
|
.order = LSM_ORDER_LAST,
|
||||||
.blobs = &evm_blob_sizes,
|
.blobs = &evm_blob_sizes,
|
||||||
|
.initcall_late = init_evm,
|
||||||
};
|
};
|
||||||
|
|
||||||
late_initcall(init_evm);
|
|
||||||
|
|
|
||||||
|
|
@ -302,10 +302,16 @@ int __init evm_init_secfs(void)
|
||||||
int error = 0;
|
int error = 0;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
|
||||||
evm_dir = securityfs_create_dir("evm", integrity_dir);
|
error = integrity_fs_init();
|
||||||
if (IS_ERR(evm_dir))
|
if (error < 0)
|
||||||
return -EFAULT;
|
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,
|
dentry = securityfs_create_file("evm", 0660,
|
||||||
evm_dir, NULL, &evm_key_ops);
|
evm_dir, NULL, &evm_key_ops);
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
|
|
@ -329,5 +335,6 @@ int __init evm_init_secfs(void)
|
||||||
out:
|
out:
|
||||||
securityfs_remove(evm_symlink);
|
securityfs_remove(evm_symlink);
|
||||||
securityfs_remove(evm_dir);
|
securityfs_remove(evm_dir);
|
||||||
|
integrity_fs_fini();
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,11 @@ void __init integrity_load_keys(void)
|
||||||
evm_load_x509();
|
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);
|
integrity_dir = securityfs_create_dir("integrity", NULL);
|
||||||
if (IS_ERR(integrity_dir)) {
|
if (IS_ERR(integrity_dir)) {
|
||||||
int ret = PTR_ERR(integrity_dir);
|
int ret = PTR_ERR(integrity_dir);
|
||||||
|
|
@ -58,4 +61,11 @@ static int __init integrity_fs_init(void)
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -499,9 +499,15 @@ int __init ima_fs_init(void)
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = integrity_fs_init();
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
ima_dir = securityfs_create_dir("ima", integrity_dir);
|
ima_dir = securityfs_create_dir("ima", integrity_dir);
|
||||||
if (IS_ERR(ima_dir))
|
if (IS_ERR(ima_dir)) {
|
||||||
return PTR_ERR(ima_dir);
|
ret = PTR_ERR(ima_dir);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima",
|
ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima",
|
||||||
NULL);
|
NULL);
|
||||||
|
|
@ -555,6 +561,7 @@ int __init ima_fs_init(void)
|
||||||
out:
|
out:
|
||||||
securityfs_remove(ima_symlink);
|
securityfs_remove(ima_symlink);
|
||||||
securityfs_remove(ima_dir);
|
securityfs_remove(ima_dir);
|
||||||
|
integrity_fs_fini();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1279,10 +1279,10 @@ struct lsm_blob_sizes ima_blob_sizes __ro_after_init = {
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_LSM(ima) = {
|
DEFINE_LSM(ima) = {
|
||||||
.name = "ima",
|
.id = &ima_lsmid,
|
||||||
.init = init_ima_lsm,
|
.init = init_ima_lsm,
|
||||||
.order = LSM_ORDER_LAST,
|
.order = LSM_ORDER_LAST,
|
||||||
.blobs = &ima_blob_sizes,
|
.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 */
|
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,8 @@ struct ima_file_id {
|
||||||
|
|
||||||
int integrity_kernel_read(struct file *file, loff_t offset,
|
int integrity_kernel_read(struct file *file, loff_t offset,
|
||||||
void *addr, unsigned long count);
|
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_EVM 0
|
||||||
#define INTEGRITY_KEYRING_IMA 1
|
#define INTEGRITY_KEYRING_IMA 1
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ static const struct file_operations enforce_fops = {
|
||||||
* Return: %0 on success. If an error occurs, the function will return
|
* Return: %0 on success. If an error occurs, the function will return
|
||||||
* the -errno.
|
* the -errno.
|
||||||
*/
|
*/
|
||||||
static int __init ipe_init_securityfs(void)
|
int __init ipe_init_securityfs(void)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct ipe_policy *ap;
|
struct ipe_policy *ap;
|
||||||
|
|
@ -244,5 +244,3 @@ static int __init ipe_init_securityfs(void)
|
||||||
securityfs_remove(root);
|
securityfs_remove(root);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_initcall(ipe_init_securityfs);
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,8 @@ static int __init ipe_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_LSM(ipe) = {
|
DEFINE_LSM(ipe) = {
|
||||||
.name = "ipe",
|
.id = &ipe_lsmid,
|
||||||
.init = ipe_init,
|
.init = ipe_init,
|
||||||
.blobs = &ipe_blobs,
|
.blobs = &ipe_blobs,
|
||||||
|
.initcall_fs = ipe_init_securityfs,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,4 +23,6 @@ struct ipe_bdev *ipe_bdev(struct block_device *b);
|
||||||
struct ipe_inode *ipe_inode(const struct inode *inode);
|
struct ipe_inode *ipe_inode(const struct inode *inode);
|
||||||
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
|
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
|
||||||
|
|
||||||
|
int ipe_init_securityfs(void);
|
||||||
|
|
||||||
#endif /* _IPE_H */
|
#endif /* _IPE_H */
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ static int __init landlock_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_LSM(LANDLOCK_NAME) = {
|
DEFINE_LSM(LANDLOCK_NAME) = {
|
||||||
.name = LANDLOCK_NAME,
|
.id = &landlock_lsmid,
|
||||||
.init = landlock_init,
|
.init = landlock_init,
|
||||||
.blobs = &landlock_blob_sizes,
|
.blobs = &landlock_blob_sizes,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -270,11 +270,6 @@ static int __init loadpin_init(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_LSM(loadpin) = {
|
|
||||||
.name = "loadpin",
|
|
||||||
.init = loadpin_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_LOADPIN_VERITY
|
#ifdef CONFIG_SECURITY_LOADPIN_VERITY
|
||||||
|
|
||||||
enum loadpin_securityfs_interface_index {
|
enum loadpin_securityfs_interface_index {
|
||||||
|
|
@ -434,10 +429,16 @@ static int __init init_loadpin_securityfs(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_initcall(init_loadpin_securityfs);
|
|
||||||
|
|
||||||
#endif /* CONFIG_SECURITY_LOADPIN_VERITY */
|
#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). */
|
/* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
|
||||||
module_param(enforce, int, 0);
|
module_param(enforce, int, 0);
|
||||||
MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
|
MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
|
||||||
|
|
|
||||||
|
|
@ -161,13 +161,12 @@ static int __init lockdown_secfs_init(void)
|
||||||
return PTR_ERR_OR_ZERO(dentry);
|
return PTR_ERR_OR_ZERO(dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
core_initcall(lockdown_secfs_init);
|
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
|
#ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
|
||||||
DEFINE_EARLY_LSM(lockdown) = {
|
DEFINE_EARLY_LSM(lockdown) = {
|
||||||
#else
|
#else
|
||||||
DEFINE_LSM(lockdown) = {
|
DEFINE_LSM(lockdown) = {
|
||||||
#endif
|
#endif
|
||||||
.name = "lockdown",
|
.id = &lockdown_lsmid,
|
||||||
.init = lockdown_lsm_init,
|
.init = lockdown_lsm_init,
|
||||||
|
.initcall_core = lockdown_secfs_init,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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_ */
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
#include <linux/lsm_hooks.h>
|
#include <linux/lsm_hooks.h>
|
||||||
#include <uapi/linux/lsm.h>
|
#include <uapi/linux/lsm.h>
|
||||||
|
|
||||||
|
#include "lsm.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lsm_name_to_attr - map an LSM attribute name to its ID
|
* lsm_name_to_attr - map an LSM attribute name to its ID
|
||||||
* @name: name of the attribute
|
* @name: name of the attribute
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
#include <linux/minmax.h>
|
#include <linux/minmax.h>
|
||||||
|
|
||||||
|
#include "lsm.h"
|
||||||
|
|
||||||
/* amount of vm to protect from userspace access by both DAC and the LSM*/
|
/* amount of vm to protect from userspace access by both DAC and the LSM*/
|
||||||
unsigned long mmap_min_addr;
|
unsigned long mmap_min_addr;
|
||||||
/* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */
|
/* 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);
|
register_sysctl_init("vm", min_addr_sysctl_table);
|
||||||
update_mmap_min_addr();
|
update_mmap_min_addr();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pure_initcall(init_mmap_min_addr);
|
|
||||||
|
|
|
||||||
|
|
@ -287,6 +287,7 @@ static int __init safesetid_security_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_LSM(safesetid_security_init) = {
|
DEFINE_LSM(safesetid_security_init) = {
|
||||||
|
.id = &safesetid_lsmid,
|
||||||
.init = safesetid_security_init,
|
.init = safesetid_security_init,
|
||||||
.name = "safesetid",
|
.initcall_fs = safesetid_init_securityfs,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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_setuid_rules;
|
||||||
extern struct setid_ruleset __rcu *safesetid_setgid_rules;
|
extern struct setid_ruleset __rcu *safesetid_setgid_rules;
|
||||||
|
|
||||||
|
int safesetid_init_securityfs(void);
|
||||||
|
|
||||||
#endif /* _SAFESETID_H */
|
#endif /* _SAFESETID_H */
|
||||||
|
|
|
||||||
|
|
@ -308,7 +308,7 @@ static const struct file_operations safesetid_gid_file_fops = {
|
||||||
.write = safesetid_gid_file_write,
|
.write = safesetid_gid_file_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init safesetid_init_securityfs(void)
|
int __init safesetid_init_securityfs(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct dentry *policy_dir;
|
struct dentry *policy_dir;
|
||||||
|
|
@ -345,4 +345,3 @@ static int __init safesetid_init_securityfs(void)
|
||||||
securityfs_remove(policy_dir);
|
securityfs_remove(policy_dir);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
fs_initcall(safesetid_init_securityfs);
|
|
||||||
|
|
|
||||||
|
|
@ -32,24 +32,7 @@
|
||||||
#include <net/flow.h>
|
#include <net/flow.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
|
|
||||||
#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
|
#include "lsm.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* 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__)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These are descriptions of the reasons that can be passed to the
|
* 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",
|
[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;
|
unsigned int lsm_active_cnt __ro_after_init;
|
||||||
static struct kmem_cache *lsm_inode_cache;
|
const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
|
||||||
|
|
||||||
char *lsm_names;
|
struct lsm_blob_sizes blob_sizes;
|
||||||
static struct lsm_blob_sizes blob_sizes __ro_after_init;
|
|
||||||
|
|
||||||
/* Boot-time LSM user choice */
|
struct kmem_cache *lsm_file_cache;
|
||||||
static __initdata const char *chosen_lsm_order;
|
struct kmem_cache *lsm_inode_cache;
|
||||||
static __initdata const char *chosen_major_lsm;
|
|
||||||
|
|
||||||
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];
|
* Identifier for the LSM static calls.
|
||||||
static __initdata struct lsm_info *exclusive;
|
* 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
|
#ifdef CONFIG_HAVE_STATIC_CALL
|
||||||
#define LSM_HOOK_TRAMP(NAME, NUM) \
|
#define LSM_HOOK_TRAMP(NAME, NUM) \
|
||||||
|
|
@ -157,519 +151,27 @@ struct lsm_static_calls_table
|
||||||
#undef INIT_LSM_STATIC_CALL
|
#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.
|
* Allocate the file blob for all the modules
|
||||||
|
*
|
||||||
|
* Returns 0, or -ENOMEM if memory can't be allocated.
|
||||||
*/
|
*/
|
||||||
int __init security_init(void)
|
static int lsm_file_alloc(struct file *file)
|
||||||
{
|
{
|
||||||
struct lsm_info *lsm;
|
if (!lsm_file_cache) {
|
||||||
|
file->f_security = NULL;
|
||||||
init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
|
return 0;
|
||||||
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. */
|
file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
|
||||||
ordered_lsm_init();
|
if (file->f_security == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
return 0;
|
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
|
|
||||||
*
|
|
||||||
* Each LSM has to register its hooks with the infrastructure.
|
|
||||||
*/
|
|
||||||
void __init security_add_hooks(struct security_hook_list *hooks, int count,
|
|
||||||
const struct lsm_id *lsmid)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A security module may call security_add_hooks() more
|
|
||||||
* than once during initialization, and LSM initialization
|
|
||||||
* is serialized. Landlock is one such case.
|
|
||||||
* Look at the previous entry, if there is one, for duplication.
|
|
||||||
*/
|
|
||||||
if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
|
|
||||||
if (lsm_active_cnt >= 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__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lsm_blob_alloc - allocate a composite blob
|
* lsm_blob_alloc - allocate a composite blob
|
||||||
* @dest: the destination for the blob
|
* @dest: the destination for the blob
|
||||||
|
|
@ -702,46 +204,11 @@ static int lsm_blob_alloc(void **dest, size_t size, gfp_t gfp)
|
||||||
*
|
*
|
||||||
* Returns 0, or -ENOMEM if memory can't be allocated.
|
* 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);
|
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
|
* lsm_inode_alloc - allocate a composite inode blob
|
||||||
* @inode: the inode that needs a blob
|
* @inode: the inode that needs a blob
|
||||||
|
|
@ -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.
|
* 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);
|
return lsm_blob_alloc(&task->security, blob_sizes.lbs_task, GFP_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
@ -874,20 +341,6 @@ static int lsm_bpf_token_alloc(struct bpf_token *token)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BPF_SYSCALL */
|
#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
|
* lsm_superblock_alloc - allocate a composite superblock blob
|
||||||
* @sb: the superblock that needs a blob
|
* @sb: the superblock that needs a blob
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
|
||||||
ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG
|
ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG
|
||||||
|
|
||||||
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
|
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/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
|
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/context.o
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@
|
||||||
#include <linux/io_uring/cmd.h>
|
#include <linux/io_uring/cmd.h>
|
||||||
#include <uapi/linux/lsm.h>
|
#include <uapi/linux/lsm.h>
|
||||||
|
|
||||||
|
#include "initcalls.h"
|
||||||
#include "avc.h"
|
#include "avc.h"
|
||||||
#include "objsec.h"
|
#include "objsec.h"
|
||||||
#include "netif.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))
|
if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET))
|
||||||
panic("SELinux: Unable to register AVC LSM notifier callback\n");
|
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)
|
if (selinux_enforcing_boot)
|
||||||
pr_debug("SELinux: Starting in enforcing mode\n");
|
pr_debug("SELinux: Starting in enforcing mode\n");
|
||||||
else
|
else
|
||||||
|
|
@ -7644,11 +7649,12 @@ void selinux_complete_init(void)
|
||||||
/* SELinux requires early initialization in order to label
|
/* SELinux requires early initialization in order to label
|
||||||
all processes and objects when they are created. */
|
all processes and objects when they are created. */
|
||||||
DEFINE_LSM(selinux) = {
|
DEFINE_LSM(selinux) = {
|
||||||
.name = "selinux",
|
.id = &selinux_lsmid,
|
||||||
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
|
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
|
||||||
.enabled = &selinux_enabled_boot,
|
.enabled = &selinux_enabled_boot,
|
||||||
.blobs = &selinux_blob_sizes,
|
.blobs = &selinux_blob_sizes,
|
||||||
.init = selinux_init,
|
.init = selinux_init,
|
||||||
|
.initcall_device = selinux_initcall,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_NETFILTER)
|
#if defined(CONFIG_NETFILTER)
|
||||||
|
|
@ -7710,7 +7716,7 @@ static struct pernet_operations selinux_net_ops = {
|
||||||
.exit = selinux_nf_unregister,
|
.exit = selinux_nf_unregister,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init selinux_nf_ip_init(void)
|
int __init selinux_nf_ip_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
|
@ -7725,5 +7731,4 @@ static int __init selinux_nf_ip_init(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
__initcall(selinux_nf_ip_init);
|
|
||||||
#endif /* CONFIG_NETFILTER */
|
#endif /* CONFIG_NETFILTER */
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
#include "initcalls.h"
|
||||||
#include "ibpkey.h"
|
#include "ibpkey.h"
|
||||||
#include "objsec.h"
|
#include "objsec.h"
|
||||||
|
|
||||||
|
|
@ -218,7 +219,7 @@ void sel_ib_pkey_flush(void)
|
||||||
spin_unlock_irqrestore(&sel_ib_pkey_lock, flags);
|
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;
|
int iter;
|
||||||
|
|
||||||
|
|
@ -232,5 +233,3 @@ static __init int sel_ib_pkey_init(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
subsys_initcall(sel_ib_pkey_init);
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,15 @@
|
||||||
#include <linux/audit.h>
|
#include <linux/audit.h>
|
||||||
#include <linux/types.h>
|
#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.
|
* selinux_audit_rule_init - alloc/init an selinux audit rule structure.
|
||||||
* @field: the field this rule refers to
|
* @field: the field this rule refers to
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <net/net_namespace.h>
|
#include <net/net_namespace.h>
|
||||||
|
|
||||||
|
#include "initcalls.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
#include "objsec.h"
|
#include "objsec.h"
|
||||||
#include "netif.h"
|
#include "netif.h"
|
||||||
|
|
@ -265,7 +266,7 @@ static struct notifier_block sel_netif_netdev_notifier = {
|
||||||
.notifier_call = sel_netif_netdev_notifier_handler,
|
.notifier_call = sel_netif_netdev_notifier_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
static __init int sel_netif_init(void)
|
int __init sel_netif_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -280,5 +281,3 @@ static __init int sel_netif_init(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__initcall(sel_netif_init);
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include <net/net_namespace.h>
|
#include <net/net_namespace.h>
|
||||||
#include <net/netlink.h>
|
#include <net/netlink.h>
|
||||||
|
|
||||||
|
#include "initcalls.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
|
|
||||||
static struct sock *selnl __ro_after_init;
|
static struct sock *selnl __ro_after_init;
|
||||||
|
|
@ -105,7 +106,7 @@ void selnl_notify_policyload(u32 seqno)
|
||||||
selnl_notify(SELNL_MSG_POLICYLOAD, &seqno);
|
selnl_notify(SELNL_MSG_POLICYLOAD, &seqno);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init selnl_init(void)
|
int __init sel_netlink_init(void)
|
||||||
{
|
{
|
||||||
struct netlink_kernel_cfg cfg = {
|
struct netlink_kernel_cfg cfg = {
|
||||||
.groups = SELNLGRP_MAX,
|
.groups = SELNLGRP_MAX,
|
||||||
|
|
@ -117,5 +118,3 @@ static int __init selnl_init(void)
|
||||||
panic("SELinux: Cannot create netlink socket.");
|
panic("SELinux: Cannot create netlink socket.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__initcall(selnl_init);
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
|
|
||||||
|
#include "initcalls.h"
|
||||||
#include "netnode.h"
|
#include "netnode.h"
|
||||||
#include "objsec.h"
|
#include "objsec.h"
|
||||||
|
|
||||||
|
|
@ -290,7 +291,7 @@ void sel_netnode_flush(void)
|
||||||
spin_unlock_bh(&sel_netnode_lock);
|
spin_unlock_bh(&sel_netnode_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __init int sel_netnode_init(void)
|
int __init sel_netnode_init(void)
|
||||||
{
|
{
|
||||||
int iter;
|
int iter;
|
||||||
|
|
||||||
|
|
@ -304,5 +305,3 @@ static __init int sel_netnode_init(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__initcall(sel_netnode_init);
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
|
|
||||||
|
#include "initcalls.h"
|
||||||
#include "netport.h"
|
#include "netport.h"
|
||||||
#include "objsec.h"
|
#include "objsec.h"
|
||||||
|
|
||||||
|
|
@ -218,7 +219,7 @@ void sel_netport_flush(void)
|
||||||
spin_unlock_bh(&sel_netport_lock);
|
spin_unlock_bh(&sel_netport_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __init int sel_netport_init(void)
|
int __init sel_netport_init(void)
|
||||||
{
|
{
|
||||||
int iter;
|
int iter;
|
||||||
|
|
||||||
|
|
@ -232,5 +233,3 @@ static __init int sel_netport_init(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__initcall(sel_netport_init);
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
/* selinuxfs pseudo filesystem for exporting the security policy API.
|
/* selinuxfs pseudo filesystem for exporting the security policy API.
|
||||||
Based on the proc code and the fs/nfsd/nfsctl.c code. */
|
Based on the proc code and the fs/nfsd/nfsctl.c code. */
|
||||||
|
|
||||||
|
#include "initcalls.h"
|
||||||
#include "flask.h"
|
#include "flask.h"
|
||||||
#include "avc.h"
|
#include "avc.h"
|
||||||
#include "avc_ss.h"
|
#include "avc_ss.h"
|
||||||
|
|
@ -2133,7 +2134,7 @@ static struct file_system_type sel_fs_type = {
|
||||||
|
|
||||||
struct path selinux_null __ro_after_init;
|
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,
|
struct qstr null_name = QSTR_INIT(NULL_FILE_NAME,
|
||||||
sizeof(NULL_FILE_NAME)-1);
|
sizeof(NULL_FILE_NAME)-1);
|
||||||
|
|
@ -2177,5 +2178,3 @@ static int __init init_sel_fs(void)
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
__initcall(init_sel_fs);
|
|
||||||
|
|
|
||||||
|
|
@ -3570,6 +3570,13 @@ struct selinux_audit_rule {
|
||||||
struct context au_ctxt;
|
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)
|
void selinux_audit_rule_free(void *vrule)
|
||||||
{
|
{
|
||||||
struct selinux_audit_rule *rule = vrule;
|
struct selinux_audit_rule *rule = vrule;
|
||||||
|
|
@ -3820,25 +3827,6 @@ int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vru
|
||||||
return match;
|
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
|
#ifdef CONFIG_NETLABEL
|
||||||
/**
|
/**
|
||||||
* security_netlbl_cache_add - Add an entry to the NetLabel cache
|
* security_netlbl_cache_add - Add an entry to the NetLabel cache
|
||||||
|
|
|
||||||
|
|
@ -275,6 +275,20 @@ struct smk_audit_info {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* These functions are in smack_access.c
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -5275,13 +5275,22 @@ static __init int smack_init(void)
|
||||||
return 0;
|
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
|
* Smack requires early initialization in order to label
|
||||||
* all processes and objects when they are created.
|
* all processes and objects when they are created.
|
||||||
*/
|
*/
|
||||||
DEFINE_LSM(smack) = {
|
DEFINE_LSM(smack) = {
|
||||||
.name = "smack",
|
.id = &smack_lsmid,
|
||||||
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
|
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
|
||||||
.blobs = &smack_blob_sizes,
|
.blobs = &smack_blob_sizes,
|
||||||
.init = smack_init,
|
.init = smack_init,
|
||||||
|
.initcall_device = smack_initcall,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ static struct pernet_operations smack_net_ops = {
|
||||||
.exit = smack_nf_unregister,
|
.exit = smack_nf_unregister,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init smack_nf_ip_init(void)
|
int __init smack_nf_ip_init(void)
|
||||||
{
|
{
|
||||||
if (smack_enabled == 0)
|
if (smack_enabled == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -76,5 +76,3 @@ static int __init smack_nf_ip_init(void)
|
||||||
printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
|
printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
|
||||||
return register_pernet_subsys(&smack_net_ops);
|
return register_pernet_subsys(&smack_net_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
__initcall(smack_nf_ip_init);
|
|
||||||
|
|
|
||||||
|
|
@ -2978,7 +2978,7 @@ static struct vfsmount *smackfs_mount;
|
||||||
* Returns true if we were not chosen on boot or if
|
* Returns true if we were not chosen on boot or if
|
||||||
* we were chosen and filesystem registration succeeded.
|
* we were chosen and filesystem registration succeeded.
|
||||||
*/
|
*/
|
||||||
static int __init init_smk_fs(void)
|
int __init init_smk_fs(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
@ -3021,5 +3021,3 @@ static int __init init_smk_fs(void)
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
__initcall(init_smk_fs);
|
|
||||||
|
|
|
||||||
|
|
@ -924,6 +924,8 @@ struct tomoyo_task {
|
||||||
|
|
||||||
/********** Function prototypes. **********/
|
/********** Function prototypes. **********/
|
||||||
|
|
||||||
|
int tomoyo_interface_init(void);
|
||||||
|
|
||||||
bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
|
bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
|
||||||
const struct tomoyo_group *group);
|
const struct tomoyo_group *group);
|
||||||
bool tomoyo_compare_number_union(const unsigned long value,
|
bool tomoyo_compare_number_union(const unsigned long value,
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode,
|
||||||
*
|
*
|
||||||
* Returns 0.
|
* Returns 0.
|
||||||
*/
|
*/
|
||||||
static int __init tomoyo_interface_init(void)
|
int __init tomoyo_interface_init(void)
|
||||||
{
|
{
|
||||||
struct tomoyo_domain_info *domain;
|
struct tomoyo_domain_info *domain;
|
||||||
struct dentry *tomoyo_dir;
|
struct dentry *tomoyo_dir;
|
||||||
|
|
@ -269,5 +269,3 @@ static int __init tomoyo_interface_init(void)
|
||||||
tomoyo_load_builtin_policy();
|
tomoyo_load_builtin_policy();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_initcall(tomoyo_interface_init);
|
|
||||||
|
|
|
||||||
|
|
@ -612,9 +612,10 @@ static int __init tomoyo_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_LSM(tomoyo) = {
|
DEFINE_LSM(tomoyo) = {
|
||||||
.name = "tomoyo",
|
.id = &tomoyo_lsmid,
|
||||||
.enabled = &tomoyo_enabled,
|
.enabled = &tomoyo_enabled,
|
||||||
.flags = LSM_FLAG_LEGACY_MAJOR,
|
.flags = LSM_FLAG_LEGACY_MAJOR,
|
||||||
.blobs = &tomoyo_blob_sizes,
|
.blobs = &tomoyo_blob_sizes,
|
||||||
.init = tomoyo_init,
|
.init = tomoyo_init,
|
||||||
|
.initcall_fs = tomoyo_interface_init,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -476,6 +476,6 @@ static int __init yama_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_LSM(yama) = {
|
DEFINE_LSM(yama) = {
|
||||||
.name = "yama",
|
.id = &yama_lsmid,
|
||||||
.init = yama_init,
|
.init = yama_init,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue