1537 lines · 41.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * AppArmor security module * * This file contains AppArmor policy manipulation functions * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. * * AppArmor policy is based around profiles, which contain the rules a * task is confined by.  Every task in the system has a profile attached * to it determined either by matching "unconfined" tasks against the * visible set of profiles or by following a profiles attachment rules. * * Each profile exists in a profile namespace which is a container of * visible profiles.  Each namespace contains a special "unconfined" profile, * which doesn't enforce any confinement on a task beyond DAC. * * Namespace and profile names can be written together in either * of two syntaxes. *	:namespace:profile - used by kernel interfaces for easy detection *	namespace://profile - used by policy * * Profile names can not start with : or @ or ^ and may not contain \0 * * Reserved profile names *	unconfined - special automatically generated unconfined profile *	inherit - special name to indicate profile inheritance *	null-XXXX-YYYY - special automatically generated learning profiles * * Namespace names may not start with / or @ and may not contain \0 or : * Reserved namespace names *	user-XXXX - user defined profiles * * a // in a profile or namespace name indicates a hierarchical name with the * name before the // being the parent and the name after the child. * * Profile and namespace hierarchies serve two different but similar purposes. * The namespace contains the set of visible profiles that are considered * for attachment.  The hierarchy of namespaces allows for virtualizing * the namespace so that for example a chroot can have its own set of profiles * which may define some local user namespaces. * The profile hierarchy severs two distinct purposes, * -  it allows for sub profiles or hats, which allows an application to run *    subprograms under its own profile with different restriction than it *    self, and not have it use the system profile. *    eg. if a mail program starts an editor, the policy might make the *        restrictions tighter on the editor tighter than the mail program, *        and definitely different than general editor restrictions * - it allows for binary hierarchy of profiles, so that execution history *   is preserved.  This feature isn't exploited by AppArmor reference policy *   but is allowed.  NOTE: this is currently suboptimal because profile *   aliasing is not currently implemented so that a profile for each *   level must be defined. *   eg. /bin/bash///bin/ls as a name would indicate /bin/ls was started *       from /bin/bash * *   A profile or namespace name that can contain one or more // separators *   is referred to as an hname (hierarchical). *   eg.  /bin/bash//bin/ls * *   An fqname is a name that may contain both namespace and profile hnames. *   eg. :ns:/bin/bash//bin/ls * * NOTES: *   - locking of profile lists is currently fairly coarse.  All profile *     lists within a namespace use the namespace lock. * FIXME: move profile lists to using rcu_lists */ #include <linux/slab.h>#include <linux/spinlock.h>#include <linux/string.h>#include <linux/cred.h>#include <linux/rculist.h>#include <linux/user_namespace.h> #include "include/apparmor.h"#include "include/capability.h"#include "include/cred.h"#include "include/file.h"#include "include/ipc.h"#include "include/match.h"#include "include/net.h"#include "include/path.h"#include "include/policy.h"#include "include/policy_ns.h"#include "include/policy_unpack.h"#include "include/resource.h" int unprivileged_userns_apparmor_policy = 1;int aa_unprivileged_unconfined_restricted; const char *const aa_profile_mode_names[] = {	"enforce",	"complain",	"kill",	"unconfined",	"user",}; void aa_destroy_tags(struct aa_tags_struct *tags){	kfree_sensitive(tags->hdrs.table);	kfree_sensitive(tags->sets.table);	aa_destroy_str_table(&tags->strs);	memset(tags, 0, sizeof(*tags));} static void aa_free_pdb(struct aa_policydb *pdb){	if (pdb) {		aa_put_dfa(pdb->dfa);		kvfree(pdb->perms);		aa_destroy_str_table(&pdb->trans);		aa_destroy_tags(&pdb->tags);		kfree(pdb);	}} /** * aa_pdb_free_kref - free aa_policydb by kref (called by aa_put_pdb) * @kref: kref callback for freeing of a dfa  (NOT NULL) */void aa_pdb_free_kref(struct kref *kref){	struct aa_policydb *pdb = container_of(kref, struct aa_policydb, count); 	aa_free_pdb(pdb);}  struct aa_policydb *aa_alloc_pdb(gfp_t gfp){	struct aa_policydb *pdb = kzalloc_obj(struct aa_policydb, gfp); 	if (!pdb)		return NULL; 	kref_init(&pdb->count); 	return pdb;}  /** * __add_profile - add a profiles to list and label tree * @list: list to add it to  (NOT NULL) * @profile: the profile to add  (NOT NULL) * * refcount @profile, should be put by __list_remove_profile * * Requires: namespace lock be held, or list not be shared */static void __add_profile(struct list_head *list, struct aa_profile *profile){	struct aa_label *l; 	AA_BUG(!list);	AA_BUG(!profile);	AA_BUG(!profile->ns);	AA_BUG(!mutex_is_locked(&profile->ns->lock)); 	list_add_rcu(&profile->base.list, list);	/* get list reference */	aa_get_profile(profile);	l = aa_label_insert(&profile->ns->labels, &profile->label);	AA_BUG(l != &profile->label);	aa_put_label(l);} /** * __list_remove_profile - remove a profile from the list it is on * @profile: the profile to remove  (NOT NULL) * * remove a profile from the list, warning generally removal should * be done with __replace_profile as most profile removals are * replacements to the unconfined profile. * * put @profile list refcount * * Requires: namespace lock be held, or list not have been live */static void __list_remove_profile(struct aa_profile *profile){	AA_BUG(!profile);	AA_BUG(!profile->ns);	AA_BUG(!mutex_is_locked(&profile->ns->lock)); 	list_del_rcu(&profile->base.list);	aa_put_profile(profile);} /** * __remove_profile - remove profile, and children * @profile: profile to be removed  (NOT NULL) * * Requires: namespace list lock be held, or list not be shared */static void __remove_profile(struct aa_profile *profile){	struct aa_profile *curr, *to_remove; 	AA_BUG(!profile);	AA_BUG(!profile->ns);	AA_BUG(!mutex_is_locked(&profile->ns->lock)); 	/* release any children lists first */	if (!list_empty(&profile->base.profiles)) {		curr = list_first_entry(&profile->base.profiles, struct aa_profile, base.list); 		while (curr != profile) { 			while (!list_empty(&curr->base.profiles))				curr = list_first_entry(&curr->base.profiles,							struct aa_profile, base.list); 			to_remove = curr;			if (!list_is_last(&to_remove->base.list,					  &aa_deref_parent(curr)->base.profiles))				curr = list_next_entry(to_remove, base.list);			else				curr = aa_deref_parent(curr); 			/* released by free_profile */			aa_label_remove(&to_remove->label);			__aafs_profile_rmdir(to_remove);			__list_remove_profile(to_remove);		}	} 	/* released by free_profile */	aa_label_remove(&profile->label);	__aafs_profile_rmdir(profile);	__list_remove_profile(profile);	/* rawdata is only ever referenced by fs lookup, that is no	 * longer possible here, so put the reference to it. This will	 * enable the rawdata to be freed if for some reason the profile	 * is pinned and going to live for a while.	 */	aa_put_profile_loaddata(profile->rawdata);	profile->rawdata = NULL;} /** * __aa_profile_list_release - remove all profiles on the list and put refs * @head: list of profiles  (NOT NULL) * * Requires: namespace lock be held */void __aa_profile_list_release(struct list_head *head){	struct aa_profile *profile, *tmp;	list_for_each_entry_safe(profile, tmp, head, base.list)		__remove_profile(profile);} /** * aa_free_data - free a data blob * @ptr: data to free * @arg: unused */static void aa_free_data(void *ptr, void *arg){	struct aa_data *data = ptr; 	if (!ptr)		return; 	kvfree_sensitive(data->data, data->size);	kfree_sensitive(data->key);	kfree_sensitive(data);} static void free_attachment(struct aa_attachment *attach){	int i; 	if (!attach)		return; 	for (i = 0; i < attach->xattr_count; i++)		kfree_sensitive(attach->xattrs[i]);	kfree_sensitive(attach->xattrs);	aa_put_pdb(attach->xmatch);} static void free_ruleset(struct aa_ruleset *rules){	int i; 	if (!rules)	  return; 	aa_put_pdb(rules->file);	aa_put_pdb(rules->policy);	aa_free_cap_rules(&rules->caps);	aa_free_rlimit_rules(&rules->rlimits); 	for (i = 0; i < rules->secmark_count; i++)		kfree_sensitive(rules->secmark[i].label);	kfree_sensitive(rules->secmark);	kfree_sensitive(rules);} struct aa_ruleset *aa_alloc_ruleset(gfp_t gfp){	struct aa_ruleset *rules; 	rules = kzalloc_obj(*rules, gfp); 	return rules;} /** * aa_free_profile - free a profile * @profile: the profile to free  (MAYBE NULL) * * Free a profile, its hats and null_profile. All references to the profile, * its hats and null_profile must have been put. * * If the profile was referenced from a task context, free_profile() will * be called from an rcu callback routine, so we must not sleep here. */void aa_free_profile(struct aa_profile *profile){	struct rhashtable *rht; 	AA_DEBUG(DEBUG_POLICY, "%s(%p)\n", __func__, profile); 	if (!profile)		return; 	/* free children profiles */	aa_policy_destroy(&profile->base);	aa_put_profile(rcu_access_pointer(profile->parent)); 	aa_put_ns(profile->ns);	kfree_sensitive(profile->rename);	kfree_sensitive(profile->disconnected); 	free_attachment(&profile->attach); 	/*	 * at this point there are no tasks that can have a reference	 * to rules	 */	for (int i = 0; i < profile->n_rules; i++)		free_ruleset(profile->label.rules[i]); 	kfree_sensitive(profile->dirname); 	if (profile->data) {		rht = profile->data;		profile->data = NULL;		rhashtable_free_and_destroy(rht, aa_free_data, NULL);		kfree_sensitive(rht);	} 	kfree_sensitive(profile->hash);	aa_put_profile_loaddata(profile->rawdata);	aa_label_destroy(&profile->label); 	kfree_sensitive(profile);} /** * aa_alloc_profile - allocate, initialize and return a new profile * @hname: name of the profile  (NOT NULL) * @proxy: proxy to use OR null if to allocate a new one * @gfp: allocation type * * Returns: refcount profile or NULL on failure */struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,				    gfp_t gfp){	struct aa_profile *profile; 	/* freed by free_profile - usually through aa_put_profile	 * this adds space for a single ruleset in the rules section of the	 * label	 */	profile = kzalloc_flex(*profile, label.rules, 1, gfp);	if (!profile)		return NULL; 	if (!aa_policy_init(&profile->base, NULL, hname, gfp))		goto fail;	if (!aa_label_init(&profile->label, 1, gfp))		goto fail; 	/* allocate the first ruleset, but leave it empty */	profile->label.rules[0] = aa_alloc_ruleset(gfp);	if (!profile->label.rules[0])		goto fail;	profile->n_rules = 1; 	/* update being set needed by fs interface */	if (!proxy) {		proxy = aa_alloc_proxy(&profile->label, gfp);		if (!proxy)			goto fail;	} else		aa_get_proxy(proxy);	profile->label.proxy = proxy; 	profile->label.hname = profile->base.hname;	profile->label.flags |= FLAG_PROFILE;	profile->label.vec[0] = profile; 	profile->signal = SIGKILL;	/* refcount released by caller */	return profile; fail:	aa_free_profile(profile); 	return NULL;} static inline bool ANY_RULE_MEDIATES(struct aa_profile *profile,				     unsigned char class){	int i; 	for (i = 0; i < profile->n_rules; i++) {		if (RULE_MEDIATES(profile->label.rules[i], class))			return true;	}	return false;} /* set of rules that are mediated by unconfined */static int unconfined_mediates[] = { AA_CLASS_NS, AA_CLASS_IO_URING, 0 }; /* must be called after profile rulesets and start information is setup */void aa_compute_profile_mediates(struct aa_profile *profile){	int c; 	if (profile_unconfined(profile)) {		int *pos; 		for (pos = unconfined_mediates; *pos; pos++) {			if (ANY_RULE_MEDIATES(profile, *pos))				profile->label.mediates |= ((u64) 1) << AA_CLASS_NS;		}		return;	}	for (c = 0; c <= AA_CLASS_LAST; c++) {		if (ANY_RULE_MEDIATES(profile, c))			profile->label.mediates |= ((u64) 1) << c;	}} /* TODO: profile accounting - setup in remove */ /** * __strn_find_child - find a profile on @head list using substring of @name * @head: list to search  (NOT NULL) * @name: name of profile (NOT NULL) * @len: length of @name substring to match * * Requires: rcu_read_lock be held * * Returns: unrefcounted profile ptr, or NULL if not found */static struct aa_profile *__strn_find_child(struct list_head *head,					    const char *name, int len){	return (struct aa_profile *)__policy_strn_find(head, name, len);} /** * __find_child - find a profile on @head list with a name matching @name * @head: list to search  (NOT NULL) * @name: name of profile (NOT NULL) * * Requires: rcu_read_lock be held * * Returns: unrefcounted profile ptr, or NULL if not found */static struct aa_profile *__find_child(struct list_head *head, const char *name){	return __strn_find_child(head, name, strlen(name));} /** * aa_find_child - find a profile by @name in @parent * @parent: profile to search  (NOT NULL) * @name: profile name to search for  (NOT NULL) * * Returns: a refcounted profile or NULL if not found */struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name){	struct aa_profile *profile; 	rcu_read_lock();

Lines 1–500 of 1537.