blob: af36af88c4ed0cd93df0596fa33f3382a9f13789 [file] [log] [blame]
John Johansen63e2b422010-07-29 14:48:03 -07001/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor /sys/kernel/security/apparmor interface functions
5 *
6 * Copyright (C) 1998-2008 Novell/SUSE
7 * Copyright 2009-2010 Canonical Ltd.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
12 * License.
13 */
14
John Johansen0d259f02013-07-10 21:13:43 -070015#include <linux/ctype.h>
John Johansen63e2b422010-07-29 14:48:03 -070016#include <linux/security.h>
17#include <linux/vmalloc.h>
18#include <linux/module.h>
19#include <linux/seq_file.h>
20#include <linux/uaccess.h>
John Johansena71ada32017-01-16 00:42:45 -080021#include <linux/mount.h>
John Johansen63e2b422010-07-29 14:48:03 -070022#include <linux/namei.h>
Kees Cooke74abcf2012-01-26 16:29:21 -080023#include <linux/capability.h>
John Johansen29b38222013-07-10 21:18:43 -070024#include <linux/rcupdate.h>
John Johansena71ada32017-01-16 00:42:45 -080025#include <uapi/linux/major.h>
26#include <linux/fs.h>
John Johansen63e2b422010-07-29 14:48:03 -070027
28#include "include/apparmor.h"
29#include "include/apparmorfs.h"
30#include "include/audit.h"
31#include "include/context.h"
John Johansenf8eb8a12013-08-14 11:27:36 -070032#include "include/crypto.h"
John Johansen63e2b422010-07-29 14:48:03 -070033#include "include/policy.h"
John Johansencff281f2017-01-16 00:42:15 -080034#include "include/policy_ns.h"
Kees Cookd384b0a2012-01-26 16:29:23 -080035#include "include/resource.h"
John Johansen5ac8c352017-01-16 00:42:55 -080036#include "include/policy_unpack.h"
John Johansen63e2b422010-07-29 14:48:03 -070037
38/**
John Johansen0d259f02013-07-10 21:13:43 -070039 * aa_mangle_name - mangle a profile name to std profile layout form
40 * @name: profile name to mangle (NOT NULL)
41 * @target: buffer to store mangled name, same length as @name (MAYBE NULL)
42 *
43 * Returns: length of mangled name
44 */
John Johansenbbe4a7c2017-01-16 00:42:30 -080045static int mangle_name(const char *name, char *target)
John Johansen0d259f02013-07-10 21:13:43 -070046{
47 char *t = target;
48
49 while (*name == '/' || *name == '.')
50 name++;
51
52 if (target) {
53 for (; *name; name++) {
54 if (*name == '/')
55 *(t)++ = '.';
56 else if (isspace(*name))
57 *(t)++ = '_';
58 else if (isalnum(*name) || strchr("._-", *name))
59 *(t)++ = *name;
60 }
61
62 *t = 0;
63 } else {
64 int len = 0;
65 for (; *name; name++) {
66 if (isalnum(*name) || isspace(*name) ||
67 strchr("/._-", *name))
68 len++;
69 }
70
71 return len;
72 }
73
74 return t - target;
75}
76
77/**
John Johansen63e2b422010-07-29 14:48:03 -070078 * aa_simple_write_to_buffer - common routine for getting policy from user
79 * @op: operation doing the user buffer copy
80 * @userbuf: user buffer to copy data from (NOT NULL)
John Johansen3ed02ad2010-10-09 00:47:53 -070081 * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size)
John Johansen63e2b422010-07-29 14:48:03 -070082 * @copy_size: size of data to copy from user buffer
83 * @pos: position write is at in the file (NOT NULL)
84 *
85 * Returns: kernel buffer containing copy of user buffer data or an
86 * ERR_PTR on failure.
87 */
John Johansen5ac8c352017-01-16 00:42:55 -080088static struct aa_loaddata *aa_simple_write_to_buffer(int op,
89 const char __user *userbuf,
90 size_t alloc_size,
91 size_t copy_size,
92 loff_t *pos)
John Johansen63e2b422010-07-29 14:48:03 -070093{
John Johansen5ac8c352017-01-16 00:42:55 -080094 struct aa_loaddata *data;
John Johansen63e2b422010-07-29 14:48:03 -070095
John Johansen3ed02ad2010-10-09 00:47:53 -070096 BUG_ON(copy_size > alloc_size);
97
John Johansen63e2b422010-07-29 14:48:03 -070098 if (*pos != 0)
99 /* only writes from pos 0, that is complete writes */
100 return ERR_PTR(-ESPIPE);
101
John Johansen63e2b422010-07-29 14:48:03 -0700102 /* freed by caller to simple_write_to_buffer */
John Johansen5ac8c352017-01-16 00:42:55 -0800103 data = kvmalloc(sizeof(*data) + alloc_size);
John Johansen63e2b422010-07-29 14:48:03 -0700104 if (data == NULL)
105 return ERR_PTR(-ENOMEM);
John Johansen5ac8c352017-01-16 00:42:55 -0800106 kref_init(&data->count);
107 data->size = copy_size;
108 data->hash = NULL;
109 data->abi = 0;
John Johansen63e2b422010-07-29 14:48:03 -0700110
John Johansen5ac8c352017-01-16 00:42:55 -0800111 if (copy_from_user(data->data, userbuf, copy_size)) {
John Johansen63e2b422010-07-29 14:48:03 -0700112 kvfree(data);
113 return ERR_PTR(-EFAULT);
114 }
115
116 return data;
117}
118
John Johansen5ac8c352017-01-16 00:42:55 -0800119static ssize_t policy_update(int binop, const char __user *buf, size_t size,
John Johansenb7fd2c02017-01-16 00:42:58 -0800120 loff_t *pos, struct aa_ns *ns)
John Johansen5ac8c352017-01-16 00:42:55 -0800121{
122 ssize_t error;
123 struct aa_loaddata *data;
124 struct aa_profile *profile = aa_current_profile();
125 int op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL;
126 /* high level check about policy management - fine grained in
127 * below after unpack
128 */
John Johansenb7fd2c02017-01-16 00:42:58 -0800129 error = aa_may_manage_policy(profile, ns, op);
John Johansen5ac8c352017-01-16 00:42:55 -0800130 if (error)
131 return error;
John Johansen63e2b422010-07-29 14:48:03 -0700132
John Johansen5ac8c352017-01-16 00:42:55 -0800133 data = aa_simple_write_to_buffer(op, buf, size, size, pos);
134 error = PTR_ERR(data);
135 if (!IS_ERR(data)) {
John Johansenb7fd2c02017-01-16 00:42:58 -0800136 error = aa_replace_profiles(ns ? ns : profile->ns, profile,
137 binop, data);
John Johansen5ac8c352017-01-16 00:42:55 -0800138 aa_put_loaddata(data);
139 }
140
141 return error;
142}
143
John Johansenb7fd2c02017-01-16 00:42:58 -0800144/* .load file hook fn to load policy */
John Johansen63e2b422010-07-29 14:48:03 -0700145static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
146 loff_t *pos)
147{
John Johansenb7fd2c02017-01-16 00:42:58 -0800148 struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
149 int error = policy_update(PROF_ADD, buf, size, pos, ns);
150
151 aa_put_ns(ns);
John Johansen63e2b422010-07-29 14:48:03 -0700152
153 return error;
154}
155
156static const struct file_operations aa_fs_profile_load = {
Arnd Bergmann6038f372010-08-15 18:52:59 +0200157 .write = profile_load,
158 .llseek = default_llseek,
John Johansen63e2b422010-07-29 14:48:03 -0700159};
160
161/* .replace file hook fn to load and/or replace policy */
162static ssize_t profile_replace(struct file *f, const char __user *buf,
163 size_t size, loff_t *pos)
164{
John Johansenb7fd2c02017-01-16 00:42:58 -0800165 struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
166 int error = policy_update(PROF_REPLACE, buf, size, pos, ns);
167
168 aa_put_ns(ns);
John Johansen63e2b422010-07-29 14:48:03 -0700169
170 return error;
171}
172
173static const struct file_operations aa_fs_profile_replace = {
Arnd Bergmann6038f372010-08-15 18:52:59 +0200174 .write = profile_replace,
175 .llseek = default_llseek,
John Johansen63e2b422010-07-29 14:48:03 -0700176};
177
John Johansenb7fd2c02017-01-16 00:42:58 -0800178/* .remove file hook fn to remove loaded policy */
John Johansen63e2b422010-07-29 14:48:03 -0700179static ssize_t profile_remove(struct file *f, const char __user *buf,
180 size_t size, loff_t *pos)
181{
John Johansen5ac8c352017-01-16 00:42:55 -0800182 struct aa_loaddata *data;
183 struct aa_profile *profile;
John Johansen63e2b422010-07-29 14:48:03 -0700184 ssize_t error;
John Johansenb7fd2c02017-01-16 00:42:58 -0800185 struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
John Johansen63e2b422010-07-29 14:48:03 -0700186
John Johansen5ac8c352017-01-16 00:42:55 -0800187 profile = aa_current_profile();
188 /* high level check about policy management - fine grained in
189 * below after unpack
190 */
John Johansenb7fd2c02017-01-16 00:42:58 -0800191 error = aa_may_manage_policy(profile, ns, OP_PROF_RM);
John Johansen5ac8c352017-01-16 00:42:55 -0800192 if (error)
193 goto out;
194
John Johansen63e2b422010-07-29 14:48:03 -0700195 /*
196 * aa_remove_profile needs a null terminated string so 1 extra
197 * byte is allocated and the copied data is null terminated.
198 */
John Johansen5ac8c352017-01-16 00:42:55 -0800199 data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size,
200 pos);
John Johansen63e2b422010-07-29 14:48:03 -0700201
202 error = PTR_ERR(data);
203 if (!IS_ERR(data)) {
John Johansen5ac8c352017-01-16 00:42:55 -0800204 data->data[size] = 0;
John Johansenb7fd2c02017-01-16 00:42:58 -0800205 error = aa_remove_profiles(ns ? ns : profile->ns, profile,
206 data->data, size);
John Johansen5ac8c352017-01-16 00:42:55 -0800207 aa_put_loaddata(data);
John Johansen63e2b422010-07-29 14:48:03 -0700208 }
John Johansen5ac8c352017-01-16 00:42:55 -0800209 out:
John Johansenb7fd2c02017-01-16 00:42:58 -0800210 aa_put_ns(ns);
John Johansen63e2b422010-07-29 14:48:03 -0700211 return error;
212}
213
214static const struct file_operations aa_fs_profile_remove = {
Arnd Bergmann6038f372010-08-15 18:52:59 +0200215 .write = profile_remove,
216 .llseek = default_llseek,
John Johansen63e2b422010-07-29 14:48:03 -0700217};
218
Kees Cooke74abcf2012-01-26 16:29:21 -0800219static int aa_fs_seq_show(struct seq_file *seq, void *v)
220{
221 struct aa_fs_entry *fs_file = seq->private;
222
223 if (!fs_file)
224 return 0;
225
226 switch (fs_file->v_type) {
227 case AA_FS_TYPE_BOOLEAN:
228 seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no");
229 break;
Kees Cooka9bf8e92012-01-26 16:29:22 -0800230 case AA_FS_TYPE_STRING:
231 seq_printf(seq, "%s\n", fs_file->v.string);
232 break;
Kees Cooke74abcf2012-01-26 16:29:21 -0800233 case AA_FS_TYPE_U64:
234 seq_printf(seq, "%#08lx\n", fs_file->v.u64);
235 break;
236 default:
237 /* Ignore unpritable entry types. */
238 break;
239 }
240
241 return 0;
242}
243
244static int aa_fs_seq_open(struct inode *inode, struct file *file)
245{
246 return single_open(file, aa_fs_seq_show, inode->i_private);
247}
248
249const struct file_operations aa_fs_seq_file_ops = {
250 .owner = THIS_MODULE,
251 .open = aa_fs_seq_open,
252 .read = seq_read,
253 .llseek = seq_lseek,
254 .release = single_release,
255};
256
John Johansen0d259f02013-07-10 21:13:43 -0700257static int aa_fs_seq_profile_open(struct inode *inode, struct file *file,
258 int (*show)(struct seq_file *, void *))
259{
John Johansen83995882017-01-16 00:42:19 -0800260 struct aa_proxy *proxy = aa_get_proxy(inode->i_private);
261 int error = single_open(file, show, proxy);
John Johansen63e2b422010-07-29 14:48:03 -0700262
John Johansen0d259f02013-07-10 21:13:43 -0700263 if (error) {
264 file->private_data = NULL;
John Johansen83995882017-01-16 00:42:19 -0800265 aa_put_proxy(proxy);
John Johansen0d259f02013-07-10 21:13:43 -0700266 }
267
268 return error;
269}
270
271static int aa_fs_seq_profile_release(struct inode *inode, struct file *file)
272{
273 struct seq_file *seq = (struct seq_file *) file->private_data;
274 if (seq)
John Johansen83995882017-01-16 00:42:19 -0800275 aa_put_proxy(seq->private);
John Johansen0d259f02013-07-10 21:13:43 -0700276 return single_release(inode, file);
277}
278
279static int aa_fs_seq_profname_show(struct seq_file *seq, void *v)
280{
John Johansen83995882017-01-16 00:42:19 -0800281 struct aa_proxy *proxy = seq->private;
282 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
John Johansen0d259f02013-07-10 21:13:43 -0700283 seq_printf(seq, "%s\n", profile->base.name);
284 aa_put_profile(profile);
285
286 return 0;
287}
288
289static int aa_fs_seq_profname_open(struct inode *inode, struct file *file)
290{
291 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profname_show);
292}
293
294static const struct file_operations aa_fs_profname_fops = {
295 .owner = THIS_MODULE,
296 .open = aa_fs_seq_profname_open,
297 .read = seq_read,
298 .llseek = seq_lseek,
299 .release = aa_fs_seq_profile_release,
300};
301
302static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v)
303{
John Johansen83995882017-01-16 00:42:19 -0800304 struct aa_proxy *proxy = seq->private;
305 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
John Johansen0d259f02013-07-10 21:13:43 -0700306 seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]);
307 aa_put_profile(profile);
308
309 return 0;
310}
311
312static int aa_fs_seq_profmode_open(struct inode *inode, struct file *file)
313{
314 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profmode_show);
315}
316
317static const struct file_operations aa_fs_profmode_fops = {
318 .owner = THIS_MODULE,
319 .open = aa_fs_seq_profmode_open,
320 .read = seq_read,
321 .llseek = seq_lseek,
322 .release = aa_fs_seq_profile_release,
323};
324
John Johansen556d0be2013-07-10 21:17:43 -0700325static int aa_fs_seq_profattach_show(struct seq_file *seq, void *v)
326{
John Johansen83995882017-01-16 00:42:19 -0800327 struct aa_proxy *proxy = seq->private;
328 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
John Johansen556d0be2013-07-10 21:17:43 -0700329 if (profile->attach)
330 seq_printf(seq, "%s\n", profile->attach);
331 else if (profile->xmatch)
332 seq_puts(seq, "<unknown>\n");
333 else
334 seq_printf(seq, "%s\n", profile->base.name);
335 aa_put_profile(profile);
336
337 return 0;
338}
339
340static int aa_fs_seq_profattach_open(struct inode *inode, struct file *file)
341{
342 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profattach_show);
343}
344
345static const struct file_operations aa_fs_profattach_fops = {
346 .owner = THIS_MODULE,
347 .open = aa_fs_seq_profattach_open,
348 .read = seq_read,
349 .llseek = seq_lseek,
350 .release = aa_fs_seq_profile_release,
351};
352
John Johansenf8eb8a12013-08-14 11:27:36 -0700353static int aa_fs_seq_hash_show(struct seq_file *seq, void *v)
354{
John Johansen83995882017-01-16 00:42:19 -0800355 struct aa_proxy *proxy = seq->private;
356 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
John Johansenf8eb8a12013-08-14 11:27:36 -0700357 unsigned int i, size = aa_hash_size();
358
359 if (profile->hash) {
360 for (i = 0; i < size; i++)
361 seq_printf(seq, "%.2x", profile->hash[i]);
362 seq_puts(seq, "\n");
363 }
John Johansen0b938a22015-11-18 11:41:05 -0800364 aa_put_profile(profile);
John Johansenf8eb8a12013-08-14 11:27:36 -0700365
366 return 0;
367}
368
369static int aa_fs_seq_hash_open(struct inode *inode, struct file *file)
370{
371 return single_open(file, aa_fs_seq_hash_show, inode->i_private);
372}
373
374static const struct file_operations aa_fs_seq_hash_fops = {
375 .owner = THIS_MODULE,
376 .open = aa_fs_seq_hash_open,
377 .read = seq_read,
378 .llseek = seq_lseek,
379 .release = single_release,
380};
381
John Johansen3e3e5692017-01-16 00:42:48 -0800382
John Johansena71ada32017-01-16 00:42:45 -0800383static int aa_fs_seq_show_ns_level(struct seq_file *seq, void *v)
384{
385 struct aa_ns *ns = aa_current_profile()->ns;
386
387 seq_printf(seq, "%d\n", ns->level);
388
389 return 0;
390}
391
392static int aa_fs_seq_open_ns_level(struct inode *inode, struct file *file)
393{
394 return single_open(file, aa_fs_seq_show_ns_level, inode->i_private);
395}
396
397static const struct file_operations aa_fs_ns_level = {
398 .owner = THIS_MODULE,
399 .open = aa_fs_seq_open_ns_level,
400 .read = seq_read,
401 .llseek = seq_lseek,
402 .release = single_release,
403};
404
John Johansen3e3e5692017-01-16 00:42:48 -0800405static int aa_fs_seq_show_ns_name(struct seq_file *seq, void *v)
406{
407 struct aa_ns *ns = aa_current_profile()->ns;
408
409 seq_printf(seq, "%s\n", ns->base.name);
410
411 return 0;
412}
413
414static int aa_fs_seq_open_ns_name(struct inode *inode, struct file *file)
415{
416 return single_open(file, aa_fs_seq_show_ns_name, inode->i_private);
417}
418
419static const struct file_operations aa_fs_ns_name = {
420 .owner = THIS_MODULE,
421 .open = aa_fs_seq_open_ns_name,
422 .read = seq_read,
423 .llseek = seq_lseek,
424 .release = single_release,
425};
426
John Johansen5ac8c352017-01-16 00:42:55 -0800427static int rawdata_release(struct inode *inode, struct file *file)
428{
429 /* TODO: switch to loaddata when profile switched to symlink */
430 aa_put_loaddata(file->private_data);
431
432 return 0;
433}
434
435static int aa_fs_seq_raw_abi_show(struct seq_file *seq, void *v)
436{
437 struct aa_proxy *proxy = seq->private;
438 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
439
440 if (profile->rawdata->abi) {
441 seq_printf(seq, "v%d", profile->rawdata->abi);
442 seq_puts(seq, "\n");
443 }
444 aa_put_profile(profile);
445
446 return 0;
447}
448
449static int aa_fs_seq_raw_abi_open(struct inode *inode, struct file *file)
450{
451 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_raw_abi_show);
452}
453
454static const struct file_operations aa_fs_seq_raw_abi_fops = {
455 .owner = THIS_MODULE,
456 .open = aa_fs_seq_raw_abi_open,
457 .read = seq_read,
458 .llseek = seq_lseek,
459 .release = aa_fs_seq_profile_release,
460};
461
462static int aa_fs_seq_raw_hash_show(struct seq_file *seq, void *v)
463{
464 struct aa_proxy *proxy = seq->private;
465 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
466 unsigned int i, size = aa_hash_size();
467
468 if (profile->rawdata->hash) {
469 for (i = 0; i < size; i++)
470 seq_printf(seq, "%.2x", profile->rawdata->hash[i]);
471 seq_puts(seq, "\n");
472 }
473 aa_put_profile(profile);
474
475 return 0;
476}
477
478static int aa_fs_seq_raw_hash_open(struct inode *inode, struct file *file)
479{
480 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_raw_hash_show);
481}
482
483static const struct file_operations aa_fs_seq_raw_hash_fops = {
484 .owner = THIS_MODULE,
485 .open = aa_fs_seq_raw_hash_open,
486 .read = seq_read,
487 .llseek = seq_lseek,
488 .release = aa_fs_seq_profile_release,
489};
490
491static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,
492 loff_t *ppos)
493{
494 struct aa_loaddata *rawdata = file->private_data;
495
496 return simple_read_from_buffer(buf, size, ppos, rawdata->data,
497 rawdata->size);
498}
499
500static int rawdata_open(struct inode *inode, struct file *file)
501{
502 struct aa_proxy *proxy = inode->i_private;
503 struct aa_profile *profile;
504
505 if (!policy_view_capable(NULL))
506 return -EACCES;
507 profile = aa_get_profile_rcu(&proxy->profile);
508 file->private_data = aa_get_loaddata(profile->rawdata);
509 aa_put_profile(profile);
510
511 return 0;
512}
513
514static const struct file_operations aa_fs_rawdata_fops = {
515 .open = rawdata_open,
516 .read = rawdata_read,
517 .llseek = generic_file_llseek,
518 .release = rawdata_release,
519};
520
John Johansen0d259f02013-07-10 21:13:43 -0700521/** fns to setup dynamic per profile/namespace files **/
522void __aa_fs_profile_rmdir(struct aa_profile *profile)
523{
524 struct aa_profile *child;
525 int i;
526
527 if (!profile)
528 return;
529
530 list_for_each_entry(child, &profile->base.profiles, base.list)
531 __aa_fs_profile_rmdir(child);
532
533 for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) {
John Johansen83995882017-01-16 00:42:19 -0800534 struct aa_proxy *proxy;
John Johansen0d259f02013-07-10 21:13:43 -0700535 if (!profile->dents[i])
536 continue;
537
John Johansen83995882017-01-16 00:42:19 -0800538 proxy = d_inode(profile->dents[i])->i_private;
John Johansen0d259f02013-07-10 21:13:43 -0700539 securityfs_remove(profile->dents[i]);
John Johansen83995882017-01-16 00:42:19 -0800540 aa_put_proxy(proxy);
John Johansen0d259f02013-07-10 21:13:43 -0700541 profile->dents[i] = NULL;
542 }
543}
544
545void __aa_fs_profile_migrate_dents(struct aa_profile *old,
546 struct aa_profile *new)
547{
548 int i;
549
550 for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
551 new->dents[i] = old->dents[i];
John Johansend671e8902014-07-25 04:01:56 -0700552 if (new->dents[i])
Deepa Dinamani078cd822016-09-14 07:48:04 -0700553 new->dents[i]->d_inode->i_mtime = current_time(new->dents[i]->d_inode);
John Johansen0d259f02013-07-10 21:13:43 -0700554 old->dents[i] = NULL;
555 }
556}
557
558static struct dentry *create_profile_file(struct dentry *dir, const char *name,
559 struct aa_profile *profile,
560 const struct file_operations *fops)
561{
John Johansen83995882017-01-16 00:42:19 -0800562 struct aa_proxy *proxy = aa_get_proxy(profile->proxy);
John Johansen0d259f02013-07-10 21:13:43 -0700563 struct dentry *dent;
564
John Johansen83995882017-01-16 00:42:19 -0800565 dent = securityfs_create_file(name, S_IFREG | 0444, dir, proxy, fops);
John Johansen0d259f02013-07-10 21:13:43 -0700566 if (IS_ERR(dent))
John Johansen83995882017-01-16 00:42:19 -0800567 aa_put_proxy(proxy);
John Johansen0d259f02013-07-10 21:13:43 -0700568
569 return dent;
570}
571
572/* requires lock be held */
573int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
574{
575 struct aa_profile *child;
576 struct dentry *dent = NULL, *dir;
577 int error;
578
579 if (!parent) {
580 struct aa_profile *p;
581 p = aa_deref_parent(profile);
582 dent = prof_dir(p);
583 /* adding to parent that previously didn't have children */
584 dent = securityfs_create_dir("profiles", dent);
585 if (IS_ERR(dent))
586 goto fail;
587 prof_child_dir(p) = parent = dent;
588 }
589
590 if (!profile->dirname) {
591 int len, id_len;
592 len = mangle_name(profile->base.name, NULL);
593 id_len = snprintf(NULL, 0, ".%ld", profile->ns->uniq_id);
594
595 profile->dirname = kmalloc(len + id_len + 1, GFP_KERNEL);
596 if (!profile->dirname)
597 goto fail;
598
599 mangle_name(profile->base.name, profile->dirname);
600 sprintf(profile->dirname + len, ".%ld", profile->ns->uniq_id++);
601 }
602
603 dent = securityfs_create_dir(profile->dirname, parent);
604 if (IS_ERR(dent))
605 goto fail;
606 prof_dir(profile) = dir = dent;
607
608 dent = create_profile_file(dir, "name", profile, &aa_fs_profname_fops);
609 if (IS_ERR(dent))
610 goto fail;
611 profile->dents[AAFS_PROF_NAME] = dent;
612
613 dent = create_profile_file(dir, "mode", profile, &aa_fs_profmode_fops);
614 if (IS_ERR(dent))
615 goto fail;
616 profile->dents[AAFS_PROF_MODE] = dent;
617
John Johansen556d0be2013-07-10 21:17:43 -0700618 dent = create_profile_file(dir, "attach", profile,
619 &aa_fs_profattach_fops);
620 if (IS_ERR(dent))
621 goto fail;
622 profile->dents[AAFS_PROF_ATTACH] = dent;
623
John Johansenf8eb8a12013-08-14 11:27:36 -0700624 if (profile->hash) {
625 dent = create_profile_file(dir, "sha1", profile,
626 &aa_fs_seq_hash_fops);
627 if (IS_ERR(dent))
628 goto fail;
629 profile->dents[AAFS_PROF_HASH] = dent;
630 }
631
John Johansen5ac8c352017-01-16 00:42:55 -0800632 if (profile->rawdata) {
633 dent = create_profile_file(dir, "raw_sha1", profile,
634 &aa_fs_seq_raw_hash_fops);
635 if (IS_ERR(dent))
636 goto fail;
637 profile->dents[AAFS_PROF_RAW_HASH] = dent;
638
639 dent = create_profile_file(dir, "raw_abi", profile,
640 &aa_fs_seq_raw_abi_fops);
641 if (IS_ERR(dent))
642 goto fail;
643 profile->dents[AAFS_PROF_RAW_ABI] = dent;
644
645 dent = securityfs_create_file("raw_data", S_IFREG | 0444, dir,
646 profile->proxy,
647 &aa_fs_rawdata_fops);
648 if (IS_ERR(dent))
649 goto fail;
650 profile->dents[AAFS_PROF_RAW_DATA] = dent;
651 d_inode(dent)->i_size = profile->rawdata->size;
652 aa_get_proxy(profile->proxy);
653 }
654
John Johansen0d259f02013-07-10 21:13:43 -0700655 list_for_each_entry(child, &profile->base.profiles, base.list) {
656 error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
657 if (error)
658 goto fail2;
659 }
660
661 return 0;
662
663fail:
664 error = PTR_ERR(dent);
665
666fail2:
667 __aa_fs_profile_rmdir(profile);
668
669 return error;
670}
671
John Johansen98849df2017-01-16 00:42:16 -0800672void __aa_fs_ns_rmdir(struct aa_ns *ns)
John Johansen0d259f02013-07-10 21:13:43 -0700673{
John Johansen98849df2017-01-16 00:42:16 -0800674 struct aa_ns *sub;
John Johansen0d259f02013-07-10 21:13:43 -0700675 struct aa_profile *child;
676 int i;
677
678 if (!ns)
679 return;
680
681 list_for_each_entry(child, &ns->base.profiles, base.list)
682 __aa_fs_profile_rmdir(child);
683
684 list_for_each_entry(sub, &ns->sub_ns, base.list) {
685 mutex_lock(&sub->lock);
John Johansen98849df2017-01-16 00:42:16 -0800686 __aa_fs_ns_rmdir(sub);
John Johansen0d259f02013-07-10 21:13:43 -0700687 mutex_unlock(&sub->lock);
688 }
689
John Johansenb7fd2c02017-01-16 00:42:58 -0800690 if (ns_subns_dir(ns)) {
691 sub = d_inode(ns_subns_dir(ns))->i_private;
692 aa_put_ns(sub);
693 }
694 if (ns_subload(ns)) {
695 sub = d_inode(ns_subload(ns))->i_private;
696 aa_put_ns(sub);
697 }
698 if (ns_subreplace(ns)) {
699 sub = d_inode(ns_subreplace(ns))->i_private;
700 aa_put_ns(sub);
701 }
702 if (ns_subremove(ns)) {
703 sub = d_inode(ns_subremove(ns))->i_private;
704 aa_put_ns(sub);
705 }
706
John Johansen0d259f02013-07-10 21:13:43 -0700707 for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
708 securityfs_remove(ns->dents[i]);
709 ns->dents[i] = NULL;
710 }
711}
712
John Johansenb7fd2c02017-01-16 00:42:58 -0800713/* assumes cleanup in caller */
714static int __aa_fs_ns_mkdir_entries(struct aa_ns *ns, struct dentry *dir)
715{
716 struct dentry *dent;
717
718 AA_BUG(!ns);
719 AA_BUG(!dir);
720
721 dent = securityfs_create_dir("profiles", dir);
722 if (IS_ERR(dent))
723 return PTR_ERR(dent);
724 ns_subprofs_dir(ns) = dent;
725
726 dent = securityfs_create_dir("raw_data", dir);
727 if (IS_ERR(dent))
728 return PTR_ERR(dent);
729 ns_subdata_dir(ns) = dent;
730
731 dent = securityfs_create_file(".load", 0640, dir, ns,
732 &aa_fs_profile_load);
733 if (IS_ERR(dent))
734 return PTR_ERR(dent);
735 aa_get_ns(ns);
736 ns_subload(ns) = dent;
737
738 dent = securityfs_create_file(".replace", 0640, dir, ns,
739 &aa_fs_profile_replace);
740 if (IS_ERR(dent))
741 return PTR_ERR(dent);
742 aa_get_ns(ns);
743 ns_subreplace(ns) = dent;
744
745 dent = securityfs_create_file(".remove", 0640, dir, ns,
746 &aa_fs_profile_remove);
747 if (IS_ERR(dent))
748 return PTR_ERR(dent);
749 aa_get_ns(ns);
750 ns_subremove(ns) = dent;
751
752 dent = securityfs_create_dir("namespaces", dir);
753 if (IS_ERR(dent))
754 return PTR_ERR(dent);
755 aa_get_ns(ns);
756 ns_subns_dir(ns) = dent;
757
758 return 0;
759}
760
John Johansen98849df2017-01-16 00:42:16 -0800761int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name)
John Johansen0d259f02013-07-10 21:13:43 -0700762{
John Johansen98849df2017-01-16 00:42:16 -0800763 struct aa_ns *sub;
John Johansen0d259f02013-07-10 21:13:43 -0700764 struct aa_profile *child;
765 struct dentry *dent, *dir;
766 int error;
767
John Johansenb7fd2c02017-01-16 00:42:58 -0800768 AA_BUG(!ns);
769 AA_BUG(!parent);
770 AA_BUG(!mutex_is_locked(&ns->lock));
771
John Johansen0d259f02013-07-10 21:13:43 -0700772 if (!name)
773 name = ns->base.name;
774
John Johansenb7fd2c02017-01-16 00:42:58 -0800775 /* create ns dir if it doesn't already exist */
John Johansen0d259f02013-07-10 21:13:43 -0700776 dent = securityfs_create_dir(name, parent);
777 if (IS_ERR(dent))
778 goto fail;
John Johansenb7fd2c02017-01-16 00:42:58 -0800779
John Johansen0d259f02013-07-10 21:13:43 -0700780 ns_dir(ns) = dir = dent;
John Johansenb7fd2c02017-01-16 00:42:58 -0800781 error = __aa_fs_ns_mkdir_entries(ns, dir);
782 if (error)
783 goto fail2;
John Johansen0d259f02013-07-10 21:13:43 -0700784
John Johansenb7fd2c02017-01-16 00:42:58 -0800785 /* profiles */
John Johansen0d259f02013-07-10 21:13:43 -0700786 list_for_each_entry(child, &ns->base.profiles, base.list) {
787 error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns));
788 if (error)
789 goto fail2;
790 }
791
John Johansenb7fd2c02017-01-16 00:42:58 -0800792 /* subnamespaces */
John Johansen0d259f02013-07-10 21:13:43 -0700793 list_for_each_entry(sub, &ns->sub_ns, base.list) {
794 mutex_lock(&sub->lock);
John Johansen98849df2017-01-16 00:42:16 -0800795 error = __aa_fs_ns_mkdir(sub, ns_subns_dir(ns), NULL);
John Johansen0d259f02013-07-10 21:13:43 -0700796 mutex_unlock(&sub->lock);
797 if (error)
798 goto fail2;
799 }
800
801 return 0;
802
803fail:
804 error = PTR_ERR(dent);
805
806fail2:
John Johansen98849df2017-01-16 00:42:16 -0800807 __aa_fs_ns_rmdir(ns);
John Johansen0d259f02013-07-10 21:13:43 -0700808
809 return error;
810}
811
812
John Johansen29b38222013-07-10 21:18:43 -0700813#define list_entry_is_head(pos, head, member) (&pos->member == (head))
814
815/**
John Johansen98849df2017-01-16 00:42:16 -0800816 * __next_ns - find the next namespace to list
John Johansen29b38222013-07-10 21:18:43 -0700817 * @root: root namespace to stop search at (NOT NULL)
818 * @ns: current ns position (NOT NULL)
819 *
820 * Find the next namespace from @ns under @root and handle all locking needed
821 * while switching current namespace.
822 *
823 * Returns: next namespace or NULL if at last namespace under @root
824 * Requires: ns->parent->lock to be held
825 * NOTE: will not unlock root->lock
826 */
John Johansen98849df2017-01-16 00:42:16 -0800827static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
John Johansen29b38222013-07-10 21:18:43 -0700828{
John Johansen98849df2017-01-16 00:42:16 -0800829 struct aa_ns *parent, *next;
John Johansen29b38222013-07-10 21:18:43 -0700830
831 /* is next namespace a child */
832 if (!list_empty(&ns->sub_ns)) {
833 next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
834 mutex_lock(&next->lock);
835 return next;
836 }
837
838 /* check if the next ns is a sibling, parent, gp, .. */
839 parent = ns->parent;
John Johansened2c7da2013-10-14 11:46:27 -0700840 while (ns != root) {
John Johansen29b38222013-07-10 21:18:43 -0700841 mutex_unlock(&ns->lock);
Geliang Tang38dbd7d2015-11-16 21:46:33 +0800842 next = list_next_entry(ns, base.list);
John Johansen29b38222013-07-10 21:18:43 -0700843 if (!list_entry_is_head(next, &parent->sub_ns, base.list)) {
844 mutex_lock(&next->lock);
845 return next;
846 }
John Johansen29b38222013-07-10 21:18:43 -0700847 ns = parent;
848 parent = parent->parent;
849 }
850
851 return NULL;
852}
853
854/**
855 * __first_profile - find the first profile in a namespace
856 * @root: namespace that is root of profiles being displayed (NOT NULL)
857 * @ns: namespace to start in (NOT NULL)
858 *
859 * Returns: unrefcounted profile or NULL if no profile
860 * Requires: profile->ns.lock to be held
861 */
John Johansen98849df2017-01-16 00:42:16 -0800862static struct aa_profile *__first_profile(struct aa_ns *root,
863 struct aa_ns *ns)
John Johansen29b38222013-07-10 21:18:43 -0700864{
John Johansen98849df2017-01-16 00:42:16 -0800865 for (; ns; ns = __next_ns(root, ns)) {
John Johansen29b38222013-07-10 21:18:43 -0700866 if (!list_empty(&ns->base.profiles))
867 return list_first_entry(&ns->base.profiles,
868 struct aa_profile, base.list);
869 }
870 return NULL;
871}
872
873/**
874 * __next_profile - step to the next profile in a profile tree
875 * @profile: current profile in tree (NOT NULL)
876 *
877 * Perform a depth first traversal on the profile tree in a namespace
878 *
879 * Returns: next profile or NULL if done
880 * Requires: profile->ns.lock to be held
881 */
882static struct aa_profile *__next_profile(struct aa_profile *p)
883{
884 struct aa_profile *parent;
John Johansen98849df2017-01-16 00:42:16 -0800885 struct aa_ns *ns = p->ns;
John Johansen29b38222013-07-10 21:18:43 -0700886
887 /* is next profile a child */
888 if (!list_empty(&p->base.profiles))
889 return list_first_entry(&p->base.profiles, typeof(*p),
890 base.list);
891
892 /* is next profile a sibling, parent sibling, gp, sibling, .. */
893 parent = rcu_dereference_protected(p->parent,
894 mutex_is_locked(&p->ns->lock));
895 while (parent) {
Geliang Tang38dbd7d2015-11-16 21:46:33 +0800896 p = list_next_entry(p, base.list);
John Johansen29b38222013-07-10 21:18:43 -0700897 if (!list_entry_is_head(p, &parent->base.profiles, base.list))
898 return p;
899 p = parent;
900 parent = rcu_dereference_protected(parent->parent,
901 mutex_is_locked(&parent->ns->lock));
902 }
903
904 /* is next another profile in the namespace */
Geliang Tang38dbd7d2015-11-16 21:46:33 +0800905 p = list_next_entry(p, base.list);
John Johansen29b38222013-07-10 21:18:43 -0700906 if (!list_entry_is_head(p, &ns->base.profiles, base.list))
907 return p;
908
909 return NULL;
910}
911
912/**
913 * next_profile - step to the next profile in where ever it may be
914 * @root: root namespace (NOT NULL)
915 * @profile: current profile (NOT NULL)
916 *
917 * Returns: next profile or NULL if there isn't one
918 */
John Johansen98849df2017-01-16 00:42:16 -0800919static struct aa_profile *next_profile(struct aa_ns *root,
John Johansen29b38222013-07-10 21:18:43 -0700920 struct aa_profile *profile)
921{
922 struct aa_profile *next = __next_profile(profile);
923 if (next)
924 return next;
925
926 /* finished all profiles in namespace move to next namespace */
John Johansen98849df2017-01-16 00:42:16 -0800927 return __first_profile(root, __next_ns(root, profile->ns));
John Johansen29b38222013-07-10 21:18:43 -0700928}
929
930/**
931 * p_start - start a depth first traversal of profile tree
932 * @f: seq_file to fill
933 * @pos: current position
934 *
935 * Returns: first profile under current namespace or NULL if none found
936 *
937 * acquires first ns->lock
938 */
939static void *p_start(struct seq_file *f, loff_t *pos)
940{
941 struct aa_profile *profile = NULL;
John Johansen98849df2017-01-16 00:42:16 -0800942 struct aa_ns *root = aa_current_profile()->ns;
John Johansen29b38222013-07-10 21:18:43 -0700943 loff_t l = *pos;
John Johansen98849df2017-01-16 00:42:16 -0800944 f->private = aa_get_ns(root);
John Johansen29b38222013-07-10 21:18:43 -0700945
946
947 /* find the first profile */
948 mutex_lock(&root->lock);
949 profile = __first_profile(root, root);
950
951 /* skip to position */
952 for (; profile && l > 0; l--)
953 profile = next_profile(root, profile);
954
955 return profile;
956}
957
958/**
959 * p_next - read the next profile entry
960 * @f: seq_file to fill
961 * @p: profile previously returned
962 * @pos: current position
963 *
964 * Returns: next profile after @p or NULL if none
965 *
966 * may acquire/release locks in namespace tree as necessary
967 */
968static void *p_next(struct seq_file *f, void *p, loff_t *pos)
969{
970 struct aa_profile *profile = p;
John Johansen98849df2017-01-16 00:42:16 -0800971 struct aa_ns *ns = f->private;
John Johansen29b38222013-07-10 21:18:43 -0700972 (*pos)++;
973
974 return next_profile(ns, profile);
975}
976
977/**
978 * p_stop - stop depth first traversal
979 * @f: seq_file we are filling
980 * @p: the last profile writen
981 *
982 * Release all locking done by p_start/p_next on namespace tree
983 */
984static void p_stop(struct seq_file *f, void *p)
985{
986 struct aa_profile *profile = p;
John Johansen98849df2017-01-16 00:42:16 -0800987 struct aa_ns *root = f->private, *ns;
John Johansen29b38222013-07-10 21:18:43 -0700988
989 if (profile) {
990 for (ns = profile->ns; ns && ns != root; ns = ns->parent)
991 mutex_unlock(&ns->lock);
992 }
993 mutex_unlock(&root->lock);
John Johansen98849df2017-01-16 00:42:16 -0800994 aa_put_ns(root);
John Johansen29b38222013-07-10 21:18:43 -0700995}
996
997/**
998 * seq_show_profile - show a profile entry
999 * @f: seq_file to file
1000 * @p: current position (profile) (NOT NULL)
1001 *
1002 * Returns: error on failure
1003 */
1004static int seq_show_profile(struct seq_file *f, void *p)
1005{
1006 struct aa_profile *profile = (struct aa_profile *)p;
John Johansen98849df2017-01-16 00:42:16 -08001007 struct aa_ns *root = f->private;
John Johansen29b38222013-07-10 21:18:43 -07001008
1009 if (profile->ns != root)
John Johansen92b6d8e2017-01-16 00:42:25 -08001010 seq_printf(f, ":%s://", aa_ns_name(root, profile->ns, true));
John Johansen29b38222013-07-10 21:18:43 -07001011 seq_printf(f, "%s (%s)\n", profile->base.hname,
1012 aa_profile_mode_names[profile->mode]);
1013
1014 return 0;
1015}
1016
1017static const struct seq_operations aa_fs_profiles_op = {
1018 .start = p_start,
1019 .next = p_next,
1020 .stop = p_stop,
1021 .show = seq_show_profile,
1022};
1023
1024static int profiles_open(struct inode *inode, struct file *file)
1025{
John Johansen5ac8c352017-01-16 00:42:55 -08001026 if (!policy_view_capable(NULL))
1027 return -EACCES;
1028
John Johansen29b38222013-07-10 21:18:43 -07001029 return seq_open(file, &aa_fs_profiles_op);
1030}
1031
1032static int profiles_release(struct inode *inode, struct file *file)
1033{
1034 return seq_release(inode, file);
1035}
1036
1037static const struct file_operations aa_fs_profiles_fops = {
1038 .open = profiles_open,
1039 .read = seq_read,
1040 .llseek = seq_lseek,
1041 .release = profiles_release,
1042};
1043
1044
John Johansen0d259f02013-07-10 21:13:43 -07001045/** Base file system setup **/
Kees Cooka9bf8e92012-01-26 16:29:22 -08001046static struct aa_fs_entry aa_fs_entry_file[] = {
1047 AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \
1048 "link lock"),
1049 { }
1050};
1051
Kees Cooke74abcf2012-01-26 16:29:21 -08001052static struct aa_fs_entry aa_fs_entry_domain[] = {
1053 AA_FS_FILE_BOOLEAN("change_hat", 1),
1054 AA_FS_FILE_BOOLEAN("change_hatv", 1),
1055 AA_FS_FILE_BOOLEAN("change_onexec", 1),
1056 AA_FS_FILE_BOOLEAN("change_profile", 1),
John Johansen34c426a2017-01-16 00:42:43 -08001057 AA_FS_FILE_BOOLEAN("fix_binfmt_elf_mmap", 1),
Kees Cooke74abcf2012-01-26 16:29:21 -08001058 { }
1059};
1060
John Johansen474d6b752017-01-16 00:42:39 -08001061static struct aa_fs_entry aa_fs_entry_versions[] = {
1062 AA_FS_FILE_BOOLEAN("v5", 1),
1063 { }
1064};
1065
John Johansen9d910a32013-07-10 21:04:43 -07001066static struct aa_fs_entry aa_fs_entry_policy[] = {
John Johansen474d6b752017-01-16 00:42:39 -08001067 AA_FS_DIR("versions", aa_fs_entry_versions),
1068 AA_FS_FILE_BOOLEAN("set_load", 1),
1069 { }
John Johansen9d910a32013-07-10 21:04:43 -07001070};
1071
Kees Cooke74abcf2012-01-26 16:29:21 -08001072static struct aa_fs_entry aa_fs_entry_features[] = {
John Johansen9d910a32013-07-10 21:04:43 -07001073 AA_FS_DIR("policy", aa_fs_entry_policy),
Kees Cooke74abcf2012-01-26 16:29:21 -08001074 AA_FS_DIR("domain", aa_fs_entry_domain),
Kees Cooka9bf8e92012-01-26 16:29:22 -08001075 AA_FS_DIR("file", aa_fs_entry_file),
Kees Cooke74abcf2012-01-26 16:29:21 -08001076 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
Kees Cookd384b0a2012-01-26 16:29:23 -08001077 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
John Johansen84f1f782013-08-14 11:27:32 -07001078 AA_FS_DIR("caps", aa_fs_entry_caps),
Kees Cooke74abcf2012-01-26 16:29:21 -08001079 { }
1080};
1081
Kees Cook9acd4942012-01-26 16:29:20 -08001082static struct aa_fs_entry aa_fs_entry_apparmor[] = {
John Johansena71ada32017-01-16 00:42:45 -08001083 AA_FS_FILE_FOPS(".ns_level", 0666, &aa_fs_ns_level),
John Johansen3e3e5692017-01-16 00:42:48 -08001084 AA_FS_FILE_FOPS(".ns_name", 0640, &aa_fs_ns_name),
John Johansenb7fd2c02017-01-16 00:42:58 -08001085 AA_FS_FILE_FOPS("profiles", 0440, &aa_fs_profiles_fops),
Kees Cooke74abcf2012-01-26 16:29:21 -08001086 AA_FS_DIR("features", aa_fs_entry_features),
Kees Cook9acd4942012-01-26 16:29:20 -08001087 { }
1088};
John Johansen63e2b422010-07-29 14:48:03 -07001089
Kees Cook9acd4942012-01-26 16:29:20 -08001090static struct aa_fs_entry aa_fs_entry =
1091 AA_FS_DIR("apparmor", aa_fs_entry_apparmor);
1092
1093/**
1094 * aafs_create_file - create a file entry in the apparmor securityfs
1095 * @fs_file: aa_fs_entry to build an entry for (NOT NULL)
1096 * @parent: the parent dentry in the securityfs
1097 *
1098 * Use aafs_remove_file to remove entries created with this fn.
1099 */
1100static int __init aafs_create_file(struct aa_fs_entry *fs_file,
1101 struct dentry *parent)
John Johansen63e2b422010-07-29 14:48:03 -07001102{
Kees Cook9acd4942012-01-26 16:29:20 -08001103 int error = 0;
John Johansen63e2b422010-07-29 14:48:03 -07001104
Kees Cook9acd4942012-01-26 16:29:20 -08001105 fs_file->dentry = securityfs_create_file(fs_file->name,
1106 S_IFREG | fs_file->mode,
1107 parent, fs_file,
1108 fs_file->file_ops);
1109 if (IS_ERR(fs_file->dentry)) {
1110 error = PTR_ERR(fs_file->dentry);
1111 fs_file->dentry = NULL;
John Johansen63e2b422010-07-29 14:48:03 -07001112 }
Kees Cook9acd4942012-01-26 16:29:20 -08001113 return error;
John Johansen63e2b422010-07-29 14:48:03 -07001114}
1115
John Johansen0d259f02013-07-10 21:13:43 -07001116static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir);
John Johansen63e2b422010-07-29 14:48:03 -07001117/**
Kees Cook9acd4942012-01-26 16:29:20 -08001118 * aafs_create_dir - recursively create a directory entry in the securityfs
1119 * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL)
1120 * @parent: the parent dentry in the securityfs
John Johansen63e2b422010-07-29 14:48:03 -07001121 *
Kees Cook9acd4942012-01-26 16:29:20 -08001122 * Use aafs_remove_dir to remove entries created with this fn.
John Johansen63e2b422010-07-29 14:48:03 -07001123 */
Kees Cook9acd4942012-01-26 16:29:20 -08001124static int __init aafs_create_dir(struct aa_fs_entry *fs_dir,
1125 struct dentry *parent)
John Johansen63e2b422010-07-29 14:48:03 -07001126{
Kees Cook9acd4942012-01-26 16:29:20 -08001127 struct aa_fs_entry *fs_file;
John Johansen0d259f02013-07-10 21:13:43 -07001128 struct dentry *dir;
1129 int error;
John Johansen63e2b422010-07-29 14:48:03 -07001130
John Johansen0d259f02013-07-10 21:13:43 -07001131 dir = securityfs_create_dir(fs_dir->name, parent);
1132 if (IS_ERR(dir))
1133 return PTR_ERR(dir);
1134 fs_dir->dentry = dir;
John Johansen63e2b422010-07-29 14:48:03 -07001135
John Johansen0d259f02013-07-10 21:13:43 -07001136 for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
Kees Cook9acd4942012-01-26 16:29:20 -08001137 if (fs_file->v_type == AA_FS_TYPE_DIR)
1138 error = aafs_create_dir(fs_file, fs_dir->dentry);
1139 else
1140 error = aafs_create_file(fs_file, fs_dir->dentry);
1141 if (error)
1142 goto failed;
1143 }
1144
1145 return 0;
1146
1147failed:
John Johansen0d259f02013-07-10 21:13:43 -07001148 aafs_remove_dir(fs_dir);
1149
Kees Cook9acd4942012-01-26 16:29:20 -08001150 return error;
1151}
1152
1153/**
1154 * aafs_remove_file - drop a single file entry in the apparmor securityfs
1155 * @fs_file: aa_fs_entry to detach from the securityfs (NOT NULL)
1156 */
1157static void __init aafs_remove_file(struct aa_fs_entry *fs_file)
1158{
1159 if (!fs_file->dentry)
1160 return;
1161
1162 securityfs_remove(fs_file->dentry);
1163 fs_file->dentry = NULL;
1164}
1165
1166/**
1167 * aafs_remove_dir - recursively drop a directory entry from the securityfs
1168 * @fs_dir: aa_fs_entry (and all child entries) to detach (NOT NULL)
1169 */
1170static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir)
1171{
1172 struct aa_fs_entry *fs_file;
1173
John Johansen0d259f02013-07-10 21:13:43 -07001174 for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
Kees Cook9acd4942012-01-26 16:29:20 -08001175 if (fs_file->v_type == AA_FS_TYPE_DIR)
1176 aafs_remove_dir(fs_file);
1177 else
1178 aafs_remove_file(fs_file);
1179 }
1180
1181 aafs_remove_file(fs_dir);
John Johansen63e2b422010-07-29 14:48:03 -07001182}
1183
1184/**
1185 * aa_destroy_aafs - cleanup and free aafs
1186 *
1187 * releases dentries allocated by aa_create_aafs
1188 */
1189void __init aa_destroy_aafs(void)
1190{
Kees Cook9acd4942012-01-26 16:29:20 -08001191 aafs_remove_dir(&aa_fs_entry);
John Johansen63e2b422010-07-29 14:48:03 -07001192}
1193
John Johansena71ada32017-01-16 00:42:45 -08001194
1195#define NULL_FILE_NAME ".null"
1196struct path aa_null;
1197
1198static int aa_mk_null_file(struct dentry *parent)
1199{
1200 struct vfsmount *mount = NULL;
1201 struct dentry *dentry;
1202 struct inode *inode;
1203 int count = 0;
1204 int error = simple_pin_fs(parent->d_sb->s_type, &mount, &count);
1205
1206 if (error)
1207 return error;
1208
1209 inode_lock(d_inode(parent));
1210 dentry = lookup_one_len(NULL_FILE_NAME, parent, strlen(NULL_FILE_NAME));
1211 if (IS_ERR(dentry)) {
1212 error = PTR_ERR(dentry);
1213 goto out;
1214 }
1215 inode = new_inode(parent->d_inode->i_sb);
1216 if (!inode) {
1217 error = -ENOMEM;
1218 goto out1;
1219 }
1220
1221 inode->i_ino = get_next_ino();
1222 inode->i_mode = S_IFCHR | S_IRUGO | S_IWUGO;
1223 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
1224 init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO,
1225 MKDEV(MEM_MAJOR, 3));
1226 d_instantiate(dentry, inode);
1227 aa_null.dentry = dget(dentry);
1228 aa_null.mnt = mntget(mount);
1229
1230 error = 0;
1231
1232out1:
1233 dput(dentry);
1234out:
1235 inode_unlock(d_inode(parent));
1236 simple_release_fs(&mount, &count);
1237 return error;
1238}
1239
John Johansen63e2b422010-07-29 14:48:03 -07001240/**
1241 * aa_create_aafs - create the apparmor security filesystem
1242 *
1243 * dentries created here are released by aa_destroy_aafs
1244 *
1245 * Returns: error on failure
1246 */
James Morris3417d8d2011-08-17 11:05:21 +10001247static int __init aa_create_aafs(void)
John Johansen63e2b422010-07-29 14:48:03 -07001248{
John Johansenb7fd2c02017-01-16 00:42:58 -08001249 struct dentry *dent;
John Johansen63e2b422010-07-29 14:48:03 -07001250 int error;
1251
1252 if (!apparmor_initialized)
1253 return 0;
1254
Kees Cook9acd4942012-01-26 16:29:20 -08001255 if (aa_fs_entry.dentry) {
John Johansen63e2b422010-07-29 14:48:03 -07001256 AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
1257 return -EEXIST;
1258 }
1259
Kees Cook9acd4942012-01-26 16:29:20 -08001260 /* Populate fs tree. */
1261 error = aafs_create_dir(&aa_fs_entry, NULL);
John Johansen63e2b422010-07-29 14:48:03 -07001262 if (error)
1263 goto error;
1264
John Johansenb7fd2c02017-01-16 00:42:58 -08001265 dent = securityfs_create_file(".load", 0666, aa_fs_entry.dentry,
1266 NULL, &aa_fs_profile_load);
1267 if (IS_ERR(dent)) {
1268 error = PTR_ERR(dent);
1269 goto error;
1270 }
1271 ns_subload(root_ns) = dent;
1272
1273 dent = securityfs_create_file(".replace", 0666, aa_fs_entry.dentry,
1274 NULL, &aa_fs_profile_replace);
1275 if (IS_ERR(dent)) {
1276 error = PTR_ERR(dent);
1277 goto error;
1278 }
1279 ns_subreplace(root_ns) = dent;
1280
1281 dent = securityfs_create_file(".remove", 0666, aa_fs_entry.dentry,
1282 NULL, &aa_fs_profile_remove);
1283 if (IS_ERR(dent)) {
1284 error = PTR_ERR(dent);
1285 goto error;
1286 }
1287 ns_subremove(root_ns) = dent;
1288
1289 mutex_lock(&root_ns->lock);
John Johansen98849df2017-01-16 00:42:16 -08001290 error = __aa_fs_ns_mkdir(root_ns, aa_fs_entry.dentry, "policy");
John Johansenb7fd2c02017-01-16 00:42:58 -08001291 mutex_unlock(&root_ns->lock);
1292
John Johansen0d259f02013-07-10 21:13:43 -07001293 if (error)
1294 goto error;
1295
John Johansena71ada32017-01-16 00:42:45 -08001296 error = aa_mk_null_file(aa_fs_entry.dentry);
1297 if (error)
1298 goto error;
1299
1300 /* TODO: add default profile to apparmorfs */
John Johansen63e2b422010-07-29 14:48:03 -07001301
1302 /* Report that AppArmor fs is enabled */
1303 aa_info_message("AppArmor Filesystem Enabled");
1304 return 0;
1305
1306error:
1307 aa_destroy_aafs();
1308 AA_ERROR("Error creating AppArmor securityfs\n");
1309 return error;
1310}
1311
1312fs_initcall(aa_create_aafs);