]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.25/patches.apparmor/apparmor-lsm.diff
Disable build of xen kernel.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.apparmor / apparmor-lsm.diff
1 From: John Johansen <jjohansen@suse.de>
2 Subject: AppArmor: Module and LSM hooks
3
4 Module parameters, LSM hooks, initialization and teardown.
5
6 Signed-off-by: John Johansen <jjohansen@suse.de>
7 Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
8
9 ---
10 security/apparmor/lsm.c | 895 ++++++++++++++++++++++++++++++++++++++++++++++++
11 1 file changed, 895 insertions(+)
12
13 --- /dev/null
14 +++ b/security/apparmor/lsm.c
15 @@ -0,0 +1,895 @@
16 +/*
17 + * Copyright (C) 1998-2007 Novell/SUSE
18 + *
19 + * This program is free software; you can redistribute it and/or
20 + * modify it under the terms of the GNU General Public License as
21 + * published by the Free Software Foundation, version 2 of the
22 + * License.
23 + *
24 + * AppArmor LSM interface
25 + */
26 +
27 +#include <linux/security.h>
28 +#include <linux/module.h>
29 +#include <linux/mm.h>
30 +#include <linux/mman.h>
31 +#include <linux/mount.h>
32 +#include <linux/namei.h>
33 +#include <linux/ctype.h>
34 +#include <linux/sysctl.h>
35 +#include <linux/audit.h>
36 +
37 +#include "apparmor.h"
38 +#include "inline.h"
39 +
40 +/* Flag indicating whether initialization completed */
41 +int apparmor_initialized = 0;
42 +
43 +static int param_set_aabool(const char *val, struct kernel_param *kp);
44 +static int param_get_aabool(char *buffer, struct kernel_param *kp);
45 +#define param_check_aabool(name, p) __param_check(name, p, int)
46 +
47 +static int param_set_aauint(const char *val, struct kernel_param *kp);
48 +static int param_get_aauint(char *buffer, struct kernel_param *kp);
49 +#define param_check_aauint(name, p) __param_check(name, p, int)
50 +
51 +/* Flag values, also controllable via /sys/module/apparmor/parameters
52 + * We define special types as we want to do additional mediation.
53 + *
54 + * Complain mode -- in complain mode access failures result in auditing only
55 + * and task is allowed access. audit events are processed by userspace to
56 + * generate policy. Default is 'enforce' (0).
57 + * Value is also togglable per profile and referenced when global value is
58 + * enforce.
59 + */
60 +int apparmor_complain = 0;
61 +module_param_named(complain, apparmor_complain, aabool, S_IRUSR | S_IWUSR);
62 +MODULE_PARM_DESC(apparmor_complain, "Toggle AppArmor complain mode");
63 +
64 +/* Debug mode */
65 +int apparmor_debug = 0;
66 +module_param_named(debug, apparmor_debug, aabool, S_IRUSR | S_IWUSR);
67 +MODULE_PARM_DESC(apparmor_debug, "Toggle AppArmor debug mode");
68 +
69 +/* Audit mode */
70 +int apparmor_audit = 0;
71 +module_param_named(audit, apparmor_audit, aabool, S_IRUSR | S_IWUSR);
72 +MODULE_PARM_DESC(apparmor_audit, "Toggle AppArmor audit mode");
73 +
74 +/* Syscall logging mode */
75 +int apparmor_logsyscall = 0;
76 +module_param_named(logsyscall, apparmor_logsyscall, aabool, S_IRUSR | S_IWUSR);
77 +MODULE_PARM_DESC(apparmor_logsyscall, "Toggle AppArmor logsyscall mode");
78 +
79 +/* Maximum pathname length before accesses will start getting rejected */
80 +unsigned int apparmor_path_max = 2 * PATH_MAX;
81 +module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR);
82 +MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");
83 +
84 +/* Boot time disable flag */
85 +#ifdef CONFIG_SECURITY_APPARMOR_DISABLE
86 +#define AA_ENABLED_PERMS 0600
87 +#else
88 +#define AA_ENABLED_PERMS 0400
89 +#endif
90 +static int param_set_aa_enabled(const char *val, struct kernel_param *kp);
91 +unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
92 +module_param_call(enabled, param_set_aa_enabled, param_get_aauint,
93 + &apparmor_enabled, AA_ENABLED_PERMS);
94 +MODULE_PARM_DESC(apparmor_enabled, "Enable/Disable Apparmor on boot");
95 +
96 +static int __init apparmor_enabled_setup(char *str)
97 +{
98 + apparmor_enabled = simple_strtol(str, NULL, 0);
99 + return 1;
100 +}
101 +__setup("apparmor=", apparmor_enabled_setup);
102 +
103 +static int param_set_aabool(const char *val, struct kernel_param *kp)
104 +{
105 + if (aa_task_context(current))
106 + return -EPERM;
107 + return param_set_bool(val, kp);
108 +}
109 +
110 +static int param_get_aabool(char *buffer, struct kernel_param *kp)
111 +{
112 + if (aa_task_context(current))
113 + return -EPERM;
114 + return param_get_bool(buffer, kp);
115 +}
116 +
117 +static int param_set_aauint(const char *val, struct kernel_param *kp)
118 +{
119 + if (aa_task_context(current))
120 + return -EPERM;
121 + return param_set_uint(val, kp);
122 +}
123 +
124 +static int param_get_aauint(char *buffer, struct kernel_param *kp)
125 +{
126 + if (aa_task_context(current))
127 + return -EPERM;
128 + return param_get_uint(buffer, kp);
129 +}
130 +
131 +/* allow run time disabling of apparmor */
132 +static int param_set_aa_enabled(const char *val, struct kernel_param *kp)
133 +{
134 + char *endp;
135 + unsigned long l;
136 +
137 + if (!apparmor_initialized) {
138 + apparmor_enabled = 0;
139 + return 0;
140 + }
141 +
142 + if (aa_task_context(current))
143 + return -EPERM;
144 +
145 + if (!apparmor_enabled)
146 + return -EINVAL;
147 +
148 + if (!val)
149 + return -EINVAL;
150 +
151 + l = simple_strtoul(val, &endp, 0);
152 + if (endp == val || l != 0)
153 + return -EINVAL;
154 +
155 + apparmor_enabled = 0;
156 + apparmor_disable();
157 + return 0;
158 +}
159 +
160 +static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
161 + const char *name)
162 +{
163 + struct aa_profile *profile = aa_get_profile(task);
164 + int error = 0;
165 +
166 + if (profile) {
167 + error = aa_audit_syscallreject(profile, flags, name);
168 + aa_put_profile(profile);
169 + }
170 +
171 + return error;
172 +}
173 +
174 +static int apparmor_ptrace(struct task_struct *parent,
175 + struct task_struct *child, unsigned int mode)
176 +{
177 + struct aa_task_context *cxt;
178 + int error = 0;
179 +
180 + /*
181 + * parent can ptrace child when
182 + * - parent is unconfined
183 + * - parent & child are in the same namespace &&
184 + * - parent is in complain mode
185 + * - parent and child are confined by the same profile
186 + * - parent profile has CAP_SYS_PTRACE
187 + */
188 +
189 + rcu_read_lock();
190 + cxt = aa_task_context(parent);
191 + if (cxt) {
192 + if (parent->nsproxy != child->nsproxy) {
193 + struct aa_audit sa;
194 + memset(&sa, 0, sizeof(sa));
195 + sa.operation = "ptrace";
196 + sa.gfp_mask = GFP_ATOMIC;
197 + sa.parent = parent->pid;
198 + sa.task = child->pid;
199 + sa.info = "different namespaces";
200 + aa_audit_reject(cxt->profile, &sa);
201 + error = -EPERM;
202 + } else {
203 + struct aa_task_context *child_cxt =
204 + aa_task_context(child);
205 +
206 + error = aa_may_ptrace(cxt, child_cxt ?
207 + child_cxt->profile : NULL);
208 + if (PROFILE_COMPLAIN(cxt->profile)) {
209 + struct aa_audit sa;
210 + memset(&sa, 0, sizeof(sa));
211 + sa.operation = "ptrace";
212 + sa.gfp_mask = GFP_ATOMIC;
213 + sa.parent = parent->pid;
214 + sa.task = child->pid;
215 + aa_audit_hint(cxt->profile, &sa);
216 + }
217 + }
218 + }
219 + rcu_read_unlock();
220 +
221 + return error;
222 +}
223 +
224 +static int apparmor_capable(struct task_struct *task, int cap)
225 +{
226 + int error;
227 + struct aa_task_context *cxt;
228 +
229 + /* cap_capable returns 0 on success, else -EPERM */
230 + error = cap_capable(task, cap);
231 +
232 + rcu_read_lock();
233 + cxt = aa_task_context(task);
234 + if (cxt && (!error || cap_raised(cxt->profile->set_caps, cap)))
235 + error = aa_capability(cxt, cap);
236 + rcu_read_unlock();
237 +
238 + return error;
239 +}
240 +
241 +static int apparmor_sysctl(struct ctl_table *table, int op)
242 +{
243 + struct aa_profile *profile = aa_get_profile(current);
244 + int error = 0;
245 +
246 + if (profile) {
247 + char *buffer, *name;
248 + int mask;
249 +
250 + mask = 0;
251 + if (op & 4)
252 + mask |= MAY_READ;
253 + if (op & 2)
254 + mask |= MAY_WRITE;
255 +
256 + error = -ENOMEM;
257 + buffer = (char*)__get_free_page(GFP_KERNEL);
258 + if (!buffer)
259 + goto out;
260 + name = sysctl_pathname(table, buffer, PAGE_SIZE);
261 + if (name && name - buffer >= 5) {
262 + name -= 5;
263 + memcpy(name, "/proc", 5);
264 + error = aa_perm_path(profile, "sysctl", name, mask, 0);
265 + }
266 + free_page((unsigned long)buffer);
267 + }
268 +
269 +out:
270 + aa_put_profile(profile);
271 + return error;
272 +}
273 +
274 +static int apparmor_bprm_set_security(struct linux_binprm *bprm)
275 +{
276 + /* handle capability bits with setuid, etc */
277 + cap_bprm_set_security(bprm);
278 + /* already set based on script name */
279 + if (bprm->sh_bang)
280 + return 0;
281 + return aa_register(bprm);
282 +}
283 +
284 +static int apparmor_bprm_secureexec(struct linux_binprm *bprm)
285 +{
286 + int ret = cap_bprm_secureexec(bprm);
287 +
288 + if (!ret && (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) {
289 + AA_DEBUG("%s: secureexec required for %s\n",
290 + __FUNCTION__, bprm->filename);
291 + ret = 1;
292 + }
293 +
294 + return ret;
295 +}
296 +
297 +static int apparmor_sb_mount(char *dev_name, struct path *path, char *type,
298 + unsigned long flags, void *data)
299 +{
300 + return aa_reject_syscall(current, GFP_KERNEL, "mount");
301 +}
302 +
303 +static int apparmor_umount(struct vfsmount *mnt, int flags)
304 +{
305 + return aa_reject_syscall(current, GFP_KERNEL, "umount");
306 +}
307 +
308 +static int apparmor_inode_mkdir(struct inode *dir, struct dentry *dentry,
309 + struct vfsmount *mnt, int mask)
310 +{
311 + struct aa_profile *profile;
312 + int error = 0;
313 +
314 + if (!mnt || !mediated_filesystem(dir))
315 + goto out;
316 +
317 + profile = aa_get_profile(current);
318 +
319 + if (profile)
320 + error = aa_perm_dir(profile, "inode_mkdir", dentry, mnt,
321 + MAY_WRITE);
322 +
323 + aa_put_profile(profile);
324 +
325 +out:
326 + return error;
327 +}
328 +
329 +static int apparmor_inode_rmdir(struct inode *dir, struct dentry *dentry,
330 + struct vfsmount *mnt)
331 +{
332 + struct aa_profile *profile;
333 + int error = 0;
334 +
335 + if (!mnt || !mediated_filesystem(dir))
336 + goto out;
337 +
338 + profile = aa_get_profile(current);
339 +
340 + if (profile)
341 + error = aa_perm_dir(profile, "inode_rmdir", dentry, mnt,
342 + MAY_WRITE);
343 +
344 + aa_put_profile(profile);
345 +
346 +out:
347 + return error;
348 +}
349 +
350 +static int aa_permission(const char *operation, struct inode *inode,
351 + struct dentry *dentry, struct vfsmount *mnt,
352 + int mask, int check)
353 +{
354 + int error = 0;
355 +
356 + if (mnt && mediated_filesystem(inode)) {
357 + struct aa_profile *profile;
358 +
359 + profile = aa_get_profile(current);
360 + if (profile)
361 + error = aa_perm(profile, operation, dentry, mnt, mask,
362 + check);
363 + aa_put_profile(profile);
364 + }
365 + return error;
366 +}
367 +
368 +static inline int aa_mask_permissions(int mask)
369 +{
370 + if (mask & MAY_APPEND)
371 + mask &= (MAY_READ | MAY_APPEND | MAY_EXEC);
372 + else
373 + mask &= (MAY_READ | MAY_WRITE | MAY_EXEC);
374 + return mask;
375 +}
376 +
377 +static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
378 + struct vfsmount *mnt, int mask)
379 +{
380 + return aa_permission("inode_create", dir, dentry, mnt, MAY_APPEND, 0);
381 +}
382 +
383 +static int apparmor_inode_link(struct dentry *old_dentry,
384 + struct vfsmount *old_mnt, struct inode *dir,
385 + struct dentry *new_dentry,
386 + struct vfsmount *new_mnt)
387 +{
388 + int error = 0;
389 + struct aa_profile *profile;
390 +
391 + if (!old_mnt || !new_mnt || !mediated_filesystem(dir))
392 + goto out;
393 +
394 + profile = aa_get_profile(current);
395 +
396 + if (profile)
397 + error = aa_link(profile, new_dentry, new_mnt,
398 + old_dentry, old_mnt);
399 +
400 + aa_put_profile(profile);
401 +
402 +out:
403 + return error;
404 +}
405 +
406 +static int apparmor_inode_unlink(struct inode *dir, struct dentry *dentry,
407 + struct vfsmount *mnt)
408 +{
409 + int check = 0;
410 +
411 + if (S_ISDIR(dentry->d_inode->i_mode))
412 + check |= AA_CHECK_DIR;
413 + return aa_permission("inode_unlink", dir, dentry, mnt, MAY_WRITE,
414 + check);
415 +}
416 +
417 +static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry,
418 + struct vfsmount *mnt, const char *old_name)
419 +{
420 + return aa_permission("inode_symlink", dir, dentry, mnt, MAY_WRITE, 0);
421 +}
422 +
423 +static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry,
424 + struct vfsmount *mnt, int mode, dev_t dev)
425 +{
426 + return aa_permission("inode_mknod", dir, dentry, mnt, MAY_WRITE, 0);
427 +}
428 +
429 +static int apparmor_inode_rename(struct inode *old_dir,
430 + struct dentry *old_dentry,
431 + struct vfsmount *old_mnt,
432 + struct inode *new_dir,
433 + struct dentry *new_dentry,
434 + struct vfsmount *new_mnt)
435 +{
436 + struct aa_profile *profile;
437 + int error = 0;
438 +
439 + if ((!old_mnt && !new_mnt) || !mediated_filesystem(old_dir))
440 + goto out;
441 +
442 + profile = aa_get_profile(current);
443 +
444 + if (profile) {
445 + struct inode *inode = old_dentry->d_inode;
446 + int check = 0;
447 +
448 + if (inode && S_ISDIR(inode->i_mode))
449 + check |= AA_CHECK_DIR;
450 + if (old_mnt)
451 + error = aa_perm(profile, "inode_rename", old_dentry,
452 + old_mnt, MAY_READ | MAY_WRITE, check);
453 +
454 + if (!error && new_mnt) {
455 + error = aa_perm(profile, "inode_rename", new_dentry,
456 + new_mnt, MAY_WRITE, check);
457 + }
458 + }
459 +
460 + aa_put_profile(profile);
461 +
462 +out:
463 + return error;
464 +}
465 +
466 +static int apparmor_inode_permission(struct inode *inode, int mask,
467 + struct nameidata *nd)
468 +{
469 + int check = 0;
470 +
471 + if (!nd || nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE))
472 + return 0;
473 + mask = aa_mask_permissions(mask);
474 + if (S_ISDIR(inode->i_mode)) {
475 + check |= AA_CHECK_DIR;
476 + /* allow traverse accesses to directories */
477 + mask &= ~MAY_EXEC;
478 + }
479 + return aa_permission("inode_permission", inode, nd->dentry, nd->mnt,
480 + mask, check);
481 +}
482 +
483 +static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
484 + struct iattr *iattr)
485 +{
486 + int error = 0;
487 +
488 + if (!mnt)
489 + goto out;
490 +
491 + if (mediated_filesystem(dentry->d_inode)) {
492 + struct aa_profile *profile;
493 +
494 + profile = aa_get_profile(current);
495 + /*
496 + * Mediate any attempt to change attributes of a file
497 + * (chmod, chown, chgrp, etc)
498 + */
499 + if (profile)
500 + error = aa_attr(profile, dentry, mnt, iattr);
501 +
502 + aa_put_profile(profile);
503 + }
504 +
505 +out:
506 + return error;
507 +}
508 +
509 +static int aa_xattr_permission(struct dentry *dentry, struct vfsmount *mnt,
510 + const char *operation, int mask,
511 + struct file *file)
512 +{
513 + int error = 0;
514 +
515 + if (mnt && mediated_filesystem(dentry->d_inode)) {
516 + struct aa_profile *profile = aa_get_profile(current);
517 + int check = file ? AA_CHECK_FD : 0;
518 +
519 + if (profile)
520 + error = aa_perm_xattr(profile, operation, dentry, mnt,
521 + mask, check);
522 + aa_put_profile(profile);
523 + }
524 +
525 + return error;
526 +}
527 +
528 +static int apparmor_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
529 + const char *name, const void *value,
530 + size_t size, int flags, struct file *file)
531 +{
532 + int error = cap_inode_setxattr(dentry, mnt, name, value, size, flags,
533 + file);
534 +
535 + if (!error)
536 + error = aa_xattr_permission(dentry, mnt, "xattr set",
537 + MAY_WRITE, file);
538 + return error;
539 +}
540 +
541 +static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
542 + const char *name, struct file *file)
543 +{
544 + return aa_xattr_permission(dentry, mnt, "xattr get", MAY_READ, file);
545 +}
546 +
547 +static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
548 + struct file *file)
549 +{
550 + return aa_xattr_permission(dentry, mnt, "xattr list", MAY_READ, file);
551 +}
552 +
553 +static int apparmor_inode_removexattr(struct dentry *dentry,
554 + struct vfsmount *mnt, const char *name,
555 + struct file *file)
556 +{
557 + return aa_xattr_permission(dentry, mnt, "xattr remove", MAY_WRITE,
558 + file);
559 +}
560 +
561 +static int aa_file_permission(const char *op, struct file *file, int mask)
562 +{
563 + struct aa_profile *profile;
564 + struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
565 + int error = 0;
566 +
567 + if (!file_profile)
568 + goto out;
569 +
570 + /*
571 + * If this file was opened under a different profile, we
572 + * revalidate the access against the current profile.
573 + */
574 + profile = aa_get_profile(current);
575 + if (profile && (file_profile != profile || mask & AA_MAY_LOCK)) {
576 + struct dentry *dentry = file->f_dentry;
577 + struct vfsmount *mnt = file->f_vfsmnt;
578 + struct inode *inode = dentry->d_inode;
579 + int check = AA_CHECK_FD;
580 +
581 + /*
582 + * FIXME: We should remember which profiles we revalidated
583 + * against.
584 + */
585 + if (S_ISDIR(inode->i_mode))
586 + check |= AA_CHECK_DIR;
587 + error = aa_permission(op, inode, dentry, mnt, mask, check);
588 + }
589 + aa_put_profile(profile);
590 +
591 +out:
592 + return error;
593 +}
594 +
595 +static int apparmor_file_permission(struct file *file, int mask)
596 +{
597 + return aa_file_permission("file_permission", file,
598 + aa_mask_permissions(mask));
599 +}
600 +
601 +static inline int apparmor_file_lock (struct file *file, unsigned int cmd)
602 +{
603 + int mask = AA_MAY_LOCK;
604 + if (cmd == F_WRLCK)
605 + mask |= MAY_WRITE;
606 + return aa_file_permission("file_lock", file, mask);
607 +}
608 +
609 +static int apparmor_file_alloc_security(struct file *file)
610 +{
611 + struct aa_profile *profile;
612 +
613 + profile = aa_get_profile(current);
614 + if (profile)
615 + file->f_security = profile;
616 +
617 + return 0;
618 +}
619 +
620 +static void apparmor_file_free_security(struct file *file)
621 +{
622 + struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
623 +
624 + aa_put_profile(file_profile);
625 +}
626 +
627 +static inline int aa_mmap(struct file *file, const char *operation,
628 + unsigned long prot, unsigned long flags)
629 +{
630 + struct dentry *dentry;
631 + int mask = 0;
632 +
633 + if (!file || !file->f_security)
634 + return 0;
635 +
636 + if (prot & PROT_READ)
637 + mask |= MAY_READ;
638 + /* Private mappings don't require write perms since they don't
639 + * write back to the files */
640 + if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
641 + mask |= MAY_WRITE;
642 + if (prot & PROT_EXEC)
643 + mask |= AA_EXEC_MMAP;
644 +
645 + dentry = file->f_dentry;
646 + return aa_permission(operation, dentry->d_inode, dentry,
647 + file->f_vfsmnt, mask, AA_CHECK_FD);
648 +}
649 +
650 +static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
651 + unsigned long prot, unsigned long flags,
652 + unsigned long addr, unsigned long addr_only)
653 +{
654 + if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) {
655 + struct aa_profile *profile = aa_get_profile(current);
656 + if (profile)
657 + /* future control check here */
658 + return -EACCES;
659 + else
660 + return -EACCES;
661 + aa_put_profile(profile);
662 + }
663 +
664 + return aa_mmap(file, "file_mmap", prot, flags);
665 +}
666 +
667 +static int apparmor_file_mprotect(struct vm_area_struct *vma,
668 + unsigned long reqprot, unsigned long prot)
669 +{
670 + return aa_mmap(vma->vm_file, "file_mprotect", prot,
671 + !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
672 +}
673 +
674 +static int apparmor_task_alloc_security(struct task_struct *task)
675 +{
676 + return aa_clone(task);
677 +}
678 +
679 +/*
680 + * Called from IRQ context from RCU callback.
681 + */
682 +static void apparmor_task_free_security(struct task_struct *task)
683 +{
684 + aa_release(task);
685 +}
686 +
687 +static int apparmor_getprocattr(struct task_struct *task, char *name,
688 + char **value)
689 +{
690 + unsigned len;
691 + int error;
692 + struct aa_profile *profile;
693 +
694 + /* AppArmor only supports the "current" process attribute */
695 + if (strcmp(name, "current") != 0)
696 + return -EINVAL;
697 +
698 + /* must be task querying itself or admin */
699 + if (current != task && !capable(CAP_SYS_ADMIN))
700 + return -EPERM;
701 +
702 + profile = aa_get_profile(task);
703 + error = aa_getprocattr(profile, value, &len);
704 + aa_put_profile(profile);
705 + if (!error)
706 + error = len;
707 +
708 + return error;
709 +}
710 +
711 +static int apparmor_setprocattr(struct task_struct *task, char *name,
712 + void *value, size_t size)
713 +{
714 + char *command, *args;
715 + int error;
716 +
717 + if (strcmp(name, "current") != 0 || size == 0 || size >= PAGE_SIZE)
718 + return -EINVAL;
719 + args = value;
720 + args[size] = '\0';
721 + args = strstrip(args);
722 + command = strsep(&args, " ");
723 + if (!args)
724 + return -EINVAL;
725 + while (isspace(*args))
726 + args++;
727 + if (!*args)
728 + return -EINVAL;
729 +
730 + if (strcmp(command, "changehat") == 0) {
731 + if (current != task)
732 + return -EACCES;
733 + error = aa_setprocattr_changehat(args);
734 + } else if (strcmp(command, "changeprofile") == 0) {
735 + if (current != task)
736 + return -EACCES;
737 + error = aa_setprocattr_changeprofile(args);
738 + } else if (strcmp(command, "setprofile") == 0) {
739 + struct aa_profile *profile;
740 +
741 + /* Only an unconfined process with admin capabilities
742 + * may change the profile of another task.
743 + */
744 +
745 + if (!capable(CAP_SYS_ADMIN))
746 + return -EACCES;
747 +
748 + profile = aa_get_profile(current);
749 + if (profile) {
750 + struct aa_audit sa;
751 + memset(&sa, 0, sizeof(sa));
752 + sa.operation = "profile_set";
753 + sa.gfp_mask = GFP_KERNEL;
754 + sa.task = task->pid;
755 + sa.info = "from confined process";
756 + aa_audit_reject(profile, &sa);
757 + aa_put_profile(profile);
758 + return -EACCES;
759 + }
760 + error = aa_setprocattr_setprofile(task, args);
761 + } else {
762 + struct aa_audit sa;
763 + memset(&sa, 0, sizeof(sa));
764 + sa.operation = "setprocattr";
765 + sa.gfp_mask = GFP_KERNEL;
766 + sa.info = "invalid command";
767 + sa.name = command;
768 + sa.task = task->pid;
769 + aa_audit_reject(NULL, &sa);
770 + return -EINVAL;
771 + }
772 +
773 + if (!error)
774 + error = size;
775 + return error;
776 +}
777 +
778 +struct security_operations apparmor_ops = {
779 + .ptrace = apparmor_ptrace,
780 + .capget = cap_capget,
781 + .capset_check = cap_capset_check,
782 + .capset_set = cap_capset_set,
783 + .sysctl = apparmor_sysctl,
784 + .capable = apparmor_capable,
785 + .syslog = cap_syslog,
786 +
787 + .netlink_send = cap_netlink_send,
788 + .netlink_recv = cap_netlink_recv,
789 +
790 + .bprm_apply_creds = cap_bprm_apply_creds,
791 + .bprm_set_security = apparmor_bprm_set_security,
792 + .bprm_secureexec = apparmor_bprm_secureexec,
793 +
794 + .sb_mount = apparmor_sb_mount,
795 + .sb_umount = apparmor_umount,
796 +
797 + .inode_mkdir = apparmor_inode_mkdir,
798 + .inode_rmdir = apparmor_inode_rmdir,
799 + .inode_create = apparmor_inode_create,
800 + .inode_link = apparmor_inode_link,
801 + .inode_unlink = apparmor_inode_unlink,
802 + .inode_symlink = apparmor_inode_symlink,
803 + .inode_mknod = apparmor_inode_mknod,
804 + .inode_rename = apparmor_inode_rename,
805 + .inode_permission = apparmor_inode_permission,
806 + .inode_setattr = apparmor_inode_setattr,
807 + .inode_setxattr = apparmor_inode_setxattr,
808 + .inode_getxattr = apparmor_inode_getxattr,
809 + .inode_listxattr = apparmor_inode_listxattr,
810 + .inode_removexattr = apparmor_inode_removexattr,
811 + .file_permission = apparmor_file_permission,
812 + .file_alloc_security = apparmor_file_alloc_security,
813 + .file_free_security = apparmor_file_free_security,
814 + .file_mmap = apparmor_file_mmap,
815 + .file_mprotect = apparmor_file_mprotect,
816 + .file_lock = apparmor_file_lock,
817 +
818 + .task_alloc_security = apparmor_task_alloc_security,
819 + .task_free_security = apparmor_task_free_security,
820 + .task_post_setuid = cap_task_post_setuid,
821 + .task_reparent_to_init = cap_task_reparent_to_init,
822 +
823 + .getprocattr = apparmor_getprocattr,
824 + .setprocattr = apparmor_setprocattr,
825 +};
826 +
827 +void info_message(const char *str)
828 +{
829 + struct aa_audit sa;
830 + memset(&sa, 0, sizeof(sa));
831 + sa.gfp_mask = GFP_KERNEL;
832 + sa.info = str;
833 + printk(KERN_INFO "AppArmor: %s\n", str);
834 + if (audit_enabled)
835 + aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS);
836 +}
837 +
838 +static int __init apparmor_init(void)
839 +{
840 + int error;
841 +
842 + if (!apparmor_enabled) {
843 + info_message("AppArmor disabled by boottime parameter\n");
844 + return 0;
845 + }
846 +
847 + if ((error = create_apparmorfs())) {
848 + AA_ERROR("Unable to activate AppArmor filesystem\n");
849 + goto createfs_out;
850 + }
851 +
852 + if ((error = alloc_default_namespace())){
853 + AA_ERROR("Unable to allocate default profile namespace\n");
854 + goto alloc_out;
855 + }
856 +
857 + if ((error = register_security(&apparmor_ops))) {
858 + AA_ERROR("Unable to register AppArmor\n");
859 + goto register_security_out;
860 + }
861 +
862 + /* Report that AppArmor successfully initialized */
863 + apparmor_initialized = 1;
864 + if (apparmor_complain)
865 + info_message("AppArmor initialized: complainmode enabled");
866 + else
867 + info_message("AppArmor initialized");
868 +
869 + return error;
870 +
871 +register_security_out:
872 + free_default_namespace();
873 +
874 +alloc_out:
875 + destroy_apparmorfs();
876 +
877 +createfs_out:
878 + return error;
879 +
880 +}
881 +
882 +security_initcall(apparmor_init);
883 +
884 +void apparmor_disable(void)
885 +{
886 + /* Remove and release all the profiles on the profile list. */
887 + mutex_lock(&aa_interface_lock);
888 + aa_profile_ns_list_release();
889 +
890 + /* FIXME: cleanup profiles references on files */
891 + free_default_namespace();
892 +
893 + /*
894 + * Delay for an rcu cycle to make sure that all active task
895 + * context readers have finished, and all profiles have been
896 + * freed by their rcu callbacks.
897 + */
898 + synchronize_rcu();
899 +
900 + destroy_apparmorfs();
901 + mutex_unlock(&aa_interface_lock);
902 +
903 + apparmor_initialized = 0;
904 +
905 + info_message("AppArmor protection removed");
906 +}
907 +
908 +MODULE_DESCRIPTION("AppArmor process confinement");
909 +MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");
910 +MODULE_LICENSE("GPL");