blob: 2501a65fe7d3001347681b83efd6f8bbcc7a9e7d [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 Johansen63e2b422010-07-29 14:48:03 -070036
37/**
John Johansen0d259f02013-07-10 21:13:43 -070038 * aa_mangle_name - mangle a profile name to std profile layout form
39 * @name: profile name to mangle (NOT NULL)
40 * @target: buffer to store mangled name, same length as @name (MAYBE NULL)
41 *
42 * Returns: length of mangled name
43 */
John Johansenbbe4a7c2017-01-16 00:42:30 -080044static int mangle_name(const char *name, char *target)
John Johansen0d259f02013-07-10 21:13:43 -070045{
46 char *t = target;
47
48 while (*name == '/' || *name == '.')
49 name++;
50
51 if (target) {
52 for (; *name; name++) {
53 if (*name == '/')
54 *(t)++ = '.';
55 else if (isspace(*name))
56 *(t)++ = '_';
57 else if (isalnum(*name) || strchr("._-", *name))
58 *(t)++ = *name;
59 }
60
61 *t = 0;
62 } else {
63 int len = 0;
64 for (; *name; name++) {
65 if (isalnum(*name) || isspace(*name) ||
66 strchr("/._-", *name))
67 len++;
68 }
69
70 return len;
71 }
72
73 return t - target;
74}
75
76/**
John Johansen63e2b422010-07-29 14:48:03 -070077 * aa_simple_write_to_buffer - common routine for getting policy from user
78 * @op: operation doing the user buffer copy
79 * @userbuf: user buffer to copy data from (NOT NULL)
John Johansen3ed02ad2010-10-09 00:47:53 -070080 * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size)
John Johansen63e2b422010-07-29 14:48:03 -070081 * @copy_size: size of data to copy from user buffer
82 * @pos: position write is at in the file (NOT NULL)
83 *
84 * Returns: kernel buffer containing copy of user buffer data or an
85 * ERR_PTR on failure.
86 */
87static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
88 size_t alloc_size, size_t copy_size,
89 loff_t *pos)
90{
91 char *data;
92
John Johansen3ed02ad2010-10-09 00:47:53 -070093 BUG_ON(copy_size > alloc_size);
94
John Johansen63e2b422010-07-29 14:48:03 -070095 if (*pos != 0)
96 /* only writes from pos 0, that is complete writes */
97 return ERR_PTR(-ESPIPE);
98
99 /*
100 * Don't allow profile load/replace/remove from profiles that don't
101 * have CAP_MAC_ADMIN
102 */
103 if (!aa_may_manage_policy(op))
104 return ERR_PTR(-EACCES);
105
106 /* freed by caller to simple_write_to_buffer */
107 data = kvmalloc(alloc_size);
108 if (data == NULL)
109 return ERR_PTR(-ENOMEM);
110
111 if (copy_from_user(data, userbuf, copy_size)) {
112 kvfree(data);
113 return ERR_PTR(-EFAULT);
114 }
115
116 return data;
117}
118
119
120/* .load file hook fn to load policy */
121static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
122 loff_t *pos)
123{
124 char *data;
125 ssize_t error;
126
127 data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos);
128
129 error = PTR_ERR(data);
130 if (!IS_ERR(data)) {
John Johansen73688d12017-01-16 00:42:34 -0800131 error = aa_replace_profiles(__aa_current_profile()->ns, data,
132 size, PROF_ADD);
John Johansen63e2b422010-07-29 14:48:03 -0700133 kvfree(data);
134 }
135
136 return error;
137}
138
139static const struct file_operations aa_fs_profile_load = {
Arnd Bergmann6038f372010-08-15 18:52:59 +0200140 .write = profile_load,
141 .llseek = default_llseek,
John Johansen63e2b422010-07-29 14:48:03 -0700142};
143
144/* .replace file hook fn to load and/or replace policy */
145static ssize_t profile_replace(struct file *f, const char __user *buf,
146 size_t size, loff_t *pos)
147{
148 char *data;
149 ssize_t error;
150
151 data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
152 error = PTR_ERR(data);
153 if (!IS_ERR(data)) {
John Johansen73688d12017-01-16 00:42:34 -0800154 error = aa_replace_profiles(__aa_current_profile()->ns, data,
155 size, PROF_REPLACE);
John Johansen63e2b422010-07-29 14:48:03 -0700156 kvfree(data);
157 }
158
159 return error;
160}
161
162static const struct file_operations aa_fs_profile_replace = {
Arnd Bergmann6038f372010-08-15 18:52:59 +0200163 .write = profile_replace,
164 .llseek = default_llseek,
John Johansen63e2b422010-07-29 14:48:03 -0700165};
166
167/* .remove file hook fn to remove loaded policy */
168static ssize_t profile_remove(struct file *f, const char __user *buf,
169 size_t size, loff_t *pos)
170{
171 char *data;
172 ssize_t error;
173
174 /*
175 * aa_remove_profile needs a null terminated string so 1 extra
176 * byte is allocated and the copied data is null terminated.
177 */
178 data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos);
179
180 error = PTR_ERR(data);
181 if (!IS_ERR(data)) {
182 data[size] = 0;
183 error = aa_remove_profiles(data, size);
184 kvfree(data);
185 }
186
187 return error;
188}
189
190static const struct file_operations aa_fs_profile_remove = {
Arnd Bergmann6038f372010-08-15 18:52:59 +0200191 .write = profile_remove,
192 .llseek = default_llseek,
John Johansen63e2b422010-07-29 14:48:03 -0700193};
194
Kees Cooke74abcf2012-01-26 16:29:21 -0800195static int aa_fs_seq_show(struct seq_file *seq, void *v)
196{
197 struct aa_fs_entry *fs_file = seq->private;
198
199 if (!fs_file)
200 return 0;
201
202 switch (fs_file->v_type) {
203 case AA_FS_TYPE_BOOLEAN:
204 seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no");
205 break;
Kees Cooka9bf8e92012-01-26 16:29:22 -0800206 case AA_FS_TYPE_STRING:
207 seq_printf(seq, "%s\n", fs_file->v.string);
208 break;
Kees Cooke74abcf2012-01-26 16:29:21 -0800209 case AA_FS_TYPE_U64:
210 seq_printf(seq, "%#08lx\n", fs_file->v.u64);
211 break;
212 default:
213 /* Ignore unpritable entry types. */
214 break;
215 }
216
217 return 0;
218}
219
220static int aa_fs_seq_open(struct inode *inode, struct file *file)
221{
222 return single_open(file, aa_fs_seq_show, inode->i_private);
223}
224
225const struct file_operations aa_fs_seq_file_ops = {
226 .owner = THIS_MODULE,
227 .open = aa_fs_seq_open,
228 .read = seq_read,
229 .llseek = seq_lseek,
230 .release = single_release,
231};
232
John Johansen0d259f02013-07-10 21:13:43 -0700233static int aa_fs_seq_profile_open(struct inode *inode, struct file *file,
234 int (*show)(struct seq_file *, void *))
235{
John Johansen83995882017-01-16 00:42:19 -0800236 struct aa_proxy *proxy = aa_get_proxy(inode->i_private);
237 int error = single_open(file, show, proxy);
John Johansen63e2b422010-07-29 14:48:03 -0700238
John Johansen0d259f02013-07-10 21:13:43 -0700239 if (error) {
240 file->private_data = NULL;
John Johansen83995882017-01-16 00:42:19 -0800241 aa_put_proxy(proxy);
John Johansen0d259f02013-07-10 21:13:43 -0700242 }
243
244 return error;
245}
246
247static int aa_fs_seq_profile_release(struct inode *inode, struct file *file)
248{
249 struct seq_file *seq = (struct seq_file *) file->private_data;
250 if (seq)
John Johansen83995882017-01-16 00:42:19 -0800251 aa_put_proxy(seq->private);
John Johansen0d259f02013-07-10 21:13:43 -0700252 return single_release(inode, file);
253}
254
255static int aa_fs_seq_profname_show(struct seq_file *seq, void *v)
256{
John Johansen83995882017-01-16 00:42:19 -0800257 struct aa_proxy *proxy = seq->private;
258 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
John Johansen0d259f02013-07-10 21:13:43 -0700259 seq_printf(seq, "%s\n", profile->base.name);
260 aa_put_profile(profile);
261
262 return 0;
263}
264
265static int aa_fs_seq_profname_open(struct inode *inode, struct file *file)
266{
267 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profname_show);
268}
269
270static const struct file_operations aa_fs_profname_fops = {
271 .owner = THIS_MODULE,
272 .open = aa_fs_seq_profname_open,
273 .read = seq_read,
274 .llseek = seq_lseek,
275 .release = aa_fs_seq_profile_release,
276};
277
278static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v)
279{
John Johansen83995882017-01-16 00:42:19 -0800280 struct aa_proxy *proxy = seq->private;
281 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
John Johansen0d259f02013-07-10 21:13:43 -0700282 seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]);
283 aa_put_profile(profile);
284
285 return 0;
286}
287
288static int aa_fs_seq_profmode_open(struct inode *inode, struct file *file)
289{
290 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profmode_show);
291}
292
293static const struct file_operations aa_fs_profmode_fops = {
294 .owner = THIS_MODULE,
295 .open = aa_fs_seq_profmode_open,
296 .read = seq_read,
297 .llseek = seq_lseek,
298 .release = aa_fs_seq_profile_release,
299};
300
John Johansen556d0be2013-07-10 21:17:43 -0700301static int aa_fs_seq_profattach_show(struct seq_file *seq, void *v)
302{
John Johansen83995882017-01-16 00:42:19 -0800303 struct aa_proxy *proxy = seq->private;
304 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
John Johansen556d0be2013-07-10 21:17:43 -0700305 if (profile->attach)
306 seq_printf(seq, "%s\n", profile->attach);
307 else if (profile->xmatch)
308 seq_puts(seq, "<unknown>\n");
309 else
310 seq_printf(seq, "%s\n", profile->base.name);
311 aa_put_profile(profile);
312
313 return 0;
314}
315
316static int aa_fs_seq_profattach_open(struct inode *inode, struct file *file)
317{
318 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profattach_show);
319}
320
321static const struct file_operations aa_fs_profattach_fops = {
322 .owner = THIS_MODULE,
323 .open = aa_fs_seq_profattach_open,
324 .read = seq_read,
325 .llseek = seq_lseek,
326 .release = aa_fs_seq_profile_release,
327};
328
John Johansenf8eb8a12013-08-14 11:27:36 -0700329static int aa_fs_seq_hash_show(struct seq_file *seq, void *v)
330{
John Johansen83995882017-01-16 00:42:19 -0800331 struct aa_proxy *proxy = seq->private;
332 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
John Johansenf8eb8a12013-08-14 11:27:36 -0700333 unsigned int i, size = aa_hash_size();
334
335 if (profile->hash) {
336 for (i = 0; i < size; i++)
337 seq_printf(seq, "%.2x", profile->hash[i]);
338 seq_puts(seq, "\n");
339 }
John Johansen0b938a22015-11-18 11:41:05 -0800340 aa_put_profile(profile);
John Johansenf8eb8a12013-08-14 11:27:36 -0700341
342 return 0;
343}
344
345static int aa_fs_seq_hash_open(struct inode *inode, struct file *file)
346{
347 return single_open(file, aa_fs_seq_hash_show, inode->i_private);
348}
349
350static const struct file_operations aa_fs_seq_hash_fops = {
351 .owner = THIS_MODULE,
352 .open = aa_fs_seq_hash_open,
353 .read = seq_read,
354 .llseek = seq_lseek,
355 .release = single_release,
356};
357
John Johansena71ada32017-01-16 00:42:45 -0800358static int aa_fs_seq_show_ns_level(struct seq_file *seq, void *v)
359{
360 struct aa_ns *ns = aa_current_profile()->ns;
361
362 seq_printf(seq, "%d\n", ns->level);
363
364 return 0;
365}
366
367static int aa_fs_seq_open_ns_level(struct inode *inode, struct file *file)
368{
369 return single_open(file, aa_fs_seq_show_ns_level, inode->i_private);
370}
371
372static const struct file_operations aa_fs_ns_level = {
373 .owner = THIS_MODULE,
374 .open = aa_fs_seq_open_ns_level,
375 .read = seq_read,
376 .llseek = seq_lseek,
377 .release = single_release,
378};
379
John Johansen0d259f02013-07-10 21:13:43 -0700380/** fns to setup dynamic per profile/namespace files **/
381void __aa_fs_profile_rmdir(struct aa_profile *profile)
382{
383 struct aa_profile *child;
384 int i;
385
386 if (!profile)
387 return;
388
389 list_for_each_entry(child, &profile->base.profiles, base.list)
390 __aa_fs_profile_rmdir(child);
391
392 for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) {
John Johansen83995882017-01-16 00:42:19 -0800393 struct aa_proxy *proxy;
John Johansen0d259f02013-07-10 21:13:43 -0700394 if (!profile->dents[i])
395 continue;
396
John Johansen83995882017-01-16 00:42:19 -0800397 proxy = d_inode(profile->dents[i])->i_private;
John Johansen0d259f02013-07-10 21:13:43 -0700398 securityfs_remove(profile->dents[i]);
John Johansen83995882017-01-16 00:42:19 -0800399 aa_put_proxy(proxy);
John Johansen0d259f02013-07-10 21:13:43 -0700400 profile->dents[i] = NULL;
401 }
402}
403
404void __aa_fs_profile_migrate_dents(struct aa_profile *old,
405 struct aa_profile *new)
406{
407 int i;
408
409 for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
410 new->dents[i] = old->dents[i];
John Johansend671e8902014-07-25 04:01:56 -0700411 if (new->dents[i])
Deepa Dinamani078cd822016-09-14 07:48:04 -0700412 new->dents[i]->d_inode->i_mtime = current_time(new->dents[i]->d_inode);
John Johansen0d259f02013-07-10 21:13:43 -0700413 old->dents[i] = NULL;
414 }
415}
416
417static struct dentry *create_profile_file(struct dentry *dir, const char *name,
418 struct aa_profile *profile,
419 const struct file_operations *fops)
420{
John Johansen83995882017-01-16 00:42:19 -0800421 struct aa_proxy *proxy = aa_get_proxy(profile->proxy);
John Johansen0d259f02013-07-10 21:13:43 -0700422 struct dentry *dent;
423
John Johansen83995882017-01-16 00:42:19 -0800424 dent = securityfs_create_file(name, S_IFREG | 0444, dir, proxy, fops);
John Johansen0d259f02013-07-10 21:13:43 -0700425 if (IS_ERR(dent))
John Johansen83995882017-01-16 00:42:19 -0800426 aa_put_proxy(proxy);
John Johansen0d259f02013-07-10 21:13:43 -0700427
428 return dent;
429}
430
431/* requires lock be held */
432int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
433{
434 struct aa_profile *child;
435 struct dentry *dent = NULL, *dir;
436 int error;
437
438 if (!parent) {
439 struct aa_profile *p;
440 p = aa_deref_parent(profile);
441 dent = prof_dir(p);
442 /* adding to parent that previously didn't have children */
443 dent = securityfs_create_dir("profiles", dent);
444 if (IS_ERR(dent))
445 goto fail;
446 prof_child_dir(p) = parent = dent;
447 }
448
449 if (!profile->dirname) {
450 int len, id_len;
451 len = mangle_name(profile->base.name, NULL);
452 id_len = snprintf(NULL, 0, ".%ld", profile->ns->uniq_id);
453
454 profile->dirname = kmalloc(len + id_len + 1, GFP_KERNEL);
455 if (!profile->dirname)
456 goto fail;
457
458 mangle_name(profile->base.name, profile->dirname);
459 sprintf(profile->dirname + len, ".%ld", profile->ns->uniq_id++);
460 }
461
462 dent = securityfs_create_dir(profile->dirname, parent);
463 if (IS_ERR(dent))
464 goto fail;
465 prof_dir(profile) = dir = dent;
466
467 dent = create_profile_file(dir, "name", profile, &aa_fs_profname_fops);
468 if (IS_ERR(dent))
469 goto fail;
470 profile->dents[AAFS_PROF_NAME] = dent;
471
472 dent = create_profile_file(dir, "mode", profile, &aa_fs_profmode_fops);
473 if (IS_ERR(dent))
474 goto fail;
475 profile->dents[AAFS_PROF_MODE] = dent;
476
John Johansen556d0be2013-07-10 21:17:43 -0700477 dent = create_profile_file(dir, "attach", profile,
478 &aa_fs_profattach_fops);
479 if (IS_ERR(dent))
480 goto fail;
481 profile->dents[AAFS_PROF_ATTACH] = dent;
482
John Johansenf8eb8a12013-08-14 11:27:36 -0700483 if (profile->hash) {
484 dent = create_profile_file(dir, "sha1", profile,
485 &aa_fs_seq_hash_fops);
486 if (IS_ERR(dent))
487 goto fail;
488 profile->dents[AAFS_PROF_HASH] = dent;
489 }
490
John Johansen0d259f02013-07-10 21:13:43 -0700491 list_for_each_entry(child, &profile->base.profiles, base.list) {
492 error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
493 if (error)
494 goto fail2;
495 }
496
497 return 0;
498
499fail:
500 error = PTR_ERR(dent);
501
502fail2:
503 __aa_fs_profile_rmdir(profile);
504
505 return error;
506}
507
John Johansen98849df2017-01-16 00:42:16 -0800508void __aa_fs_ns_rmdir(struct aa_ns *ns)
John Johansen0d259f02013-07-10 21:13:43 -0700509{
John Johansen98849df2017-01-16 00:42:16 -0800510 struct aa_ns *sub;
John Johansen0d259f02013-07-10 21:13:43 -0700511 struct aa_profile *child;
512 int i;
513
514 if (!ns)
515 return;
516
517 list_for_each_entry(child, &ns->base.profiles, base.list)
518 __aa_fs_profile_rmdir(child);
519
520 list_for_each_entry(sub, &ns->sub_ns, base.list) {
521 mutex_lock(&sub->lock);
John Johansen98849df2017-01-16 00:42:16 -0800522 __aa_fs_ns_rmdir(sub);
John Johansen0d259f02013-07-10 21:13:43 -0700523 mutex_unlock(&sub->lock);
524 }
525
526 for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
527 securityfs_remove(ns->dents[i]);
528 ns->dents[i] = NULL;
529 }
530}
531
John Johansen98849df2017-01-16 00:42:16 -0800532int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name)
John Johansen0d259f02013-07-10 21:13:43 -0700533{
John Johansen98849df2017-01-16 00:42:16 -0800534 struct aa_ns *sub;
John Johansen0d259f02013-07-10 21:13:43 -0700535 struct aa_profile *child;
536 struct dentry *dent, *dir;
537 int error;
538
539 if (!name)
540 name = ns->base.name;
541
542 dent = securityfs_create_dir(name, parent);
543 if (IS_ERR(dent))
544 goto fail;
545 ns_dir(ns) = dir = dent;
546
547 dent = securityfs_create_dir("profiles", dir);
548 if (IS_ERR(dent))
549 goto fail;
550 ns_subprofs_dir(ns) = dent;
551
552 dent = securityfs_create_dir("namespaces", dir);
553 if (IS_ERR(dent))
554 goto fail;
555 ns_subns_dir(ns) = dent;
556
557 list_for_each_entry(child, &ns->base.profiles, base.list) {
558 error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns));
559 if (error)
560 goto fail2;
561 }
562
563 list_for_each_entry(sub, &ns->sub_ns, base.list) {
564 mutex_lock(&sub->lock);
John Johansen98849df2017-01-16 00:42:16 -0800565 error = __aa_fs_ns_mkdir(sub, ns_subns_dir(ns), NULL);
John Johansen0d259f02013-07-10 21:13:43 -0700566 mutex_unlock(&sub->lock);
567 if (error)
568 goto fail2;
569 }
570
571 return 0;
572
573fail:
574 error = PTR_ERR(dent);
575
576fail2:
John Johansen98849df2017-01-16 00:42:16 -0800577 __aa_fs_ns_rmdir(ns);
John Johansen0d259f02013-07-10 21:13:43 -0700578
579 return error;
580}
581
582
John Johansen29b38222013-07-10 21:18:43 -0700583#define list_entry_is_head(pos, head, member) (&pos->member == (head))
584
585/**
John Johansen98849df2017-01-16 00:42:16 -0800586 * __next_ns - find the next namespace to list
John Johansen29b38222013-07-10 21:18:43 -0700587 * @root: root namespace to stop search at (NOT NULL)
588 * @ns: current ns position (NOT NULL)
589 *
590 * Find the next namespace from @ns under @root and handle all locking needed
591 * while switching current namespace.
592 *
593 * Returns: next namespace or NULL if at last namespace under @root
594 * Requires: ns->parent->lock to be held
595 * NOTE: will not unlock root->lock
596 */
John Johansen98849df2017-01-16 00:42:16 -0800597static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
John Johansen29b38222013-07-10 21:18:43 -0700598{
John Johansen98849df2017-01-16 00:42:16 -0800599 struct aa_ns *parent, *next;
John Johansen29b38222013-07-10 21:18:43 -0700600
601 /* is next namespace a child */
602 if (!list_empty(&ns->sub_ns)) {
603 next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
604 mutex_lock(&next->lock);
605 return next;
606 }
607
608 /* check if the next ns is a sibling, parent, gp, .. */
609 parent = ns->parent;
John Johansened2c7da2013-10-14 11:46:27 -0700610 while (ns != root) {
John Johansen29b38222013-07-10 21:18:43 -0700611 mutex_unlock(&ns->lock);
Geliang Tang38dbd7d2015-11-16 21:46:33 +0800612 next = list_next_entry(ns, base.list);
John Johansen29b38222013-07-10 21:18:43 -0700613 if (!list_entry_is_head(next, &parent->sub_ns, base.list)) {
614 mutex_lock(&next->lock);
615 return next;
616 }
John Johansen29b38222013-07-10 21:18:43 -0700617 ns = parent;
618 parent = parent->parent;
619 }
620
621 return NULL;
622}
623
624/**
625 * __first_profile - find the first profile in a namespace
626 * @root: namespace that is root of profiles being displayed (NOT NULL)
627 * @ns: namespace to start in (NOT NULL)
628 *
629 * Returns: unrefcounted profile or NULL if no profile
630 * Requires: profile->ns.lock to be held
631 */
John Johansen98849df2017-01-16 00:42:16 -0800632static struct aa_profile *__first_profile(struct aa_ns *root,
633 struct aa_ns *ns)
John Johansen29b38222013-07-10 21:18:43 -0700634{
John Johansen98849df2017-01-16 00:42:16 -0800635 for (; ns; ns = __next_ns(root, ns)) {
John Johansen29b38222013-07-10 21:18:43 -0700636 if (!list_empty(&ns->base.profiles))
637 return list_first_entry(&ns->base.profiles,
638 struct aa_profile, base.list);
639 }
640 return NULL;
641}
642
643/**
644 * __next_profile - step to the next profile in a profile tree
645 * @profile: current profile in tree (NOT NULL)
646 *
647 * Perform a depth first traversal on the profile tree in a namespace
648 *
649 * Returns: next profile or NULL if done
650 * Requires: profile->ns.lock to be held
651 */
652static struct aa_profile *__next_profile(struct aa_profile *p)
653{
654 struct aa_profile *parent;
John Johansen98849df2017-01-16 00:42:16 -0800655 struct aa_ns *ns = p->ns;
John Johansen29b38222013-07-10 21:18:43 -0700656
657 /* is next profile a child */
658 if (!list_empty(&p->base.profiles))
659 return list_first_entry(&p->base.profiles, typeof(*p),
660 base.list);
661
662 /* is next profile a sibling, parent sibling, gp, sibling, .. */
663 parent = rcu_dereference_protected(p->parent,
664 mutex_is_locked(&p->ns->lock));
665 while (parent) {
Geliang Tang38dbd7d2015-11-16 21:46:33 +0800666 p = list_next_entry(p, base.list);
John Johansen29b38222013-07-10 21:18:43 -0700667 if (!list_entry_is_head(p, &parent->base.profiles, base.list))
668 return p;
669 p = parent;
670 parent = rcu_dereference_protected(parent->parent,
671 mutex_is_locked(&parent->ns->lock));
672 }
673
674 /* is next another profile in the namespace */
Geliang Tang38dbd7d2015-11-16 21:46:33 +0800675 p = list_next_entry(p, base.list);
John Johansen29b38222013-07-10 21:18:43 -0700676 if (!list_entry_is_head(p, &ns->base.profiles, base.list))
677 return p;
678
679 return NULL;
680}
681
682/**
683 * next_profile - step to the next profile in where ever it may be
684 * @root: root namespace (NOT NULL)
685 * @profile: current profile (NOT NULL)
686 *
687 * Returns: next profile or NULL if there isn't one
688 */
John Johansen98849df2017-01-16 00:42:16 -0800689static struct aa_profile *next_profile(struct aa_ns *root,
John Johansen29b38222013-07-10 21:18:43 -0700690 struct aa_profile *profile)
691{
692 struct aa_profile *next = __next_profile(profile);
693 if (next)
694 return next;
695
696 /* finished all profiles in namespace move to next namespace */
John Johansen98849df2017-01-16 00:42:16 -0800697 return __first_profile(root, __next_ns(root, profile->ns));
John Johansen29b38222013-07-10 21:18:43 -0700698}
699
700/**
701 * p_start - start a depth first traversal of profile tree
702 * @f: seq_file to fill
703 * @pos: current position
704 *
705 * Returns: first profile under current namespace or NULL if none found
706 *
707 * acquires first ns->lock
708 */
709static void *p_start(struct seq_file *f, loff_t *pos)
710{
711 struct aa_profile *profile = NULL;
John Johansen98849df2017-01-16 00:42:16 -0800712 struct aa_ns *root = aa_current_profile()->ns;
John Johansen29b38222013-07-10 21:18:43 -0700713 loff_t l = *pos;
John Johansen98849df2017-01-16 00:42:16 -0800714 f->private = aa_get_ns(root);
John Johansen29b38222013-07-10 21:18:43 -0700715
716
717 /* find the first profile */
718 mutex_lock(&root->lock);
719 profile = __first_profile(root, root);
720
721 /* skip to position */
722 for (; profile && l > 0; l--)
723 profile = next_profile(root, profile);
724
725 return profile;
726}
727
728/**
729 * p_next - read the next profile entry
730 * @f: seq_file to fill
731 * @p: profile previously returned
732 * @pos: current position
733 *
734 * Returns: next profile after @p or NULL if none
735 *
736 * may acquire/release locks in namespace tree as necessary
737 */
738static void *p_next(struct seq_file *f, void *p, loff_t *pos)
739{
740 struct aa_profile *profile = p;
John Johansen98849df2017-01-16 00:42:16 -0800741 struct aa_ns *ns = f->private;
John Johansen29b38222013-07-10 21:18:43 -0700742 (*pos)++;
743
744 return next_profile(ns, profile);
745}
746
747/**
748 * p_stop - stop depth first traversal
749 * @f: seq_file we are filling
750 * @p: the last profile writen
751 *
752 * Release all locking done by p_start/p_next on namespace tree
753 */
754static void p_stop(struct seq_file *f, void *p)
755{
756 struct aa_profile *profile = p;
John Johansen98849df2017-01-16 00:42:16 -0800757 struct aa_ns *root = f->private, *ns;
John Johansen29b38222013-07-10 21:18:43 -0700758
759 if (profile) {
760 for (ns = profile->ns; ns && ns != root; ns = ns->parent)
761 mutex_unlock(&ns->lock);
762 }
763 mutex_unlock(&root->lock);
John Johansen98849df2017-01-16 00:42:16 -0800764 aa_put_ns(root);
John Johansen29b38222013-07-10 21:18:43 -0700765}
766
767/**
768 * seq_show_profile - show a profile entry
769 * @f: seq_file to file
770 * @p: current position (profile) (NOT NULL)
771 *
772 * Returns: error on failure
773 */
774static int seq_show_profile(struct seq_file *f, void *p)
775{
776 struct aa_profile *profile = (struct aa_profile *)p;
John Johansen98849df2017-01-16 00:42:16 -0800777 struct aa_ns *root = f->private;
John Johansen29b38222013-07-10 21:18:43 -0700778
779 if (profile->ns != root)
John Johansen92b6d8e2017-01-16 00:42:25 -0800780 seq_printf(f, ":%s://", aa_ns_name(root, profile->ns, true));
John Johansen29b38222013-07-10 21:18:43 -0700781 seq_printf(f, "%s (%s)\n", profile->base.hname,
782 aa_profile_mode_names[profile->mode]);
783
784 return 0;
785}
786
787static const struct seq_operations aa_fs_profiles_op = {
788 .start = p_start,
789 .next = p_next,
790 .stop = p_stop,
791 .show = seq_show_profile,
792};
793
794static int profiles_open(struct inode *inode, struct file *file)
795{
796 return seq_open(file, &aa_fs_profiles_op);
797}
798
799static int profiles_release(struct inode *inode, struct file *file)
800{
801 return seq_release(inode, file);
802}
803
804static const struct file_operations aa_fs_profiles_fops = {
805 .open = profiles_open,
806 .read = seq_read,
807 .llseek = seq_lseek,
808 .release = profiles_release,
809};
810
811
John Johansen0d259f02013-07-10 21:13:43 -0700812/** Base file system setup **/
Kees Cooka9bf8e92012-01-26 16:29:22 -0800813static struct aa_fs_entry aa_fs_entry_file[] = {
814 AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \
815 "link lock"),
816 { }
817};
818
Kees Cooke74abcf2012-01-26 16:29:21 -0800819static struct aa_fs_entry aa_fs_entry_domain[] = {
820 AA_FS_FILE_BOOLEAN("change_hat", 1),
821 AA_FS_FILE_BOOLEAN("change_hatv", 1),
822 AA_FS_FILE_BOOLEAN("change_onexec", 1),
823 AA_FS_FILE_BOOLEAN("change_profile", 1),
John Johansen34c426a2017-01-16 00:42:43 -0800824 AA_FS_FILE_BOOLEAN("fix_binfmt_elf_mmap", 1),
Kees Cooke74abcf2012-01-26 16:29:21 -0800825 { }
826};
827
John Johansen474d6b752017-01-16 00:42:39 -0800828static struct aa_fs_entry aa_fs_entry_versions[] = {
829 AA_FS_FILE_BOOLEAN("v5", 1),
830 { }
831};
832
John Johansen9d910a32013-07-10 21:04:43 -0700833static struct aa_fs_entry aa_fs_entry_policy[] = {
John Johansen474d6b752017-01-16 00:42:39 -0800834 AA_FS_DIR("versions", aa_fs_entry_versions),
835 AA_FS_FILE_BOOLEAN("set_load", 1),
836 { }
John Johansen9d910a32013-07-10 21:04:43 -0700837};
838
Kees Cooke74abcf2012-01-26 16:29:21 -0800839static struct aa_fs_entry aa_fs_entry_features[] = {
John Johansen9d910a32013-07-10 21:04:43 -0700840 AA_FS_DIR("policy", aa_fs_entry_policy),
Kees Cooke74abcf2012-01-26 16:29:21 -0800841 AA_FS_DIR("domain", aa_fs_entry_domain),
Kees Cooka9bf8e92012-01-26 16:29:22 -0800842 AA_FS_DIR("file", aa_fs_entry_file),
Kees Cooke74abcf2012-01-26 16:29:21 -0800843 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
Kees Cookd384b0a2012-01-26 16:29:23 -0800844 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
John Johansen84f1f782013-08-14 11:27:32 -0700845 AA_FS_DIR("caps", aa_fs_entry_caps),
Kees Cooke74abcf2012-01-26 16:29:21 -0800846 { }
847};
848
Kees Cook9acd4942012-01-26 16:29:20 -0800849static struct aa_fs_entry aa_fs_entry_apparmor[] = {
850 AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
851 AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
852 AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
John Johansena71ada32017-01-16 00:42:45 -0800853 AA_FS_FILE_FOPS(".ns_level", 0666, &aa_fs_ns_level),
John Johansen29b38222013-07-10 21:18:43 -0700854 AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
Kees Cooke74abcf2012-01-26 16:29:21 -0800855 AA_FS_DIR("features", aa_fs_entry_features),
Kees Cook9acd4942012-01-26 16:29:20 -0800856 { }
857};
John Johansen63e2b422010-07-29 14:48:03 -0700858
Kees Cook9acd4942012-01-26 16:29:20 -0800859static struct aa_fs_entry aa_fs_entry =
860 AA_FS_DIR("apparmor", aa_fs_entry_apparmor);
861
862/**
863 * aafs_create_file - create a file entry in the apparmor securityfs
864 * @fs_file: aa_fs_entry to build an entry for (NOT NULL)
865 * @parent: the parent dentry in the securityfs
866 *
867 * Use aafs_remove_file to remove entries created with this fn.
868 */
869static int __init aafs_create_file(struct aa_fs_entry *fs_file,
870 struct dentry *parent)
John Johansen63e2b422010-07-29 14:48:03 -0700871{
Kees Cook9acd4942012-01-26 16:29:20 -0800872 int error = 0;
John Johansen63e2b422010-07-29 14:48:03 -0700873
Kees Cook9acd4942012-01-26 16:29:20 -0800874 fs_file->dentry = securityfs_create_file(fs_file->name,
875 S_IFREG | fs_file->mode,
876 parent, fs_file,
877 fs_file->file_ops);
878 if (IS_ERR(fs_file->dentry)) {
879 error = PTR_ERR(fs_file->dentry);
880 fs_file->dentry = NULL;
John Johansen63e2b422010-07-29 14:48:03 -0700881 }
Kees Cook9acd4942012-01-26 16:29:20 -0800882 return error;
John Johansen63e2b422010-07-29 14:48:03 -0700883}
884
John Johansen0d259f02013-07-10 21:13:43 -0700885static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir);
John Johansen63e2b422010-07-29 14:48:03 -0700886/**
Kees Cook9acd4942012-01-26 16:29:20 -0800887 * aafs_create_dir - recursively create a directory entry in the securityfs
888 * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL)
889 * @parent: the parent dentry in the securityfs
John Johansen63e2b422010-07-29 14:48:03 -0700890 *
Kees Cook9acd4942012-01-26 16:29:20 -0800891 * Use aafs_remove_dir to remove entries created with this fn.
John Johansen63e2b422010-07-29 14:48:03 -0700892 */
Kees Cook9acd4942012-01-26 16:29:20 -0800893static int __init aafs_create_dir(struct aa_fs_entry *fs_dir,
894 struct dentry *parent)
John Johansen63e2b422010-07-29 14:48:03 -0700895{
Kees Cook9acd4942012-01-26 16:29:20 -0800896 struct aa_fs_entry *fs_file;
John Johansen0d259f02013-07-10 21:13:43 -0700897 struct dentry *dir;
898 int error;
John Johansen63e2b422010-07-29 14:48:03 -0700899
John Johansen0d259f02013-07-10 21:13:43 -0700900 dir = securityfs_create_dir(fs_dir->name, parent);
901 if (IS_ERR(dir))
902 return PTR_ERR(dir);
903 fs_dir->dentry = dir;
John Johansen63e2b422010-07-29 14:48:03 -0700904
John Johansen0d259f02013-07-10 21:13:43 -0700905 for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
Kees Cook9acd4942012-01-26 16:29:20 -0800906 if (fs_file->v_type == AA_FS_TYPE_DIR)
907 error = aafs_create_dir(fs_file, fs_dir->dentry);
908 else
909 error = aafs_create_file(fs_file, fs_dir->dentry);
910 if (error)
911 goto failed;
912 }
913
914 return 0;
915
916failed:
John Johansen0d259f02013-07-10 21:13:43 -0700917 aafs_remove_dir(fs_dir);
918
Kees Cook9acd4942012-01-26 16:29:20 -0800919 return error;
920}
921
922/**
923 * aafs_remove_file - drop a single file entry in the apparmor securityfs
924 * @fs_file: aa_fs_entry to detach from the securityfs (NOT NULL)
925 */
926static void __init aafs_remove_file(struct aa_fs_entry *fs_file)
927{
928 if (!fs_file->dentry)
929 return;
930
931 securityfs_remove(fs_file->dentry);
932 fs_file->dentry = NULL;
933}
934
935/**
936 * aafs_remove_dir - recursively drop a directory entry from the securityfs
937 * @fs_dir: aa_fs_entry (and all child entries) to detach (NOT NULL)
938 */
939static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir)
940{
941 struct aa_fs_entry *fs_file;
942
John Johansen0d259f02013-07-10 21:13:43 -0700943 for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
Kees Cook9acd4942012-01-26 16:29:20 -0800944 if (fs_file->v_type == AA_FS_TYPE_DIR)
945 aafs_remove_dir(fs_file);
946 else
947 aafs_remove_file(fs_file);
948 }
949
950 aafs_remove_file(fs_dir);
John Johansen63e2b422010-07-29 14:48:03 -0700951}
952
953/**
954 * aa_destroy_aafs - cleanup and free aafs
955 *
956 * releases dentries allocated by aa_create_aafs
957 */
958void __init aa_destroy_aafs(void)
959{
Kees Cook9acd4942012-01-26 16:29:20 -0800960 aafs_remove_dir(&aa_fs_entry);
John Johansen63e2b422010-07-29 14:48:03 -0700961}
962
John Johansena71ada32017-01-16 00:42:45 -0800963
964#define NULL_FILE_NAME ".null"
965struct path aa_null;
966
967static int aa_mk_null_file(struct dentry *parent)
968{
969 struct vfsmount *mount = NULL;
970 struct dentry *dentry;
971 struct inode *inode;
972 int count = 0;
973 int error = simple_pin_fs(parent->d_sb->s_type, &mount, &count);
974
975 if (error)
976 return error;
977
978 inode_lock(d_inode(parent));
979 dentry = lookup_one_len(NULL_FILE_NAME, parent, strlen(NULL_FILE_NAME));
980 if (IS_ERR(dentry)) {
981 error = PTR_ERR(dentry);
982 goto out;
983 }
984 inode = new_inode(parent->d_inode->i_sb);
985 if (!inode) {
986 error = -ENOMEM;
987 goto out1;
988 }
989
990 inode->i_ino = get_next_ino();
991 inode->i_mode = S_IFCHR | S_IRUGO | S_IWUGO;
992 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
993 init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO,
994 MKDEV(MEM_MAJOR, 3));
995 d_instantiate(dentry, inode);
996 aa_null.dentry = dget(dentry);
997 aa_null.mnt = mntget(mount);
998
999 error = 0;
1000
1001out1:
1002 dput(dentry);
1003out:
1004 inode_unlock(d_inode(parent));
1005 simple_release_fs(&mount, &count);
1006 return error;
1007}
1008
John Johansen63e2b422010-07-29 14:48:03 -07001009/**
1010 * aa_create_aafs - create the apparmor security filesystem
1011 *
1012 * dentries created here are released by aa_destroy_aafs
1013 *
1014 * Returns: error on failure
1015 */
James Morris3417d8d2011-08-17 11:05:21 +10001016static int __init aa_create_aafs(void)
John Johansen63e2b422010-07-29 14:48:03 -07001017{
1018 int error;
1019
1020 if (!apparmor_initialized)
1021 return 0;
1022
Kees Cook9acd4942012-01-26 16:29:20 -08001023 if (aa_fs_entry.dentry) {
John Johansen63e2b422010-07-29 14:48:03 -07001024 AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
1025 return -EEXIST;
1026 }
1027
Kees Cook9acd4942012-01-26 16:29:20 -08001028 /* Populate fs tree. */
1029 error = aafs_create_dir(&aa_fs_entry, NULL);
John Johansen63e2b422010-07-29 14:48:03 -07001030 if (error)
1031 goto error;
1032
John Johansen98849df2017-01-16 00:42:16 -08001033 error = __aa_fs_ns_mkdir(root_ns, aa_fs_entry.dentry, "policy");
John Johansen0d259f02013-07-10 21:13:43 -07001034 if (error)
1035 goto error;
1036
John Johansena71ada32017-01-16 00:42:45 -08001037 error = aa_mk_null_file(aa_fs_entry.dentry);
1038 if (error)
1039 goto error;
1040
1041 /* TODO: add default profile to apparmorfs */
John Johansen63e2b422010-07-29 14:48:03 -07001042
1043 /* Report that AppArmor fs is enabled */
1044 aa_info_message("AppArmor Filesystem Enabled");
1045 return 0;
1046
1047error:
1048 aa_destroy_aafs();
1049 AA_ERROR("Error creating AppArmor securityfs\n");
1050 return error;
1051}
1052
1053fs_initcall(aa_create_aafs);