mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	apparmor: refactor prepare_ns() and make usable from different views
prepare_ns() will need to be called from alternate views, and namespaces will need to be created via different interfaces. So refactor and allow specifying the view ns. Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
		
							parent
							
								
									5fd1b95fc9
								
							
						
					
					
						commit
						73688d1ed0
					
				
					 5 changed files with 81 additions and 40 deletions
				
			
		| 
						 | 
					@ -125,7 +125,8 @@ static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = PTR_ERR(data);
 | 
						error = PTR_ERR(data);
 | 
				
			||||||
	if (!IS_ERR(data)) {
 | 
						if (!IS_ERR(data)) {
 | 
				
			||||||
		error = aa_replace_profiles(data, size, PROF_ADD);
 | 
							error = aa_replace_profiles(__aa_current_profile()->ns, data,
 | 
				
			||||||
 | 
										    size, PROF_ADD);
 | 
				
			||||||
		kvfree(data);
 | 
							kvfree(data);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,7 +148,8 @@ static ssize_t profile_replace(struct file *f, const char __user *buf,
 | 
				
			||||||
	data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
 | 
						data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
 | 
				
			||||||
	error = PTR_ERR(data);
 | 
						error = PTR_ERR(data);
 | 
				
			||||||
	if (!IS_ERR(data)) {
 | 
						if (!IS_ERR(data)) {
 | 
				
			||||||
		error = aa_replace_profiles(data, size, PROF_REPLACE);
 | 
							error = aa_replace_profiles(__aa_current_profile()->ns, data,
 | 
				
			||||||
 | 
										    size, PROF_REPLACE);
 | 
				
			||||||
		kvfree(data);
 | 
							kvfree(data);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -184,7 +184,8 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base,
 | 
				
			||||||
					const char *fqname, size_t n);
 | 
										const char *fqname, size_t n);
 | 
				
			||||||
struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name);
 | 
					struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace);
 | 
					ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size,
 | 
				
			||||||
 | 
								    bool noreplace);
 | 
				
			||||||
ssize_t aa_remove_profiles(char *name, size_t size);
 | 
					ssize_t aa_remove_profiles(char *name, size_t size);
 | 
				
			||||||
void __aa_profile_list_release(struct list_head *head);
 | 
					void __aa_profile_list_release(struct list_head *head);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,7 +83,9 @@ void aa_free_ns_kref(struct kref *kref);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name);
 | 
					struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name);
 | 
				
			||||||
struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n);
 | 
					struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n);
 | 
				
			||||||
struct aa_ns *aa_prepare_ns(const char *name);
 | 
					struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,
 | 
				
			||||||
 | 
									     struct dentry *dir);
 | 
				
			||||||
 | 
					struct aa_ns *aa_prepare_ns(struct aa_ns *root, const char *name);
 | 
				
			||||||
void __aa_remove_ns(struct aa_ns *ns);
 | 
					void __aa_remove_ns(struct aa_ns *ns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct aa_profile *aa_deref_parent(struct aa_profile *p)
 | 
					static inline struct aa_profile *aa_deref_parent(struct aa_profile *p)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -731,6 +731,7 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * aa_replace_profiles - replace profile(s) on the profile list
 | 
					 * aa_replace_profiles - replace profile(s) on the profile list
 | 
				
			||||||
 | 
					 * @view: namespace load is viewed from
 | 
				
			||||||
 * @udata: serialized data stream  (NOT NULL)
 | 
					 * @udata: serialized data stream  (NOT NULL)
 | 
				
			||||||
 * @size: size of the serialized data stream
 | 
					 * @size: size of the serialized data stream
 | 
				
			||||||
 * @noreplace: true if only doing addition, no replacement allowed
 | 
					 * @noreplace: true if only doing addition, no replacement allowed
 | 
				
			||||||
| 
						 | 
					@ -741,7 +742,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns: size of data consumed else error code on failure.
 | 
					 * Returns: size of data consumed else error code on failure.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
 | 
					ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size,
 | 
				
			||||||
 | 
								    bool noreplace)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *ns_name, *info = NULL;
 | 
						const char *ns_name, *info = NULL;
 | 
				
			||||||
	struct aa_ns *ns = NULL;
 | 
						struct aa_ns *ns = NULL;
 | 
				
			||||||
