6142 lines · 177.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * Security plug functions * * Copyright (C) 2001 WireX Communications, Inc <chris@wirex.com> * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com> * Copyright (C) 2016 Mellanox Technologies * Copyright (C) 2023 Microsoft Corporation <paul@paul-moore.com> */ #define pr_fmt(fmt) "LSM: " fmt #include <linux/bpf.h>#include <linux/capability.h>#include <linux/dcache.h>#include <linux/export.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/kernel_read_file.h>#include <linux/lsm_hooks.h>#include <linux/mman.h>#include <linux/mount.h>#include <linux/personality.h>#include <linux/backing-dev.h>#include <linux/string.h>#include <linux/xattr.h>#include <linux/msg.h>#include <linux/overflow.h>#include <linux/perf_event.h>#include <linux/fs.h>#include <net/flow.h>#include <net/sock.h> #define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX /* * Identifier for the LSM static calls. * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT */#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX /* * Call the macro M for each LSM hook MAX_LSM_COUNT times. */#define LSM_LOOP_UNROLL(M, ...) 		\do {						\	UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)	\} while (0) #define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__) /* * These are descriptions of the reasons that can be passed to the * security_locked_down() LSM hook. Placing this array here allows * all security modules to use the same descriptions for auditing * purposes. */const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {	[LOCKDOWN_NONE] = "none",	[LOCKDOWN_MODULE_SIGNATURE] = "unsigned module loading",	[LOCKDOWN_DEV_MEM] = "/dev/mem,kmem,port",	[LOCKDOWN_EFI_TEST] = "/dev/efi_test access",	[LOCKDOWN_KEXEC] = "kexec of unsigned images",	[LOCKDOWN_HIBERNATION] = "hibernation",	[LOCKDOWN_PCI_ACCESS] = "direct PCI access",	[LOCKDOWN_IOPORT] = "raw io port access",	[LOCKDOWN_MSR] = "raw MSR access",	[LOCKDOWN_ACPI_TABLES] = "modifying ACPI tables",	[LOCKDOWN_DEVICE_TREE] = "modifying device tree contents",	[LOCKDOWN_PCMCIA_CIS] = "direct PCMCIA CIS storage",	[LOCKDOWN_TIOCSSERIAL] = "reconfiguration of serial port IO",	[LOCKDOWN_MODULE_PARAMETERS] = "unsafe module parameters",	[LOCKDOWN_MMIOTRACE] = "unsafe mmio",	[LOCKDOWN_DEBUGFS] = "debugfs access",	[LOCKDOWN_XMON_WR] = "xmon write access",	[LOCKDOWN_BPF_WRITE_USER] = "use of bpf to write user RAM",	[LOCKDOWN_DBG_WRITE_KERNEL] = "use of kgdb/kdb to write kernel RAM",	[LOCKDOWN_RTAS_ERROR_INJECTION] = "RTAS error injection",	[LOCKDOWN_INTEGRITY_MAX] = "integrity",	[LOCKDOWN_KCORE] = "/proc/kcore access",	[LOCKDOWN_KPROBES] = "use of kprobes",	[LOCKDOWN_BPF_READ_KERNEL] = "use of bpf to read kernel RAM",	[LOCKDOWN_DBG_READ_KERNEL] = "use of kgdb/kdb to read kernel RAM",	[LOCKDOWN_PERF] = "unsafe use of perf",	[LOCKDOWN_TRACEFS] = "use of tracefs",	[LOCKDOWN_XMON_RW] = "xmon read and write access",	[LOCKDOWN_XFRM_SECRET] = "xfrm SA secret",	[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",}; static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain); static struct kmem_cache *lsm_file_cache;static struct kmem_cache *lsm_inode_cache; char *lsm_names;static struct lsm_blob_sizes blob_sizes __ro_after_init; /* Boot-time LSM user choice */static __initdata const char *chosen_lsm_order;static __initdata const char *chosen_major_lsm; static __initconst const char *const builtin_lsm_order = CONFIG_LSM; /* Ordered list of LSMs to initialize. */static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];static __initdata struct lsm_info *exclusive; #ifdef CONFIG_HAVE_STATIC_CALL#define LSM_HOOK_TRAMP(NAME, NUM) \	&STATIC_CALL_TRAMP(LSM_STATIC_CALL(NAME, NUM))#else#define LSM_HOOK_TRAMP(NAME, NUM) NULL#endif /* * Define static calls and static keys for each LSM hook. */#define DEFINE_LSM_STATIC_CALL(NUM, NAME, RET, ...)			\	DEFINE_STATIC_CALL_NULL(LSM_STATIC_CALL(NAME, NUM),		\				*((RET(*)(__VA_ARGS__))NULL));		\	DEFINE_STATIC_KEY_FALSE(SECURITY_HOOK_ACTIVE_KEY(NAME, NUM)); #define LSM_HOOK(RET, DEFAULT, NAME, ...)				\	LSM_DEFINE_UNROLL(DEFINE_LSM_STATIC_CALL, NAME, RET, __VA_ARGS__)#include <linux/lsm_hook_defs.h>#undef LSM_HOOK#undef DEFINE_LSM_STATIC_CALL /* * Initialise a table of static calls for each LSM hook. * DEFINE_STATIC_CALL_NULL invocation above generates a key (STATIC_CALL_KEY) * and a trampoline (STATIC_CALL_TRAMP) which are used to call * __static_call_update when updating the static call. * * The static calls table is used by early LSMs, some architectures can fault on * unaligned accesses and the fault handling code may not be ready by then. * Thus, the static calls table should be aligned to avoid any unhandled faults * in early init. */struct lsm_static_calls_table	static_calls_table __ro_after_init __aligned(sizeof(u64)) = {#define INIT_LSM_STATIC_CALL(NUM, NAME)					\	(struct lsm_static_call) {					\		.key = &STATIC_CALL_KEY(LSM_STATIC_CALL(NAME, NUM)),	\		.trampoline = LSM_HOOK_TRAMP(NAME, NUM),		\		.active = &SECURITY_HOOK_ACTIVE_KEY(NAME, NUM),		\	},#define LSM_HOOK(RET, DEFAULT, NAME, ...)				\	.NAME = {							\		LSM_DEFINE_UNROLL(INIT_LSM_STATIC_CALL, NAME)		\	},#include <linux/lsm_hook_defs.h>#undef LSM_HOOK#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);

Lines 1–500 of 6142.