2357 lines · 57.9 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 */ #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/lsm_hooks.h>#include <linux/integrity.h>#include <linux/ima.h>#include <linux/evm.h>#include <linux/fsnotify.h>#include <linux/mman.h>#include <linux/mount.h>#include <linux/personality.h>#include <linux/backing-dev.h>#include <linux/string.h>#include <linux/msg.h>#include <net/flow.h> #define MAX_LSM_EVM_XATTR	2 /* How many LSMs were built into the kernel? */#define LSM_COUNT (__end_lsm_info - __start_lsm_info) struct security_hook_heads security_hook_heads __lsm_ro_after_init;static ATOMIC_NOTIFIER_HEAD(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 __lsm_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;static __initdata struct lsm_info *exclusive; 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 == LSM_COUNT, "%s: out of LSM slots!?\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 ordering: %s (%sabled)\n", from, lsm->name,		   is_enabled(lsm) ? "en" : "dis");} /* 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) {		offset = *lbs;		*lbs += *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);	/*	 * 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_msg_msg, &blob_sizes.lbs_msg_msg);	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);} /* 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);	}} /* 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\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 (lsm->order == LSM_ORDER_MUTABLE &&			    strcmp(lsm->name, name) == 0) {				append_ordered_lsm(lsm, origin);				found = true;			}		} 		if (!found)			init_debug("%s ignored: %s\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=");		}	} 	/* 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 disabled: %s\n", origin, lsm->name);	} 	kfree(sep);} static void __init lsm_early_cred(struct cred *cred);static void __init lsm_early_task(struct task_struct *task); static void __init ordered_lsm_init(void){	struct lsm_info **lsm; 	ordered_lsms = kcalloc(LSM_COUNT + 1, sizeof(*ordered_lsms),				GFP_KERNEL); 	if (chosen_lsm_order) {		if (chosen_major_lsm) {			pr_info("security= is ignored because it is superseded by lsm=\n");			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); 	init_debug("cred blob size     = %d\n", blob_sizes.lbs_cred);	init_debug("file blob size     = %d\n", blob_sizes.lbs_file);	init_debug("inode blob size    = %d\n", blob_sizes.lbs_inode);	init_debug("ipc blob size      = %d\n", blob_sizes.lbs_ipc);	init_debug("msg_msg blob size  = %d\n", blob_sizes.lbs_msg_msg);	init_debug("task blob size     = %d\n", blob_sizes.lbs_task); 	/*	 * 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); 	kfree(ordered_lsms);} /** * security_init - initializes the security framework * * This should be called early in the kernel initialization sequence. */int __init security_init(void){	int i;	struct hlist_head *list = (struct hlist_head *) &security_hook_heads; 	pr_info("Security Framework initializing\n"); 	for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head);	     i++)		INIT_HLIST_HEAD(&list[i]); 	/* Load LSMs in specified order. */	ordered_lsm_init(); 	return 0;} /* Save user chosen LSM */static int __init choose_major_lsm(char *str){	chosen_major_lsm = str;	return 1;}__setup("security=", choose_major_lsm); /* Explicitly choose LSM initialization order. */static int __init choose_lsm_order(char *str){	chosen_lsm_order = str;	return 1;}__setup("lsm=", choose_lsm_order); /* Enable LSM order debugging. */static int __init enable_debug(char *str){	debug = true;	return 1;}__setup("lsm.debug", enable_debug); static bool match_last_lsm(const char *list, const char *lsm){	const char *last; 	if (WARN_ON(!list || !lsm))		return false;	last = strrchr(list, ',');	if (last)		/* Pass the comma, strcmp() will check for '\0' */		last++;	else		last = list;	return !strcmp(last, lsm);} static int lsm_append(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 * @lsm: the name of 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,				char *lsm){	int i; 	for (i = 0; i < count; i++) {		hooks[i].lsm = lsm;		hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);	}	if (lsm_append(lsm, &lsm_names) < 0)		panic("%s - Cannot get early memory.\n", __func__);} int call_lsm_notifier(enum lsm_event event, void *data){	return atomic_notifier_call_chain(&lsm_notifier_chain, event, data);}EXPORT_SYMBOL(call_lsm_notifier); int register_lsm_notifier(struct notifier_block *nb){	return atomic_notifier_chain_register(&lsm_notifier_chain, nb);}EXPORT_SYMBOL(register_lsm_notifier); int unregister_lsm_notifier(struct notifier_block *nb){	return atomic_notifier_chain_unregister(&lsm_notifier_chain, nb);}EXPORT_SYMBOL(unregister_lsm_notifier); /** * lsm_cred_alloc - allocate a composite cred blob * @cred: the cred that needs a blob * @gfp: allocation type * * Allocate the cred blob for all the modules * * Returns 0, or -ENOMEM if memory can't be allocated. */static int lsm_cred_alloc(struct cred *cred, gfp_t gfp){	if (blob_sizes.lbs_cred == 0) {		cred->security = NULL;		return 0;	} 	cred->security = kzalloc(blob_sizes.lbs_cred, gfp);	if (cred->security == NULL)		return -ENOMEM;	return 0;} /** * 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;

Lines 1–500 of 2357.