Commit 0d259f043f5f60f74c4fd020aac190cb6450e918
1 parent
038165070a
Exists in
master
and in
20 other branches
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>
Showing 7 changed files with 436 additions and 29 deletions Side-by-side Diff
security/apparmor/apparmorfs.c
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 | * License. |
13 | 13 | */ |
14 | 14 | |
15 | +#include <linux/ctype.h> | |
15 | 16 | #include <linux/security.h> |
16 | 17 | #include <linux/vmalloc.h> |
17 | 18 | #include <linux/module.h> |
... | ... | @@ -28,6 +29,45 @@ |
28 | 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 | + */ | |
38 | +static 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 | 71 | * aa_simple_write_to_buffer - common routine for getting policy from user |
32 | 72 | * @op: operation doing the user buffer copy |
33 | 73 | * @userbuf: user buffer to copy data from (NOT NULL) |
34 | 74 | |
... | ... | @@ -182,8 +222,263 @@ |
182 | 222 | .release = single_release, |
183 | 223 | }; |
184 | 224 | |
185 | -/** Base file system setup **/ | |
225 | +static 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); | |
186 | 230 | |
231 | + if (error) { | |
232 | + file->private_data = NULL; | |
233 | + aa_put_replacedby(r); | |
234 | + } | |
235 | + | |
236 | + return error; | |
237 | +} | |
238 | + | |
239 | +static 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 | + | |
247 | +static 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 | + | |
257 | +static 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 | + | |
262 | +static 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 | + | |
270 | +static 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 | + | |
280 | +static 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 | + | |
285 | +static 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 **/ | |
294 | +void __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 | + | |
317 | +void __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 | + | |
328 | +static 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 */ | |
343 | +int __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 | + | |
396 | +fail: | |
397 | + error = PTR_ERR(dent); | |
398 | + | |
399 | +fail2: | |
400 | + __aa_fs_profile_rmdir(profile); | |
401 | + | |
402 | + return error; | |
403 | +} | |
404 | + | |
405 | +void __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 | + | |
429 | +int __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; | |
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 | + | |
471 | +fail: | |
472 | + error = PTR_ERR(dent); | |
473 | + | |
474 | +fail2: | |
475 | + __aa_fs_namespace_rmdir(ns); | |
476 | + | |
477 | + return error; | |
478 | +} | |
479 | + | |
480 | + | |
481 | +/** Base file system setup **/ | |
187 | 482 | static struct aa_fs_entry aa_fs_entry_file[] = { |
188 | 483 | AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \ |
189 | 484 | "link lock"), |
... | ... | @@ -246,6 +541,7 @@ |
246 | 541 | return error; |
247 | 542 | } |
248 | 543 | |
544 | +static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir); | |
249 | 545 | /** |
250 | 546 | * aafs_create_dir - recursively create a directory entry in the securityfs |
251 | 547 | * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL) |
252 | 548 | |
253 | 549 | |
254 | 550 | |
... | ... | @@ -256,17 +552,16 @@ |
256 | 552 | static int __init aafs_create_dir(struct aa_fs_entry *fs_dir, |
257 | 553 | struct dentry *parent) |
258 | 554 | { |
259 | - int error; | |
260 | 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); | |
263 | - if (IS_ERR(fs_dir->dentry)) { | |
264 | - error = PTR_ERR(fs_dir->dentry); | |
265 | - fs_dir->dentry = NULL; | |
266 | - goto failed; | |
267 | - } | |
559 | + dir = securityfs_create_dir(fs_dir->name, parent); | |
560 | + if (IS_ERR(dir)) | |
561 | + return PTR_ERR(dir); | |
562 | + fs_dir->dentry = dir; | |
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 | 565 | if (fs_file->v_type == AA_FS_TYPE_DIR) |
271 | 566 | error = aafs_create_dir(fs_file, fs_dir->dentry); |
272 | 567 | else |
... | ... | @@ -278,6 +573,8 @@ |
278 | 573 | return 0; |
279 | 574 | |
280 | 575 | failed: |
576 | + aafs_remove_dir(fs_dir); | |
577 | + | |
281 | 578 | return error; |
282 | 579 | } |
283 | 580 | |
... | ... | @@ -302,7 +599,7 @@ |
302 | 599 | { |
303 | 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 | 603 | if (fs_file->v_type == AA_FS_TYPE_DIR) |
307 | 604 | aafs_remove_dir(fs_file); |
308 | 605 | else |
... | ... | @@ -343,6 +640,11 @@ |
343 | 640 | |
344 | 641 | /* Populate fs tree. */ |
345 | 642 | error = aafs_create_dir(&aa_fs_entry, NULL); |
643 | + if (error) | |
644 | + goto error; | |
645 | + | |
646 | + error = __aa_fs_namespace_mkdir(root_ns, aa_fs_entry.dentry, | |
647 | + "policy"); | |
346 | 648 | if (error) |
347 | 649 | goto error; |
348 | 650 |
security/apparmor/include/apparmorfs.h
... | ... | @@ -61,5 +61,43 @@ |
61 | 61 | |
62 | 62 | extern void __init aa_destroy_aafs(void); |
63 | 63 | |
64 | +struct aa_profile; | |
65 | +struct aa_namespace; | |
66 | + | |
67 | +enum 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 | + | |
79 | +enum 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 | + | |
94 | +void __aa_fs_profile_rmdir(struct aa_profile *profile); | |
95 | +void __aa_fs_profile_migrate_dents(struct aa_profile *old, | |
96 | + struct aa_profile *new); | |
97 | +int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent); | |
98 | +void __aa_fs_namespace_rmdir(struct aa_namespace *ns); | |
99 | +int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent, | |
100 | + const char *name); | |
101 | + | |
64 | 102 | #endif /* __AA_APPARMORFS_H */ |
security/apparmor/include/audit.h
security/apparmor/include/policy.h
... | ... | @@ -29,8 +29,8 @@ |
29 | 29 | #include "file.h" |
30 | 30 | #include "resource.h" |
31 | 31 | |
32 | -extern const char *const profile_mode_names[]; | |
33 | -#define APPARMOR_NAMES_MAX_INDEX 3 | |
32 | +extern const char *const aa_profile_mode_names[]; | |
33 | +#define APPARMOR_MODE_NAMES_MAX_INDEX 4 | |
34 | 34 | |
35 | 35 | #define PROFILE_MODE(_profile, _mode) \ |
36 | 36 | ((aa_g_profile_mode == (_mode)) || \ |
... | ... | @@ -110,6 +110,8 @@ |
110 | 110 | * @unconfined: special unconfined profile for the namespace |
111 | 111 | * @sub_ns: list of namespaces under the current namespace. |
112 | 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 | 116 | * An aa_namespace defines the set profiles that are searched to determine |
115 | 117 | * which profile to attach to a task. Profiles can not be shared between |
... | ... | @@ -133,6 +135,9 @@ |
133 | 135 | struct aa_profile *unconfined; |
134 | 136 | struct list_head sub_ns; |
135 | 137 | atomic_t uniq_null; |
138 | + long uniq_id; | |
139 | + | |
140 | + struct dentry *dents[AAFS_NS_SIZEOF]; | |
136 | 141 | }; |
137 | 142 | |
138 | 143 | /* struct aa_policydb - match engine for a policy |
... | ... | @@ -172,6 +177,9 @@ |
172 | 177 | * @caps: capabilities for the profile |
173 | 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 | 183 | * The AppArmor profile contains the basic confinement data. Each profile |
176 | 184 | * has a name, and exists in a namespace. The @name and @exec_match are |
177 | 185 | * used to determine profile attachment against unconfined tasks. All other |
... | ... | @@ -208,6 +216,9 @@ |
208 | 216 | struct aa_file_rules file; |
209 | 217 | struct aa_caps caps; |
210 | 218 | struct aa_rlimit rlimits; |
219 | + | |
220 | + char *dirname; | |
221 | + struct dentry *dents[AAFS_PROF_SIZEOF]; | |
211 | 222 | }; |
212 | 223 | |
213 | 224 | extern struct aa_namespace *root_ns; |
... | ... | @@ -242,6 +253,12 @@ |
242 | 253 | |
243 | 254 | #define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED) |
244 | 255 | |
256 | + | |
257 | +static 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 | +} | |
245 | 262 | |
246 | 263 | /** |
247 | 264 | * aa_get_profile - increment refcount on profile @p |
security/apparmor/lsm.c
... | ... | @@ -843,7 +843,7 @@ |
843 | 843 | if (!apparmor_enabled) |
844 | 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 | |
849 | 849 | static int param_set_mode(const char *val, struct kernel_param *kp) |
... | ... | @@ -858,8 +858,8 @@ |
858 | 858 | if (!val) |
859 | 859 | return -EINVAL; |
860 | 860 | |
861 | - for (i = 0; i < APPARMOR_NAMES_MAX_INDEX; i++) { | |
862 | - if (strcmp(val, profile_mode_names[i]) == 0) { | |
861 | + for (i = 0; i < APPARMOR_MODE_NAMES_MAX_INDEX; i++) { | |
862 | + if (strcmp(val, aa_profile_mode_names[i]) == 0) { | |
863 | 863 | aa_g_profile_mode = i; |
864 | 864 | return 0; |
865 | 865 | } |
security/apparmor/policy.c
... | ... | @@ -92,7 +92,7 @@ |
92 | 92 | /* root profile namespace */ |
93 | 93 | struct aa_namespace *root_ns; |
94 | 94 | |
95 | -const char *const profile_mode_names[] = { | |
95 | +const char *const aa_profile_mode_names[] = { | |
96 | 96 | "enforce", |
97 | 97 | "complain", |
98 | 98 | "kill", |
... | ... | @@ -394,7 +394,13 @@ |
394 | 394 | ns = alloc_namespace(root->base.hname, name); |
395 | 395 | if (!ns) |
396 | 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 | 404 | ns->parent = aa_get_namespace(root); |
399 | 405 | list_add_rcu(&ns->base.list, &root->sub_ns); |
400 | 406 | /* add list ref */ |
... | ... | @@ -456,6 +462,7 @@ |
456 | 462 | __profile_list_release(&profile->base.profiles); |
457 | 463 | /* released by free_profile */ |
458 | 464 | __aa_update_replacedby(profile, profile->ns->unconfined); |
465 | + __aa_fs_profile_rmdir(profile); | |
459 | 466 | __list_remove_profile(profile); |
460 | 467 | } |
461 | 468 | |
... | ... | @@ -492,6 +499,7 @@ |
492 | 499 | |
493 | 500 | if (ns->parent) |
494 | 501 | __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); |
502 | + __aa_fs_namespace_rmdir(ns); | |
495 | 503 | mutex_unlock(&ns->lock); |
496 | 504 | } |
497 | 505 | |
... | ... | @@ -596,6 +604,7 @@ |
596 | 604 | aa_free_cap_rules(&profile->caps); |
597 | 605 | aa_free_rlimit_rules(&profile->rlimits); |
598 | 606 | |
607 | + kzfree(profile->dirname); | |
599 | 608 | aa_put_dfa(profile->xmatch); |
600 | 609 | aa_put_dfa(profile->policy.dfa); |
601 | 610 | aa_put_replacedby(profile->replacedby); |
... | ... | @@ -986,8 +995,7 @@ |
986 | 995 | /* inherit @child and its children */ |
987 | 996 | /* TODO: update hname of inherited children */ |
988 | 997 | /* list refcount transferred to @new */ |
989 | - p = rcu_dereference_protected(child->parent, | |
990 | - mutex_is_locked(&child->ns->lock)); | |
998 | + p = aa_deref_parent(child); | |
991 | 999 | rcu_assign_pointer(child->parent, aa_get_profile(new)); |
992 | 1000 | list_add_rcu(&child->base.list, &new->base.profiles); |
993 | 1001 | aa_put_profile(p); |
994 | 1002 | |
... | ... | @@ -995,14 +1003,18 @@ |
995 | 1003 | } |
996 | 1004 | |
997 | 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 | 1007 | rcu_assign_pointer(new->parent, aa_get_profile(parent)); |
1000 | 1008 | } |
1001 | 1009 | __aa_update_replacedby(old, new); |
1002 | 1010 | if (share_replacedby) { |
1003 | 1011 | aa_put_replacedby(new->replacedby); |
1004 | 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 | 1019 | if (list_empty(&new->base.list)) { |
1008 | 1020 | /* new is not on a list already */ |
... | ... | @@ -1118,7 +1130,33 @@ |
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 | 1160 | list_for_each_entry_safe(ent, tmp, &lh, list) { |
1123 | 1161 | list_del_init(&ent->list); |
1124 | 1162 | op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; |
1125 | 1163 | |
1126 | 1164 | |
1127 | 1165 | |
... | ... | @@ -1127,14 +1165,21 @@ |
1127 | 1165 | |
1128 | 1166 | if (ent->old) { |
1129 | 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 | 1173 | __replace_profile(ent->rename, ent->new, 0); |
1174 | + } | |
1132 | 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 | 1179 | __replace_profile(ent->rename, ent->new, 0); |
1134 | 1180 | } else if (ent->new->parent) { |
1135 | 1181 | struct aa_profile *parent, *newest; |
1136 | - parent = rcu_dereference_protected(ent->new->parent, | |
1137 | - mutex_is_locked(&ns->lock)); | |
1182 | + parent = aa_deref_parent(ent->new); | |
1138 | 1183 | newest = aa_get_newest_profile(parent); |
1139 | 1184 | |
1140 | 1185 | /* parent replaced in this atomic set? */ |
1141 | 1186 | |
1142 | 1187 | |
... | ... | @@ -1144,10 +1189,16 @@ |
1144 | 1189 | rcu_assign_pointer(ent->new->parent, newest); |
1145 | 1190 | } else |
1146 | 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 | 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 | 1200 | __list_add_profile(&ns->base.profiles, ent->new); |
1150 | - | |
1201 | + } | |
1151 | 1202 | aa_load_ent_free(ent); |
1152 | 1203 | } |
1153 | 1204 | mutex_unlock(&ns->lock); |
security/apparmor/procattr.c
... | ... | @@ -37,7 +37,7 @@ |
37 | 37 | { |
38 | 38 | char *str; |
39 | 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 | 41 | const char *ns_name = NULL; |
42 | 42 | struct aa_namespace *ns = profile->ns; |
43 | 43 | struct aa_namespace *current_ns = __aa_current_profile()->ns; |