aboutsummaryrefslogtreecommitdiffstats
path: root/security
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
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')
-rw-r--r--security/apparmor/apparmorfs.c322
-rw-r--r--security/apparmor/include/apparmorfs.h38
-rw-r--r--security/apparmor/include/audit.h1
-rw-r--r--security/apparmor/include/policy.h21
-rw-r--r--security/apparmor/lsm.c6
-rw-r--r--security/apparmor/policy.c75
-rw-r--r--security/apparmor/procattr.c2
7 files changed, 436 insertions, 29 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 */
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
index 7ea4769fab3f..2494e112f2bf 100644
--- a/security/apparmor/include/apparmorfs.h
+++ b/security/apparmor/include/apparmorfs.h
@@ -61,4 +61,42 @@ extern const struct file_operations aa_fs_seq_file_ops;
61 61
62extern void __init aa_destroy_aafs(void); 62extern void __init aa_destroy_aafs(void);
63 63
64struct aa_profile;
65struct aa_namespace;
66
67enum aafs_ns_type {
68 AAFS_NS_DIR,
69 AAFS_NS_PROFS,
70 AAFS_NS_NS,
71 AAFS_NS_COUNT,
72 AAFS_NS_MAX_COUNT,
73 AAFS_NS_SIZE,
74 AAFS_NS_MAX_SIZE,
75 AAFS_NS_OWNER,
76 AAFS_NS_SIZEOF,
77};
78
79enum aafs_prof_type {
80 AAFS_PROF_DIR,
81 AAFS_PROF_PROFS,
82 AAFS_PROF_NAME,
83 AAFS_PROF_MODE,
84 AAFS_PROF_SIZEOF,
85};
86
87#define ns_dir(X) ((X)->dents[AAFS_NS_DIR])
88#define ns_subns_dir(X) ((X)->dents[AAFS_NS_NS])
89#define ns_subprofs_dir(X) ((X)->dents[AAFS_NS_PROFS])
90
91#define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
92#define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
93
94void __aa_fs_profile_rmdir(struct aa_profile *profile);
95void __aa_fs_profile_migrate_dents(struct aa_profile *old,
96 struct aa_profile *new);
97int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent);
98void __aa_fs_namespace_rmdir(struct aa_namespace *ns);
99int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent,
100 const char *name);
101
64#endif /* __AA_APPARMORFS_H */ 102#endif /* __AA_APPARMORFS_H */
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 69d8cae634e7..30e8d7687259 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -27,7 +27,6 @@ struct aa_profile;
27 27
28extern const char *const audit_mode_names[]; 28extern const char *const audit_mode_names[];
29#define AUDIT_MAX_INDEX 5 29#define AUDIT_MAX_INDEX 5
30
31enum audit_mode { 30enum audit_mode {
32 AUDIT_NORMAL, /* follow normal auditing of accesses */ 31 AUDIT_NORMAL, /* follow normal auditing of accesses */
33 AUDIT_QUIET_DENIED, /* quiet all denied access messages */ 32 AUDIT_QUIET_DENIED, /* quiet all denied access messages */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 65662e3c75cf..5c72231d1c42 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -29,8 +29,8 @@
29#include "file.h" 29#include "file.h"
30#include "resource.h" 30#include "resource.h"
31 31
32extern const char *const profile_mode_names[]; 32extern const char *const aa_profile_mode_names[];
33#define APPARMOR_NAMES_MAX_INDEX 3 33#define APPARMOR_MODE_NAMES_MAX_INDEX 4
34 34
35#define PROFILE_MODE(_profile, _mode) \ 35#define PROFILE_MODE(_profile, _mode) \
36 ((aa_g_profile_mode == (_mode)) || \ 36 ((aa_g_profile_mode == (_mode)) || \
@@ -110,6 +110,8 @@ struct aa_ns_acct {
110 * @unconfined: special unconfined profile for the namespace 110 * @unconfined: special unconfined profile for the namespace
111 * @sub_ns: list of namespaces under the current namespace. 111 * @sub_ns: list of namespaces under the current namespace.
112 * @uniq_null: uniq value used for null learning profiles 112 * @uniq_null: uniq value used for null learning profiles
113 * @uniq_id: a unique id count for the profiles in the namespace
114 * @dents: dentries for the namespaces file entries in apparmorfs
113 * 115 *
114 * An aa_namespace defines the set profiles that are searched to determine 116 * An aa_namespace defines the set profiles that are searched to determine
115 * which profile to attach to a task. Profiles can not be shared between 117 * which profile to attach to a task. Profiles can not be shared between
@@ -133,6 +135,9 @@ struct aa_namespace {
133 struct aa_profile *unconfined; 135 struct aa_profile *unconfined;
134 struct list_head sub_ns; 136 struct list_head sub_ns;
135 atomic_t uniq_null; 137 atomic_t uniq_null;
138 long uniq_id;
139
140 struct dentry *dents[AAFS_NS_SIZEOF];
136}; 141};
137 142
138/* struct aa_policydb - match engine for a policy 143/* struct aa_policydb - match engine for a policy
@@ -172,6 +177,9 @@ struct aa_replacedby {
172 * @caps: capabilities for the profile 177 * @caps: capabilities for the profile
173 * @rlimits: rlimits for the profile 178 * @rlimits: rlimits for the profile
174 * 179 *
180 * @dents: dentries for the profiles file entries in apparmorfs
181 * @dirname: name of the profile dir in apparmorfs
182 *
175 * The AppArmor profile contains the basic confinement data. Each profile 183 * The AppArmor profile contains the basic confinement data. Each profile
176 * has a name, and exists in a namespace. The @name and @exec_match are 184 * has a name, and exists in a namespace. The @name and @exec_match are
177 * used to determine profile attachment against unconfined tasks. All other 185 * used to determine profile attachment against unconfined tasks. All other
@@ -208,6 +216,9 @@ struct aa_profile {
208 struct aa_file_rules file; 216 struct aa_file_rules file;
209 struct aa_caps caps; 217 struct aa_caps caps;
210 struct aa_rlimit rlimits; 218 struct aa_rlimit rlimits;
219
220 char *dirname;
221 struct dentry *dents[AAFS_PROF_SIZEOF];
211}; 222};
212 223
213extern struct aa_namespace *root_ns; 224extern struct aa_namespace *root_ns;
@@ -243,6 +254,12 @@ ssize_t aa_remove_profiles(char *name, size_t size);
243#define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED) 254#define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED)
244 255
245 256
257static inline struct aa_profile *aa_deref_parent(struct aa_profile *p)
258{
259 return rcu_dereference_protected(p->parent,
260 mutex_is_locked(&p->ns->lock));
261}
262
246/** 263/**
247 * aa_get_profile - increment refcount on profile @p 264 * aa_get_profile - increment refcount on profile @p
248 * @p: profile (MAYBE NULL) 265 * @p: profile (MAYBE NULL)
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index c8c148a738f7..edb3ce15e92d 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -843,7 +843,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp)
843 if (!apparmor_enabled) 843 if (!apparmor_enabled)
844 return -EINVAL; 844 return -EINVAL;
845 845
846 return sprintf(buffer, "%s", profile_mode_names[aa_g_profile_mode]); 846 return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]);
847} 847}
848 848
849static int param_set_mode(const char *val, struct kernel_param *kp) 849static int param_set_mode(const char *val, struct kernel_param *kp)
@@ -858,8 +858,8 @@ static int param_set_mode(const char *val, struct kernel_param *kp)
858 if (!val) 858 if (!val)
859 return -EINVAL; 859 return -EINVAL;
860 860
861 for (i = 0; i < APPARMOR_NAMES_MAX_INDEX; i++) { 861 for (i = 0; i < APPARMOR_MODE_NAMES_MAX_INDEX; i++) {
862 if (strcmp(val, profile_mode_names[i]) == 0) { 862 if (strcmp(val, aa_profile_mode_names[i]) == 0) {
863 aa_g_profile_mode = i; 863 aa_g_profile_mode = i;
864 return 0; 864 return 0;
865 } 865 }
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 2e4e2ecb25bc..6172509fa2b7 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -92,7 +92,7 @@
92/* root profile namespace */ 92/* root profile namespace */
93struct aa_namespace *root_ns; 93struct aa_namespace *root_ns;
94 94
95const char *const profile_mode_names[] = { 95const char *const aa_profile_mode_names[] = {
96 "enforce", 96 "enforce",
97 "complain", 97 "complain",
98 "kill", 98 "kill",
@@ -394,7 +394,13 @@ static struct aa_namespace *aa_prepare_namespace(const char *name)
394 ns = alloc_namespace(root->base.hname, name); 394 ns = alloc_namespace(root->base.hname, name);
395 if (!ns) 395 if (!ns)
396 goto out; 396 goto out;
397 /* add parent ref */ 397 if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) {
398 AA_ERROR("Failed to create interface for ns %s\n",
399 ns->base.name);
400 free_namespace(ns);
401 ns = NULL;
402 goto out;
403 }
398 ns->parent = aa_get_namespace(root); 404 ns->parent = aa_get_namespace(root);
399 list_add_rcu(&ns->base.list, &root->sub_ns); 405 list_add_rcu(&ns->base.list, &root->sub_ns);
400 /* add list ref */ 406 /* add list ref */
@@ -456,6 +462,7 @@ static void __remove_profile(struct aa_profile *profile)
456 __profile_list_release(&profile->base.profiles); 462 __profile_list_release(&profile->base.profiles);
457 /* released by free_profile */ 463 /* released by free_profile */
458 __aa_update_replacedby(profile, profile->ns->unconfined); 464 __aa_update_replacedby(profile, profile->ns->unconfined);
465 __aa_fs_profile_rmdir(profile);
459 __list_remove_profile(profile); 466 __list_remove_profile(profile);
460} 467}
461 468
@@ -492,6 +499,7 @@ static void destroy_namespace(struct aa_namespace *ns)
492 499
493 if (ns->parent) 500 if (ns->parent)
494 __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); 501 __aa_update_replacedby(ns->unconfined, ns->parent->unconfined);
502 __aa_fs_namespace_rmdir(ns);
495 mutex_unlock(&ns->lock); 503 mutex_unlock(&ns->lock);
496} 504}
497 505
@@ -596,6 +604,7 @@ void aa_free_profile(struct aa_profile *profile)
596 aa_free_cap_rules(&profile->caps); 604 aa_free_cap_rules(&profile->caps);
597 aa_free_rlimit_rules(&profile->rlimits); 605 aa_free_rlimit_rules(&profile->rlimits);
598 606
607 kzfree(profile->dirname);
599 aa_put_dfa(profile->xmatch); 608 aa_put_dfa(profile->xmatch);
600 aa_put_dfa(profile->policy.dfa); 609 aa_put_dfa(profile->policy.dfa);
601 aa_put_replacedby(profile->replacedby); 610 aa_put_replacedby(profile->replacedby);
@@ -986,8 +995,7 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
986 /* inherit @child and its children */ 995 /* inherit @child and its children */
987 /* TODO: update hname of inherited children */ 996 /* TODO: update hname of inherited children */
988 /* list refcount transferred to @new */ 997 /* list refcount transferred to @new */
989 p = rcu_dereference_protected(child->parent, 998 p = aa_deref_parent(child);
990 mutex_is_locked(&child->ns->lock));
991 rcu_assign_pointer(child->parent, aa_get_profile(new)); 999 rcu_assign_pointer(child->parent, aa_get_profile(new));
992 list_add_rcu(&child->base.list, &new->base.profiles); 1000 list_add_rcu(&child->base.list, &new->base.profiles);
993 aa_put_profile(p); 1001 aa_put_profile(p);
@@ -995,14 +1003,18 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
995 } 1003 }
996 1004
997 if (!rcu_access_pointer(new->parent)) { 1005 if (!rcu_access_pointer(new->parent)) {
998 struct aa_profile *parent = rcu_dereference(old->parent); 1006 struct aa_profile *parent = aa_deref_parent(old);
999 rcu_assign_pointer(new->parent, aa_get_profile(parent)); 1007 rcu_assign_pointer(new->parent, aa_get_profile(parent));
1000 } 1008 }
1001 __aa_update_replacedby(old, new); 1009 __aa_update_replacedby(old, new);
1002 if (share_replacedby) { 1010 if (share_replacedby) {
1003 aa_put_replacedby(new->replacedby); 1011 aa_put_replacedby(new->replacedby);
1004 new->replacedby = aa_get_replacedby(old->replacedby); 1012 new->replacedby = aa_get_replacedby(old->replacedby);
1005 } 1013 } else if (!rcu_access_pointer(new->replacedby->profile))
1014 /* aafs interface uses replacedby */
1015 rcu_assign_pointer(new->replacedby->profile,
1016 aa_get_profile(new));
1017 __aa_fs_profile_migrate_dents(old, new);
1006 1018
1007 if (list_empty(&new->base.list)) { 1019 if (list_empty(&new->base.list)) {
1008 /* new is not on a list already */ 1020 /* new is not on a list already */
@@ -1118,7 +1130,33 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
1118 } 1130 }
1119 } 1131 }
1120 1132
1121 /* do actual replacement */ 1133 /* create new fs entries for introspection if needed */
1134 list_for_each_entry(ent, &lh, list) {
1135 if (ent->old) {
1136 /* inherit old interface files */
1137
1138 /* if (ent->rename)
1139 TODO: support rename */
1140 /* } else if (ent->rename) {
1141 TODO: support rename */
1142 } else {
1143 struct dentry *parent;
1144 if (rcu_access_pointer(ent->new->parent)) {
1145 struct aa_profile *p;
1146 p = aa_deref_parent(ent->new);
1147 parent = prof_child_dir(p);
1148 } else
1149 parent = ns_subprofs_dir(ent->new->ns);
1150 error = __aa_fs_profile_mkdir(ent->new, parent);
1151 }
1152
1153 if (error) {
1154 info = "failed to create ";
1155 goto fail_lock;
1156 }
1157 }
1158
1159 /* Done with checks that may fail - do actual replacement */
1122 list_for_each_entry_safe(ent, tmp, &lh, list) { 1160 list_for_each_entry_safe(ent, tmp, &lh, list) {
1123 list_del_init(&ent->list); 1161 list_del_init(&ent->list);
1124 op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; 1162 op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
@@ -1127,14 +1165,21 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
1127 1165
1128 if (ent->old) { 1166 if (ent->old) {
1129 __replace_profile(ent->old, ent->new, 1); 1167 __replace_profile(ent->old, ent->new, 1);
1130 if (ent->rename) 1168 if (ent->rename) {
1169 /* aafs interface uses replacedby */
1170 struct aa_replacedby *r = ent->new->replacedby;
1171 rcu_assign_pointer(r->profile,
1172 aa_get_profile(ent->new));
1131 __replace_profile(ent->rename, ent->new, 0); 1173 __replace_profile(ent->rename, ent->new, 0);
1174 }
1132 } else if (ent->rename) { 1175 } else if (ent->rename) {
1176 /* aafs interface uses replacedby */
1177 rcu_assign_pointer(ent->new->replacedby->profile,
1178 aa_get_profile(ent->new));
1133 __replace_profile(ent->rename, ent->new, 0); 1179 __replace_profile(ent->rename, ent->new, 0);
1134 } else if (ent->new->parent) { 1180 } else if (ent->new->parent) {
1135 struct aa_profile *parent, *newest; 1181 struct aa_profile *parent, *newest;
1136 parent = rcu_dereference_protected(ent->new->parent, 1182 parent = aa_deref_parent(ent->new);
1137 mutex_is_locked(&ns->lock));
1138 newest = aa_get_newest_profile(parent); 1183 newest = aa_get_newest_profile(parent);
1139 1184
1140 /* parent replaced in this atomic set? */ 1185 /* parent replaced in this atomic set? */
@@ -1144,10 +1189,16 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
1144 rcu_assign_pointer(ent->new->parent, newest); 1189 rcu_assign_pointer(ent->new->parent, newest);
1145 } else 1190 } else
1146 aa_put_profile(newest); 1191 aa_put_profile(newest);
1192 /* aafs interface uses replacedby */
1193 rcu_assign_pointer(ent->new->replacedby->profile,
1194 aa_get_profile(ent->new));
1147 __list_add_profile(&parent->base.profiles, ent->new); 1195 __list_add_profile(&parent->base.profiles, ent->new);
1148 } else 1196 } else {
1197 /* aafs interface uses replacedby */
1198 rcu_assign_pointer(ent->new->replacedby->profile,
1199 aa_get_profile(ent->new));
1149 __list_add_profile(&ns->base.profiles, ent->new); 1200 __list_add_profile(&ns->base.profiles, ent->new);
1150 1201 }
1151 aa_load_ent_free(ent); 1202 aa_load_ent_free(ent);
1152 } 1203 }
1153 mutex_unlock(&ns->lock); 1204 mutex_unlock(&ns->lock);
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
index 6c9390179b89..b125acc9aa26 100644
--- a/security/apparmor/procattr.c
+++ b/security/apparmor/procattr.c
@@ -37,7 +37,7 @@ int aa_getprocattr(struct aa_profile *profile, char **string)
37{ 37{
38 char *str; 38 char *str;
39 int len = 0, mode_len = 0, ns_len = 0, name_len; 39 int len = 0, mode_len = 0, ns_len = 0, name_len;
40 const char *mode_str = profile_mode_names[profile->mode]; 40 const char *mode_str = aa_profile_mode_names[profile->mode];
41 const char *ns_name = NULL; 41 const char *ns_name = NULL;
42 struct aa_namespace *ns = profile->ns; 42 struct aa_namespace *ns = profile->ns;
43 struct aa_namespace *current_ns = __aa_current_profile()->ns; 43 struct aa_namespace *current_ns = __aa_current_profile()->ns;