aboutsummaryrefslogtreecommitdiffstats
path: root/security/apparmor/apparmorfs.c
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2013-07-11 00:13:43 -0400
committerJohn Johansen <john.johansen@canonical.com>2013-08-14 14:42:07 -0400
commit0d259f043f5f60f74c4fd020aac190cb6450e918 (patch)
tree92fed6a02a1dc6069d7d92e14f2418c85f936303 /security/apparmor/apparmorfs.c
parent038165070aa55375d4bdd2f84b34a486feca63d6 (diff)
apparmor: add interface files for profiles and namespaces
Add basic interface files to access namespace and profile information. The interface files are created when a profile is loaded and removed when the profile or namespace is removed. Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor/apparmorfs.c')
-rw-r--r--security/apparmor/apparmorfs.c322
1 files changed, 312 insertions, 10 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 3ed56e21a9fd..0fdd08c6ea59 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -12,6 +12,7 @@
12 * License. 12 * License.
13 */ 13 */
14 14
15#include <linux/ctype.h>
15#include <linux/security.h> 16#include <linux/security.h>
16#include <linux/vmalloc.h> 17#include <linux/vmalloc.h>
17#include <linux/module.h> 18#include <linux/module.h>
@@ -28,6 +29,45 @@
28#include "include/resource.h" 29#include "include/resource.h"
29 30
30/** 31/**
32 * aa_mangle_name - mangle a profile name to std profile layout form
33 * @name: profile name to mangle (NOT NULL)
34 * @target: buffer to store mangled name, same length as @name (MAYBE NULL)
35 *
36 * Returns: length of mangled name
37 */
38static int mangle_name(char *name, char *target)
39{
40 char *t = target;
41
42 while (*name == '/' || *name == '.')
43 name++;
44
45 if (target) {
46 for (; *name; name++) {
47 if (*name == '/')
48 *(t)++ = '.';
49 else if (isspace(*name))
50 *(t)++ = '_';
51 else if (isalnum(*name) || strchr("._-", *name))
52 *(t)++ = *name;
53 }
54
55 *t = 0;
56 } else {
57 int len = 0;
58 for (; *name; name++) {
59 if (isalnum(*name) || isspace(*name) ||
60 strchr("/._-", *name))
61 len++;
62 }
63
64 return len;
65 }
66
67 return t - target;
68}
69
70/**
31 * aa_simple_write_to_buffer - common routine for getting policy from user 71 * aa_simple_write_to_buffer - common routine for getting policy from user
32 * @op: operation doing the user buffer copy 72 * @op: operation doing the user buffer copy
33 * @userbuf: user buffer to copy data from (NOT NULL) 73 * @userbuf: user buffer to copy data from (NOT NULL)
@@ -182,8 +222,263 @@ const struct file_operations aa_fs_seq_file_ops = {
182 .release = single_release, 222 .release = single_release,
183}; 223};
184 224
185/** Base file system setup **/ 225static int aa_fs_seq_profile_open(struct inode *inode, struct file *file,
226 int (*show)(struct seq_file *, void *))
227{
228 struct aa_replacedby *r = aa_get_replacedby(inode->i_private);
229 int error = single_open(file, show, r);
230
231 if (error) {
232 file->private_data = NULL;
233 aa_put_replacedby(r);
234 }
235
236 return error;
237}
238
239static int aa_fs_seq_profile_release(struct inode *inode, struct file *file)
240{
241 struct seq_file *seq = (struct seq_file *) file->private_data;
242 if (seq)
243 aa_put_replacedby(seq->private);
244 return single_release(inode, file);
245}
246
247static int aa_fs_seq_profname_show(struct seq_file *seq, void *v)
248{
249 struct aa_replacedby *r = seq->private;
250 struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
251 seq_printf(seq, "%s\n", profile->base.name);
252 aa_put_profile(profile);
253
254 return 0;
255}
256
257static int aa_fs_seq_profname_open(struct inode *inode, struct file *file)
258{
259 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profname_show);
260}
261
262static const struct file_operations aa_fs_profname_fops = {
263 .owner = THIS_MODULE,
264 .open = aa_fs_seq_profname_open,
265 .read = seq_read,
266 .llseek = seq_lseek,
267 .release = aa_fs_seq_profile_release,
268};
269
270static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v)
271{
272 struct aa_replacedby *r = seq->private;
273 struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
274 seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]);
275 aa_put_profile(profile);
276
277 return 0;
278}
279
280static int aa_fs_seq_profmode_open(struct inode *inode, struct file *file)
281{
282 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profmode_show);
283}
284
285static const struct file_operations aa_fs_profmode_fops = {
286 .owner = THIS_MODULE,
287 .open = aa_fs_seq_profmode_open,
288 .read = seq_read,
289 .llseek = seq_lseek,
290 .release = aa_fs_seq_profile_release,
291};
292
293/** fns to setup dynamic per profile/namespace files **/
294void __aa_fs_profile_rmdir(struct aa_profile *profile)
295{
296 struct aa_profile *child;
297 int i;
298
299 if (!profile)
300 return;
301
302 list_for_each_entry(child, &profile->base.profiles, base.list)
303 __aa_fs_profile_rmdir(child);
304
305 for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) {
306 struct aa_replacedby *r;
307 if (!profile->dents[i])
308 continue;
309
310 r = profile->dents[i]->d_inode->i_private;
311 securityfs_remove(profile->dents[i]);
312 aa_put_replacedby(r);
313 profile->dents[i] = NULL;
314 }
315}
316
317void __aa_fs_profile_migrate_dents(struct aa_profile *old,
318 struct aa_profile *new)
319{
320 int i;
321
322 for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
323 new->dents[i] = old->dents[i];
324 old->dents[i] = NULL;
325 }
326}
327
328static struct dentry *create_profile_file(struct dentry *dir, const char *name,
329 struct aa_profile *profile,
330 const struct file_operations *fops)
331{
332 struct aa_replacedby *r = aa_get_replacedby(profile->replacedby);
333 struct dentry *dent;
334
335 dent = securityfs_create_file(name, S_IFREG | 0444, dir, r, fops);
336 if (IS_ERR(dent))
337 aa_put_replacedby(r);
338
339 return dent;
340}
341
342/* requires lock be held */
343int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
344{
345 struct aa_profile *child;
346 struct dentry *dent = NULL, *dir;
347 int error;
348
349 if (!parent) {
350 struct aa_profile *p;
351 p = aa_deref_parent(profile);
352 dent = prof_dir(p);
353 /* adding to parent that previously didn't have children */
354 dent = securityfs_create_dir("profiles", dent);
355 if (IS_ERR(dent))
356 goto fail;
357 prof_child_dir(p) = parent = dent;
358 }
359
360 if (!profile->dirname) {
361 int len, id_len;
362 len = mangle_name(profile->base.name, NULL);
363 id_len = snprintf(NULL, 0, ".%ld", profile->ns->uniq_id);
364
365 profile->dirname = kmalloc(len + id_len + 1, GFP_KERNEL);
366 if (!profile->dirname)
367 goto fail;
368
369 mangle_name(profile->base.name, profile->dirname);
370 sprintf(profile->dirname + len, ".%ld", profile->ns->uniq_id++);
371 }
372
373 dent = securityfs_create_dir(profile->dirname, parent);
374 if (IS_ERR(dent))
375 goto fail;
376 prof_dir(profile) = dir = dent;
377
378 dent = create_profile_file(dir, "name", profile, &aa_fs_profname_fops);
379 if (IS_ERR(dent))
380 goto fail;
381 profile->dents[AAFS_PROF_NAME] = dent;
382
383 dent = create_profile_file(dir, "mode", profile, &aa_fs_profmode_fops);
384 if (IS_ERR(dent))
385 goto fail;
386 profile->dents[AAFS_PROF_MODE] = dent;
387
388 list_for_each_entry(child, &profile->base.profiles, base.list) {
389 error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
390 if (error)
391 goto fail2;
392 }
393
394 return 0;
395
396fail:
397 error = PTR_ERR(dent);
398
399fail2:
400 __aa_fs_profile_rmdir(profile);
401
402 return error;
403}
404
405void __aa_fs_namespace_rmdir(struct aa_namespace *ns)
406{
407 struct aa_namespace *sub;
408 struct aa_profile *child;
409 int i;
410
411 if (!ns)
412 return;
413
414 list_for_each_entry(child, &ns->base.profiles, base.list)
415 __aa_fs_profile_rmdir(child);
416
417 list_for_each_entry(sub, &ns->sub_ns, base.list) {
418 mutex_lock(&sub->lock);
419 __aa_fs_namespace_rmdir(sub);
420 mutex_unlock(&sub->lock);
421 }
422
423 for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
424 securityfs_remove(ns->dents[i]);
425 ns->dents[i] = NULL;
426 }
427}
428
429int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent,
430 const char *name)
431{
432 struct aa_namespace *sub;
433 struct aa_profile *child;
434 struct dentry *dent, *dir;
435 int error;
436
437 if (!name)
438 name = ns->base.name;
439
440 dent = securityfs_create_dir(name, parent);
441 if (IS_ERR(dent))
442 goto fail;
443 ns_dir(ns) = dir = dent;
444
445 dent = securityfs_create_dir("profiles", dir);
446 if (IS_ERR(dent))
447 goto fail;
448 ns_subprofs_dir(ns) = dent;
186 449
450 dent = securityfs_create_dir("namespaces", dir);
451 if (IS_ERR(dent))
452 goto fail;
453 ns_subns_dir(ns) = dent;
454
455 list_for_each_entry(child, &ns->base.profiles, base.list) {
456 error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns));
457 if (error)
458 goto fail2;
459 }
460
461 list_for_each_entry(sub, &ns->sub_ns, base.list) {
462 mutex_lock(&sub->lock);
463 error = __aa_fs_namespace_mkdir(sub, ns_subns_dir(ns), NULL);
464 mutex_unlock(&sub->lock);
465 if (error)
466 goto fail2;
467 }
468
469 return 0;
470
471fail:
472 error = PTR_ERR(dent);
473
474fail2:
475 __aa_fs_namespace_rmdir(ns);
476
477 return error;
478}
479
480
481/** Base file system setup **/
187static struct aa_fs_entry aa_fs_entry_file[] = { 482static struct aa_fs_entry aa_fs_entry_file[] = {
188 AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \ 483 AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \
189 "link lock"), 484 "link lock"),
@@ -246,6 +541,7 @@ static int __init aafs_create_file(struct aa_fs_entry *fs_file,
246 return error; 541 return error;
247} 542}
248 543
544static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir);
249/** 545/**
250 * aafs_create_dir - recursively create a directory entry in the securityfs 546 * aafs_create_dir - recursively create a directory entry in the securityfs
251 * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL) 547 * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL)
@@ -256,17 +552,16 @@ static int __init aafs_create_file(struct aa_fs_entry *fs_file,
256static int __init aafs_create_dir(struct aa_fs_entry *fs_dir, 552static int __init aafs_create_dir(struct aa_fs_entry *fs_dir,
257 struct dentry *parent) 553 struct dentry *parent)
258{ 554{
259 int error;
260 struct aa_fs_entry *fs_file; 555 struct aa_fs_entry *fs_file;
556 struct dentry *dir;
557 int error;
261 558
262 fs_dir->dentry = securityfs_create_dir(fs_dir->name, parent); 559 dir = securityfs_create_dir(fs_dir->name, parent);
263 if (IS_ERR(fs_dir->dentry)) { 560 if (IS_ERR(dir))
264 error = PTR_ERR(fs_dir->dentry); 561 return PTR_ERR(dir);
265 fs_dir->dentry = NULL; 562 fs_dir->dentry = dir;
266 goto failed;
267 }
268 563
269 for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) { 564 for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
270 if (fs_file->v_type == AA_FS_TYPE_DIR) 565 if (fs_file->v_type == AA_FS_TYPE_DIR)
271 error = aafs_create_dir(fs_file, fs_dir->dentry); 566 error = aafs_create_dir(fs_file, fs_dir->dentry);
272 else 567 else
@@ -278,6 +573,8 @@ static int __init aafs_create_dir(struct aa_fs_entry *fs_dir,
278 return 0; 573 return 0;
279 574
280failed: 575failed:
576 aafs_remove_dir(fs_dir);
577
281 return error; 578 return error;
282} 579}
283 580
@@ -302,7 +599,7 @@ static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir)
302{ 599{
303 struct aa_fs_entry *fs_file; 600 struct aa_fs_entry *fs_file;
304 601
305 for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) { 602 for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
306 if (fs_file->v_type == AA_FS_TYPE_DIR) 603 if (fs_file->v_type == AA_FS_TYPE_DIR)
307 aafs_remove_dir(fs_file); 604 aafs_remove_dir(fs_file);
308 else 605 else
@@ -346,6 +643,11 @@ static int __init aa_create_aafs(void)
346 if (error) 643 if (error)
347 goto error; 644 goto error;
348 645
646 error = __aa_fs_namespace_mkdir(root_ns, aa_fs_entry.dentry,
647 "policy");
648 if (error)
649 goto error;
650
349 /* TODO: add support for apparmorfs_null and apparmorfs_mnt */ 651 /* TODO: add support for apparmorfs_null and apparmorfs_mnt */
350 652
351 /* Report that AppArmor fs is enabled */ 653 /* Report that AppArmor fs is enabled */