163e2b423SJohn Johansen /*
263e2b423SJohn Johansen  * AppArmor security module
363e2b423SJohn Johansen  *
463e2b423SJohn Johansen  * This file contains AppArmor /sys/kernel/security/apparmor interface functions
563e2b423SJohn Johansen  *
663e2b423SJohn Johansen  * Copyright (C) 1998-2008 Novell/SUSE
763e2b423SJohn Johansen  * Copyright 2009-2010 Canonical Ltd.
863e2b423SJohn Johansen  *
963e2b423SJohn Johansen  * This program is free software; you can redistribute it and/or
1063e2b423SJohn Johansen  * modify it under the terms of the GNU General Public License as
1163e2b423SJohn Johansen  * published by the Free Software Foundation, version 2 of the
1263e2b423SJohn Johansen  * License.
1363e2b423SJohn Johansen  */
1463e2b423SJohn Johansen 
150d259f04SJohn Johansen #include <linux/ctype.h>
1663e2b423SJohn Johansen #include <linux/security.h>
1763e2b423SJohn Johansen #include <linux/vmalloc.h>
1863e2b423SJohn Johansen #include <linux/module.h>
1963e2b423SJohn Johansen #include <linux/seq_file.h>
2063e2b423SJohn Johansen #include <linux/uaccess.h>
21a71ada30SJohn Johansen #include <linux/mount.h>
2263e2b423SJohn Johansen #include <linux/namei.h>
23e74abcf3SKees Cook #include <linux/capability.h>
2429b3822fSJohn Johansen #include <linux/rcupdate.h>
25a71ada30SJohn Johansen #include <linux/fs.h>
26a481f4d9SJohn Johansen #include <uapi/linux/major.h>
27a481f4d9SJohn Johansen #include <uapi/linux/magic.h>
2863e2b423SJohn Johansen 
2963e2b423SJohn Johansen #include "include/apparmor.h"
3063e2b423SJohn Johansen #include "include/apparmorfs.h"
3163e2b423SJohn Johansen #include "include/audit.h"
3263e2b423SJohn Johansen #include "include/context.h"
33f8eb8a13SJohn Johansen #include "include/crypto.h"
3463e2b423SJohn Johansen #include "include/policy.h"
35cff281f6SJohn Johansen #include "include/policy_ns.h"
36d384b0a1SKees Cook #include "include/resource.h"
375ac8c355SJohn Johansen #include "include/policy_unpack.h"
3863e2b423SJohn Johansen 
3963e2b423SJohn Johansen /**
400d259f04SJohn Johansen  * aa_mangle_name - mangle a profile name to std profile layout form
410d259f04SJohn Johansen  * @name: profile name to mangle  (NOT NULL)
420d259f04SJohn Johansen  * @target: buffer to store mangled name, same length as @name (MAYBE NULL)
430d259f04SJohn Johansen  *
440d259f04SJohn Johansen  * Returns: length of mangled name
450d259f04SJohn Johansen  */
46bbe4a7c8SJohn Johansen static int mangle_name(const char *name, char *target)
470d259f04SJohn Johansen {
480d259f04SJohn Johansen 	char *t = target;
490d259f04SJohn Johansen 
500d259f04SJohn Johansen 	while (*name == '/' || *name == '.')
510d259f04SJohn Johansen 		name++;
520d259f04SJohn Johansen 
530d259f04SJohn Johansen 	if (target) {
540d259f04SJohn Johansen 		for (; *name; name++) {
550d259f04SJohn Johansen 			if (*name == '/')
560d259f04SJohn Johansen 				*(t)++ = '.';
570d259f04SJohn Johansen 			else if (isspace(*name))
580d259f04SJohn Johansen 				*(t)++ = '_';
590d259f04SJohn Johansen 			else if (isalnum(*name) || strchr("._-", *name))
600d259f04SJohn Johansen 				*(t)++ = *name;
610d259f04SJohn Johansen 		}
620d259f04SJohn Johansen 
630d259f04SJohn Johansen 		*t = 0;
640d259f04SJohn Johansen 	} else {
650d259f04SJohn Johansen 		int len = 0;
660d259f04SJohn Johansen 		for (; *name; name++) {
670d259f04SJohn Johansen 			if (isalnum(*name) || isspace(*name) ||
680d259f04SJohn Johansen 			    strchr("/._-", *name))
690d259f04SJohn Johansen 				len++;
700d259f04SJohn Johansen 		}
710d259f04SJohn Johansen 
720d259f04SJohn Johansen 		return len;
730d259f04SJohn Johansen 	}
740d259f04SJohn Johansen 
750d259f04SJohn Johansen 	return t - target;
760d259f04SJohn Johansen }
770d259f04SJohn Johansen 
78a481f4d9SJohn Johansen 
79a481f4d9SJohn Johansen /*
80a481f4d9SJohn Johansen  * aafs - core fns and data for the policy tree
81a481f4d9SJohn Johansen  */
82a481f4d9SJohn Johansen 
83a481f4d9SJohn Johansen #define AAFS_NAME		"apparmorfs"
84a481f4d9SJohn Johansen static struct vfsmount *aafs_mnt;
85a481f4d9SJohn Johansen static int aafs_count;
86a481f4d9SJohn Johansen 
87a481f4d9SJohn Johansen 
88a481f4d9SJohn Johansen static int aafs_show_path(struct seq_file *seq, struct dentry *dentry)
89a481f4d9SJohn Johansen {
90a481f4d9SJohn Johansen 	struct inode *inode = d_inode(dentry);
91a481f4d9SJohn Johansen 
92a481f4d9SJohn Johansen 	seq_printf(seq, "%s:[%lu]", AAFS_NAME, inode->i_ino);
93a481f4d9SJohn Johansen 	return 0;
94a481f4d9SJohn Johansen }
95a481f4d9SJohn Johansen 
96a481f4d9SJohn Johansen static void aafs_evict_inode(struct inode *inode)
97a481f4d9SJohn Johansen {
98a481f4d9SJohn Johansen 	truncate_inode_pages_final(&inode->i_data);
99a481f4d9SJohn Johansen 	clear_inode(inode);
100a481f4d9SJohn Johansen 	if (S_ISLNK(inode->i_mode))
101a481f4d9SJohn Johansen 		kfree(inode->i_link);
102a481f4d9SJohn Johansen }
103a481f4d9SJohn Johansen 
104a481f4d9SJohn Johansen static const struct super_operations aafs_super_ops = {
105a481f4d9SJohn Johansen 	.statfs = simple_statfs,
106a481f4d9SJohn Johansen 	.evict_inode = aafs_evict_inode,
107a481f4d9SJohn Johansen 	.show_path = aafs_show_path,
108a481f4d9SJohn Johansen };
109a481f4d9SJohn Johansen 
110a481f4d9SJohn Johansen static int fill_super(struct super_block *sb, void *data, int silent)
111a481f4d9SJohn Johansen {
112a481f4d9SJohn Johansen 	static struct tree_descr files[] = { {""} };
113a481f4d9SJohn Johansen 	int error;
114a481f4d9SJohn Johansen 
115a481f4d9SJohn Johansen 	error = simple_fill_super(sb, AAFS_MAGIC, files);
116a481f4d9SJohn Johansen 	if (error)
117a481f4d9SJohn Johansen 		return error;
118a481f4d9SJohn Johansen 	sb->s_op = &aafs_super_ops;
119a481f4d9SJohn Johansen 
120a481f4d9SJohn Johansen 	return 0;
121a481f4d9SJohn Johansen }
122a481f4d9SJohn Johansen 
123a481f4d9SJohn Johansen static struct dentry *aafs_mount(struct file_system_type *fs_type,
124a481f4d9SJohn Johansen 				 int flags, const char *dev_name, void *data)
125a481f4d9SJohn Johansen {
126a481f4d9SJohn Johansen 	return mount_single(fs_type, flags, data, fill_super);
127a481f4d9SJohn Johansen }
128a481f4d9SJohn Johansen 
129a481f4d9SJohn Johansen static struct file_system_type aafs_ops = {
130a481f4d9SJohn Johansen 	.owner = THIS_MODULE,
131a481f4d9SJohn Johansen 	.name = AAFS_NAME,
132a481f4d9SJohn Johansen 	.mount = aafs_mount,
133a481f4d9SJohn Johansen 	.kill_sb = kill_anon_super,
134a481f4d9SJohn Johansen };
135a481f4d9SJohn Johansen 
136a481f4d9SJohn Johansen /**
137a481f4d9SJohn Johansen  * __aafs_setup_d_inode - basic inode setup for apparmorfs
138a481f4d9SJohn Johansen  * @dir: parent directory for the dentry
139a481f4d9SJohn Johansen  * @dentry: dentry we are seting the inode up for
140a481f4d9SJohn Johansen  * @mode: permissions the file should have
141a481f4d9SJohn Johansen  * @data: data to store on inode.i_private, available in open()
142a481f4d9SJohn Johansen  * @link: if symlink, symlink target string
143a481f4d9SJohn Johansen  * @fops: struct file_operations that should be used
144a481f4d9SJohn Johansen  * @iops: struct of inode_operations that should be used
145a481f4d9SJohn Johansen  */
146a481f4d9SJohn Johansen static int __aafs_setup_d_inode(struct inode *dir, struct dentry *dentry,
147a481f4d9SJohn Johansen 			       umode_t mode, void *data, char *link,
148a481f4d9SJohn Johansen 			       const struct file_operations *fops,
149a481f4d9SJohn Johansen 			       const struct inode_operations *iops)
150a481f4d9SJohn Johansen {
151a481f4d9SJohn Johansen 	struct inode *inode = new_inode(dir->i_sb);
152a481f4d9SJohn Johansen 
153a481f4d9SJohn Johansen 	AA_BUG(!dir);
154a481f4d9SJohn Johansen 	AA_BUG(!dentry);
155a481f4d9SJohn Johansen 
156a481f4d9SJohn Johansen 	if (!inode)
157a481f4d9SJohn Johansen 		return -ENOMEM;
158a481f4d9SJohn Johansen 
159a481f4d9SJohn Johansen 	inode->i_ino = get_next_ino();
160a481f4d9SJohn Johansen 	inode->i_mode = mode;
161a481f4d9SJohn Johansen 	inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
162a481f4d9SJohn Johansen 	inode->i_private = data;
163a481f4d9SJohn Johansen 	if (S_ISDIR(mode)) {
164a481f4d9SJohn Johansen 		inode->i_op = iops ? iops : &simple_dir_inode_operations;
165a481f4d9SJohn Johansen 		inode->i_fop = &simple_dir_operations;
166a481f4d9SJohn Johansen 		inc_nlink(inode);
167a481f4d9SJohn Johansen 		inc_nlink(dir);
168a481f4d9SJohn Johansen 	} else if (S_ISLNK(mode)) {
169a481f4d9SJohn Johansen 		inode->i_op = iops ? iops : &simple_symlink_inode_operations;
170a481f4d9SJohn Johansen 		inode->i_link = link;
171a481f4d9SJohn Johansen 	} else {
172a481f4d9SJohn Johansen 		inode->i_fop = fops;
173a481f4d9SJohn Johansen 	}
174a481f4d9SJohn Johansen 	d_instantiate(dentry, inode);
175a481f4d9SJohn Johansen 	dget(dentry);
176a481f4d9SJohn Johansen 
177a481f4d9SJohn Johansen 	return 0;
178a481f4d9SJohn Johansen }
179a481f4d9SJohn Johansen 
180a481f4d9SJohn Johansen /**
181a481f4d9SJohn Johansen  * aafs_create - create a dentry in the apparmorfs filesystem
182a481f4d9SJohn Johansen  *
183a481f4d9SJohn Johansen  * @name: name of dentry to create
184a481f4d9SJohn Johansen  * @mode: permissions the file should have
185a481f4d9SJohn Johansen  * @parent: parent directory for this dentry
186a481f4d9SJohn Johansen  * @data: data to store on inode.i_private, available in open()
187a481f4d9SJohn Johansen  * @link: if symlink, symlink target string
188a481f4d9SJohn Johansen  * @fops: struct file_operations that should be used for
189a481f4d9SJohn Johansen  * @iops: struct of inode_operations that should be used
190a481f4d9SJohn Johansen  *
191a481f4d9SJohn Johansen  * This is the basic "create a xxx" function for apparmorfs.
192a481f4d9SJohn Johansen  *
193a481f4d9SJohn Johansen  * Returns a pointer to a dentry if it succeeds, that must be free with
194a481f4d9SJohn Johansen  * aafs_remove(). Will return ERR_PTR on failure.
195a481f4d9SJohn Johansen  */
196a481f4d9SJohn Johansen static struct dentry *aafs_create(const char *name, umode_t mode,
197a481f4d9SJohn Johansen 				  struct dentry *parent, void *data, void *link,
198a481f4d9SJohn Johansen 				  const struct file_operations *fops,
199a481f4d9SJohn Johansen 				  const struct inode_operations *iops)
200a481f4d9SJohn Johansen {
201a481f4d9SJohn Johansen 	struct dentry *dentry;
202a481f4d9SJohn Johansen 	struct inode *dir;
203a481f4d9SJohn Johansen 	int error;
204a481f4d9SJohn Johansen 
205a481f4d9SJohn Johansen 	AA_BUG(!name);
206a481f4d9SJohn Johansen 	AA_BUG(!parent);
207a481f4d9SJohn Johansen 
208a481f4d9SJohn Johansen 	if (!(mode & S_IFMT))
209a481f4d9SJohn Johansen 		mode = (mode & S_IALLUGO) | S_IFREG;
210a481f4d9SJohn Johansen 
211a481f4d9SJohn Johansen 	error = simple_pin_fs(&aafs_ops, &aafs_mnt, &aafs_count);
212a481f4d9SJohn Johansen 	if (error)
213a481f4d9SJohn Johansen 		return ERR_PTR(error);
214a481f4d9SJohn Johansen 
215a481f4d9SJohn Johansen 	dir = d_inode(parent);
216a481f4d9SJohn Johansen 
217a481f4d9SJohn Johansen 	inode_lock(dir);
218a481f4d9SJohn Johansen 	dentry = lookup_one_len(name, parent, strlen(name));
219a481f4d9SJohn Johansen 	if (IS_ERR(dentry))
220a481f4d9SJohn Johansen 		goto fail_lock;
221a481f4d9SJohn Johansen 
222a481f4d9SJohn Johansen 	if (d_really_is_positive(dentry)) {
223a481f4d9SJohn Johansen 		error = -EEXIST;
224a481f4d9SJohn Johansen 		goto fail_dentry;
225a481f4d9SJohn Johansen 	}
226a481f4d9SJohn Johansen 
227a481f4d9SJohn Johansen 	error = __aafs_setup_d_inode(dir, dentry, mode, data, link, fops, iops);
228a481f4d9SJohn Johansen 	if (error)
229a481f4d9SJohn Johansen 		goto fail_dentry;
230a481f4d9SJohn Johansen 	inode_unlock(dir);
231a481f4d9SJohn Johansen 
232a481f4d9SJohn Johansen 	return dentry;
233a481f4d9SJohn Johansen 
234a481f4d9SJohn Johansen fail_dentry:
235a481f4d9SJohn Johansen 	dput(dentry);
236a481f4d9SJohn Johansen 
237a481f4d9SJohn Johansen fail_lock:
238a481f4d9SJohn Johansen 	inode_unlock(dir);
239a481f4d9SJohn Johansen 	simple_release_fs(&aafs_mnt, &aafs_count);
240a481f4d9SJohn Johansen 
241a481f4d9SJohn Johansen 	return ERR_PTR(error);
242a481f4d9SJohn Johansen }
243a481f4d9SJohn Johansen 
244a481f4d9SJohn Johansen /**
245a481f4d9SJohn Johansen  * aafs_create_file - create a file in the apparmorfs filesystem
246a481f4d9SJohn Johansen  *
247a481f4d9SJohn Johansen  * @name: name of dentry to create
248a481f4d9SJohn Johansen  * @mode: permissions the file should have
249a481f4d9SJohn Johansen  * @parent: parent directory for this dentry
250a481f4d9SJohn Johansen  * @data: data to store on inode.i_private, available in open()
251a481f4d9SJohn Johansen  * @fops: struct file_operations that should be used for
252a481f4d9SJohn Johansen  *
253a481f4d9SJohn Johansen  * see aafs_create
254a481f4d9SJohn Johansen  */
255a481f4d9SJohn Johansen static struct dentry *aafs_create_file(const char *name, umode_t mode,
256a481f4d9SJohn Johansen 				       struct dentry *parent, void *data,
257a481f4d9SJohn Johansen 				       const struct file_operations *fops)
258a481f4d9SJohn Johansen {
259a481f4d9SJohn Johansen 	return aafs_create(name, mode, parent, data, NULL, fops, NULL);
260a481f4d9SJohn Johansen }
261a481f4d9SJohn Johansen 
262a481f4d9SJohn Johansen /**
263a481f4d9SJohn Johansen  * aafs_create_dir - create a directory in the apparmorfs filesystem
264a481f4d9SJohn Johansen  *
265a481f4d9SJohn Johansen  * @name: name of dentry to create
266a481f4d9SJohn Johansen  * @parent: parent directory for this dentry
267a481f4d9SJohn Johansen  *
268a481f4d9SJohn Johansen  * see aafs_create
269a481f4d9SJohn Johansen  */
270a481f4d9SJohn Johansen static struct dentry *aafs_create_dir(const char *name, struct dentry *parent)
271a481f4d9SJohn Johansen {
272a481f4d9SJohn Johansen 	return aafs_create(name, S_IFDIR | 0755, parent, NULL, NULL, NULL,
273a481f4d9SJohn Johansen 			   NULL);
274a481f4d9SJohn Johansen }
275a481f4d9SJohn Johansen 
276a481f4d9SJohn Johansen /**
277a481f4d9SJohn Johansen  * aafs_create_symlink - create a symlink in the apparmorfs filesystem
278a481f4d9SJohn Johansen  * @name: name of dentry to create
279a481f4d9SJohn Johansen  * @parent: parent directory for this dentry
280a481f4d9SJohn Johansen  * @target: if symlink, symlink target string
281a481f4d9SJohn Johansen  * @iops: struct of inode_operations that should be used
282a481f4d9SJohn Johansen  *
283a481f4d9SJohn Johansen  * If @target parameter is %NULL, then the @iops parameter needs to be
284a481f4d9SJohn Johansen  * setup to handle .readlink and .get_link inode_operations.
285a481f4d9SJohn Johansen  */
286a481f4d9SJohn Johansen static struct dentry *aafs_create_symlink(const char *name,
287a481f4d9SJohn Johansen 					  struct dentry *parent,
288a481f4d9SJohn Johansen 					  const char *target,
289a481f4d9SJohn Johansen 					  const struct inode_operations *iops)
290a481f4d9SJohn Johansen {
291a481f4d9SJohn Johansen 	struct dentry *dent;
292a481f4d9SJohn Johansen 	char *link = NULL;
293a481f4d9SJohn Johansen 
294a481f4d9SJohn Johansen 	if (target) {
295a481f4d9SJohn Johansen 		link = kstrdup(target, GFP_KERNEL);
296a481f4d9SJohn Johansen 		if (!link)
297a481f4d9SJohn Johansen 			return ERR_PTR(-ENOMEM);
298a481f4d9SJohn Johansen 	}
299a481f4d9SJohn Johansen 	dent = aafs_create(name, S_IFLNK | 0444, parent, NULL, link, NULL,
300a481f4d9SJohn Johansen 			   iops);
301a481f4d9SJohn Johansen 	if (IS_ERR(dent))
302a481f4d9SJohn Johansen 		kfree(link);
303a481f4d9SJohn Johansen 
304a481f4d9SJohn Johansen 	return dent;
305a481f4d9SJohn Johansen }
306a481f4d9SJohn Johansen 
307a481f4d9SJohn Johansen /**
308a481f4d9SJohn Johansen  * aafs_remove - removes a file or directory from the apparmorfs filesystem
309a481f4d9SJohn Johansen  *
310a481f4d9SJohn Johansen  * @dentry: dentry of the file/directory/symlink to removed.
311a481f4d9SJohn Johansen  */
312a481f4d9SJohn Johansen static void aafs_remove(struct dentry *dentry)
313a481f4d9SJohn Johansen {
314a481f4d9SJohn Johansen 	struct inode *dir;
315a481f4d9SJohn Johansen 
316a481f4d9SJohn Johansen 	if (!dentry || IS_ERR(dentry))
317a481f4d9SJohn Johansen 		return;
318a481f4d9SJohn Johansen 
319a481f4d9SJohn Johansen 	dir = d_inode(dentry->d_parent);
320a481f4d9SJohn Johansen 	inode_lock(dir);
321a481f4d9SJohn Johansen 	if (simple_positive(dentry)) {
322a481f4d9SJohn Johansen 		if (d_is_dir(dentry))
323a481f4d9SJohn Johansen 			simple_rmdir(dir, dentry);
324a481f4d9SJohn Johansen 		else
325a481f4d9SJohn Johansen 			simple_unlink(dir, dentry);
326a481f4d9SJohn Johansen 		dput(dentry);
327a481f4d9SJohn Johansen 	}
328a481f4d9SJohn Johansen 	inode_unlock(dir);
329a481f4d9SJohn Johansen 	simple_release_fs(&aafs_mnt, &aafs_count);
330a481f4d9SJohn Johansen }
331a481f4d9SJohn Johansen 
332a481f4d9SJohn Johansen 
333a481f4d9SJohn Johansen /*
334a481f4d9SJohn Johansen  * aa_fs - policy load/replace/remove
335a481f4d9SJohn Johansen  */
336a481f4d9SJohn Johansen 
3370d259f04SJohn Johansen /**
33863e2b423SJohn Johansen  * aa_simple_write_to_buffer - common routine for getting policy from user
33963e2b423SJohn Johansen  * @userbuf: user buffer to copy data from  (NOT NULL)
3403ed02adaSJohn Johansen  * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size)
34163e2b423SJohn Johansen  * @copy_size: size of data to copy from user buffer
34263e2b423SJohn Johansen  * @pos: position write is at in the file (NOT NULL)
34363e2b423SJohn Johansen  *
34463e2b423SJohn Johansen  * Returns: kernel buffer containing copy of user buffer data or an
34563e2b423SJohn Johansen  *          ERR_PTR on failure.
34663e2b423SJohn Johansen  */
3475ef50d01SJohn Johansen static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf,
3485ac8c355SJohn Johansen 						     size_t alloc_size,
3495ac8c355SJohn Johansen 						     size_t copy_size,
35063e2b423SJohn Johansen 						     loff_t *pos)
35163e2b423SJohn Johansen {
3525ac8c355SJohn Johansen 	struct aa_loaddata *data;
35363e2b423SJohn Johansen 
354e6bfa25dSJohn Johansen 	AA_BUG(copy_size > alloc_size);
3553ed02adaSJohn Johansen 
35663e2b423SJohn Johansen 	if (*pos != 0)
35763e2b423SJohn Johansen 		/* only writes from pos 0, that is complete writes */
35863e2b423SJohn Johansen 		return ERR_PTR(-ESPIPE);
35963e2b423SJohn Johansen 
36063e2b423SJohn Johansen 	/* freed by caller to simple_write_to_buffer */
3615d5182caSJohn Johansen 	data = aa_loaddata_alloc(alloc_size);
3625d5182caSJohn Johansen 	if (IS_ERR(data))
3635d5182caSJohn Johansen 		return data;
36463e2b423SJohn Johansen 
3655d5182caSJohn Johansen 	data->size = copy_size;
3665ac8c355SJohn Johansen 	if (copy_from_user(data->data, userbuf, copy_size)) {
36763e2b423SJohn Johansen 		kvfree(data);
36863e2b423SJohn Johansen 		return ERR_PTR(-EFAULT);
36963e2b423SJohn Johansen 	}
37063e2b423SJohn Johansen 
37163e2b423SJohn Johansen 	return data;
37263e2b423SJohn Johansen }
37363e2b423SJohn Johansen 
3745ac8c355SJohn Johansen static ssize_t policy_update(int binop, const char __user *buf, size_t size,
375b7fd2c03SJohn Johansen 			     loff_t *pos, struct aa_ns *ns)
3765ac8c355SJohn Johansen {
3775ac8c355SJohn Johansen 	ssize_t error;
3785ac8c355SJohn Johansen 	struct aa_loaddata *data;
3795ac8c355SJohn Johansen 	struct aa_profile *profile = aa_current_profile();
38047f6e5ccSJohn Johansen 	const char *op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL;
3815ac8c355SJohn Johansen 	/* high level check about policy management - fine grained in
3825ac8c355SJohn Johansen 	 * below after unpack
3835ac8c355SJohn Johansen 	 */
384b7fd2c03SJohn Johansen 	error = aa_may_manage_policy(profile, ns, op);
3855ac8c355SJohn Johansen 	if (error)
3865ac8c355SJohn Johansen 		return error;
38763e2b423SJohn Johansen 
3885ef50d01SJohn Johansen 	data = aa_simple_write_to_buffer(buf, size, size, pos);
3895ac8c355SJohn Johansen 	error = PTR_ERR(data);
3905ac8c355SJohn Johansen 	if (!IS_ERR(data)) {
391b7fd2c03SJohn Johansen 		error = aa_replace_profiles(ns ? ns : profile->ns, profile,
392b7fd2c03SJohn Johansen 					    binop, data);
3935ac8c355SJohn Johansen 		aa_put_loaddata(data);
3945ac8c355SJohn Johansen 	}
3955ac8c355SJohn Johansen 
3965ac8c355SJohn Johansen 	return error;
3975ac8c355SJohn Johansen }
3985ac8c355SJohn Johansen 
399b7fd2c03SJohn Johansen /* .load file hook fn to load policy */
40063e2b423SJohn Johansen static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
40163e2b423SJohn Johansen 			    loff_t *pos)
40263e2b423SJohn Johansen {
403b7fd2c03SJohn Johansen 	struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
404b7fd2c03SJohn Johansen 	int error = policy_update(PROF_ADD, buf, size, pos, ns);
405b7fd2c03SJohn Johansen 
406b7fd2c03SJohn Johansen 	aa_put_ns(ns);
40763e2b423SJohn Johansen 
40863e2b423SJohn Johansen 	return error;
40963e2b423SJohn Johansen }
41063e2b423SJohn Johansen 
41163e2b423SJohn Johansen static const struct file_operations aa_fs_profile_load = {
4126038f373SArnd Bergmann 	.write = profile_load,
4136038f373SArnd Bergmann 	.llseek = default_llseek,
41463e2b423SJohn Johansen };
41563e2b423SJohn Johansen 
41663e2b423SJohn Johansen /* .replace file hook fn to load and/or replace policy */
41763e2b423SJohn Johansen static ssize_t profile_replace(struct file *f, const char __user *buf,
41863e2b423SJohn Johansen 			       size_t size, loff_t *pos)
41963e2b423SJohn Johansen {
420b7fd2c03SJohn Johansen 	struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
421b7fd2c03SJohn Johansen 	int error = policy_update(PROF_REPLACE, buf, size, pos, ns);
422b7fd2c03SJohn Johansen 
423b7fd2c03SJohn Johansen 	aa_put_ns(ns);
42463e2b423SJohn Johansen 
42563e2b423SJohn Johansen 	return error;
42663e2b423SJohn Johansen }
42763e2b423SJohn Johansen 
42863e2b423SJohn Johansen static const struct file_operations aa_fs_profile_replace = {
4296038f373SArnd Bergmann 	.write = profile_replace,
4306038f373SArnd Bergmann 	.llseek = default_llseek,
43163e2b423SJohn Johansen };
43263e2b423SJohn Johansen 
433b7fd2c03SJohn Johansen /* .remove file hook fn to remove loaded policy */
43463e2b423SJohn Johansen static ssize_t profile_remove(struct file *f, const char __user *buf,
43563e2b423SJohn Johansen 			      size_t size, loff_t *pos)
43663e2b423SJohn Johansen {
4375ac8c355SJohn Johansen 	struct aa_loaddata *data;
4385ac8c355SJohn Johansen 	struct aa_profile *profile;
43963e2b423SJohn Johansen 	ssize_t error;
440b7fd2c03SJohn Johansen 	struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
44163e2b423SJohn Johansen 
4425ac8c355SJohn Johansen 	profile = aa_current_profile();
4435ac8c355SJohn Johansen 	/* high level check about policy management - fine grained in
4445ac8c355SJohn Johansen 	 * below after unpack
4455ac8c355SJohn Johansen 	 */
446b7fd2c03SJohn Johansen 	error = aa_may_manage_policy(profile, ns, OP_PROF_RM);
4475ac8c355SJohn Johansen 	if (error)
4485ac8c355SJohn Johansen 		goto out;
4495ac8c355SJohn Johansen 
45063e2b423SJohn Johansen 	/*
45163e2b423SJohn Johansen 	 * aa_remove_profile needs a null terminated string so 1 extra
45263e2b423SJohn Johansen 	 * byte is allocated and the copied data is null terminated.
45363e2b423SJohn Johansen 	 */
4545ef50d01SJohn Johansen 	data = aa_simple_write_to_buffer(buf, size + 1, size, pos);
45563e2b423SJohn Johansen 
45663e2b423SJohn Johansen 	error = PTR_ERR(data);
45763e2b423SJohn Johansen 	if (!IS_ERR(data)) {
4585ac8c355SJohn Johansen 		data->data[size] = 0;
459b7fd2c03SJohn Johansen 		error = aa_remove_profiles(ns ? ns : profile->ns, profile,
460b7fd2c03SJohn Johansen 					   data->data, size);
4615ac8c355SJohn Johansen 		aa_put_loaddata(data);
46263e2b423SJohn Johansen 	}
4635ac8c355SJohn Johansen  out:
464b7fd2c03SJohn Johansen 	aa_put_ns(ns);
46563e2b423SJohn Johansen 	return error;
46663e2b423SJohn Johansen }
46763e2b423SJohn Johansen 
46863e2b423SJohn Johansen static const struct file_operations aa_fs_profile_remove = {
4696038f373SArnd Bergmann 	.write = profile_remove,
4706038f373SArnd Bergmann 	.llseek = default_llseek,
47163e2b423SJohn Johansen };
47263e2b423SJohn Johansen 
4735d5182caSJohn Johansen void __aa_bump_ns_revision(struct aa_ns *ns)
4745d5182caSJohn Johansen {
4755d5182caSJohn Johansen 	ns->revision++;
4765d5182caSJohn Johansen }
4775d5182caSJohn Johansen 
478e025be0fSWilliam Hua /**
479e025be0fSWilliam Hua  * query_data - queries a policy and writes its data to buf
480e025be0fSWilliam Hua  * @buf: the resulting data is stored here (NOT NULL)
481e025be0fSWilliam Hua  * @buf_len: size of buf
482e025be0fSWilliam Hua  * @query: query string used to retrieve data
483e025be0fSWilliam Hua  * @query_len: size of query including second NUL byte
484e025be0fSWilliam Hua  *
485e025be0fSWilliam Hua  * The buffers pointed to by buf and query may overlap. The query buffer is
486e025be0fSWilliam Hua  * parsed before buf is written to.
487e025be0fSWilliam Hua  *
488e025be0fSWilliam Hua  * The query should look like "<LABEL>\0<KEY>\0", where <LABEL> is the name of
489e025be0fSWilliam Hua  * the security confinement context and <KEY> is the name of the data to
490e025be0fSWilliam Hua  * retrieve. <LABEL> and <KEY> must not be NUL-terminated.
491e025be0fSWilliam Hua  *
492e025be0fSWilliam Hua  * Don't expect the contents of buf to be preserved on failure.
493e025be0fSWilliam Hua  *
494e025be0fSWilliam Hua  * Returns: number of characters written to buf or -errno on failure
495e025be0fSWilliam Hua  */
496e025be0fSWilliam Hua static ssize_t query_data(char *buf, size_t buf_len,
497e025be0fSWilliam Hua 			  char *query, size_t query_len)
498e025be0fSWilliam Hua {
499e025be0fSWilliam Hua 	char *out;
500e025be0fSWilliam Hua 	const char *key;
501e025be0fSWilliam Hua 	struct aa_profile *profile;
502e025be0fSWilliam Hua 	struct aa_data *data;
503e025be0fSWilliam Hua 	u32 bytes, blocks;
504e025be0fSWilliam Hua 	__le32 outle32;
505e025be0fSWilliam Hua 
506e025be0fSWilliam Hua 	if (!query_len)
507e025be0fSWilliam Hua 		return -EINVAL; /* need a query */
508e025be0fSWilliam Hua 
509e025be0fSWilliam Hua 	key = query + strnlen(query, query_len) + 1;
510e025be0fSWilliam Hua 	if (key + 1 >= query + query_len)
511e025be0fSWilliam Hua 		return -EINVAL; /* not enough space for a non-empty key */
512e025be0fSWilliam Hua 	if (key + strnlen(key, query + query_len - key) >= query + query_len)
513e025be0fSWilliam Hua 		return -EINVAL; /* must end with NUL */
514e025be0fSWilliam Hua 
515e025be0fSWilliam Hua 	if (buf_len < sizeof(bytes) + sizeof(blocks))
516e025be0fSWilliam Hua 		return -EINVAL; /* not enough space */
517e025be0fSWilliam Hua 
518e025be0fSWilliam Hua 	profile = aa_current_profile();
519e025be0fSWilliam Hua 
520e025be0fSWilliam Hua 	/* We are going to leave space for two numbers. The first is the total
521e025be0fSWilliam Hua 	 * number of bytes we are writing after the first number. This is so
522e025be0fSWilliam Hua 	 * users can read the full output without reallocation.
523e025be0fSWilliam Hua 	 *
524e025be0fSWilliam Hua 	 * The second number is the number of data blocks we're writing. An
525e025be0fSWilliam Hua 	 * application might be confined by multiple policies having data in
526e025be0fSWilliam Hua 	 * the same key.
527e025be0fSWilliam Hua 	 */
528e025be0fSWilliam Hua 	memset(buf, 0, sizeof(bytes) + sizeof(blocks));
529e025be0fSWilliam Hua 	out = buf + sizeof(bytes) + sizeof(blocks);
530e025be0fSWilliam Hua 
531e025be0fSWilliam Hua 	blocks = 0;
532e025be0fSWilliam Hua 	if (profile->data) {
533e025be0fSWilliam Hua 		data = rhashtable_lookup_fast(profile->data, &key,
534e025be0fSWilliam Hua 					      profile->data->p);
535e025be0fSWilliam Hua 
536e025be0fSWilliam Hua 		if (data) {
537e025be0fSWilliam Hua 			if (out + sizeof(outle32) + data->size > buf + buf_len)
538e025be0fSWilliam Hua 				return -EINVAL; /* not enough space */
539e025be0fSWilliam Hua 			outle32 = __cpu_to_le32(data->size);
540e025be0fSWilliam Hua 			memcpy(out, &outle32, sizeof(outle32));
541e025be0fSWilliam Hua 			out += sizeof(outle32);
542e025be0fSWilliam Hua 			memcpy(out, data->data, data->size);
543e025be0fSWilliam Hua 			out += data->size;
544e025be0fSWilliam Hua 			blocks++;
545e025be0fSWilliam Hua 		}
546e025be0fSWilliam Hua 	}
547e025be0fSWilliam Hua 
548e025be0fSWilliam Hua 	outle32 = __cpu_to_le32(out - buf - sizeof(bytes));
549e025be0fSWilliam Hua 	memcpy(buf, &outle32, sizeof(outle32));
550e025be0fSWilliam Hua 	outle32 = __cpu_to_le32(blocks);
551e025be0fSWilliam Hua 	memcpy(buf + sizeof(bytes), &outle32, sizeof(outle32));
552e025be0fSWilliam Hua 
553e025be0fSWilliam Hua 	return out - buf;
554e025be0fSWilliam Hua }
555e025be0fSWilliam Hua 
556e025be0fSWilliam Hua #define QUERY_CMD_DATA		"data\0"
557e025be0fSWilliam Hua #define QUERY_CMD_DATA_LEN	5
558e025be0fSWilliam Hua 
559e025be0fSWilliam Hua /**
560e025be0fSWilliam Hua  * aa_write_access - generic permissions and data query
561e025be0fSWilliam Hua  * @file: pointer to open apparmorfs/access file
562e025be0fSWilliam Hua  * @ubuf: user buffer containing the complete query string (NOT NULL)
563e025be0fSWilliam Hua  * @count: size of ubuf
564e025be0fSWilliam Hua  * @ppos: position in the file (MUST BE ZERO)
565e025be0fSWilliam Hua  *
566e025be0fSWilliam Hua  * Allows for one permissions or data query per open(), write(), and read()
567e025be0fSWilliam Hua  * sequence. The only queries currently supported are label-based queries for
568e025be0fSWilliam Hua  * permissions or data.
569e025be0fSWilliam Hua  *
570e025be0fSWilliam Hua  * For permissions queries, ubuf must begin with "label\0", followed by the
571e025be0fSWilliam Hua  * profile query specific format described in the query_label() function
572e025be0fSWilliam Hua  * documentation.
573e025be0fSWilliam Hua  *
574e025be0fSWilliam Hua  * For data queries, ubuf must have the form "data\0<LABEL>\0<KEY>\0", where
575e025be0fSWilliam Hua  * <LABEL> is the name of the security confinement context and <KEY> is the
576e025be0fSWilliam Hua  * name of the data to retrieve.
577e025be0fSWilliam Hua  *
578e025be0fSWilliam Hua  * Returns: number of bytes written or -errno on failure
579e025be0fSWilliam Hua  */
580e025be0fSWilliam Hua static ssize_t aa_write_access(struct file *file, const char __user *ubuf,
581e025be0fSWilliam Hua 			       size_t count, loff_t *ppos)
582e025be0fSWilliam Hua {
583e025be0fSWilliam Hua 	char *buf;
584e025be0fSWilliam Hua 	ssize_t len;
585e025be0fSWilliam Hua 
586e025be0fSWilliam Hua 	if (*ppos)
587e025be0fSWilliam Hua 		return -ESPIPE;
588e025be0fSWilliam Hua 
589e025be0fSWilliam Hua 	buf = simple_transaction_get(file, ubuf, count);
590e025be0fSWilliam Hua 	if (IS_ERR(buf))
591e025be0fSWilliam Hua 		return PTR_ERR(buf);
592e025be0fSWilliam Hua 
593e025be0fSWilliam Hua 	if (count > QUERY_CMD_DATA_LEN &&
594e025be0fSWilliam Hua 		   !memcmp(buf, QUERY_CMD_DATA, QUERY_CMD_DATA_LEN)) {
595e025be0fSWilliam Hua 		len = query_data(buf, SIMPLE_TRANSACTION_LIMIT,
596e025be0fSWilliam Hua 				 buf + QUERY_CMD_DATA_LEN,
597e025be0fSWilliam Hua 				 count - QUERY_CMD_DATA_LEN);
598e025be0fSWilliam Hua 	} else
599e025be0fSWilliam Hua 		len = -EINVAL;
600e025be0fSWilliam Hua 
601e025be0fSWilliam Hua 	if (len < 0)
602e025be0fSWilliam Hua 		return len;
603e025be0fSWilliam Hua 
604e025be0fSWilliam Hua 	simple_transaction_set(file, len);
605e025be0fSWilliam Hua 
606e025be0fSWilliam Hua 	return count;
607e025be0fSWilliam Hua }
608e025be0fSWilliam Hua 
609e025be0fSWilliam Hua static const struct file_operations aa_fs_access = {
610e025be0fSWilliam Hua 	.write		= aa_write_access,
611e025be0fSWilliam Hua 	.read		= simple_transaction_read,
612e025be0fSWilliam Hua 	.release	= simple_transaction_release,
613e025be0fSWilliam Hua 	.llseek		= generic_file_llseek,
614e025be0fSWilliam Hua };
615e025be0fSWilliam Hua 
616e74abcf3SKees Cook static int aa_fs_seq_show(struct seq_file *seq, void *v)
617e74abcf3SKees Cook {
618e74abcf3SKees Cook 	struct aa_fs_entry *fs_file = seq->private;
619e74abcf3SKees Cook 
620e74abcf3SKees Cook 	if (!fs_file)
621e74abcf3SKees Cook 		return 0;
622e74abcf3SKees Cook 
623e74abcf3SKees Cook 	switch (fs_file->v_type) {
624e74abcf3SKees Cook 	case AA_FS_TYPE_BOOLEAN:
625e74abcf3SKees Cook 		seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no");
626e74abcf3SKees Cook 		break;
627a9bf8e9fSKees Cook 	case AA_FS_TYPE_STRING:
628a9bf8e9fSKees Cook 		seq_printf(seq, "%s\n", fs_file->v.string);
629a9bf8e9fSKees Cook 		break;
630e74abcf3SKees Cook 	case AA_FS_TYPE_U64:
631e74abcf3SKees Cook 		seq_printf(seq, "%#08lx\n", fs_file->v.u64);
632e74abcf3SKees Cook 		break;
633e74abcf3SKees Cook 	default:
634e74abcf3SKees Cook 		/* Ignore unpritable entry types. */
635e74abcf3SKees Cook 		break;
636e74abcf3SKees Cook 	}
637e74abcf3SKees Cook 
638e74abcf3SKees Cook 	return 0;
639e74abcf3SKees Cook }
640e74abcf3SKees Cook 
641e74abcf3SKees Cook static int aa_fs_seq_open(struct inode *inode, struct file *file)
642e74abcf3SKees Cook {
643e74abcf3SKees Cook 	return single_open(file, aa_fs_seq_show, inode->i_private);
644e74abcf3SKees Cook }
645e74abcf3SKees Cook 
646e74abcf3SKees Cook const struct file_operations aa_fs_seq_file_ops = {
647e74abcf3SKees Cook 	.owner		= THIS_MODULE,
648e74abcf3SKees Cook 	.open		= aa_fs_seq_open,
649e74abcf3SKees Cook 	.read		= seq_read,
650e74abcf3SKees Cook 	.llseek		= seq_lseek,
651e74abcf3SKees Cook 	.release	= single_release,
652e74abcf3SKees Cook };
653e74abcf3SKees Cook 
65452b97de3SJohn Johansen /*
65552b97de3SJohn Johansen  * profile based file operations
65652b97de3SJohn Johansen  *     policy/profiles/XXXX/profiles/ *
65752b97de3SJohn Johansen  */
65852b97de3SJohn Johansen 
65952b97de3SJohn Johansen #define SEQ_PROFILE_FOPS(NAME)						      \
66052b97de3SJohn Johansen static int seq_profile_ ##NAME ##_open(struct inode *inode, struct file *file)\
66152b97de3SJohn Johansen {									      \
66252b97de3SJohn Johansen 	return seq_profile_open(inode, file, seq_profile_ ##NAME ##_show);    \
66352b97de3SJohn Johansen }									      \
66452b97de3SJohn Johansen 									      \
66552b97de3SJohn Johansen static const struct file_operations seq_profile_ ##NAME ##_fops = {	      \
66652b97de3SJohn Johansen 	.owner		= THIS_MODULE,					      \
66752b97de3SJohn Johansen 	.open		= seq_profile_ ##NAME ##_open,			      \
66852b97de3SJohn Johansen 	.read		= seq_read,					      \
66952b97de3SJohn Johansen 	.llseek		= seq_lseek,					      \
67052b97de3SJohn Johansen 	.release	= seq_profile_release,				      \
67152b97de3SJohn Johansen }									      \
67252b97de3SJohn Johansen 
67352b97de3SJohn Johansen static int seq_profile_open(struct inode *inode, struct file *file,
6740d259f04SJohn Johansen 			    int (*show)(struct seq_file *, void *))
6750d259f04SJohn Johansen {
6768399588aSJohn Johansen 	struct aa_proxy *proxy = aa_get_proxy(inode->i_private);
6778399588aSJohn Johansen 	int error = single_open(file, show, proxy);
67863e2b423SJohn Johansen 
6790d259f04SJohn Johansen 	if (error) {
6800d259f04SJohn Johansen 		file->private_data = NULL;
6818399588aSJohn Johansen 		aa_put_proxy(proxy);
6820d259f04SJohn Johansen 	}
6830d259f04SJohn Johansen 
6840d259f04SJohn Johansen 	return error;
6850d259f04SJohn Johansen }
6860d259f04SJohn Johansen 
68752b97de3SJohn Johansen static int seq_profile_release(struct inode *inode, struct file *file)
6880d259f04SJohn Johansen {
6890d259f04SJohn Johansen 	struct seq_file *seq = (struct seq_file *) file->private_data;
6900d259f04SJohn Johansen 	if (seq)
6918399588aSJohn Johansen 		aa_put_proxy(seq->private);
6920d259f04SJohn Johansen 	return single_release(inode, file);
6930d259f04SJohn Johansen }
6940d259f04SJohn Johansen 
69552b97de3SJohn Johansen static int seq_profile_name_show(struct seq_file *seq, void *v)
6960d259f04SJohn Johansen {
6978399588aSJohn Johansen 	struct aa_proxy *proxy = seq->private;
6988399588aSJohn Johansen 	struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
6990d259f04SJohn Johansen 	seq_printf(seq, "%s\n", profile->base.name);
7000d259f04SJohn Johansen 	aa_put_profile(profile);
7010d259f04SJohn Johansen 
7020d259f04SJohn Johansen 	return 0;
7030d259f04SJohn Johansen }
7040d259f04SJohn Johansen 
70552b97de3SJohn Johansen static int seq_profile_mode_show(struct seq_file *seq, void *v)
7060d259f04SJohn Johansen {
7078399588aSJohn Johansen 	struct aa_proxy *proxy = seq->private;
7088399588aSJohn Johansen 	struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
7090d259f04SJohn Johansen 	seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]);
7100d259f04SJohn Johansen 	aa_put_profile(profile);
7110d259f04SJohn Johansen 
7120d259f04SJohn Johansen 	return 0;
7130d259f04SJohn Johansen }
7140d259f04SJohn Johansen 
71552b97de3SJohn Johansen static int seq_profile_attach_show(struct seq_file *seq, void *v)
716556d0be7SJohn Johansen {
7178399588aSJohn Johansen 	struct aa_proxy *proxy = seq->private;
7188399588aSJohn Johansen 	struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
719556d0be7SJohn Johansen 	if (profile->attach)
720556d0be7SJohn Johansen 		seq_printf(seq, "%s\n", profile->attach);
721556d0be7SJohn Johansen 	else if (profile->xmatch)
722556d0be7SJohn Johansen 		seq_puts(seq, "<unknown>\n");
723556d0be7SJohn Johansen 	else
724556d0be7SJohn Johansen 		seq_printf(seq, "%s\n", profile->base.name);
725556d0be7SJohn Johansen 	aa_put_profile(profile);
726556d0be7SJohn Johansen 
727556d0be7SJohn Johansen 	return 0;
728556d0be7SJohn Johansen }
729556d0be7SJohn Johansen 
73052b97de3SJohn Johansen static int seq_profile_hash_show(struct seq_file *seq, void *v)
731f8eb8a13SJohn Johansen {
7328399588aSJohn Johansen 	struct aa_proxy *proxy = seq->private;
7338399588aSJohn Johansen 	struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
734f8eb8a13SJohn Johansen 	unsigned int i, size = aa_hash_size();
735f8eb8a13SJohn Johansen 
736f8eb8a13SJohn Johansen 	if (profile->hash) {
737f8eb8a13SJohn Johansen 		for (i = 0; i < size; i++)
738f8eb8a13SJohn Johansen 			seq_printf(seq, "%.2x", profile->hash[i]);
73947dbd1cdSMarkus Elfring 		seq_putc(seq, '\n');
740f8eb8a13SJohn Johansen 	}
7410b938a2eSJohn Johansen 	aa_put_profile(profile);
742f8eb8a13SJohn Johansen 
743f8eb8a13SJohn Johansen 	return 0;
744f8eb8a13SJohn Johansen }
745f8eb8a13SJohn Johansen 
74652b97de3SJohn Johansen SEQ_PROFILE_FOPS(name);
74752b97de3SJohn Johansen SEQ_PROFILE_FOPS(mode);
74852b97de3SJohn Johansen SEQ_PROFILE_FOPS(attach);
74952b97de3SJohn Johansen SEQ_PROFILE_FOPS(hash);
750f8eb8a13SJohn Johansen 
75164c86970SJohn Johansen /*
75264c86970SJohn Johansen  * namespace based files
75364c86970SJohn Johansen  *     several root files and
75464c86970SJohn Johansen  *     policy/ *
75564c86970SJohn Johansen  */
756f8eb8a13SJohn Johansen 
75764c86970SJohn Johansen #define SEQ_NS_FOPS(NAME)						      \
75864c86970SJohn Johansen static int seq_ns_ ##NAME ##_open(struct inode *inode, struct file *file)     \
75964c86970SJohn Johansen {									      \
76064c86970SJohn Johansen 	return single_open(file, seq_ns_ ##NAME ##_show, inode->i_private);   \
76164c86970SJohn Johansen }									      \
76264c86970SJohn Johansen 									      \
76364c86970SJohn Johansen static const struct file_operations seq_ns_ ##NAME ##_fops = {	      \
76464c86970SJohn Johansen 	.owner		= THIS_MODULE,					      \
76564c86970SJohn Johansen 	.open		= seq_ns_ ##NAME ##_open,			      \
76664c86970SJohn Johansen 	.read		= seq_read,					      \
76764c86970SJohn Johansen 	.llseek		= seq_lseek,					      \
76864c86970SJohn Johansen 	.release	= single_release,				      \
76964c86970SJohn Johansen }									      \
7703e3e5695SJohn Johansen 
77164c86970SJohn Johansen static int seq_ns_level_show(struct seq_file *seq, void *v)
772a71ada30SJohn Johansen {
773a71ada30SJohn Johansen 	struct aa_ns *ns = aa_current_profile()->ns;
774a71ada30SJohn Johansen 
775a71ada30SJohn Johansen 	seq_printf(seq, "%d\n", ns->level);
776a71ada30SJohn Johansen 
777a71ada30SJohn Johansen 	return 0;
778a71ada30SJohn Johansen }
779a71ada30SJohn Johansen 
78064c86970SJohn Johansen static int seq_ns_name_show(struct seq_file *seq, void *v)
7813e3e5695SJohn Johansen {
7823e3e5695SJohn Johansen 	struct aa_ns *ns = aa_current_profile()->ns;
7833e3e5695SJohn Johansen 
7843e3e5695SJohn Johansen 	seq_printf(seq, "%s\n", ns->base.name);
7853e3e5695SJohn Johansen 
7863e3e5695SJohn Johansen 	return 0;
7873e3e5695SJohn Johansen }
7883e3e5695SJohn Johansen 
78964c86970SJohn Johansen SEQ_NS_FOPS(level);
79064c86970SJohn Johansen SEQ_NS_FOPS(name);
7913e3e5695SJohn Johansen 
7925d5182caSJohn Johansen 
7935d5182caSJohn Johansen /* policy/raw_data/ * file ops */
7945d5182caSJohn Johansen 
7955d5182caSJohn Johansen #define SEQ_RAWDATA_FOPS(NAME)						      \
7965d5182caSJohn Johansen static int seq_rawdata_ ##NAME ##_open(struct inode *inode, struct file *file)\
7975d5182caSJohn Johansen {									      \
7985d5182caSJohn Johansen 	return seq_rawdata_open(inode, file, seq_rawdata_ ##NAME ##_show);    \
7995d5182caSJohn Johansen }									      \
8005d5182caSJohn Johansen 									      \
8015d5182caSJohn Johansen static const struct file_operations seq_rawdata_ ##NAME ##_fops = {	      \
8025d5182caSJohn Johansen 	.owner		= THIS_MODULE,					      \
8035d5182caSJohn Johansen 	.open		= seq_rawdata_ ##NAME ##_open,			      \
8045d5182caSJohn Johansen 	.read		= seq_read,					      \
8055d5182caSJohn Johansen 	.llseek		= seq_lseek,					      \
8065d5182caSJohn Johansen 	.release	= seq_rawdata_release,				      \
8075d5182caSJohn Johansen }									      \
8085d5182caSJohn Johansen 
8095d5182caSJohn Johansen static int seq_rawdata_open(struct inode *inode, struct file *file,
8105d5182caSJohn Johansen 			    int (*show)(struct seq_file *, void *))
8115ac8c355SJohn Johansen {
8125d5182caSJohn Johansen 	struct aa_loaddata *data = __aa_get_loaddata(inode->i_private);
8135d5182caSJohn Johansen 	int error;
8145d5182caSJohn Johansen 
8155d5182caSJohn Johansen 	if (!data)
8165d5182caSJohn Johansen 		/* lost race this ent is being reaped */
8175d5182caSJohn Johansen 		return -ENOENT;
8185d5182caSJohn Johansen 
8195d5182caSJohn Johansen 	error = single_open(file, show, data);
8205d5182caSJohn Johansen 	if (error) {
8215d5182caSJohn Johansen 		AA_BUG(file->private_data &&
8225d5182caSJohn Johansen 		       ((struct seq_file *)file->private_data)->private);
8235d5182caSJohn Johansen 		aa_put_loaddata(data);
8245d5182caSJohn Johansen 	}
8255d5182caSJohn Johansen 
8265d5182caSJohn Johansen 	return error;
8275d5182caSJohn Johansen }
8285d5182caSJohn Johansen 
8295d5182caSJohn Johansen static int seq_rawdata_release(struct inode *inode, struct file *file)
8305d5182caSJohn Johansen {
8315d5182caSJohn Johansen 	struct seq_file *seq = (struct seq_file *) file->private_data;
8325d5182caSJohn Johansen 
8335d5182caSJohn Johansen 	if (seq)
8345d5182caSJohn Johansen 		aa_put_loaddata(seq->private);
8355d5182caSJohn Johansen 
8365d5182caSJohn Johansen 	return single_release(inode, file);
8375d5182caSJohn Johansen }
8385d5182caSJohn Johansen 
8395d5182caSJohn Johansen static int seq_rawdata_abi_show(struct seq_file *seq, void *v)
8405d5182caSJohn Johansen {
8415d5182caSJohn Johansen 	struct aa_loaddata *data = seq->private;
8425d5182caSJohn Johansen 
8435d5182caSJohn Johansen 	seq_printf(seq, "v%d\n", data->abi);
8445ac8c355SJohn Johansen 
8455ac8c355SJohn Johansen 	return 0;
8465ac8c355SJohn Johansen }
8475ac8c355SJohn Johansen 
8485d5182caSJohn Johansen static int seq_rawdata_revision_show(struct seq_file *seq, void *v)
8495ac8c355SJohn Johansen {
8505d5182caSJohn Johansen 	struct aa_loaddata *data = seq->private;
8515ac8c355SJohn Johansen 
8525d5182caSJohn Johansen 	seq_printf(seq, "%ld\n", data->revision);
8535ac8c355SJohn Johansen 
8545ac8c355SJohn Johansen 	return 0;
8555ac8c355SJohn Johansen }
8565ac8c355SJohn Johansen 
8575d5182caSJohn Johansen static int seq_rawdata_hash_show(struct seq_file *seq, void *v)
8585ac8c355SJohn Johansen {
8595d5182caSJohn Johansen 	struct aa_loaddata *data = seq->private;
8605ac8c355SJohn Johansen 	unsigned int i, size = aa_hash_size();
8615ac8c355SJohn Johansen 
8625d5182caSJohn Johansen 	if (data->hash) {
8635ac8c355SJohn Johansen 		for (i = 0; i < size; i++)
8645d5182caSJohn Johansen 			seq_printf(seq, "%.2x", data->hash[i]);
86547dbd1cdSMarkus Elfring 		seq_putc(seq, '\n');
8665ac8c355SJohn Johansen 	}
8675ac8c355SJohn Johansen 
8685ac8c355SJohn Johansen 	return 0;
8695ac8c355SJohn Johansen }
8705ac8c355SJohn Johansen 
8715d5182caSJohn Johansen SEQ_RAWDATA_FOPS(abi);
8725d5182caSJohn Johansen SEQ_RAWDATA_FOPS(revision);
8735d5182caSJohn Johansen SEQ_RAWDATA_FOPS(hash);
8745ac8c355SJohn Johansen 
8755ac8c355SJohn Johansen static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,
8765ac8c355SJohn Johansen 			    loff_t *ppos)
8775ac8c355SJohn Johansen {
8785ac8c355SJohn Johansen 	struct aa_loaddata *rawdata = file->private_data;
8795ac8c355SJohn Johansen 
8805ac8c355SJohn Johansen 	return simple_read_from_buffer(buf, size, ppos, rawdata->data,
8815ac8c355SJohn Johansen 				       rawdata->size);
8825ac8c355SJohn Johansen }
8835ac8c355SJohn Johansen 
8845d5182caSJohn Johansen static int rawdata_release(struct inode *inode, struct file *file)
8855ac8c355SJohn Johansen {
8865d5182caSJohn Johansen 	aa_put_loaddata(file->private_data);
8875ac8c355SJohn Johansen 
8885ac8c355SJohn Johansen 	return 0;
8895ac8c355SJohn Johansen }
8905ac8c355SJohn Johansen 
8915d5182caSJohn Johansen static int rawdata_open(struct inode *inode, struct file *file)
8925d5182caSJohn Johansen {
8935d5182caSJohn Johansen 	if (!policy_view_capable(NULL))
8945d5182caSJohn Johansen 		return -EACCES;
8955d5182caSJohn Johansen 	file->private_data = __aa_get_loaddata(inode->i_private);
8965d5182caSJohn Johansen 	if (!file->private_data)
8975d5182caSJohn Johansen 		/* lost race: this entry is being reaped */
8985d5182caSJohn Johansen 		return -ENOENT;
8995d5182caSJohn Johansen 
9005d5182caSJohn Johansen 	return 0;
9015d5182caSJohn Johansen }
9025d5182caSJohn Johansen 
9035d5182caSJohn Johansen static const struct file_operations rawdata_fops = {
9045ac8c355SJohn Johansen 	.open = rawdata_open,
9055ac8c355SJohn Johansen 	.read = rawdata_read,
9065ac8c355SJohn Johansen 	.llseek = generic_file_llseek,
9075ac8c355SJohn Johansen 	.release = rawdata_release,
9085ac8c355SJohn Johansen };
9095ac8c355SJohn Johansen 
9105d5182caSJohn Johansen static void remove_rawdata_dents(struct aa_loaddata *rawdata)
9115d5182caSJohn Johansen {
9125d5182caSJohn Johansen 	int i;
9135d5182caSJohn Johansen 
9145d5182caSJohn Johansen 	for (i = 0; i < AAFS_LOADDATA_NDENTS; i++) {
9155d5182caSJohn Johansen 		if (!IS_ERR_OR_NULL(rawdata->dents[i])) {
9165d5182caSJohn Johansen 			/* no refcounts on i_private */
9175d5182caSJohn Johansen 			securityfs_remove(rawdata->dents[i]);
9185d5182caSJohn Johansen 			rawdata->dents[i] = NULL;
9195d5182caSJohn Johansen 		}
9205d5182caSJohn Johansen 	}
9215d5182caSJohn Johansen }
9225d5182caSJohn Johansen 
9235d5182caSJohn Johansen void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata)
9245d5182caSJohn Johansen {
9255d5182caSJohn Johansen 	AA_BUG(rawdata->ns && !mutex_is_locked(&rawdata->ns->lock));
9265d5182caSJohn Johansen 
9275d5182caSJohn Johansen 	if (rawdata->ns) {
9285d5182caSJohn Johansen 		remove_rawdata_dents(rawdata);
9295d5182caSJohn Johansen 		list_del_init(&rawdata->list);
9305d5182caSJohn Johansen 		aa_put_ns(rawdata->ns);
9315d5182caSJohn Johansen 		rawdata->ns = NULL;
9325d5182caSJohn Johansen 	}
9335d5182caSJohn Johansen }
9345d5182caSJohn Johansen 
9355d5182caSJohn Johansen int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata)
9365d5182caSJohn Johansen {
9375d5182caSJohn Johansen 	struct dentry *dent, *dir;
9385d5182caSJohn Johansen 
9395d5182caSJohn Johansen 	AA_BUG(!ns);
9405d5182caSJohn Johansen 	AA_BUG(!rawdata);
9415d5182caSJohn Johansen 	AA_BUG(!mutex_is_locked(&ns->lock));
9425d5182caSJohn Johansen 	AA_BUG(!ns_subdata_dir(ns));
9435d5182caSJohn Johansen 
9445d5182caSJohn Johansen 	/*
9455d5182caSJohn Johansen 	 * just use ns revision dir was originally created at. This is
9465d5182caSJohn Johansen 	 * under ns->lock and if load is successful revision will be
9475d5182caSJohn Johansen 	 * bumped and is guaranteed to be unique
9485d5182caSJohn Johansen 	 */
9495d5182caSJohn Johansen 	rawdata->name = kasprintf(GFP_KERNEL, "%ld", ns->revision);
9505d5182caSJohn Johansen 	if (!rawdata->name)
9515d5182caSJohn Johansen 		return -ENOMEM;
9525d5182caSJohn Johansen 
9535d5182caSJohn Johansen 	dir = securityfs_create_dir(rawdata->name, ns_subdata_dir(ns));
9545d5182caSJohn Johansen 	if (IS_ERR(dir))
9555d5182caSJohn Johansen 		/* ->name freed when rawdata freed */
9565d5182caSJohn Johansen 		return PTR_ERR(dir);
9575d5182caSJohn Johansen 	rawdata->dents[AAFS_LOADDATA_DIR] = dir;
9585d5182caSJohn Johansen 
9595d5182caSJohn Johansen 	dent = securityfs_create_file("abi", S_IFREG | 0444, dir, rawdata,
9605d5182caSJohn Johansen 				      &seq_rawdata_abi_fops);
9615d5182caSJohn Johansen 	if (IS_ERR(dent))
9625d5182caSJohn Johansen 		goto fail;
9635d5182caSJohn Johansen 	rawdata->dents[AAFS_LOADDATA_ABI] = dent;
9645d5182caSJohn Johansen 
9655d5182caSJohn Johansen 	dent = securityfs_create_file("revision", S_IFREG | 0444, dir, rawdata,
9665d5182caSJohn Johansen 				      &seq_rawdata_revision_fops);
9675d5182caSJohn Johansen 	if (IS_ERR(dent))
9685d5182caSJohn Johansen 		goto fail;
9695d5182caSJohn Johansen 	rawdata->dents[AAFS_LOADDATA_REVISION] = dent;
9705d5182caSJohn Johansen 
9715d5182caSJohn Johansen 	if (aa_g_hash_policy) {
9725d5182caSJohn Johansen 		dent = securityfs_create_file("sha1", S_IFREG | 0444, dir,
9735d5182caSJohn Johansen 					      rawdata, &seq_rawdata_hash_fops);
9745d5182caSJohn Johansen 		if (IS_ERR(dent))
9755d5182caSJohn Johansen 			goto fail;
9765d5182caSJohn Johansen 		rawdata->dents[AAFS_LOADDATA_HASH] = dent;
9775d5182caSJohn Johansen 	}
9785d5182caSJohn Johansen 
9795d5182caSJohn Johansen 	dent = securityfs_create_file("raw_data", S_IFREG | 0444,
9805d5182caSJohn Johansen 				      dir, rawdata, &rawdata_fops);
9815d5182caSJohn Johansen 	if (IS_ERR(dent))
9825d5182caSJohn Johansen 		goto fail;
9835d5182caSJohn Johansen 	rawdata->dents[AAFS_LOADDATA_DATA] = dent;
9845d5182caSJohn Johansen 	d_inode(dent)->i_size = rawdata->size;
9855d5182caSJohn Johansen 
9865d5182caSJohn Johansen 	rawdata->ns = aa_get_ns(ns);
9875d5182caSJohn Johansen 	list_add(&rawdata->list, &ns->rawdata_list);
9885d5182caSJohn Johansen 	/* no refcount on inode rawdata */
9895d5182caSJohn Johansen 
9905d5182caSJohn Johansen 	return 0;
9915d5182caSJohn Johansen 
9925d5182caSJohn Johansen fail:
9935d5182caSJohn Johansen 	remove_rawdata_dents(rawdata);
9945d5182caSJohn Johansen 
9955d5182caSJohn Johansen 	return PTR_ERR(dent);
9965d5182caSJohn Johansen }
9975d5182caSJohn Johansen 
9980d259f04SJohn Johansen /** fns to setup dynamic per profile/namespace files **/
9990d259f04SJohn Johansen void __aa_fs_profile_rmdir(struct aa_profile *profile)
10000d259f04SJohn Johansen {
10010d259f04SJohn Johansen 	struct aa_profile *child;
10020d259f04SJohn Johansen 	int i;
10030d259f04SJohn Johansen 
10040d259f04SJohn Johansen 	if (!profile)
10050d259f04SJohn Johansen 		return;
10060d259f04SJohn Johansen 
10070d259f04SJohn Johansen 	list_for_each_entry(child, &profile->base.profiles, base.list)
10080d259f04SJohn Johansen 		__aa_fs_profile_rmdir(child);
10090d259f04SJohn Johansen 
10100d259f04SJohn Johansen 	for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) {
10118399588aSJohn Johansen 		struct aa_proxy *proxy;
10120d259f04SJohn Johansen 		if (!profile->dents[i])
10130d259f04SJohn Johansen 			continue;
10140d259f04SJohn Johansen 
10158399588aSJohn Johansen 		proxy = d_inode(profile->dents[i])->i_private;
10160d259f04SJohn Johansen 		securityfs_remove(profile->dents[i]);
10178399588aSJohn Johansen 		aa_put_proxy(proxy);
10180d259f04SJohn Johansen 		profile->dents[i] = NULL;
10190d259f04SJohn Johansen 	}
10200d259f04SJohn Johansen }
10210d259f04SJohn Johansen 
10220d259f04SJohn Johansen void __aa_fs_profile_migrate_dents(struct aa_profile *old,
10230d259f04SJohn Johansen 				   struct aa_profile *new)
10240d259f04SJohn Johansen {
10250d259f04SJohn Johansen 	int i;
10260d259f04SJohn Johansen 
10270d259f04SJohn Johansen 	for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
10280d259f04SJohn Johansen 		new->dents[i] = old->dents[i];
1029d671e890SJohn Johansen 		if (new->dents[i])
1030078cd827SDeepa Dinamani 			new->dents[i]->d_inode->i_mtime = current_time(new->dents[i]->d_inode);
10310d259f04SJohn Johansen 		old->dents[i] = NULL;
10320d259f04SJohn Johansen 	}
10330d259f04SJohn Johansen }
10340d259f04SJohn Johansen 
10350d259f04SJohn Johansen static struct dentry *create_profile_file(struct dentry *dir, const char *name,
10360d259f04SJohn Johansen 					  struct aa_profile *profile,
10370d259f04SJohn Johansen 					  const struct file_operations *fops)
10380d259f04SJohn Johansen {
10398399588aSJohn Johansen 	struct aa_proxy *proxy = aa_get_proxy(profile->proxy);
10400d259f04SJohn Johansen 	struct dentry *dent;
10410d259f04SJohn Johansen 
10428399588aSJohn Johansen 	dent = securityfs_create_file(name, S_IFREG | 0444, dir, proxy, fops);
10430d259f04SJohn Johansen 	if (IS_ERR(dent))
10448399588aSJohn Johansen 		aa_put_proxy(proxy);
10450d259f04SJohn Johansen 
10460d259f04SJohn Johansen 	return dent;
10470d259f04SJohn Johansen }
10480d259f04SJohn Johansen 
10495d5182caSJohn Johansen static int profile_depth(struct aa_profile *profile)
10505d5182caSJohn Johansen {
10515d5182caSJohn Johansen 	int depth = 0;
10525d5182caSJohn Johansen 
10535d5182caSJohn Johansen 	rcu_read_lock();
10545d5182caSJohn Johansen 	for (depth = 0; profile; profile = rcu_access_pointer(profile->parent))
10555d5182caSJohn Johansen 		depth++;
10565d5182caSJohn Johansen 	rcu_read_unlock();
10575d5182caSJohn Johansen 
10585d5182caSJohn Johansen 	return depth;
10595d5182caSJohn Johansen }
10605d5182caSJohn Johansen 
10615d5182caSJohn Johansen static int gen_symlink_name(char *buffer, size_t bsize, int depth,
10625d5182caSJohn Johansen 			    const char *dirname, const char *fname)
10635d5182caSJohn Johansen {
10645d5182caSJohn Johansen 	int error;
10655d5182caSJohn Johansen 
10665d5182caSJohn Johansen 	for (; depth > 0; depth--) {
10675d5182caSJohn Johansen 		if (bsize < 7)
10685d5182caSJohn Johansen 			return -ENAMETOOLONG;
10695d5182caSJohn Johansen 		strcpy(buffer, "../../");
10705d5182caSJohn Johansen 		buffer += 6;
10715d5182caSJohn Johansen 		bsize -= 6;
10725d5182caSJohn Johansen 	}
10735d5182caSJohn Johansen 
10745d5182caSJohn Johansen 	error = snprintf(buffer, bsize, "raw_data/%s/%s", dirname, fname);
10755d5182caSJohn Johansen 	if (error >= bsize || error < 0)
10765d5182caSJohn Johansen 		return -ENAMETOOLONG;
10775d5182caSJohn Johansen 
10785d5182caSJohn Johansen 	return 0;
10795d5182caSJohn Johansen }
10805d5182caSJohn Johansen 
10815d5182caSJohn Johansen /*
10825d5182caSJohn Johansen  * Requires: @profile->ns->lock held
10835d5182caSJohn Johansen  */
10840d259f04SJohn Johansen int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
10850d259f04SJohn Johansen {
10860d259f04SJohn Johansen 	struct aa_profile *child;
10870d259f04SJohn Johansen 	struct dentry *dent = NULL, *dir;
10880d259f04SJohn Johansen 	int error;
10890d259f04SJohn Johansen 
10900d259f04SJohn Johansen 	if (!parent) {
10910d259f04SJohn Johansen 		struct aa_profile *p;
10920d259f04SJohn Johansen 		p = aa_deref_parent(profile);
10930d259f04SJohn Johansen 		dent = prof_dir(p);
10940d259f04SJohn Johansen 		/* adding to parent that previously didn't have children */
10950d259f04SJohn Johansen 		dent = securityfs_create_dir("profiles", dent);
10960d259f04SJohn Johansen 		if (IS_ERR(dent))
10970d259f04SJohn Johansen 			goto fail;
10980d259f04SJohn Johansen 		prof_child_dir(p) = parent = dent;
10990d259f04SJohn Johansen 	}
11000d259f04SJohn Johansen 
11010d259f04SJohn Johansen 	if (!profile->dirname) {
11020d259f04SJohn Johansen 		int len, id_len;
11030d259f04SJohn Johansen 		len = mangle_name(profile->base.name, NULL);
11040d259f04SJohn Johansen 		id_len = snprintf(NULL, 0, ".%ld", profile->ns->uniq_id);
11050d259f04SJohn Johansen 
11060d259f04SJohn Johansen 		profile->dirname = kmalloc(len + id_len + 1, GFP_KERNEL);
1107ffac1de6SDan Carpenter 		if (!profile->dirname) {
1108ffac1de6SDan Carpenter 			error = -ENOMEM;
1109ffac1de6SDan Carpenter 			goto fail2;
1110ffac1de6SDan Carpenter 		}
11110d259f04SJohn Johansen 
11120d259f04SJohn Johansen 		mangle_name(profile->base.name, profile->dirname);
11130d259f04SJohn Johansen 		sprintf(profile->dirname + len, ".%ld", profile->ns->uniq_id++);
11140d259f04SJohn Johansen 	}
11150d259f04SJohn Johansen 
11160d259f04SJohn Johansen 	dent = securityfs_create_dir(profile->dirname, parent);
11170d259f04SJohn Johansen 	if (IS_ERR(dent))
11180d259f04SJohn Johansen 		goto fail;
11190d259f04SJohn Johansen 	prof_dir(profile) = dir = dent;
11200d259f04SJohn Johansen 
112152b97de3SJohn Johansen 	dent = create_profile_file(dir, "name", profile,
112252b97de3SJohn Johansen 				   &seq_profile_name_fops);
11230d259f04SJohn Johansen 	if (IS_ERR(dent))
11240d259f04SJohn Johansen 		goto fail;
11250d259f04SJohn Johansen 	profile->dents[AAFS_PROF_NAME] = dent;
11260d259f04SJohn Johansen 
112752b97de3SJohn Johansen 	dent = create_profile_file(dir, "mode", profile,
112852b97de3SJohn Johansen 				   &seq_profile_mode_fops);
11290d259f04SJohn Johansen 	if (IS_ERR(dent))
11300d259f04SJohn Johansen 		goto fail;
11310d259f04SJohn Johansen 	profile->dents[AAFS_PROF_MODE] = dent;
11320d259f04SJohn Johansen 
1133556d0be7SJohn Johansen 	dent = create_profile_file(dir, "attach", profile,
113452b97de3SJohn Johansen 				   &seq_profile_attach_fops);
1135556d0be7SJohn Johansen 	if (IS_ERR(dent))
1136556d0be7SJohn Johansen 		goto fail;
1137556d0be7SJohn Johansen 	profile->dents[AAFS_PROF_ATTACH] = dent;
1138556d0be7SJohn Johansen 
1139f8eb8a13SJohn Johansen 	if (profile->hash) {
1140f8eb8a13SJohn Johansen 		dent = create_profile_file(dir, "sha1", profile,
114152b97de3SJohn Johansen 					   &seq_profile_hash_fops);
1142f8eb8a13SJohn Johansen 		if (IS_ERR(dent))
1143f8eb8a13SJohn Johansen 			goto fail;
1144f8eb8a13SJohn Johansen 		profile->dents[AAFS_PROF_HASH] = dent;
1145f8eb8a13SJohn Johansen 	}
1146f8eb8a13SJohn Johansen 
11475ac8c355SJohn Johansen 	if (profile->rawdata) {
11485d5182caSJohn Johansen 		char target[64];
11495d5182caSJohn Johansen 		int depth = profile_depth(profile);
11505d5182caSJohn Johansen 
11515d5182caSJohn Johansen 		error = gen_symlink_name(target, sizeof(target), depth,
11525d5182caSJohn Johansen 					 profile->rawdata->name, "sha1");
11535d5182caSJohn Johansen 		if (error < 0)
11545d5182caSJohn Johansen 			goto fail2;
11555d5182caSJohn Johansen 		dent = securityfs_create_symlink("raw_sha1", dir, target, NULL);
11565ac8c355SJohn Johansen 		if (IS_ERR(dent))
11575ac8c355SJohn Johansen 			goto fail;
11585ac8c355SJohn Johansen 		profile->dents[AAFS_PROF_RAW_HASH] = dent;
11595ac8c355SJohn Johansen 
11605d5182caSJohn Johansen 		error = gen_symlink_name(target, sizeof(target), depth,
11615d5182caSJohn Johansen 					 profile->rawdata->name, "abi");
11625d5182caSJohn Johansen 		if (error < 0)
11635d5182caSJohn Johansen 			goto fail2;
11645d5182caSJohn Johansen 		dent = securityfs_create_symlink("raw_abi", dir, target, NULL);
11655ac8c355SJohn Johansen 		if (IS_ERR(dent))
11665ac8c355SJohn Johansen 			goto fail;
11675ac8c355SJohn Johansen 		profile->dents[AAFS_PROF_RAW_ABI] = dent;
11685ac8c355SJohn Johansen 
11695d5182caSJohn Johansen 		error = gen_symlink_name(target, sizeof(target), depth,
11705d5182caSJohn Johansen 					 profile->rawdata->name, "raw_data");
11715d5182caSJohn Johansen 		if (error < 0)
11725d5182caSJohn Johansen 			goto fail2;
11735d5182caSJohn Johansen 		dent = securityfs_create_symlink("raw_data", dir, target, NULL);
11745ac8c355SJohn Johansen 		if (IS_ERR(dent))
11755ac8c355SJohn Johansen 			goto fail;
11765ac8c355SJohn Johansen 		profile->dents[AAFS_PROF_RAW_DATA] = dent;
11775ac8c355SJohn Johansen 	}
11785ac8c355SJohn Johansen 
11790d259f04SJohn Johansen 	list_for_each_entry(child, &profile->base.profiles, base.list) {
11800d259f04SJohn Johansen 		error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
11810d259f04SJohn Johansen 		if (error)
11820d259f04SJohn Johansen 			goto fail2;
11830d259f04SJohn Johansen 	}
11840d259f04SJohn Johansen 
11850d259f04SJohn Johansen 	return 0;
11860d259f04SJohn Johansen 
11870d259f04SJohn Johansen fail:
11880d259f04SJohn Johansen 	error = PTR_ERR(dent);
11890d259f04SJohn Johansen 
11900d259f04SJohn Johansen fail2:
11910d259f04SJohn Johansen 	__aa_fs_profile_rmdir(profile);
11920d259f04SJohn Johansen 
11930d259f04SJohn Johansen 	return error;
11940d259f04SJohn Johansen }
11950d259f04SJohn Johansen 
11965d5182caSJohn Johansen static void __aa_fs_list_remove_rawdata(struct aa_ns *ns)
11975d5182caSJohn Johansen {
11985d5182caSJohn Johansen 	struct aa_loaddata *ent, *tmp;
11995d5182caSJohn Johansen 
12005d5182caSJohn Johansen 	AA_BUG(!mutex_is_locked(&ns->lock));
12015d5182caSJohn Johansen 
12025d5182caSJohn Johansen 	list_for_each_entry_safe(ent, tmp, &ns->rawdata_list, list)
12035d5182caSJohn Johansen 		__aa_fs_remove_rawdata(ent);
12045d5182caSJohn Johansen }
12055d5182caSJohn Johansen 
120698849dffSJohn Johansen void __aa_fs_ns_rmdir(struct aa_ns *ns)
12070d259f04SJohn Johansen {
120898849dffSJohn Johansen 	struct aa_ns *sub;
12090d259f04SJohn Johansen 	struct aa_profile *child;
12100d259f04SJohn Johansen 	int i;
12110d259f04SJohn Johansen 
12120d259f04SJohn Johansen 	if (!ns)
12130d259f04SJohn Johansen 		return;
12140d259f04SJohn Johansen 
12150d259f04SJohn Johansen 	list_for_each_entry(child, &ns->base.profiles, base.list)
12160d259f04SJohn Johansen 		__aa_fs_profile_rmdir(child);
12170d259f04SJohn Johansen 
12180d259f04SJohn Johansen 	list_for_each_entry(sub, &ns->sub_ns, base.list) {
12190d259f04SJohn Johansen 		mutex_lock(&sub->lock);
122098849dffSJohn Johansen 		__aa_fs_ns_rmdir(sub);
12210d259f04SJohn Johansen 		mutex_unlock(&sub->lock);
12220d259f04SJohn Johansen 	}
12230d259f04SJohn Johansen 
12245d5182caSJohn Johansen 	__aa_fs_list_remove_rawdata(ns);
12255d5182caSJohn Johansen 
1226b7fd2c03SJohn Johansen 	if (ns_subns_dir(ns)) {
1227b7fd2c03SJohn Johansen 		sub = d_inode(ns_subns_dir(ns))->i_private;
1228b7fd2c03SJohn Johansen 		aa_put_ns(sub);
1229b7fd2c03SJohn Johansen 	}
1230b7fd2c03SJohn Johansen 	if (ns_subload(ns)) {
1231b7fd2c03SJohn Johansen 		sub = d_inode(ns_subload(ns))->i_private;
1232b7fd2c03SJohn Johansen 		aa_put_ns(sub);
1233b7fd2c03SJohn Johansen 	}
1234b7fd2c03SJohn Johansen 	if (ns_subreplace(ns)) {
1235b7fd2c03SJohn Johansen 		sub = d_inode(ns_subreplace(ns))->i_private;
1236b7fd2c03SJohn Johansen 		aa_put_ns(sub);
1237b7fd2c03SJohn Johansen 	}
1238b7fd2c03SJohn Johansen 	if (ns_subremove(ns)) {
1239b7fd2c03SJohn Johansen 		sub = d_inode(ns_subremove(ns))->i_private;
1240b7fd2c03SJohn Johansen 		aa_put_ns(sub);
1241b7fd2c03SJohn Johansen 	}
1242b7fd2c03SJohn Johansen 
12430d259f04SJohn Johansen 	for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
12440d259f04SJohn Johansen 		securityfs_remove(ns->dents[i]);
12450d259f04SJohn Johansen 		ns->dents[i] = NULL;
12460d259f04SJohn Johansen 	}
12470d259f04SJohn Johansen }
12480d259f04SJohn Johansen 
1249b7fd2c03SJohn Johansen /* assumes cleanup in caller */
1250b7fd2c03SJohn Johansen static int __aa_fs_ns_mkdir_entries(struct aa_ns *ns, struct dentry *dir)
1251b7fd2c03SJohn Johansen {
1252b7fd2c03SJohn Johansen 	struct dentry *dent;
1253b7fd2c03SJohn Johansen 
1254b7fd2c03SJohn Johansen 	AA_BUG(!ns);
1255b7fd2c03SJohn Johansen 	AA_BUG(!dir);
1256b7fd2c03SJohn Johansen 
1257b7fd2c03SJohn Johansen 	dent = securityfs_create_dir("profiles", dir);
1258b7fd2c03SJohn Johansen 	if (IS_ERR(dent))
1259b7fd2c03SJohn Johansen 		return PTR_ERR(dent);
1260b7fd2c03SJohn Johansen 	ns_subprofs_dir(ns) = dent;
1261b7fd2c03SJohn Johansen 
1262b7fd2c03SJohn Johansen 	dent = securityfs_create_dir("raw_data", dir);
1263b7fd2c03SJohn Johansen 	if (IS_ERR(dent))
1264b7fd2c03SJohn Johansen 		return PTR_ERR(dent);
1265b7fd2c03SJohn Johansen 	ns_subdata_dir(ns) = dent;
1266b7fd2c03SJohn Johansen 
1267b7fd2c03SJohn Johansen 	dent = securityfs_create_file(".load", 0640, dir, ns,
1268b7fd2c03SJohn Johansen 				      &aa_fs_profile_load);
1269b7fd2c03SJohn Johansen 	if (IS_ERR(dent))
1270b7fd2c03SJohn Johansen 		return PTR_ERR(dent);
1271b7fd2c03SJohn Johansen 	aa_get_ns(ns);
1272b7fd2c03SJohn Johansen 	ns_subload(ns) = dent;
1273b7fd2c03SJohn Johansen 
1274b7fd2c03SJohn Johansen 	dent = securityfs_create_file(".replace", 0640, dir, ns,
1275b7fd2c03SJohn Johansen 				      &aa_fs_profile_replace);
1276b7fd2c03SJohn Johansen 	if (IS_ERR(dent))
1277b7fd2c03SJohn Johansen 		return PTR_ERR(dent);
1278b7fd2c03SJohn Johansen 	aa_get_ns(ns);
1279b7fd2c03SJohn Johansen 	ns_subreplace(ns) = dent;
1280b7fd2c03SJohn Johansen 
1281b7fd2c03SJohn Johansen 	dent = securityfs_create_file(".remove", 0640, dir, ns,
1282b7fd2c03SJohn Johansen 				      &aa_fs_profile_remove);
1283b7fd2c03SJohn Johansen 	if (IS_ERR(dent))
1284b7fd2c03SJohn Johansen 		return PTR_ERR(dent);
1285b7fd2c03SJohn Johansen 	aa_get_ns(ns);
1286b7fd2c03SJohn Johansen 	ns_subremove(ns) = dent;
1287b7fd2c03SJohn Johansen 
1288b7fd2c03SJohn Johansen 	dent = securityfs_create_dir("namespaces", dir);
1289b7fd2c03SJohn Johansen 	if (IS_ERR(dent))
1290b7fd2c03SJohn Johansen 		return PTR_ERR(dent);
1291b7fd2c03SJohn Johansen 	aa_get_ns(ns);
1292b7fd2c03SJohn Johansen 	ns_subns_dir(ns) = dent;
1293b7fd2c03SJohn Johansen 
1294b7fd2c03SJohn Johansen 	return 0;
1295b7fd2c03SJohn Johansen }
1296b7fd2c03SJohn Johansen 
129798849dffSJohn Johansen int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name)
12980d259f04SJohn Johansen {
129998849dffSJohn Johansen 	struct aa_ns *sub;
13000d259f04SJohn Johansen 	struct aa_profile *child;
13010d259f04SJohn Johansen 	struct dentry *dent, *dir;
13020d259f04SJohn Johansen 	int error;
13030d259f04SJohn Johansen 
1304b7fd2c03SJohn Johansen 	AA_BUG(!ns);
1305b7fd2c03SJohn Johansen 	AA_BUG(!parent);
1306b7fd2c03SJohn Johansen 	AA_BUG(!mutex_is_locked(&ns->lock));
1307b7fd2c03SJohn Johansen 
13080d259f04SJohn Johansen 	if (!name)
13090d259f04SJohn Johansen 		name = ns->base.name;
13100d259f04SJohn Johansen 
1311b7fd2c03SJohn Johansen 	/* create ns dir if it doesn't already exist */
13120d259f04SJohn Johansen 	dent = securityfs_create_dir(name, parent);
13130d259f04SJohn Johansen 	if (IS_ERR(dent))
13140d259f04SJohn Johansen 		goto fail;
1315b7fd2c03SJohn Johansen 
13160d259f04SJohn Johansen 	ns_dir(ns) = dir = dent;
1317b7fd2c03SJohn Johansen 	error = __aa_fs_ns_mkdir_entries(ns, dir);
1318b7fd2c03SJohn Johansen 	if (error)
1319b7fd2c03SJohn Johansen 		goto fail2;
13200d259f04SJohn Johansen 
1321b7fd2c03SJohn Johansen 	/* profiles */
13220d259f04SJohn Johansen 	list_for_each_entry(child, &ns->base.profiles, base.list) {
13230d259f04SJohn Johansen 		error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns));
13240d259f04SJohn Johansen 		if (error)
13250d259f04SJohn Johansen 			goto fail2;
13260d259f04SJohn Johansen 	}
13270d259f04SJohn Johansen 
1328b7fd2c03SJohn Johansen 	/* subnamespaces */
13290d259f04SJohn Johansen 	list_for_each_entry(sub, &ns->sub_ns, base.list) {
13300d259f04SJohn Johansen 		mutex_lock(&sub->lock);
133198849dffSJohn Johansen 		error = __aa_fs_ns_mkdir(sub, ns_subns_dir(ns), NULL);
13320d259f04SJohn Johansen 		mutex_unlock(&sub->lock);
13330d259f04SJohn Johansen 		if (error)
13340d259f04SJohn Johansen 			goto fail2;
13350d259f04SJohn Johansen 	}
13360d259f04SJohn Johansen 
13370d259f04SJohn Johansen 	return 0;
13380d259f04SJohn Johansen 
13390d259f04SJohn Johansen fail:
13400d259f04SJohn Johansen 	error = PTR_ERR(dent);
13410d259f04SJohn Johansen 
13420d259f04SJohn Johansen fail2:
134398849dffSJohn Johansen 	__aa_fs_ns_rmdir(ns);
13440d259f04SJohn Johansen 
13450d259f04SJohn Johansen 	return error;
13460d259f04SJohn Johansen }
13470d259f04SJohn Johansen 
13480d259f04SJohn Johansen 
134929b3822fSJohn Johansen #define list_entry_is_head(pos, head, member) (&pos->member == (head))
135029b3822fSJohn Johansen 
135129b3822fSJohn Johansen /**
135298849dffSJohn Johansen  * __next_ns - find the next namespace to list
135329b3822fSJohn Johansen  * @root: root namespace to stop search at (NOT NULL)
135429b3822fSJohn Johansen  * @ns: current ns position (NOT NULL)
135529b3822fSJohn Johansen  *
135629b3822fSJohn Johansen  * Find the next namespace from @ns under @root and handle all locking needed
135729b3822fSJohn Johansen  * while switching current namespace.
135829b3822fSJohn Johansen  *
135929b3822fSJohn Johansen  * Returns: next namespace or NULL if at last namespace under @root
136029b3822fSJohn Johansen  * Requires: ns->parent->lock to be held
136129b3822fSJohn Johansen  * NOTE: will not unlock root->lock
136229b3822fSJohn Johansen  */
136398849dffSJohn Johansen static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
136429b3822fSJohn Johansen {
136598849dffSJohn Johansen 	struct aa_ns *parent, *next;
136629b3822fSJohn Johansen 
136729b3822fSJohn Johansen 	/* is next namespace a child */
136829b3822fSJohn Johansen 	if (!list_empty(&ns->sub_ns)) {
136929b3822fSJohn Johansen 		next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
137029b3822fSJohn Johansen 		mutex_lock(&next->lock);
137129b3822fSJohn Johansen 		return next;
137229b3822fSJohn Johansen 	}
137329b3822fSJohn Johansen 
137429b3822fSJohn Johansen 	/* check if the next ns is a sibling, parent, gp, .. */
137529b3822fSJohn Johansen 	parent = ns->parent;
1376ed2c7da3SJohn Johansen 	while (ns != root) {
137729b3822fSJohn Johansen 		mutex_unlock(&ns->lock);
137838dbd7d8SGeliang Tang 		next = list_next_entry(ns, base.list);
137929b3822fSJohn Johansen 		if (!list_entry_is_head(next, &parent->sub_ns, base.list)) {
138029b3822fSJohn Johansen 			mutex_lock(&next->lock);
138129b3822fSJohn Johansen 			return next;
138229b3822fSJohn Johansen 		}
138329b3822fSJohn Johansen 		ns = parent;
138429b3822fSJohn Johansen 		parent = parent->parent;
138529b3822fSJohn Johansen 	}
138629b3822fSJohn Johansen 
138729b3822fSJohn Johansen 	return NULL;
138829b3822fSJohn Johansen }
138929b3822fSJohn Johansen 
139029b3822fSJohn Johansen /**
139129b3822fSJohn Johansen  * __first_profile - find the first profile in a namespace
139229b3822fSJohn Johansen  * @root: namespace that is root of profiles being displayed (NOT NULL)
139329b3822fSJohn Johansen  * @ns: namespace to start in   (NOT NULL)
139429b3822fSJohn Johansen  *
139529b3822fSJohn Johansen  * Returns: unrefcounted profile or NULL if no profile
139629b3822fSJohn Johansen  * Requires: profile->ns.lock to be held
139729b3822fSJohn Johansen  */
139898849dffSJohn Johansen static struct aa_profile *__first_profile(struct aa_ns *root,
139998849dffSJohn Johansen 					  struct aa_ns *ns)
140029b3822fSJohn Johansen {
140198849dffSJohn Johansen 	for (; ns; ns = __next_ns(root, ns)) {
140229b3822fSJohn Johansen 		if (!list_empty(&ns->base.profiles))
140329b3822fSJohn Johansen 			return list_first_entry(&ns->base.profiles,
140429b3822fSJohn Johansen 						struct aa_profile, base.list);
140529b3822fSJohn Johansen 	}
140629b3822fSJohn Johansen 	return NULL;
140729b3822fSJohn Johansen }
140829b3822fSJohn Johansen 
140929b3822fSJohn Johansen /**
141029b3822fSJohn Johansen  * __next_profile - step to the next profile in a profile tree
141129b3822fSJohn Johansen  * @profile: current profile in tree (NOT NULL)
141229b3822fSJohn Johansen  *
141329b3822fSJohn Johansen  * Perform a depth first traversal on the profile tree in a namespace
141429b3822fSJohn Johansen  *
141529b3822fSJohn Johansen  * Returns: next profile or NULL if done
141629b3822fSJohn Johansen  * Requires: profile->ns.lock to be held
141729b3822fSJohn Johansen  */
141829b3822fSJohn Johansen static struct aa_profile *__next_profile(struct aa_profile *p)
141929b3822fSJohn Johansen {
142029b3822fSJohn Johansen 	struct aa_profile *parent;
142198849dffSJohn Johansen 	struct aa_ns *ns = p->ns;
142229b3822fSJohn Johansen 
142329b3822fSJohn Johansen 	/* is next profile a child */
142429b3822fSJohn Johansen 	if (!list_empty(&p->base.profiles))
142529b3822fSJohn Johansen 		return list_first_entry(&p->base.profiles, typeof(*p),
142629b3822fSJohn Johansen 					base.list);
142729b3822fSJohn Johansen 
142829b3822fSJohn Johansen 	/* is next profile a sibling, parent sibling, gp, sibling, .. */
142929b3822fSJohn Johansen 	parent = rcu_dereference_protected(p->parent,
143029b3822fSJohn Johansen 					   mutex_is_locked(&p->ns->lock));
143129b3822fSJohn Johansen 	while (parent) {
143238dbd7d8SGeliang Tang 		p = list_next_entry(p, base.list);
143329b3822fSJohn Johansen 		if (!list_entry_is_head(p, &parent->base.profiles, base.list))
143429b3822fSJohn Johansen 			return p;
143529b3822fSJohn Johansen 		p = parent;
143629b3822fSJohn Johansen 		parent = rcu_dereference_protected(parent->parent,
143729b3822fSJohn Johansen 					    mutex_is_locked(&parent->ns->lock));
143829b3822fSJohn Johansen 	}
143929b3822fSJohn Johansen 
144029b3822fSJohn Johansen 	/* is next another profile in the namespace */
144138dbd7d8SGeliang Tang 	p = list_next_entry(p, base.list);
144229b3822fSJohn Johansen 	if (!list_entry_is_head(p, &ns->base.profiles, base.list))
144329b3822fSJohn Johansen 		return p;
144429b3822fSJohn Johansen 
144529b3822fSJohn Johansen 	return NULL;
144629b3822fSJohn Johansen }
144729b3822fSJohn Johansen 
144829b3822fSJohn Johansen /**
144929b3822fSJohn Johansen  * next_profile - step to the next profile in where ever it may be
145029b3822fSJohn Johansen  * @root: root namespace  (NOT NULL)
145129b3822fSJohn Johansen  * @profile: current profile  (NOT NULL)
145229b3822fSJohn Johansen  *
145329b3822fSJohn Johansen  * Returns: next profile or NULL if there isn't one
145429b3822fSJohn Johansen  */
145598849dffSJohn Johansen static struct aa_profile *next_profile(struct aa_ns *root,
145629b3822fSJohn Johansen 				       struct aa_profile *profile)
145729b3822fSJohn Johansen {
145829b3822fSJohn Johansen 	struct aa_profile *next = __next_profile(profile);
145929b3822fSJohn Johansen 	if (next)
146029b3822fSJohn Johansen 		return next;
146129b3822fSJohn Johansen 
146229b3822fSJohn Johansen 	/* finished all profiles in namespace move to next namespace */
146398849dffSJohn Johansen 	return __first_profile(root, __next_ns(root, profile->ns));
146429b3822fSJohn Johansen }
146529b3822fSJohn Johansen 
146629b3822fSJohn Johansen /**
146729b3822fSJohn Johansen  * p_start - start a depth first traversal of profile tree
146829b3822fSJohn Johansen  * @f: seq_file to fill
146929b3822fSJohn Johansen  * @pos: current position
147029b3822fSJohn Johansen  *
147129b3822fSJohn Johansen  * Returns: first profile under current namespace or NULL if none found
147229b3822fSJohn Johansen  *
147329b3822fSJohn Johansen  * acquires first ns->lock
147429b3822fSJohn Johansen  */
147529b3822fSJohn Johansen static void *p_start(struct seq_file *f, loff_t *pos)
147629b3822fSJohn Johansen {
147729b3822fSJohn Johansen 	struct aa_profile *profile = NULL;
147898849dffSJohn Johansen 	struct aa_ns *root = aa_current_profile()->ns;
147929b3822fSJohn Johansen 	loff_t l = *pos;
148098849dffSJohn Johansen 	f->private = aa_get_ns(root);
148129b3822fSJohn Johansen 
148229b3822fSJohn Johansen 
148329b3822fSJohn Johansen 	/* find the first profile */
148429b3822fSJohn Johansen 	mutex_lock(&root->lock);
148529b3822fSJohn Johansen 	profile = __first_profile(root, root);
148629b3822fSJohn Johansen 
148729b3822fSJohn Johansen 	/* skip to position */
148829b3822fSJohn Johansen 	for (; profile && l > 0; l--)
148929b3822fSJohn Johansen 		profile = next_profile(root, profile);
149029b3822fSJohn Johansen 
149129b3822fSJohn Johansen 	return profile;
149229b3822fSJohn Johansen }
149329b3822fSJohn Johansen 
149429b3822fSJohn Johansen /**
149529b3822fSJohn Johansen  * p_next - read the next profile entry
149629b3822fSJohn Johansen  * @f: seq_file to fill
149729b3822fSJohn Johansen  * @p: profile previously returned
149829b3822fSJohn Johansen  * @pos: current position
149929b3822fSJohn Johansen  *
150029b3822fSJohn Johansen  * Returns: next profile after @p or NULL if none
150129b3822fSJohn Johansen  *
150229b3822fSJohn Johansen  * may acquire/release locks in namespace tree as necessary
150329b3822fSJohn Johansen  */
150429b3822fSJohn Johansen static void *p_next(struct seq_file *f, void *p, loff_t *pos)
150529b3822fSJohn Johansen {
150629b3822fSJohn Johansen 	struct aa_profile *profile = p;
150798849dffSJohn Johansen 	struct aa_ns *ns = f->private;
150829b3822fSJohn Johansen 	(*pos)++;
150929b3822fSJohn Johansen 
151029b3822fSJohn Johansen 	return next_profile(ns, profile);
151129b3822fSJohn Johansen }
151229b3822fSJohn Johansen 
151329b3822fSJohn Johansen /**
151429b3822fSJohn Johansen  * p_stop - stop depth first traversal
151529b3822fSJohn Johansen  * @f: seq_file we are filling
151629b3822fSJohn Johansen  * @p: the last profile writen
151729b3822fSJohn Johansen  *
151829b3822fSJohn Johansen  * Release all locking done by p_start/p_next on namespace tree
151929b3822fSJohn Johansen  */
152029b3822fSJohn Johansen static void p_stop(struct seq_file *f, void *p)
152129b3822fSJohn Johansen {
152229b3822fSJohn Johansen 	struct aa_profile *profile = p;
152398849dffSJohn Johansen 	struct aa_ns *root = f->private, *ns;
152429b3822fSJohn Johansen 
152529b3822fSJohn Johansen 	if (profile) {
152629b3822fSJohn Johansen 		for (ns = profile->ns; ns && ns != root; ns = ns->parent)
152729b3822fSJohn Johansen 			mutex_unlock(&ns->lock);
152829b3822fSJohn Johansen 	}
152929b3822fSJohn Johansen 	mutex_unlock(&root->lock);
153098849dffSJohn Johansen 	aa_put_ns(root);
153129b3822fSJohn Johansen }
153229b3822fSJohn Johansen 
153329b3822fSJohn Johansen /**
153429b3822fSJohn Johansen  * seq_show_profile - show a profile entry
153529b3822fSJohn Johansen  * @f: seq_file to file
153629b3822fSJohn Johansen  * @p: current position (profile)    (NOT NULL)
153729b3822fSJohn Johansen  *
153829b3822fSJohn Johansen  * Returns: error on failure
153929b3822fSJohn Johansen  */
154029b3822fSJohn Johansen static int seq_show_profile(struct seq_file *f, void *p)
154129b3822fSJohn Johansen {
154229b3822fSJohn Johansen 	struct aa_profile *profile = (struct aa_profile *)p;
154398849dffSJohn Johansen 	struct aa_ns *root = f->private;
154429b3822fSJohn Johansen 
154529b3822fSJohn Johansen 	if (profile->ns != root)
154692b6d8efSJohn Johansen 		seq_printf(f, ":%s://", aa_ns_name(root, profile->ns, true));
154729b3822fSJohn Johansen 	seq_printf(f, "%s (%s)\n", profile->base.hname,
154829b3822fSJohn Johansen 		   aa_profile_mode_names[profile->mode]);
154929b3822fSJohn Johansen 
155029b3822fSJohn Johansen 	return 0;
155129b3822fSJohn Johansen }
155229b3822fSJohn Johansen 
155329b3822fSJohn Johansen static const struct seq_operations aa_fs_profiles_op = {
155429b3822fSJohn Johansen 	.start = p_start,
155529b3822fSJohn Johansen 	.next = p_next,
155629b3822fSJohn Johansen 	.stop = p_stop,
155729b3822fSJohn Johansen 	.show = seq_show_profile,
155829b3822fSJohn Johansen };
155929b3822fSJohn Johansen 
156029b3822fSJohn Johansen static int profiles_open(struct inode *inode, struct file *file)
156129b3822fSJohn Johansen {
15625ac8c355SJohn Johansen 	if (!policy_view_capable(NULL))
15635ac8c355SJohn Johansen 		return -EACCES;
15645ac8c355SJohn Johansen 
156529b3822fSJohn Johansen 	return seq_open(file, &aa_fs_profiles_op);
156629b3822fSJohn Johansen }
156729b3822fSJohn Johansen 
156829b3822fSJohn Johansen static int profiles_release(struct inode *inode, struct file *file)
156929b3822fSJohn Johansen {
157029b3822fSJohn Johansen 	return seq_release(inode, file);
157129b3822fSJohn Johansen }
157229b3822fSJohn Johansen 
157329b3822fSJohn Johansen static const struct file_operations aa_fs_profiles_fops = {
157429b3822fSJohn Johansen 	.open = profiles_open,
157529b3822fSJohn Johansen 	.read = seq_read,
157629b3822fSJohn Johansen 	.llseek = seq_lseek,
157729b3822fSJohn Johansen 	.release = profiles_release,
157829b3822fSJohn Johansen };
157929b3822fSJohn Johansen 
158029b3822fSJohn Johansen 
15810d259f04SJohn Johansen /** Base file system setup **/
1582a9bf8e9fSKees Cook static struct aa_fs_entry aa_fs_entry_file[] = {
1583a9bf8e9fSKees Cook 	AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \
1584a9bf8e9fSKees Cook 				  "link lock"),
1585a9bf8e9fSKees Cook 	{ }
1586a9bf8e9fSKees Cook };
1587a9bf8e9fSKees Cook 
1588e74abcf3SKees Cook static struct aa_fs_entry aa_fs_entry_domain[] = {
1589e74abcf3SKees Cook 	AA_FS_FILE_BOOLEAN("change_hat",	1),
1590e74abcf3SKees Cook 	AA_FS_FILE_BOOLEAN("change_hatv",	1),
1591e74abcf3SKees Cook 	AA_FS_FILE_BOOLEAN("change_onexec",	1),
1592e74abcf3SKees Cook 	AA_FS_FILE_BOOLEAN("change_profile",	1),
159334c426acSJohn Johansen 	AA_FS_FILE_BOOLEAN("fix_binfmt_elf_mmap",	1),
1594aa9a39adSJohn Johansen 	AA_FS_FILE_STRING("version", "1.2"),
1595e74abcf3SKees Cook 	{ }
1596e74abcf3SKees Cook };
1597e74abcf3SKees Cook 
1598474d6b75SJohn Johansen static struct aa_fs_entry aa_fs_entry_versions[] = {
1599474d6b75SJohn Johansen 	AA_FS_FILE_BOOLEAN("v5",	1),
1600474d6b75SJohn Johansen 	{ }
1601474d6b75SJohn Johansen };
1602474d6b75SJohn Johansen 
16039d910a3bSJohn Johansen static struct aa_fs_entry aa_fs_entry_policy[] = {
1604474d6b75SJohn Johansen 	AA_FS_DIR("versions",                   aa_fs_entry_versions),
1605dd51c848SJohn Johansen 	AA_FS_FILE_BOOLEAN("set_load",		1),
16069d910a3bSJohn Johansen 	{ }
16079d910a3bSJohn Johansen };
16089d910a3bSJohn Johansen 
1609e74abcf3SKees Cook static struct aa_fs_entry aa_fs_entry_features[] = {
16109d910a3bSJohn Johansen 	AA_FS_DIR("policy",			aa_fs_entry_policy),
1611e74abcf3SKees Cook 	AA_FS_DIR("domain",			aa_fs_entry_domain),
1612a9bf8e9fSKees Cook 	AA_FS_DIR("file",			aa_fs_entry_file),
1613e74abcf3SKees Cook 	AA_FS_FILE_U64("capability",		VFS_CAP_FLAGS_MASK),
1614d384b0a1SKees Cook 	AA_FS_DIR("rlimit",			aa_fs_entry_rlimit),
161584f1f787SJohn Johansen 	AA_FS_DIR("caps",			aa_fs_entry_caps),
1616e74abcf3SKees Cook 	{ }
1617e74abcf3SKees Cook };
1618e74abcf3SKees Cook 
16199acd494bSKees Cook static struct aa_fs_entry aa_fs_entry_apparmor[] = {
1620e025be0fSWilliam Hua 	AA_FS_FILE_FOPS(".access", 0640, &aa_fs_access),
162164c86970SJohn Johansen 	AA_FS_FILE_FOPS(".ns_level", 0666, &seq_ns_level_fops),
162264c86970SJohn Johansen 	AA_FS_FILE_FOPS(".ns_name", 0640, &seq_ns_name_fops),
1623b7fd2c03SJohn Johansen 	AA_FS_FILE_FOPS("profiles", 0440, &aa_fs_profiles_fops),
1624e74abcf3SKees Cook 	AA_FS_DIR("features", aa_fs_entry_features),
16259acd494bSKees Cook 	{ }
16269acd494bSKees Cook };
162763e2b423SJohn Johansen 
16289acd494bSKees Cook static struct aa_fs_entry aa_fs_entry =
16299acd494bSKees Cook 	AA_FS_DIR("apparmor", aa_fs_entry_apparmor);
16309acd494bSKees Cook 
16319acd494bSKees Cook /**
1632a481f4d9SJohn Johansen  * entry_create_file - create a file entry in the apparmor securityfs
16339acd494bSKees Cook  * @fs_file: aa_fs_entry to build an entry for (NOT NULL)
16349acd494bSKees Cook  * @parent: the parent dentry in the securityfs
16359acd494bSKees Cook  *
1636a481f4d9SJohn Johansen  * Use entry_remove_file to remove entries created with this fn.
16379acd494bSKees Cook  */
1638a481f4d9SJohn Johansen static int __init entry_create_file(struct aa_fs_entry *fs_file,
16399acd494bSKees Cook 				    struct dentry *parent)
164063e2b423SJohn Johansen {
16419acd494bSKees Cook 	int error = 0;
164263e2b423SJohn Johansen 
16439acd494bSKees Cook 	fs_file->dentry = securityfs_create_file(fs_file->name,
16449acd494bSKees Cook 						 S_IFREG | fs_file->mode,
16459acd494bSKees Cook 						 parent, fs_file,
16469acd494bSKees Cook 						 fs_file->file_ops);
16479acd494bSKees Cook 	if (IS_ERR(fs_file->dentry)) {
16489acd494bSKees Cook 		error = PTR_ERR(fs_file->dentry);
16499acd494bSKees Cook 		fs_file->dentry = NULL;
165063e2b423SJohn Johansen 	}
16519acd494bSKees Cook 	return error;
165263e2b423SJohn Johansen }
165363e2b423SJohn Johansen 
1654a481f4d9SJohn Johansen static void __init entry_remove_dir(struct aa_fs_entry *fs_dir);
165563e2b423SJohn Johansen /**
1656a481f4d9SJohn Johansen  * entry_create_dir - recursively create a directory entry in the securityfs
16579acd494bSKees Cook  * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL)
16589acd494bSKees Cook  * @parent: the parent dentry in the securityfs
165963e2b423SJohn Johansen  *
1660a481f4d9SJohn Johansen  * Use entry_remove_dir to remove entries created with this fn.
166163e2b423SJohn Johansen  */
1662a481f4d9SJohn Johansen static int __init entry_create_dir(struct aa_fs_entry *fs_dir,
16639acd494bSKees Cook 				  struct dentry *parent)
166463e2b423SJohn Johansen {
16659acd494bSKees Cook 	struct aa_fs_entry *fs_file;
16660d259f04SJohn Johansen 	struct dentry *dir;
16670d259f04SJohn Johansen 	int error;
166863e2b423SJohn Johansen 
16690d259f04SJohn Johansen 	dir = securityfs_create_dir(fs_dir->name, parent);
16700d259f04SJohn Johansen 	if (IS_ERR(dir))
16710d259f04SJohn Johansen 		return PTR_ERR(dir);
16720d259f04SJohn Johansen 	fs_dir->dentry = dir;
167363e2b423SJohn Johansen 
16740d259f04SJohn Johansen 	for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
16759acd494bSKees Cook 		if (fs_file->v_type == AA_FS_TYPE_DIR)
1676a481f4d9SJohn Johansen 			error = entry_create_dir(fs_file, fs_dir->dentry);
16779acd494bSKees Cook 		else
1678a481f4d9SJohn Johansen 			error = entry_create_file(fs_file, fs_dir->dentry);
16799acd494bSKees Cook 		if (error)
16809acd494bSKees Cook 			goto failed;
16819acd494bSKees Cook 	}
16829acd494bSKees Cook 
16839acd494bSKees Cook 	return 0;
16849acd494bSKees Cook 
16859acd494bSKees Cook failed:
1686a481f4d9SJohn Johansen 	entry_remove_dir(fs_dir);
16870d259f04SJohn Johansen 
16889acd494bSKees Cook 	return error;
16899acd494bSKees Cook }
16909acd494bSKees Cook 
16919acd494bSKees Cook /**
16929acd494bSKees Cook  * aafs_remove_file - drop a single file entry in the apparmor securityfs
16939acd494bSKees Cook  * @fs_file: aa_fs_entry to detach from the securityfs (NOT NULL)
16949acd494bSKees Cook  */
16959acd494bSKees Cook static void __init aafs_remove_file(struct aa_fs_entry *fs_file)
16969acd494bSKees Cook {
16979acd494bSKees Cook 	if (!fs_file->dentry)
16989acd494bSKees Cook 		return;
16999acd494bSKees Cook 
17009acd494bSKees Cook 	securityfs_remove(fs_file->dentry);
17019acd494bSKees Cook 	fs_file->dentry = NULL;
17029acd494bSKees Cook }
17039acd494bSKees Cook 
17049acd494bSKees Cook /**
1705a481f4d9SJohn Johansen  * entry_remove_dir - recursively drop a directory entry from the securityfs
17069acd494bSKees Cook  * @fs_dir: aa_fs_entry (and all child entries) to detach (NOT NULL)
17079acd494bSKees Cook  */
1708a481f4d9SJohn Johansen static void __init entry_remove_dir(struct aa_fs_entry *fs_dir)
17099acd494bSKees Cook {
17109acd494bSKees Cook 	struct aa_fs_entry *fs_file;
17119acd494bSKees Cook 
17120d259f04SJohn Johansen 	for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
17139acd494bSKees Cook 		if (fs_file->v_type == AA_FS_TYPE_DIR)
1714a481f4d9SJohn Johansen 			entry_remove_dir(fs_file);
17159acd494bSKees Cook 		else
17169acd494bSKees Cook 			aafs_remove_file(fs_file);
17179acd494bSKees Cook 	}
17189acd494bSKees Cook 
17199acd494bSKees Cook 	aafs_remove_file(fs_dir);
172063e2b423SJohn Johansen }
172163e2b423SJohn Johansen 
172263e2b423SJohn Johansen /**
172363e2b423SJohn Johansen  * aa_destroy_aafs - cleanup and free aafs
172463e2b423SJohn Johansen  *
172563e2b423SJohn Johansen  * releases dentries allocated by aa_create_aafs
172663e2b423SJohn Johansen  */
172763e2b423SJohn Johansen void __init aa_destroy_aafs(void)
172863e2b423SJohn Johansen {
1729a481f4d9SJohn Johansen 	entry_remove_dir(&aa_fs_entry);
173063e2b423SJohn Johansen }
173163e2b423SJohn Johansen 
1732a71ada30SJohn Johansen 
1733a71ada30SJohn Johansen #define NULL_FILE_NAME ".null"
1734a71ada30SJohn Johansen struct path aa_null;
1735a71ada30SJohn Johansen 
1736a71ada30SJohn Johansen static int aa_mk_null_file(struct dentry *parent)
1737a71ada30SJohn Johansen {
1738a71ada30SJohn Johansen 	struct vfsmount *mount = NULL;
1739a71ada30SJohn Johansen 	struct dentry *dentry;
1740a71ada30SJohn Johansen 	struct inode *inode;
1741a71ada30SJohn Johansen 	int count = 0;
1742a71ada30SJohn Johansen 	int error = simple_pin_fs(parent->d_sb->s_type, &mount, &count);
1743a71ada30SJohn Johansen 
1744a71ada30SJohn Johansen 	if (error)
1745a71ada30SJohn Johansen 		return error;
1746a71ada30SJohn Johansen 
1747a71ada30SJohn Johansen 	inode_lock(d_inode(parent));
1748a71ada30SJohn Johansen 	dentry = lookup_one_len(NULL_FILE_NAME, parent, strlen(NULL_FILE_NAME));
1749a71ada30SJohn Johansen 	if (IS_ERR(dentry)) {
1750a71ada30SJohn Johansen 		error = PTR_ERR(dentry);
1751a71ada30SJohn Johansen 		goto out;
1752a71ada30SJohn Johansen 	}
1753a71ada30SJohn Johansen 	inode = new_inode(parent->d_inode->i_sb);
1754a71ada30SJohn Johansen 	if (!inode) {
1755a71ada30SJohn Johansen 		error = -ENOMEM;
1756a71ada30SJohn Johansen 		goto out1;
1757a71ada30SJohn Johansen 	}
1758a71ada30SJohn Johansen 
1759a71ada30SJohn Johansen 	inode->i_ino = get_next_ino();
1760a71ada30SJohn Johansen 	inode->i_mode = S_IFCHR | S_IRUGO | S_IWUGO;
176124d0d03cSDeepa Dinamani 	inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
1762a71ada30SJohn Johansen 	init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO,
1763a71ada30SJohn Johansen 			   MKDEV(MEM_MAJOR, 3));
1764a71ada30SJohn Johansen 	d_instantiate(dentry, inode);
1765a71ada30SJohn Johansen 	aa_null.dentry = dget(dentry);
1766a71ada30SJohn Johansen 	aa_null.mnt = mntget(mount);
1767a71ada30SJohn Johansen 
1768a71ada30SJohn Johansen 	error = 0;
1769a71ada30SJohn Johansen 
1770a71ada30SJohn Johansen out1:
1771a71ada30SJohn Johansen 	dput(dentry);
1772a71ada30SJohn Johansen out:
1773a71ada30SJohn Johansen 	inode_unlock(d_inode(parent));
1774a71ada30SJohn Johansen 	simple_release_fs(&mount, &count);
1775a71ada30SJohn Johansen 	return error;
1776a71ada30SJohn Johansen }
1777a71ada30SJohn Johansen 
1778a481f4d9SJohn Johansen 
1779a481f4d9SJohn Johansen 
1780a481f4d9SJohn Johansen static const char *policy_get_link(struct dentry *dentry,
1781a481f4d9SJohn Johansen 				   struct inode *inode,
1782a481f4d9SJohn Johansen 				   struct delayed_call *done)
1783a481f4d9SJohn Johansen {
1784a481f4d9SJohn Johansen 	struct aa_ns *ns;
1785a481f4d9SJohn Johansen 	struct path path;
1786a481f4d9SJohn Johansen 
1787a481f4d9SJohn Johansen 	if (!dentry)
1788a481f4d9SJohn Johansen 		return ERR_PTR(-ECHILD);
1789a481f4d9SJohn Johansen 	ns = aa_get_current_ns();
1790a481f4d9SJohn Johansen 	path.mnt = mntget(aafs_mnt);
1791a481f4d9SJohn Johansen 	path.dentry = dget(ns_dir(ns));
1792a481f4d9SJohn Johansen 	nd_jump_link(&path);
1793a481f4d9SJohn Johansen 	aa_put_ns(ns);
1794a481f4d9SJohn Johansen 
1795a481f4d9SJohn Johansen 	return NULL;
1796a481f4d9SJohn Johansen }
1797a481f4d9SJohn Johansen 
1798a481f4d9SJohn Johansen static int ns_get_name(char *buf, size_t size, struct aa_ns *ns,
1799a481f4d9SJohn Johansen 		       struct inode *inode)
1800a481f4d9SJohn Johansen {
1801a481f4d9SJohn Johansen 	int res = snprintf(buf, size, "%s:[%lu]", AAFS_NAME, inode->i_ino);
1802a481f4d9SJohn Johansen 
1803a481f4d9SJohn Johansen 	if (res < 0 || res >= size)
1804a481f4d9SJohn Johansen 		res = -ENOENT;
1805a481f4d9SJohn Johansen 
1806a481f4d9SJohn Johansen 	return res;
1807a481f4d9SJohn Johansen }
1808a481f4d9SJohn Johansen 
1809a481f4d9SJohn Johansen static int policy_readlink(struct dentry *dentry, char __user *buffer,
1810a481f4d9SJohn Johansen 			   int buflen)
1811a481f4d9SJohn Johansen {
1812a481f4d9SJohn Johansen 	struct aa_ns *ns;
1813a481f4d9SJohn Johansen 	char name[32];
1814a481f4d9SJohn Johansen 	int res;
1815a481f4d9SJohn Johansen 
1816a481f4d9SJohn Johansen 	ns = aa_get_current_ns();
1817a481f4d9SJohn Johansen 	res = ns_get_name(name, sizeof(name), ns, d_inode(dentry));
1818a481f4d9SJohn Johansen 	if (res >= 0)
1819a481f4d9SJohn Johansen 		res = readlink_copy(buffer, buflen, name);
1820a481f4d9SJohn Johansen 	aa_put_ns(ns);
1821a481f4d9SJohn Johansen 
1822a481f4d9SJohn Johansen 	return res;
1823a481f4d9SJohn Johansen }
1824a481f4d9SJohn Johansen 
1825a481f4d9SJohn Johansen static const struct inode_operations policy_link_iops = {
1826a481f4d9SJohn Johansen 	.readlink	= policy_readlink,
1827a481f4d9SJohn Johansen 	.get_link	= policy_get_link,
1828a481f4d9SJohn Johansen };
1829a481f4d9SJohn Johansen 
1830a481f4d9SJohn Johansen 
183163e2b423SJohn Johansen /**
183263e2b423SJohn Johansen  * aa_create_aafs - create the apparmor security filesystem
183363e2b423SJohn Johansen  *
183463e2b423SJohn Johansen  * dentries created here are released by aa_destroy_aafs
183563e2b423SJohn Johansen  *
183663e2b423SJohn Johansen  * Returns: error on failure
183763e2b423SJohn Johansen  */
18383417d8d5SJames Morris static int __init aa_create_aafs(void)
183963e2b423SJohn Johansen {
1840b7fd2c03SJohn Johansen 	struct dentry *dent;
184163e2b423SJohn Johansen 	int error;
184263e2b423SJohn Johansen 
184363e2b423SJohn Johansen 	if (!apparmor_initialized)
184463e2b423SJohn Johansen 		return 0;
184563e2b423SJohn Johansen 
18469acd494bSKees Cook 	if (aa_fs_entry.dentry) {
184763e2b423SJohn Johansen 		AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
184863e2b423SJohn Johansen 		return -EEXIST;
184963e2b423SJohn Johansen 	}
185063e2b423SJohn Johansen 
1851a481f4d9SJohn Johansen 	/* setup apparmorfs used to virtualize policy/ */
1852a481f4d9SJohn Johansen 	aafs_mnt = kern_mount(&aafs_ops);
1853a481f4d9SJohn Johansen 	if (IS_ERR(aafs_mnt))
1854a481f4d9SJohn Johansen 		panic("can't set apparmorfs up\n");
1855a481f4d9SJohn Johansen 	aafs_mnt->mnt_sb->s_flags &= ~MS_NOUSER;
1856a481f4d9SJohn Johansen 
18579acd494bSKees Cook 	/* Populate fs tree. */
1858a481f4d9SJohn Johansen 	error = entry_create_dir(&aa_fs_entry, NULL);
185963e2b423SJohn Johansen 	if (error)
186063e2b423SJohn Johansen 		goto error;
186163e2b423SJohn Johansen 
1862b7fd2c03SJohn Johansen 	dent = securityfs_create_file(".load", 0666, aa_fs_entry.dentry,
1863b7fd2c03SJohn Johansen 				      NULL, &aa_fs_profile_load);
1864b7fd2c03SJohn Johansen 	if (IS_ERR(dent)) {
1865b7fd2c03SJohn Johansen 		error = PTR_ERR(dent);
1866b7fd2c03SJohn Johansen 		goto error;
1867b7fd2c03SJohn Johansen 	}
1868b7fd2c03SJohn Johansen 	ns_subload(root_ns) = dent;
1869b7fd2c03SJohn Johansen 
1870b7fd2c03SJohn Johansen 	dent = securityfs_create_file(".replace", 0666, aa_fs_entry.dentry,
1871b7fd2c03SJohn Johansen 				      NULL, &aa_fs_profile_replace);
1872b7fd2c03SJohn Johansen 	if (IS_ERR(dent)) {
1873b7fd2c03SJohn Johansen 		error = PTR_ERR(dent);
1874b7fd2c03SJohn Johansen 		goto error;
1875b7fd2c03SJohn Johansen 	}
1876b7fd2c03SJohn Johansen 	ns_subreplace(root_ns) = dent;
1877b7fd2c03SJohn Johansen 
1878b7fd2c03SJohn Johansen 	dent = securityfs_create_file(".remove", 0666, aa_fs_entry.dentry,
1879b7fd2c03SJohn Johansen 				      NULL, &aa_fs_profile_remove);
1880b7fd2c03SJohn Johansen 	if (IS_ERR(dent)) {
1881b7fd2c03SJohn Johansen 		error = PTR_ERR(dent);
1882b7fd2c03SJohn Johansen 		goto error;
1883b7fd2c03SJohn Johansen 	}
1884b7fd2c03SJohn Johansen 	ns_subremove(root_ns) = dent;
1885b7fd2c03SJohn Johansen 
1886b7fd2c03SJohn Johansen 	mutex_lock(&root_ns->lock);
188798849dffSJohn Johansen 	error = __aa_fs_ns_mkdir(root_ns, aa_fs_entry.dentry, "policy");
1888b7fd2c03SJohn Johansen 	mutex_unlock(&root_ns->lock);
1889b7fd2c03SJohn Johansen 
18900d259f04SJohn Johansen 	if (error)
18910d259f04SJohn Johansen 		goto error;
18920d259f04SJohn Johansen 
1893a71ada30SJohn Johansen 	error = aa_mk_null_file(aa_fs_entry.dentry);
1894a71ada30SJohn Johansen 	if (error)
1895a71ada30SJohn Johansen 		goto error;
1896a71ada30SJohn Johansen 
1897a71ada30SJohn Johansen 	/* TODO: add default profile to apparmorfs */
189863e2b423SJohn Johansen 
189963e2b423SJohn Johansen 	/* Report that AppArmor fs is enabled */
190063e2b423SJohn Johansen 	aa_info_message("AppArmor Filesystem Enabled");
190163e2b423SJohn Johansen 	return 0;
190263e2b423SJohn Johansen 
190363e2b423SJohn Johansen error:
190463e2b423SJohn Johansen 	aa_destroy_aafs();
190563e2b423SJohn Johansen 	AA_ERROR("Error creating AppArmor securityfs\n");
190663e2b423SJohn Johansen 	return error;
190763e2b423SJohn Johansen }
190863e2b423SJohn Johansen 
190963e2b423SJohn Johansen fs_initcall(aa_create_aafs);
1910