| 
						 | 
					@ -756,7 +758,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* released below */
 | 
						/* released below */
 | 
				
			||||||
	ns = aa_prepare_ns(ns_name);
 | 
						ns = aa_prepare_ns(view, ns_name);
 | 
				
			||||||
	if (!ns) {
 | 
						if (!ns) {
 | 
				
			||||||
		error = audit_policy(op, GFP_KERNEL, ns_name,
 | 
							error = audit_policy(op, GFP_KERNEL, ns_name,
 | 
				
			||||||
				     "failed to prepare namespace", -ENOMEM);
 | 
									     "failed to prepare namespace", -ENOMEM);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -181,48 +181,82 @@ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name)
 | 
				
			||||||
	return aa_findn_ns(root, name, strlen(name));
 | 
						return aa_findn_ns(root, name, strlen(name));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,
 | 
				
			||||||
 * aa_prepare_ns - find an existing or create a new namespace of @name
 | 
									    struct dentry *dir)
 | 
				
			||||||
 * @name: the namespace to find or add  (MAYBE NULL)
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns: refcounted ns or NULL if failed to create one
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct aa_ns *aa_prepare_ns(const char *name)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct aa_ns *ns, *root;
 | 
						struct aa_ns *ns;
 | 
				
			||||||
 | 
						int error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	root = aa_current_profile()->ns;
 | 
						AA_BUG(!parent);
 | 
				
			||||||
 | 
						AA_BUG(!name);
 | 
				
			||||||
 | 
						AA_BUG(!mutex_is_locked(&parent->lock));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&root->lock);
 | 
						ns = alloc_ns(parent->base.hname, name);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* if name isn't specified the profile is loaded to the current ns */
 | 
					 | 
				
			||||||
	if (!name) {
 | 
					 | 
				
			||||||
		/* released by caller */
 | 
					 | 
				
			||||||
		ns = aa_get_ns(root);
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* try and find the specified ns and if it doesn't exist create it */
 | 
					 | 
				
			||||||
	/* released by caller */
 | 
					 | 
				
			||||||
	ns = aa_get_ns(__aa_find_ns(&root->sub_ns, name));
 | 
					 | 
				
			||||||
	if (!ns) {
 | 
					 | 
				
			||||||
		ns = alloc_ns(root->base.hname, name);
 | 
					 | 
				
			||||||
	if (!ns)
 | 
						if (!ns)
 | 
				
			||||||
			goto out;
 | 
							return NULL;
 | 
				
			||||||
		if (__aa_fs_ns_mkdir(ns, ns_subns_dir(root), name)) {
 | 
						mutex_lock(&ns->lock);
 | 
				
			||||||
 | 
						error = __aa_fs_ns_mkdir(ns, ns_subns_dir(parent), name);
 | 
				
			||||||
 | 
						if (error) {
 | 
				
			||||||
		AA_ERROR("Failed to create interface for ns %s\n",
 | 
							AA_ERROR("Failed to create interface for ns %s\n",
 | 
				
			||||||
			 ns->base.name);
 | 
								 ns->base.name);
 | 
				
			||||||
 | 
							mutex_unlock(&ns->lock);
 | 
				
			||||||
		aa_free_ns(ns);
 | 
							aa_free_ns(ns);
 | 
				
			||||||
			ns = NULL;
 | 
							return ERR_PTR(error);
 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		ns->parent = aa_get_ns(root);
 | 
						ns->parent = aa_get_ns(parent);
 | 
				
			||||||
		list_add_rcu(&ns->base.list, &root->sub_ns);
 | 
						list_add_rcu(&ns->base.list, &parent->sub_ns);
 | 
				
			||||||
	/* add list ref */
 | 
						/* add list ref */
 | 
				
			||||||
	aa_get_ns(ns);
 | 
						aa_get_ns(ns);
 | 
				
			||||||
	}
 | 
						mutex_unlock(&ns->lock);
 | 
				
			||||||
out:
 | 
					
 | 
				
			||||||
	mutex_unlock(&root->lock);
 | 
						return ns;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * aa_create_ns - create an ns, fail if it already exists
 | 
				
			||||||
 | 
					 * @parent: the parent of the namespace being created
 | 
				
			||||||
 | 
					 * @name: the name of the namespace
 | 
				
			||||||
 | 
					 * @dir: if not null the dir to put the ns entries in
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: the a refcounted ns that has been add or an ERR_PTR
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,
 | 
				
			||||||
 | 
									     struct dentry *dir)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct aa_ns *ns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AA_BUG(!mutex_is_locked(&parent->lock));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* try and find the specified ns */
 | 
				
			||||||
 | 
						/* released by caller */
 | 
				
			||||||
 | 
						ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name));
 | 
				
			||||||
 | 
						if (!ns)
 | 
				
			||||||
 | 
							ns = __aa_create_ns(parent, name, dir);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							ns = ERR_PTR(-EEXIST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* return ref */
 | 
				
			||||||
 | 
						return ns;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * aa_prepare_ns - find an existing or create a new namespace of @name
 | 
				
			||||||
 | 
					 * @parent: ns to treat as parent
 | 
				
			||||||
 | 
					 * @name: the namespace to find or add  (NOT NULL)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: refcounted namespace or PTR_ERR if failed to create one
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct aa_ns *aa_prepare_ns(struct aa_ns *parent, const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct aa_ns *ns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&parent->lock);
 | 
				
			||||||
 | 
						/* try and find the specified ns and if it doesn't exist create it */
 | 
				
			||||||
 | 
						/* released by caller */
 | 
				
			||||||
 | 
						ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name));
 | 
				
			||||||
 | 
						if (!ns)
 | 
				
			||||||
 | 
							ns = __aa_create_ns(parent, name, NULL);
 | 
				
			||||||
 | 
						mutex_unlock(&parent->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* return ref */
 | 
						/* return ref */
 | 
				
			||||||
	return ns;
 | 
						return ns;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue