~apparmor-dev/apparmor/2_3

« back to all changes in this revision

Viewing changes to kernel-patches/for-mainline/apparmor-lsm.diff

  • Committer: jrjohansen
  • Date: 2008-05-27 12:04:33 UTC
  • Revision ID: svn-v4:40609528-9d10-0410-9bd8-e926d5471da9:branches/2_3:1265
remove for-mainline dir from kernel patches

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 |  889 ++++++++++++++++++++++++++++++++++++++++++++++++
11
 
 1 file changed, 889 insertions(+)
12
 
 
13
 
--- /dev/null
14
 
+++ b/security/apparmor/lsm.c
15
 
@@ -0,0 +1,889 @@
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)
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 nameidata *nd, 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
 
+                                  char *name, void *value, size_t size,
530
 
+                                  int flags, struct file *file)
531
 
+{
532
 
+       return aa_xattr_permission(dentry, mnt, "xattr set", MAY_WRITE, file);
533
 
+}
534
 
+
535
 
+static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
536
 
+                                  char *name, struct file *file)
537
 
+{
538
 
+       return aa_xattr_permission(dentry, mnt, "xattr get", MAY_READ, file);
539
 
+}
540
 
+
541
 
+static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
542
 
+                                   struct file *file)
543
 
+{
544
 
+       return aa_xattr_permission(dentry, mnt, "xattr list", MAY_READ, file);
545
 
+}
546
 
+
547
 
+static int apparmor_inode_removexattr(struct dentry *dentry,
548
 
+                                     struct vfsmount *mnt, char *name,
549
 
+                                     struct file *file)
550
 
+{
551
 
+       return aa_xattr_permission(dentry, mnt, "xattr remove", MAY_WRITE,
552
 
+                                  file);
553
 
+}
554
 
+
555
 
+static int aa_file_permission(const char *op, struct file *file, int mask)
556
 
+{
557
 
+       struct aa_profile *profile;
558
 
+       struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
559
 
+       int error = 0;
560
 
+
561
 
+       if (!file_profile)
562
 
+               goto out;
563
 
+
564
 
+       /*
565
 
+        * If this file was opened under a different profile, we
566
 
+        * revalidate the access against the current profile.
567
 
+        */
568
 
+       profile = aa_get_profile(current);
569
 
+       if (profile && (file_profile != profile || mask & AA_MAY_LOCK)) {
570
 
+               struct dentry *dentry = file->f_dentry;
571
 
+               struct vfsmount *mnt = file->f_vfsmnt;
572
 
+               struct inode *inode = dentry->d_inode;
573
 
+               int check = AA_CHECK_FD;
574
 
+
575
 
+               /*
576
 
+                * FIXME: We should remember which profiles we revalidated
577
 
+                *        against.
578
 
+                */
579
 
+               if (S_ISDIR(inode->i_mode))
580
 
+                       check |= AA_CHECK_DIR;
581
 
+               error = aa_permission(op, inode, dentry, mnt, mask, check);
582
 
+       }
583
 
+       aa_put_profile(profile);
584
 
+
585
 
+out:
586
 
+       return error;
587
 
+}
588
 
+
589
 
+static int apparmor_file_permission(struct file *file, int mask)
590
 
+{
591
 
+       return aa_file_permission("file_permission", file,
592
 
+                                 aa_mask_permissions(mask));
593
 
+}
594
 
+
595
 
+static inline int apparmor_file_lock (struct file *file, unsigned int cmd)
596
 
+{
597
 
+       int mask = AA_MAY_LOCK;
598
 
+       if (cmd == F_WRLCK)
599
 
+               mask |= MAY_WRITE;
600
 
+       return aa_file_permission("file_lock", file, mask);
601
 
+}
602
 
+
603
 
+static int apparmor_file_alloc_security(struct file *file)
604
 
+{
605
 
+       struct aa_profile *profile;
606
 
+
607
 
+       profile = aa_get_profile(current);
608
 
+       if (profile)
609
 
+               file->f_security = profile;
610
 
+
611
 
+       return 0;
612
 
+}
613
 
+
614
 
+static void apparmor_file_free_security(struct file *file)
615
 
+{
616
 
+       struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
617
 
+
618
 
+       aa_put_profile(file_profile);
619
 
+}
620
 
+
621
 
+static inline int aa_mmap(struct file *file, const char *operation,
622
 
+                         unsigned long prot, unsigned long flags)
623
 
+{
624
 
+       struct dentry *dentry;
625
 
+       int mask = 0;
626
 
+
627
 
+       if (!file || !file->f_security)
628
 
+               return 0;
629
 
+
630
 
+       if (prot & PROT_READ)
631
 
+               mask |= MAY_READ;
632
 
+       /* Private mappings don't require write perms since they don't
633
 
+        * write back to the files */
634
 
+       if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
635
 
+               mask |= MAY_WRITE;
636
 
+       if (prot & PROT_EXEC)
637
 
+               mask |= AA_EXEC_MMAP;
638
 
+
639
 
+       dentry = file->f_dentry;
640
 
+       return aa_permission(operation, dentry->d_inode, dentry,
641
 
+                            file->f_vfsmnt, mask, AA_CHECK_FD);
642
 
+}
643
 
+
644
 
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
645
 
+                             unsigned long prot, unsigned long flags,
646
 
+                             unsigned long addr, unsigned long addr_only)
647
 
+{
648
 
+       if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) {
649
 
+               struct aa_profile *profile = aa_get_profile(current);
650
 
+               if (profile)
651
 
+                       /* future control check here */
652
 
+                       return -EACCES;
653
 
+               else
654
 
+                       return -EACCES;
655
 
+               aa_put_profile(profile);
656
 
+       }
657
 
+
658
 
+       return aa_mmap(file, "file_mmap", prot, flags);
659
 
+}
660
 
+
661
 
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
662
 
+                                 unsigned long reqprot, unsigned long prot)
663
 
+{
664
 
+       return aa_mmap(vma->vm_file, "file_mprotect", prot,
665
 
+                      !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
666
 
+}
667
 
+
668
 
+static int apparmor_task_alloc_security(struct task_struct *task)
669
 
+{
670
 
+       return aa_clone(task);
671
 
+}
672
 
+
673
 
+/*
674
 
+ * Called from IRQ context from RCU callback.
675
 
+ */
676
 
+static void apparmor_task_free_security(struct task_struct *task)
677
 
+{
678
 
+       aa_release(task);
679
 
+}
680
 
+
681
 
+static int apparmor_getprocattr(struct task_struct *task, char *name,
682
 
+                               char **value)
683
 
+{
684
 
+       unsigned len;
685
 
+       int error;
686
 
+       struct aa_profile *profile;
687
 
+
688
 
+       /* AppArmor only supports the "current" process attribute */
689
 
+       if (strcmp(name, "current") != 0)
690
 
+               return -EINVAL;
691
 
+
692
 
+       /* must be task querying itself or admin */
693
 
+       if (current != task && !capable(CAP_SYS_ADMIN))
694
 
+               return -EPERM;
695
 
+
696
 
+       profile = aa_get_profile(task);
697
 
+       error = aa_getprocattr(profile, value, &len);
698
 
+       aa_put_profile(profile);
699
 
+       if (!error)
700
 
+               error = len;
701
 
+
702
 
+       return error;
703
 
+}
704
 
+
705
 
+static int apparmor_setprocattr(struct task_struct *task, char *name,
706
 
+                               void *value, size_t size)
707
 
+{
708
 
+       char *command, *args;
709
 
+       int error;
710
 
+
711
 
+       if (strcmp(name, "current") != 0 || size == 0 || size >= PAGE_SIZE)
712
 
+               return -EINVAL;
713
 
+       args = value;
714
 
+       args[size] = '\0';
715
 
+       args = strstrip(args);
716
 
+       command = strsep(&args, " ");
717
 
+       if (!args)
718
 
+               return -EINVAL;
719
 
+       while (isspace(*args))
720
 
+               args++;
721
 
+       if (!*args)
722
 
+               return -EINVAL;
723
 
+
724
 
+       if (strcmp(command, "changehat") == 0) {
725
 
+               if (current != task)
726
 
+                       return -EACCES;
727
 
+               error = aa_setprocattr_changehat(args);
728
 
+       } else if (strcmp(command, "changeprofile") == 0) {
729
 
+               if (current != task)
730
 
+                       return -EACCES;
731
 
+               error = aa_setprocattr_changeprofile(args);
732
 
+       } else if (strcmp(command, "setprofile") == 0) {
733
 
+               struct aa_profile *profile;
734
 
+
735
 
+               /* Only an unconfined process with admin capabilities
736
 
+                * may change the profile of another task.
737
 
+                */
738
 
+
739
 
+               if (!capable(CAP_SYS_ADMIN))
740
 
+                       return -EACCES;
741
 
+
742
 
+               profile = aa_get_profile(current);
743
 
+               if (profile) {
744
 
+                       struct aa_audit sa;
745
 
+                       memset(&sa, 0, sizeof(sa));
746
 
+                       sa.operation = "profile_set";
747
 
+                       sa.gfp_mask = GFP_KERNEL;
748
 
+                       sa.task = task->pid;
749
 
+                       sa.info = "from confined process";
750
 
+                       aa_audit_reject(profile, &sa);
751
 
+                       aa_put_profile(profile);
752
 
+                       return -EACCES;
753
 
+               }
754
 
+               error = aa_setprocattr_setprofile(task, args);
755
 
+       } else {
756
 
+               struct aa_audit sa;
757
 
+               memset(&sa, 0, sizeof(sa));
758
 
+               sa.operation = "setprocattr";
759
 
+               sa.gfp_mask = GFP_KERNEL;
760
 
+               sa.info = "invalid command";
761
 
+               sa.name = command;
762
 
+               sa.task = task->pid;
763
 
+               aa_audit_reject(NULL, &sa);
764
 
+               return -EINVAL;
765
 
+       }
766
 
+
767
 
+       if (!error)
768
 
+               error = size;
769
 
+       return error;
770
 
+}
771
 
+
772
 
+struct security_operations apparmor_ops = {
773
 
+       .ptrace =                       apparmor_ptrace,
774
 
+       .capget =                       cap_capget,
775
 
+       .capset_check =                 cap_capset_check,
776
 
+       .capset_set =                   cap_capset_set,
777
 
+       .sysctl =                       apparmor_sysctl,
778
 
+       .capable =                      apparmor_capable,
779
 
+       .syslog =                       cap_syslog,
780
 
+
781
 
+       .netlink_send =                 cap_netlink_send,
782
 
+       .netlink_recv =                 cap_netlink_recv,
783
 
+
784
 
+       .bprm_apply_creds =             cap_bprm_apply_creds,
785
 
+       .bprm_set_security =            apparmor_bprm_set_security,
786
 
+       .bprm_secureexec =              apparmor_bprm_secureexec,
787
 
+
788
 
+       .sb_mount =                     apparmor_sb_mount,
789
 
+       .sb_umount =                    apparmor_umount,
790
 
+
791
 
+       .inode_mkdir =                  apparmor_inode_mkdir,
792
 
+       .inode_rmdir =                  apparmor_inode_rmdir,
793
 
+       .inode_create =                 apparmor_inode_create,
794
 
+       .inode_link =                   apparmor_inode_link,
795
 
+       .inode_unlink =                 apparmor_inode_unlink,
796
 
+       .inode_symlink =                apparmor_inode_symlink,
797
 
+       .inode_mknod =                  apparmor_inode_mknod,
798
 
+       .inode_rename =                 apparmor_inode_rename,
799
 
+       .inode_permission =             apparmor_inode_permission,
800
 
+       .inode_setattr =                apparmor_inode_setattr,
801
 
+       .inode_setxattr =               apparmor_inode_setxattr,
802
 
+       .inode_getxattr =               apparmor_inode_getxattr,
803
 
+       .inode_listxattr =              apparmor_inode_listxattr,
804
 
+       .inode_removexattr =            apparmor_inode_removexattr,
805
 
+       .file_permission =              apparmor_file_permission,
806
 
+       .file_alloc_security =          apparmor_file_alloc_security,
807
 
+       .file_free_security =           apparmor_file_free_security,
808
 
+       .file_mmap =                    apparmor_file_mmap,
809
 
+       .file_mprotect =                apparmor_file_mprotect,
810
 
+       .file_lock =                    apparmor_file_lock,
811
 
+
812
 
+       .task_alloc_security =          apparmor_task_alloc_security,
813
 
+       .task_free_security =           apparmor_task_free_security,
814
 
+       .task_post_setuid =             cap_task_post_setuid,
815
 
+       .task_reparent_to_init =        cap_task_reparent_to_init,
816
 
+
817
 
+       .getprocattr =                  apparmor_getprocattr,
818
 
+       .setprocattr =                  apparmor_setprocattr,
819
 
+};
820
 
+
821
 
+void info_message(const char *str)
822
 
+{
823
 
+       struct aa_audit sa;
824
 
+       memset(&sa, 0, sizeof(sa));
825
 
+       sa.gfp_mask = GFP_KERNEL;
826
 
+       sa.info = str;
827
 
+       printk(KERN_INFO "AppArmor: %s\n", str);
828
 
+       if (audit_enabled)
829
 
+               aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS);
830
 
+}
831
 
+
832
 
+static int __init apparmor_init(void)
833
 
+{
834
 
+       int error;
835
 
+
836
 
+       if (!apparmor_enabled) {
837
 
+               info_message("AppArmor disabled by boottime parameter\n");
838
 
+               return 0;
839
 
+       }
840
 
+
841
 
+       if ((error = create_apparmorfs())) {
842
 
+               AA_ERROR("Unable to activate AppArmor filesystem\n");
843
 
+               goto createfs_out;
844
 
+       }
845
 
+
846
 
+       if ((error = alloc_default_namespace())){
847
 
+               AA_ERROR("Unable to allocate default profile namespace\n");
848
 
+               goto alloc_out;
849
 
+       }
850
 
+
851
 
+       if ((error = register_security(&apparmor_ops))) {
852
 
+               AA_ERROR("Unable to register AppArmor\n");
853
 
+               goto register_security_out;
854
 
+       }
855
 
+
856
 
+       /* Report that AppArmor successfully initialized */
857
 
+       apparmor_initialized = 1;
858
 
+       if (apparmor_complain)
859
 
+               info_message("AppArmor initialized: complainmode enabled");
860
 
+       else
861
 
+               info_message("AppArmor initialized");
862
 
+
863
 
+       return error;
864
 
+
865
 
+register_security_out:
866
 
+       free_default_namespace();
867
 
+
868
 
+alloc_out:
869
 
+       destroy_apparmorfs();
870
 
+
871
 
+createfs_out:
872
 
+       return error;
873
 
+
874
 
+}
875
 
+
876
 
+security_initcall(apparmor_init);
877
 
+
878
 
+void apparmor_disable(void)
879
 
+{
880
 
+       /* Remove and release all the profiles on the profile list. */
881
 
+       mutex_lock(&aa_interface_lock);
882
 
+       aa_profile_ns_list_release();
883
 
+
884
 
+       /* FIXME: cleanup profiles references on files */
885
 
+       free_default_namespace();
886
 
+
887
 
+       /*
888
 
+        * Delay for an rcu cycle to make sure that all active task
889
 
+        * context readers have finished, and all profiles have been
890
 
+        * freed by their rcu callbacks.
891
 
+        */
892
 
+       synchronize_rcu();
893
 
+
894
 
+       destroy_apparmorfs();
895
 
+       mutex_unlock(&aa_interface_lock);
896
 
+
897
 
+       apparmor_initialized = 0;
898
 
+
899
 
+       info_message("AppArmor protection removed");
900
 
+}
901
 
+
902
 
+MODULE_DESCRIPTION("AppArmor process confinement");
903
 
+MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");
904
 
+MODULE_LICENSE("GPL");