~ubuntu-branches/ubuntu/wily/apparmor/wily

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2011-04-27 10:38:07 UTC
  • mfrom: (5.1.118 natty)
  • Revision ID: james.westby@ubuntu.com-20110427103807-ym3rhwys6o84ith0
Tags: 2.6.1-2
debian/copyright: clarify for some full organization names.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
Index: b/security/apparmor/Kconfig
2
 
===================================================================
3
 
--- /dev/null
4
 
+++ b/security/apparmor/Kconfig
5
 
@@ -0,0 +1,9 @@
6
 
+config SECURITY_APPARMOR
7
 
+       tristate "AppArmor support"
8
 
+       depends on SECURITY!=n
9
 
+       help
10
 
+         This enables the AppArmor security module.
11
 
+         Required userspace tools (if they are not included in your
12
 
+         distribution) and further information may be found at
13
 
+         <http://forge.novell.com/modules/xfmod/project/?apparmor>
14
 
+         If you are unsure how to answer this question, answer N.
15
 
Index: b/security/apparmor/Makefile
16
 
===================================================================
17
 
--- /dev/null
18
 
+++ b/security/apparmor/Makefile
19
 
@@ -0,0 +1,6 @@
20
 
+# Makefile for AppArmor Linux Security Module
21
 
+#
22
 
+obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
23
 
+
24
 
+apparmor-y := main.o list.o procattr.o lsm.o apparmorfs.o capabilities.o \
25
 
+             module_interface.o match.o
26
 
Index: b/security/apparmor/apparmor.h
27
 
===================================================================
28
 
--- /dev/null
29
 
+++ b/security/apparmor/apparmor.h
30
 
@@ -0,0 +1,266 @@
31
 
+/*
32
 
+ *     Copyright (C) 1998-2005 Novell/SUSE
33
 
+ *
34
 
+ *     This program is free software; you can redistribute it and/or
35
 
+ *     modify it under the terms of the GNU General Public License as
36
 
+ *     published by the Free Software Foundation, version 2 of the
37
 
+ *     License.
38
 
+ *
39
 
+ *     AppArmor internal prototypes
40
 
+ */
41
 
+
42
 
+#ifndef __APPARMOR_H
43
 
+#define __APPARMOR_H
44
 
+
45
 
+#include <linux/fs.h>  /* Include for defn of iattr */
46
 
+#include <linux/binfmts.h>     /* defn of linux_binprm */
47
 
+#include <linux/rcupdate.h>
48
 
+
49
 
+#include "shared.h"
50
 
+#include "match.h"
51
 
+
52
 
+/* Control parameters (0 or 1), settable thru module/boot flags or
53
 
+ * via /sys/kernel/security/apparmor/control */
54
 
+extern int apparmor_complain;
55
 
+extern int apparmor_debug;
56
 
+extern int apparmor_audit;
57
 
+extern int apparmor_logsyscall;
58
 
+
59
 
+static inline int mediated_filesystem(struct inode *inode)
60
 
+{
61
 
+       return !(inode->i_sb->s_flags & MS_NOUSER);
62
 
+}
63
 
+
64
 
+#define PROFILE_COMPLAIN(_profile) \
65
 
+       (apparmor_complain == 1 || ((_profile) && (_profile)->flags.complain))
66
 
+
67
 
+#define SUBDOMAIN_COMPLAIN(_sd) \
68
 
+       (apparmor_complain == 1 || \
69
 
+        ((_sd) && (_sd)->active && (_sd)->active->flags.complain))
70
 
+
71
 
+#define PROFILE_AUDIT(_profile) \
72
 
+       (apparmor_audit == 1 || ((_profile) && (_profile)->flags.audit))
73
 
+
74
 
+#define SUBDOMAIN_AUDIT(_sd) \
75
 
+       (apparmor_audit == 1 || \
76
 
+        ((_sd) && (_sd)->active && (_sd)->active->flags.audit))
77
 
+
78
 
+/*
79
 
+ * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
80
 
+ * which is not related to profile accesses.
81
 
+ */
82
 
+
83
 
+#define AA_DEBUG(fmt, args...)                                         \
84
 
+       do {                                                            \
85
 
+               if (apparmor_debug)                                     \
86
 
+                       printk(KERN_DEBUG "AppArmor: " fmt, ##args);    \
87
 
+       } while (0)
88
 
+#define AA_INFO(fmt, args...)  printk(KERN_INFO "AppArmor: " fmt, ##args)
89
 
+#define AA_WARN(fmt, args...)  printk(KERN_WARNING "AppArmor: " fmt, ##args)
90
 
+#define AA_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args)
91
 
+
92
 
+/* basic AppArmor data structures */
93
 
+
94
 
+struct flagval {
95
 
+       int debug;
96
 
+       int complain;
97
 
+       int audit;
98
 
+};
99
 
+
100
 
+#define AA_SECURE_EXEC_NEEDED 0x00000001
101
 
+
102
 
+#define AA_EXEC_MODIFIER_MASK(mask) ((mask) & AA_EXEC_MODIFIERS)
103
 
+#define AA_EXEC_MASK(mask) ((mask) & (AA_EXEC_MODIFIERS | AA_EXEC_UNSAFE))
104
 
+
105
 
+/* struct aa_profile - basic confinement data
106
 
+ * @parent: non refcounted pointer to parent profile
107
 
+ * @name: the profiles name
108
 
+ * @file_rules: dfa containing the profiles file rules
109
 
+ * @list: list this profile is on
110
 
+ * @sub: profiles list of subprofiles (HATS)
111
 
+ * @flags: flags controlling profile behavior
112
 
+ * @null_profile: if needed per profile learning and null confinement profile
113
 
+ * @isstale: flag to indicate the profile is stale
114
 
+ * @capabilities: capabilities granted by the process
115
 
+ * @rcu: rcu head used when freeing the profile
116
 
+ * @count: reference count of the profile
117
 
+ *
118
 
+ * The AppArmor profile contains the basic confinement data.  Each profile
119
 
+ * has a name and potentially a list of profile entries. The profiles are
120
 
+ * connected in a list
121
 
+ */
122
 
+struct aa_profile {
123
 
+       struct aa_profile *parent;
124
 
+       char *name;
125
 
+
126
 
+       struct aa_dfa *file_rules;
127
 
+
128
 
+       struct list_head list;
129
 
+       struct list_head sub;
130
 
+       struct flagval flags;
131
 
+       struct aa_profile *null_profile;
132
 
+       int isstale;
133
 
+
134
 
+       kernel_cap_t capabilities;
135
 
+
136
 
+       struct rcu_head rcu;
137
 
+
138
 
+       struct kref count;
139
 
+};
140
 
+
141
 
+/**
142
 
+ * struct subdomain - primary label for confined tasks
143
 
+ * @active: the current active profile
144
 
+ * @hat_magic: the magic token controling the ability to leave a hat
145
 
+ * @list: list this subdomain is on
146
 
+ * @task: task that the subdomain confines
147
 
+ *
148
 
+ * Contains the tasks current active profile (which could change due to
149
 
+ * change_hat).  Plus the hat_magic needed during change_hat.
150
 
+ *
151
 
+ * N.B AppArmor's previous product name SubDomain was derived from the name
152
 
+ * of this structure/concept (changehat reducing a task into a sub-domain).
153
 
+ */
154
 
+struct subdomain {
155
 
+       struct aa_profile *active;      /* The current active profile */
156
 
+       u32 hat_magic;                  /* used with change_hat */
157
 
+       struct list_head list;          /* list of subdomains */
158
 
+       struct task_struct *task;
159
 
+};
160
 
+
161
 
+typedef int (*aa_iter) (struct subdomain *, void *);
162
 
+
163
 
+#define AA_SUBDOMAIN(sec)      ((struct subdomain*)(sec))
164
 
+#define AA_PROFILE(sec)                ((struct aa_profile*)(sec))
165
 
+
166
 
+/* Lock protecting access to 'struct subdomain' accesses */
167
 
+extern spinlock_t sd_lock;
168
 
+
169
 
+extern struct aa_profile *null_complain_profile;
170
 
+
171
 
+/* aa_audit - AppArmor auditing structure
172
 
+ * Structure is populated by access control code and passed to aa_audit which
173
 
+ * provides for a single point of logging.
174
 
+ */
175
 
+
176
 
+struct aa_audit {
177
 
+       unsigned short type, flags;
178
 
+       unsigned int result;
179
 
+       gfp_t gfp_mask;
180
 
+       int error_code;
181
 
+
182
 
+       const char *operation;
183
 
+       const char *name;
184
 
+       union {
185
 
+               int capability;
186
 
+               int mask;
187
 
+       };
188
 
+       union {
189
 
+               const void *pval;
190
 
+               va_list vaval;
191
 
+       };
192
 
+};
193
 
+
194
 
+/* audit types */
195
 
+#define AA_AUDITTYPE_FILE      1
196
 
+#define AA_AUDITTYPE_DIR       2
197
 
+#define AA_AUDITTYPE_ATTR      3
198
 
+#define AA_AUDITTYPE_XATTR     4
199
 
+#define AA_AUDITTYPE_LINK      5
200
 
+#define AA_AUDITTYPE_CAP       6
201
 
+#define AA_AUDITTYPE_MSG       7
202
 
+#define AA_AUDITTYPE_SYSCALL   8
203
 
+#define AA_AUDITTYPE__END      9
204
 
+
205
 
+/* audit flags */
206
 
+#define AA_AUDITFLAG_AUDITSS_SYSCALL 1 /* log syscall context */
207
 
+#define AA_AUDITFLAG_LOGERR         2 /* log operations that failed due to
208
 
+                                          non permission errors  */
209
 
+
210
 
+#define HINT_UNKNOWN_HAT "unknown_hat"
211
 
+#define HINT_FORK "fork"
212
 
+#define HINT_MANDPROF "missing_mandatory_profile"
213
 
+#define HINT_CHGPROF "changing_profile"
214
 
+
215
 
+#define LOG_HINT(p, gfp, hint, fmt, args...) \
216
 
+       do {\
217
 
+               aa_audit_message(p, gfp, 0, \
218
 
+                       "LOGPROF-HINT " hint " " fmt, ##args);\
219
 
+       } while(0)
220
 
+
221
 
+#define BASE_PROFILE(p) ((p)->parent ? (p)->parent : (p))
222
 
+#define IN_SUBPROFILE(p) ((p)->parent)
223
 
+
224
 
+/* main.c */
225
 
+extern int alloc_null_complain_profile(void);
226
 
+extern void free_null_complain_profile(void);
227
 
+extern int attach_nullprofile(struct aa_profile *profile);
228
 
+extern int aa_audit_message(struct aa_profile *active, gfp_t gfp, int,
229
 
+                           const char *, ...);
230
 
+extern int aa_audit_syscallreject(struct aa_profile *active, gfp_t gfp,
231
 
+                                 const char *);
232
 
+extern int aa_audit(struct aa_profile *active, const struct aa_audit *);
233
 
+extern char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt);
234
 
+
235
 
+extern int aa_attr(struct aa_profile *active, struct dentry *dentry,
236
 
+                  struct vfsmount *mnt, struct iattr *iattr);
237
 
+extern int aa_perm_xattr(struct aa_profile *active, struct dentry *dentry,
238
 
+                        struct vfsmount *mnt, const char *operation,
239
 
+                        const char *xattr_xattr, int mask);
240
 
+extern int aa_capability(struct aa_profile *active, int cap);
241
 
+extern int aa_perm(struct aa_profile *active, struct dentry *dentry,
242
 
+                  struct vfsmount *mnt, int mask);
243
 
+extern int aa_perm_dir(struct aa_profile *active, struct dentry *dentry,
244
 
+                      struct vfsmount *mnt, const char *operation, int mask);
245
 
+extern int aa_link(struct aa_profile *active,
246
 
+                  struct dentry *link, struct vfsmount *link_mnt,
247
 
+                  struct dentry *target, struct vfsmount *target_mnt);
248
 
+extern int aa_fork(struct task_struct *p);
249
 
+extern int aa_register(struct linux_binprm *bprm);
250
 
+extern void aa_release(struct task_struct *p);
251
 
+extern int aa_change_hat(const char *id, u32 hat_magic);
252
 
+extern int aa_associate_filp(struct file *filp);
253
 
+
254
 
+/* list.c */
255
 
+extern struct aa_profile *aa_profilelist_find(const char *name);
256
 
+extern int aa_profilelist_add(struct aa_profile *profile);
257
 
+extern struct aa_profile *aa_profilelist_remove(const char *name);
258
 
+extern void aa_profilelist_release(void);
259
 
+extern struct aa_profile *aa_profilelist_replace(struct aa_profile *profile);
260
 
+extern void aa_profile_dump(struct aa_profile *);
261
 
+extern void aa_profilelist_dump(void);
262
 
+extern void aa_subdomainlist_add(struct subdomain *);
263
 
+extern void aa_subdomainlist_remove(struct subdomain *);
264
 
+extern void aa_subdomainlist_iterate(aa_iter, void *);
265
 
+extern void aa_subdomainlist_iterateremove(aa_iter, void *);
266
 
+extern void aa_subdomainlist_release(void);
267
 
+
268
 
+/* module_interface.c */
269
 
+extern ssize_t aa_file_prof_add(void *, size_t);
270
 
+extern ssize_t aa_file_prof_repl(void *, size_t);
271
 
+extern ssize_t aa_file_prof_remove(const char *, size_t);
272
 
+extern void free_aa_profile(struct aa_profile *profile);
273
 
+extern void free_aa_profile_kref(struct kref *kref);
274
 
+
275
 
+/* procattr.c */
276
 
+extern size_t aa_getprocattr(struct aa_profile *active, char *str, size_t size);
277
 
+extern int aa_setprocattr_changehat(char *hatinfo, size_t infosize);
278
 
+extern int aa_setprocattr_setprofile(struct task_struct *p, char *profilename,
279
 
+                                    size_t profilesize);
280
 
+
281
 
+/* apparmorfs.c */
282
 
+extern int create_apparmorfs(void);
283
 
+extern void destroy_apparmorfs(void);
284
 
+
285
 
+/* capabilities.c */
286
 
+extern const char *capability_to_name(unsigned int cap);
287
 
+
288
 
+/* match.c */
289
 
+struct aa_dfa *aa_match_alloc(void);
290
 
+void aa_match_free(struct aa_dfa *dfa);
291
 
+int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size);
292
 
+int verify_dfa(struct aa_dfa *dfa);
293
 
+const char *aa_match_features(void);
294
 
+unsigned int aa_match(struct aa_dfa *dfa, const char *pathname);
295
 
+
296
 
+#endif                         /* __APPARMOR_H */
297
 
Index: b/security/apparmor/apparmorfs.c
298
 
===================================================================
299
 
--- /dev/null
300
 
+++ b/security/apparmor/apparmorfs.c
301
 
@@ -0,0 +1,431 @@
302
 
+/*
303
 
+ *     Copyright (C) 2005 Novell/SUSE
304
 
+ *
305
 
+ *     This program is free software; you can redistribute it and/or
306
 
+ *     modify it under the terms of the GNU General Public License as
307
 
+ *     published by the Free Software Foundation, version 2 of the
308
 
+ *     License.
309
 
+ *
310
 
+ *     AppArmor filesystem (part of securityfs)
311
 
+ */
312
 
+
313
 
+#include <linux/security.h>
314
 
+#include <linux/vmalloc.h>
315
 
+#include <linux/module.h>
316
 
+#include <linux/seq_file.h>
317
 
+#include <asm/uaccess.h>
318
 
+
319
 
+#include "apparmor.h"
320
 
+#include "inline.h"
321
 
+
322
 
+#define SECFS_AA "apparmor"
323
 
+static struct dentry *aa_fs_dentry = NULL;
324
 
+
325
 
+/* profile */
326
 
+extern struct seq_operations apparmorfs_profiles_op;
327
 
+static int aa_prof_open(struct inode *inode, struct file *file);
328
 
+static int aa_prof_release(struct inode *inode, struct file *file);
329
 
+
330
 
+static struct file_operations apparmorfs_profiles_fops = {
331
 
+       .open =         aa_prof_open,
332
 
+       .read =         seq_read,
333
 
+       .llseek =       seq_lseek,
334
 
+       .release =      aa_prof_release,
335
 
+};
336
 
+
337
 
+/* matching */
338
 
+static ssize_t aa_matching_read(struct file *file, char __user *buf,
339
 
+                              size_t size, loff_t *ppos);
340
 
+
341
 
+static struct file_operations apparmorfs_matching_fops = {
342
 
+       .read =         aa_matching_read,
343
 
+};
344
 
+
345
 
+
346
 
+/* interface */
347
 
+static ssize_t aa_profile_load(struct file *f, const char __user *buf,
348
 
+                              size_t size, loff_t *pos);
349
 
+static ssize_t aa_profile_replace(struct file *f, const char __user *buf,
350
 
+                                 size_t size, loff_t *pos);
351
 
+static ssize_t aa_profile_remove(struct file *f, const char __user *buf,
352
 
+                                size_t size, loff_t *pos);
353
 
+
354
 
+static struct file_operations apparmorfs_profile_load = {
355
 
+       .write = aa_profile_load
356
 
+};
357
 
+
358
 
+static struct file_operations apparmorfs_profile_replace = {
359
 
+       .write = aa_profile_replace
360
 
+};
361
 
+
362
 
+static struct file_operations apparmorfs_profile_remove = {
363
 
+       .write = aa_profile_remove
364
 
+};
365
 
+
366
 
+
367
 
+/* control */
368
 
+static u64 aa_control_get(void *data);
369
 
+static void aa_control_set(void *data, u64 val);
370
 
+
371
 
+DEFINE_SIMPLE_ATTRIBUTE(apparmorfs_control_fops, aa_control_get,
372
 
+                       aa_control_set, "%lld\n");
373
 
+
374
 
+
375
 
+
376
 
+/* table of static entries */
377
 
+
378
 
+static struct root_entry {
379
 
+       const char *name;
380
 
+       int mode;
381
 
+       int access;
382
 
+       struct file_operations *fops;
383
 
+       void *data;
384
 
+
385
 
+       /* internal fields */
386
 
+       struct dentry *dentry;
387
 
+       int parent_index;
388
 
+} root_entries[] = {
389
 
+       /* our root, normally /sys/kernel/security/apparmor */
390
 
+       {SECFS_AA,      S_IFDIR, 0550}, /* DO NOT EDIT/MOVE */
391
 
+
392
 
+       /* interface for obtaining list of profiles currently loaded */
393
 
+       {"profiles",    S_IFREG, 0440, &apparmorfs_profiles_fops,
394
 
+                                      NULL},
395
 
+
396
 
+       /* interface for obtaining matching features supported */
397
 
+       {"matching",    S_IFREG, 0440, &apparmorfs_matching_fops,
398
 
+                                      NULL},
399
 
+
400
 
+       /* interface for loading/removing/replacing profiles */
401
 
+       {".load",       S_IFREG, 0640, &apparmorfs_profile_load,
402
 
+                                      NULL},
403
 
+       {".replace",    S_IFREG, 0640, &apparmorfs_profile_replace,
404
 
+                                      NULL},
405
 
+       {".remove",     S_IFREG, 0640, &apparmorfs_profile_remove,
406
 
+                                      NULL},
407
 
+
408
 
+       /* interface for setting binary config values */
409
 
+       {"control",     S_IFDIR, 0550},
410
 
+       {"complain",    S_IFREG, 0640, &apparmorfs_control_fops,
411
 
+                                      &apparmor_complain},
412
 
+       {"audit",       S_IFREG, 0640, &apparmorfs_control_fops,
413
 
+                                      &apparmor_audit},
414
 
+       {"debug",       S_IFREG, 0640, &apparmorfs_control_fops,
415
 
+                                      &apparmor_debug},
416
 
+       {"logsyscall",  S_IFREG, 0640, &apparmorfs_control_fops,
417
 
+                                      &apparmor_logsyscall},
418
 
+       {NULL,          S_IFDIR, 0},
419
 
+
420
 
+       /* root end */
421
 
+       {NULL,          S_IFDIR, 0}
422
 
+};
423
 
+
424
 
+#define AA_FS_DENTRY root_entries[0].dentry
425
 
+
426
 
+static const unsigned int num_entries =
427
 
+       sizeof(root_entries) / sizeof(struct root_entry);
428
 
+
429
 
+
430
 
+
431
 
+static int aa_prof_open(struct inode *inode, struct file *file)
432
 
+{
433
 
+       return seq_open(file, &apparmorfs_profiles_op);
434
 
+}
435
 
+
436
 
+
437
 
+static int aa_prof_release(struct inode *inode, struct file *file)
438
 
+{
439
 
+       return seq_release(inode, file);
440
 
+}
441
 
+
442
 
+static ssize_t aa_matching_read(struct file *file, char __user *buf,
443
 
+                              size_t size, loff_t *ppos)
444
 
+{
445
 
+       const char *matching = aa_match_features();
446
 
+
447
 
+       return simple_read_from_buffer(buf, size, ppos, matching,
448
 
+                                      strlen(matching));
449
 
+}
450
 
+
451
 
+static char *aa_simple_write_to_buffer(const char __user *userbuf,
452
 
+                                      size_t alloc_size, size_t copy_size,
453
 
+                                      loff_t *pos, const char *msg)
454
 
+{
455
 
+       struct aa_profile *active;
456
 
+       char *data;
457
 
+
458
 
+       if (*pos != 0) {
459
 
+               /* only writes from pos 0, that is complete writes */
460
 
+               data = ERR_PTR(-ESPIPE);
461
 
+               goto out;
462
 
+       }
463
 
+
464
 
+       /* Don't allow confined processes to load/replace/remove profiles.
465
 
+        * No sane person would add rules allowing this to a profile
466
 
+        * but we enforce the restriction anyways.
467
 
+        */
468
 
+       rcu_read_lock();
469
 
+       active = get_activeptr_rcu();
470
 
+       if (active) {
471
 
+               AA_WARN("REJECTING access to profile %s (%s(%d) "
472
 
+                       "profile %s active %s)\n",
473
 
+                       msg, current->comm, current->pid,
474
 
+                       BASE_PROFILE(active)->name, active->name);
475
 
+
476
 
+               data = ERR_PTR(-EPERM);
477
 
+               goto out;
478
 
+       }
479
 
+       rcu_read_unlock();
480
 
+
481
 
+       data = vmalloc(alloc_size);
482
 
+       if (data == NULL) {
483
 
+               data = ERR_PTR(-ENOMEM);
484
 
+               goto out;
485
 
+       }
486
 
+
487
 
+       if (copy_from_user(data, userbuf, copy_size)) {
488
 
+               vfree(data);
489
 
+               data = ERR_PTR(-EFAULT);
490
 
+               goto out;
491
 
+       }
492
 
+
493
 
+out:
494
 
+       return data;
495
 
+}
496
 
+
497
 
+static ssize_t aa_profile_load(struct file *f, const char __user *buf,
498
 
+                              size_t size, loff_t *pos)
499
 
+{
500
 
+       char *data;
501
 
+       ssize_t error;
502
 
+
503
 
+       data = aa_simple_write_to_buffer(buf, size, size, pos, "load");
504
 
+
505
 
+       if (!IS_ERR(data)) {
506
 
+               error = aa_file_prof_add(data, size);
507
 
+               vfree(data);
508
 
+       } else {
509
 
+               error = PTR_ERR(data);
510
 
+       }
511
 
+
512
 
+       return error;
513
 
+}
514
 
+
515
 
+static ssize_t aa_profile_replace(struct file *f, const char __user *buf,
516
 
+                                 size_t size, loff_t *pos)
517
 
+{
518
 
+       char *data;
519
 
+       ssize_t error;
520
 
+
521
 
+       data = aa_simple_write_to_buffer(buf, size, size, pos, "replacement");
522
 
+
523
 
+       if (!IS_ERR(data)) {
524
 
+               error = aa_file_prof_repl(data, size);
525
 
+               vfree(data);
526
 
+       } else {
527
 
+               error = PTR_ERR(data);
528
 
+       }
529
 
+
530
 
+       return error;
531
 
+}
532
 
+
533
 
+static ssize_t aa_profile_remove(struct file *f, const char __user *buf,
534
 
+                                 size_t size, loff_t *pos)
535
 
+{
536
 
+       char *data;
537
 
+       ssize_t error;
538
 
+
539
 
+       /* aa_file_prof_remove needs a null terminated string so 1 extra
540
 
+        * byte is allocated and null the copied data is then null terminated
541
 
+        */
542
 
+       data = aa_simple_write_to_buffer(buf, size+1, size, pos, "removal");
543
 
+
544
 
+       if (!IS_ERR(data)) {
545
 
+               data[size] = 0;
546
 
+               error = aa_file_prof_remove(data, size);
547
 
+               vfree(data);
548
 
+       } else {
549
 
+               error = PTR_ERR(data);
550
 
+       }
551
 
+
552
 
+       return error;
553
 
+}
554
 
+
555
 
+static u64 aa_control_get(void *data)
556
 
+{
557
 
+       return *(int *)data;
558
 
+}
559
 
+
560
 
+static void aa_control_set(void *data, u64 val)
561
 
+{
562
 
+       if (val > 1)
563
 
+               val = 1;
564
 
+
565
 
+       *(int*)data = (int)val;
566
 
+}
567
 
+
568
 
+static void clear_apparmorfs(void)
569
 
+{
570
 
+       unsigned int i;
571
 
+
572
 
+       for (i=0; i < num_entries;i++) {
573
 
+               unsigned int index;
574
 
+
575
 
+               if (root_entries[i].mode == S_IFDIR) {
576
 
+                       if (root_entries[i].name)
577
 
+                               /* defer dir free till all sub-entries freed */
578
 
+                               continue;
579
 
+                       else
580
 
+                               /* cleanup parent */
581
 
+                               index = root_entries[i].parent_index;
582
 
+               } else {
583
 
+                       index = i;
584
 
+               }
585
 
+
586
 
+               if (root_entries[index].dentry) {
587
 
+                       securityfs_remove(root_entries[index].dentry);
588
 
+
589
 
+                       AA_DEBUG("%s: deleted apparmorfs entry name=%s "
590
 
+                                "dentry=%p\n",
591
 
+                               __FUNCTION__,
592
 
+                               root_entries[index].name,
593
 
+                               root_entries[index].dentry);
594
 
+
595
 
+                       root_entries[index].dentry = NULL;
596
 
+                       root_entries[index].parent_index = 0;
597
 
+               }
598
 
+       }
599
 
+}
600
 
+
601
 
+static int populate_apparmorfs(struct dentry *root)
602
 
+{
603
 
+       unsigned int i, parent_index, depth;
604
 
+
605
 
+       for (i = 0; i < num_entries; i++) {
606
 
+               root_entries[i].dentry = NULL;
607
 
+               root_entries[i].parent_index = 0;
608
 
+       }
609
 
+
610
 
+       /* 1. Verify entry 0 is valid [sanity check] */
611
 
+       if (num_entries == 0 ||
612
 
+           !root_entries[0].name ||
613
 
+           strcmp(root_entries[0].name, SECFS_AA) != 0 ||
614
 
+           root_entries[0].mode != S_IFDIR) {
615
 
+               AA_ERROR("%s: root entry 0 is not SECFS_AA/dir\n",
616
 
+                       __FUNCTION__);
617
 
+               goto error;
618
 
+       }
619
 
+
620
 
+       /* 2. Build back pointers */
621
 
+       parent_index = 0;
622
 
+       depth = 1;
623
 
+
624
 
+       for (i = 1; i < num_entries; i++) {
625
 
+               root_entries[i].parent_index = parent_index;
626
 
+
627
 
+               if (root_entries[i].name &&
628
 
+                   root_entries[i].mode == S_IFDIR) {
629
 
+                       depth++;
630
 
+                       parent_index = i;
631
 
+               } else if (!root_entries[i].name) {
632
 
+                       if (root_entries[i].mode != S_IFDIR || depth == 0) {
633
 
+                               AA_ERROR("%s: root_entry %d invalid (%u %d)",
634
 
+                                        __FUNCTION__, i,
635
 
+                                        root_entries[i].mode,
636
 
+                                        root_entries[i].parent_index);
637
 
+                               goto error;
638
 
+                       }
639
 
+
640
 
+                       depth--;
641
 
+                       parent_index = root_entries[parent_index].parent_index;
642
 
+               }
643
 
+       }
644
 
+
645
 
+       if (depth != 0) {
646
 
+               AA_ERROR("%s: root_entry table not correctly terminated\n",
647
 
+                       __FUNCTION__);
648
 
+               goto error;
649
 
+       }
650
 
+
651
 
+       /* 3. Create root (parent=NULL) */
652
 
+       root_entries[0].dentry = securityfs_create_file(
653
 
+                                       root_entries[0].name,
654
 
+                                       root_entries[0].mode |
655
 
+                                               root_entries[0].access,
656
 
+                                       NULL, NULL, NULL);
657
 
+
658
 
+       if (IS_ERR(root_entries[0].dentry))
659
 
+               goto error;
660
 
+       else
661
 
+               AA_DEBUG("%s: created securityfs/apparmor [dentry=%p]\n",
662
 
+                       __FUNCTION__, root_entries[0].dentry);
663
 
+
664
 
+
665
 
+       /* 4. create remaining nodes */
666
 
+       for (i = 1; i < num_entries; i++) {
667
 
+               struct dentry *parent;
668
 
+               void *data = NULL;
669
 
+               struct file_operations *fops = NULL;
670
 
+
671
 
+               /* end of directory ? */
672
 
+               if (!root_entries[i].name)
673
 
+                       continue;
674
 
+
675
 
+               parent = root_entries[root_entries[i].parent_index].dentry;
676
 
+
677
 
+               if (root_entries[i].mode != S_IFDIR) {
678
 
+                       data = root_entries[i].data;
679
 
+                       fops = root_entries[i].fops;
680
 
+               }
681
 
+
682
 
+               root_entries[i].dentry = securityfs_create_file(
683
 
+                                               root_entries[i].name,
684
 
+                                               root_entries[i].mode |
685
 
+                                                       root_entries[i].access,
686
 
+                                               parent,
687
 
+                                               data,
688
 
+                                               fops);
689
 
+
690
 
+               if (IS_ERR(root_entries[i].dentry))
691
 
+                       goto cleanup_error;
692
 
+
693
 
+               AA_DEBUG("%s: added apparmorfs entry "
694
 
+                        "name=%s mode=%x dentry=%p [parent %p]\n",
695
 
+                       __FUNCTION__, root_entries[i].name,
696
 
+                       root_entries[i].mode|root_entries[i].access,
697
 
+                       root_entries[i].dentry, parent);
698
 
+       }
699
 
+
700
 
+       return 0;
701
 
+
702
 
+cleanup_error:
703
 
+       clear_apparmorfs();
704
 
+
705
 
+error:
706
 
+       return -EINVAL;
707
 
+}
708
 
+
709
 
+int create_apparmorfs(void)
710
 
+{
711
 
+       int error = 0;
712
 
+
713
 
+       if (AA_FS_DENTRY) {
714
 
+               error = -EEXIST;
715
 
+               AA_ERROR("%s: AppArmor securityfs already exists\n",
716
 
+                       __FUNCTION__);
717
 
+       } else {
718
 
+               error = populate_apparmorfs(aa_fs_dentry);
719
 
+               if (error != 0) {
720
 
+                       AA_ERROR("%s: Error populating AppArmor securityfs\n",
721
 
+                               __FUNCTION__);
722
 
+               }
723
 
+       }
724
 
+
725
 
+       return error;
726
 
+}
727
 
+
728
 
+void destroy_apparmorfs(void)
729
 
+{
730
 
+       if (AA_FS_DENTRY)
731
 
+               clear_apparmorfs();
732
 
+}
733
 
Index: b/security/apparmor/capabilities.c
734
 
===================================================================
735
 
--- /dev/null
736
 
+++ b/security/apparmor/capabilities.c
737
 
@@ -0,0 +1,54 @@
738
 
+/*
739
 
+ *     Copyright (C) 2005 Novell/SUSE
740
 
+ *
741
 
+ *     This program is free software; you can redistribute it and/or
742
 
+ *     modify it under the terms of the GNU General Public License as
743
 
+ *     published by the Free Software Foundation, version 2 of the
744
 
+ *     License.
745
 
+ *
746
 
+ *     AppArmor capability definitions
747
 
+ */
748
 
+
749
 
+#include "apparmor.h"
750
 
+
751
 
+static const char *cap_names[] = {
752
 
+       "chown",
753
 
+       "dac_override",
754
 
+       "dac_read_search",
755
 
+       "fowner",
756
 
+       "fsetid",
757
 
+       "kill",
758
 
+       "setgid",
759
 
+       "setuid",
760
 
+       "setpcap",
761
 
+       "linux_immutable",
762
 
+       "net_bind_service",
763
 
+       "net_broadcast",
764
 
+       "net_admin",
765
 
+       "net_raw",
766
 
+       "ipc_lock",
767
 
+       "ipc_owner",
768
 
+       "sys_module",
769
 
+       "sys_rawio",
770
 
+       "sys_chroot",
771
 
+       "sys_ptrace",
772
 
+       "sys_pacct",
773
 
+       "sys_admin",
774
 
+       "sys_boot",
775
 
+       "sys_nice",
776
 
+       "sys_resource",
777
 
+       "sys_time",
778
 
+       "sys_tty_config",
779
 
+       "mknod",
780
 
+       "lease"
781
 
+};
782
 
+
783
 
+const char *capability_to_name(unsigned int cap)
784
 
+{
785
 
+       const char *name;
786
 
+
787
 
+       name = (cap < (sizeof(cap_names) / sizeof(char *))
788
 
+                  ? cap_names[cap] : "invalid-capability");
789
 
+
790
 
+       return name;
791
 
+}
792
 
Index: b/security/apparmor/inline.h
793
 
===================================================================
794
 
--- /dev/null
795
 
+++ b/security/apparmor/inline.h
796
 
@@ -0,0 +1,249 @@
797
 
+/*
798
 
+ *     Copyright (C) 2005 Novell/SUSE
799
 
+ *
800
 
+ *     This program is free software; you can redistribute it and/or
801
 
+ *     modify it under the terms of the GNU General Public License as
802
 
+ *     published by the Free Software Foundation, version 2 of the
803
 
+ *     License.
804
 
+ */
805
 
+
806
 
+#ifndef __INLINE_H
807
 
+#define __INLINE_H
808
 
+
809
 
+#include <linux/sched.h>
810
 
+
811
 
+static inline int __aa_is_confined(struct subdomain *sd)
812
 
+{
813
 
+       return (sd && sd->active);
814
 
+}
815
 
+
816
 
+/**
817
 
+ *  aa_is_confined
818
 
+ *  Determine whether current task contains a valid profile (confined).
819
 
+ *  Return %1 if confined, %0 otherwise.
820
 
+ */
821
 
+static inline int aa_is_confined(void)
822
 
+{
823
 
+       struct subdomain *sd = AA_SUBDOMAIN(current->security);
824
 
+       return __aa_is_confined(sd);
825
 
+}
826
 
+
827
 
+static inline int __aa_sub_defined(struct subdomain *sd)
828
 
+{
829
 
+    return __aa_is_confined(sd) && !list_empty(&BASE_PROFILE(sd->active)->sub);
830
 
+}
831
 
+
832
 
+/**
833
 
+ * aa_sub_defined - check to see if current task has any subprofiles
834
 
+ * Return 1 if true, 0 otherwise
835
 
+ */
836
 
+static inline int aa_sub_defined(void)
837
 
+{
838
 
+       struct subdomain *sd = AA_SUBDOMAIN(current->security);
839
 
+       return __aa_sub_defined(sd);
840
 
+}
841
 
+
842
 
+/**
843
 
+ * get_aa_profile - increment refcount on profile @p
844
 
+ * @p: profile
845
 
+ */
846
 
+static inline struct aa_profile *get_aa_profile(struct aa_profile *p)
847
 
+{
848
 
+       if (p)
849
 
+               kref_get(&(BASE_PROFILE(p)->count));
850
 
+
851
 
+       return p;
852
 
+}
853
 
+
854
 
+/**
855
 
+ * put_aa_profile - decrement refcount on profile @p
856
 
+ * @p: profile
857
 
+ */
858
 
+static inline void put_aa_profile(struct aa_profile *p)
859
 
+{
860
 
+       if (p)
861
 
+               kref_put(&BASE_PROFILE(p)->count, free_aa_profile_kref);
862
 
+}
863
 
+
864
 
+/**
865
 
+ * get_task_activeptr_rcu - get pointer to @tsk's active profile.
866
 
+ * @tsk: task to get active profile from
867
 
+ *
868
 
+ * Requires rcu_read_lock is held
869
 
+ */
870
 
+static inline struct aa_profile *get_task_activeptr_rcu(struct task_struct *tsk)
871
 
+{
872
 
+       struct subdomain *sd = AA_SUBDOMAIN(tsk->security);
873
 
+       struct aa_profile *active = NULL;
874
 
+
875
 
+       if (sd)
876
 
+               active = (struct aa_profile *) rcu_dereference(sd->active);
877
 
+
878
 
+       return active;
879
 
+}
880
 
+
881
 
+/**
882
 
+ * get_activeptr_rcu - get pointer to current task's active profile
883
 
+ * Requires rcu_read_lock is held
884
 
+ */
885
 
+static inline struct aa_profile *get_activeptr_rcu(void)
886
 
+{
887
 
+       return get_task_activeptr_rcu(current);
888
 
+}
889
 
+
890
 
+/**
891
 
+ * get_task_active_aa_profile - get a reference to tsk's active profile.
892
 
+ * @tsk: the task to get the active profile reference for
893
 
+ */
894
 
+static inline struct aa_profile *get_task_active_aa_profile(struct task_struct *tsk)
895
 
+{
896
 
+       struct aa_profile *active;
897
 
+
898
 
+       rcu_read_lock();
899
 
+       active = get_aa_profile(get_task_activeptr_rcu(tsk));
900
 
+       rcu_read_unlock();
901
 
+
902
 
+       return active;
903
 
+}
904
 
+
905
 
+/**
906
 
+ * get_active_aa_profile - get a reference to the current tasks active profile
907
 
+ */
908
 
+static inline struct aa_profile *get_active_aa_profile(void)
909
 
+{
910
 
+       return get_task_active_aa_profile(current);
911
 
+}
912
 
+
913
 
+/**
914
 
+ * aa_switch - change subdomain to use a new profile
915
 
+ * @sd: subdomain to switch the active profile on
916
 
+ * @newactive: new active profile
917
 
+ *
918
 
+ * aa_switch handles the changing of a subdomain's active profile.  The
919
 
+ * sd_lock must be held to ensure consistency against other writers.
920
 
+ * Some write paths (ex. aa_register) require sd->active not to change
921
 
+ * over several operations, so the calling function is responsible
922
 
+ * for grabing the sd_lock to meet its consistency constraints before
923
 
+ * calling aa_switch
924
 
+ */
925
 
+static inline void aa_switch(struct subdomain *sd, struct aa_profile *newactive)
926
 
+{
927
 
+       struct aa_profile *oldactive = sd->active;
928
 
+
929
 
+       /* noop if NULL */
930
 
+       rcu_assign_pointer(sd->active, get_aa_profile(newactive));
931
 
+       put_aa_profile(oldactive);
932
 
+}
933
 
+
934
 
+/**
935
 
+ * aa_switch_unconfined - change subdomain to be unconfined (no profile)
936
 
+ * @sd: subdomain to switch
937
 
+ *
938
 
+ * aa_switch_unconfined handles the removal of a subdomain's active profile.
939
 
+ * The sd_lock must be held to ensure consistency against other writers.
940
 
+ * Like aa_switch the sd_lock is used to maintain consistency.
941
 
+ */
942
 
+static inline void aa_switch_unconfined(struct subdomain *sd)
943
 
+{
944
 
+       aa_switch(sd, NULL);
945
 
+
946
 
+       /* reset magic in case we were in a subhat before */
947
 
+       sd->hat_magic = 0;
948
 
+}
949
 
+
950
 
+/**
951
 
+ * alloc_subdomain - allocate a new subdomain
952
 
+ * @tsk: task struct
953
 
+ *
954
 
+ * Allocate a new subdomain including a backpointer to it's referring task.
955
 
+ */
956
 
+static inline struct subdomain *alloc_subdomain(struct task_struct *tsk)
957
 
+{
958
 
+       struct subdomain *sd;
959
 
+
960
 
+       sd = kzalloc(sizeof(struct subdomain), GFP_KERNEL);
961
 
+       if (!sd)
962
 
+               goto out;
963
 
+
964
 
+       /* back pointer to task */
965
 
+       sd->task = tsk;
966
 
+
967
 
+       /* any readers of the list must make sure that they can handle
968
 
+        * case where sd->active is not yet set (null)
969
 
+        */
970
 
+       aa_subdomainlist_add(sd);
971
 
+
972
 
+out:
973
 
+       return sd;
974
 
+}
975
 
+
976
 
+/**
977
 
+ * free_subdomain - Free a subdomain previously allocated by alloc_subdomain
978
 
+ * @sd: subdomain
979
 
+ */
980
 
+static inline void free_subdomain(struct subdomain *sd)
981
 
+{
982
 
+       aa_subdomainlist_remove(sd);
983
 
+       kfree(sd);
984
 
+}
985
 
+
986
 
+/**
987
 
+ * alloc_aa_profile - Allocate, initialize and return a new zeroed profile.
988
 
+ * Returns NULL on failure.
989
 
+ */
990
 
+static inline struct aa_profile *alloc_aa_profile(void)
991
 
+{
992
 
+       struct aa_profile *profile;
993
 
+
994
 
+       profile = (struct aa_profile *)kzalloc(sizeof(struct aa_profile),
995
 
+                                             GFP_KERNEL);
996
 
+       AA_DEBUG("%s(%p)\n", __FUNCTION__, profile);
997
 
+       if (profile) {
998
 
+               INIT_LIST_HEAD(&profile->list);
999
 
+               INIT_LIST_HEAD(&profile->sub);
1000
 
+               INIT_RCU_HEAD(&profile->rcu);
1001
 
+               kref_init(&profile->count);
1002
 
+       }
1003
 
+       return profile;
1004
 
+}
1005
 
+
1006
 
+/**
1007
 
+ * aa_put_name
1008
 
+ * @name: name to release.
1009
 
+ *
1010
 
+ * Release space (free_page) allocated to hold pathname
1011
 
+ * name may be NULL (checked for by free_page)
1012
 
+ */
1013
 
+static inline void aa_put_name(const char *name)
1014
 
+{
1015
 
+       free_page((unsigned long)name);
1016
 
+}
1017
 
+
1018
 
+/** __aa_find_profile
1019
 
+ * @name: name of profile to find
1020
 
+ * @head: list to search
1021
 
+ *
1022
 
+ * Return reference counted copy of profile. NULL if not found
1023
 
+ * Caller must hold any necessary locks
1024
 
+ */
1025
 
+static inline struct aa_profile *__aa_find_profile(const char *name,
1026
 
+                                                 struct list_head *head)
1027
 
+{
1028
 
+       struct aa_profile *p;
1029
 
+
1030
 
+       if (!name || !head)
1031
 
+               return NULL;
1032
 
+
1033
 
+       AA_DEBUG("%s: finding profile %s\n", __FUNCTION__, name);
1034
 
+       list_for_each_entry(p, head, list) {
1035
 
+               if (!strcmp(p->name, name)) {
1036
 
+                       /* return refcounted object */
1037
 
+                       p = get_aa_profile(p);
1038
 
+                       return p;
1039
 
+               } else {
1040
 
+                       AA_DEBUG("%s: skipping %s\n", __FUNCTION__, p->name);
1041
 
+               }
1042
 
+       }
1043
 
+       return NULL;
1044
 
+}
1045
 
+#endif /* __INLINE_H__ */
1046
 
Index: b/security/apparmor/list.c
1047
 
===================================================================
1048
 
--- /dev/null
1049
 
+++ b/security/apparmor/list.c
1050
 
@@ -0,0 +1,268 @@
1051
 
+/*
1052
 
+ *     Copyright (C) 1998-2005 Novell/SUSE
1053
 
+ *
1054
 
+ *     This program is free software; you can redistribute it and/or
1055
 
+ *     modify it under the terms of the GNU General Public License as
1056
 
+ *     published by the Free Software Foundation, version 2 of the
1057
 
+ *     License.
1058
 
+ *
1059
 
+ *     AppArmor Profile List Management
1060
 
+ */
1061
 
+
1062
 
+#include <linux/seq_file.h>
1063
 
+#include "apparmor.h"
1064
 
+#include "inline.h"
1065
 
+
1066
 
+/* list of all profiles and lock */
1067
 
+static LIST_HEAD(profile_list);
1068
 
+static rwlock_t profile_lock = RW_LOCK_UNLOCKED;
1069
 
+
1070
 
+/* list of all subdomains and lock */
1071
 
+static LIST_HEAD(subdomain_list);
1072
 
+static rwlock_t subdomain_lock = RW_LOCK_UNLOCKED;
1073
 
+
1074
 
+/**
1075
 
+ * aa_profilelist_find
1076
 
+ * @name: profile name (program name)
1077
 
+ *
1078
 
+ * Search the profile list for profile @name.  Return refcounted profile on
1079
 
+ * success, NULL on failure.
1080
 
+ */
1081
 
+struct aa_profile *aa_profilelist_find(const char *name)
1082
 
+{
1083
 
+       struct aa_profile *p = NULL;
1084
 
+       if (name) {
1085
 
+               read_lock(&profile_lock);
1086
 
+               p = __aa_find_profile(name, &profile_list);
1087
 
+               read_unlock(&profile_lock);
1088
 
+       }
1089
 
+       return p;
1090
 
+}
1091
 
+
1092
 
+/**
1093
 
+ * aa_profilelist_add - add new profile to list
1094
 
+ * @profile: new profile to add to list
1095
 
+ *
1096
 
+ * NOTE: Caller must allocate necessary reference count that will be used
1097
 
+ * by the profile_list.  This is because profile allocation alloc_aa_profile()
1098
 
+ * returns an unreferenced object with a initial count of %1.
1099
 
+ *
1100
 
+ * Return %1 on success, %0 on failure (already exists)
1101
 
+ */
1102
 
+int aa_profilelist_add(struct aa_profile *profile)
1103
 
+{
1104
 
+       struct aa_profile *old_profile;
1105
 
+       int ret = 0;
1106
 
+
1107
 
+       if (!profile)
1108
 
+               goto out;
1109
 
+
1110
 
+       write_lock(&profile_lock);
1111
 
+       old_profile = __aa_find_profile(profile->name, &profile_list);
1112
 
+       if (old_profile) {
1113
 
+               put_aa_profile(old_profile);
1114
 
+               goto out;
1115
 
+       }
1116
 
+
1117
 
+       list_add(&profile->list, &profile_list);
1118
 
+       ret = 1;
1119
 
+ out:
1120
 
+       write_unlock(&profile_lock);
1121
 
+       return ret;
1122
 
+}
1123
 
+
1124
 
+/**
1125
 
+ * aa_profilelist_remove - remove a profile from the list by name
1126
 
+ * @name: name of profile to be removed
1127
 
+ *
1128
 
+ * If the profile exists remove profile from list and return its reference.
1129
 
+ * The reference count on profile is not decremented and should be decremented
1130
 
+ * when the profile is no longer needed
1131
 
+ */
1132
 
+struct aa_profile *aa_profilelist_remove(const char *name)
1133
 
+{
1134
 
+       struct aa_profile *profile = NULL;
1135
 
+       struct aa_profile *p, *tmp;
1136
 
+
1137
 
+       if (!name)
1138
 
+               goto out;
1139
 
+
1140
 
+       write_lock(&profile_lock);
1141
 
+       list_for_each_entry_safe(p, tmp, &profile_list, list) {
1142
 
+               if (!strcmp(p->name, name)) {
1143
 
+                       list_del_init(&p->list);
1144
 
+                       /* mark old profile as stale */
1145
 
+                       p->isstale = 1;
1146
 
+                       profile = p;
1147
 
+                       break;
1148
 
+               }
1149
 
+       }
1150
 
+       write_unlock(&profile_lock);
1151
 
+
1152
 
+out:
1153
 
+       return profile;
1154
 
+}
1155
 
+
1156
 
+/**
1157
 
+ * aa_profilelist_replace - replace a profile on the list
1158
 
+ * @profile: new profile
1159
 
+ *
1160
 
+ * Replace a profile on the profile list.  Find the old profile by name in
1161
 
+ * the list, and replace it with the new profile.   NOTE: Caller must allocate
1162
 
+ * necessary initial reference count for new profile as aa_profilelist_add().
1163
 
+ *
1164
 
+ * This is an atomic list operation.  Returns the old profile (which is still
1165
 
+ * refcounted) if there was one, or NULL.
1166
 
+ */
1167
 
+struct aa_profile *aa_profilelist_replace(struct aa_profile *profile)
1168
 
+{
1169
 
+       struct aa_profile *oldprofile;
1170
 
+
1171
 
+       write_lock(&profile_lock);
1172
 
+       oldprofile = __aa_find_profile(profile->name, &profile_list);
1173
 
+       if (oldprofile) {
1174
 
+               list_del_init(&oldprofile->list);
1175
 
+               /* mark old profile as stale */
1176
 
+               oldprofile->isstale = 1;
1177
 
+
1178
 
+               /* __aa_find_profile incremented count, so adjust down */
1179
 
+               put_aa_profile(oldprofile);
1180
 
+       }
1181
 
+
1182
 
+       list_add(&profile->list, &profile_list);
1183
 
+       write_unlock(&profile_lock);
1184
 
+
1185
 
+       return oldprofile;
1186
 
+}
1187
 
+
1188
 
+/**
1189
 
+ * aa_profilelist_release - Remove all profiles from profile_list
1190
 
+ */
1191
 
+void aa_profilelist_release(void)
1192
 
+{
1193
 
+       struct aa_profile *p, *tmp;
1194
 
+
1195
 
+       write_lock(&profile_lock);
1196
 
+       list_for_each_entry_safe(p, tmp, &profile_list, list) {
1197
 
+               list_del_init(&p->list);
1198
 
+               put_aa_profile(p);
1199
 
+       }
1200
 
+       write_unlock(&profile_lock);
1201
 
+}
1202
 
+
1203
 
+/**
1204
 
+ * aa_subdomainlist_add - Add subdomain to subdomain_list
1205
 
+ * @sd: new subdomain
1206
 
+ */
1207
 
+void aa_subdomainlist_add(struct subdomain *sd)
1208
 
+{
1209
 
+       unsigned long flags;
1210
 
+
1211
 
+       if (!sd) {
1212
 
+               AA_INFO("%s: bad subdomain\n", __FUNCTION__);
1213
 
+               return;
1214
 
+       }
1215
 
+
1216
 
+       write_lock_irqsave(&subdomain_lock, flags);
1217
 
+       /* new subdomains must be added to the end of the list due to a
1218
 
+        * subtle interaction between fork and profile replacement.
1219
 
+        */
1220
 
+       list_add_tail(&sd->list, &subdomain_list);
1221
 
+       write_unlock_irqrestore(&subdomain_lock, flags);
1222
 
+}
1223
 
+
1224
 
+/**
1225
 
+ * aa_subdomainlist_remove - Remove subdomain from subdomain_list
1226
 
+ * @sd: subdomain to be removed
1227
 
+ */
1228
 
+void aa_subdomainlist_remove(struct subdomain *sd)
1229
 
+{
1230
 
+       unsigned long flags;
1231
 
+
1232
 
+       if (sd) {
1233
 
+               write_lock_irqsave(&subdomain_lock, flags);
1234
 
+               list_del_init(&sd->list);
1235
 
+               write_unlock_irqrestore(&subdomain_lock, flags);
1236
 
+       }
1237
 
+}
1238
 
+
1239
 
+/**
1240
 
+ * aa_subdomainlist_iterate - iterate over the subdomain list applying @func
1241
 
+ * @func: method to be called for each element
1242
 
+ * @cookie: user passed data
1243
 
+ *
1244
 
+ * Iterate over subdomain list applying @func, stop when @func returns
1245
 
+ * non zero
1246
 
+ */
1247
 
+void aa_subdomainlist_iterate(aa_iter func, void *cookie)
1248
 
+{
1249
 
+       struct subdomain *node;
1250
 
+       int ret = 0;
1251
 
+       unsigned long flags;
1252
 
+
1253
 
+       read_lock_irqsave(&subdomain_lock, flags);
1254
 
+       list_for_each_entry(node, &subdomain_list, list) {
1255
 
+               ret = (*func) (node, cookie);
1256
 
+               if (ret != 0)
1257
 
+                       break;
1258
 
+       }
1259
 
+       read_unlock_irqrestore(&subdomain_lock, flags);
1260
 
+}
1261
 
+
1262
 
+/**
1263
 
+ * aa_subdomainlist_release - Remove all subdomains from subdomain_list
1264
 
+ */
1265
 
+void aa_subdomainlist_release(void)
1266
 
+{
1267
 
+       struct subdomain *node, *tmp;
1268
 
+       unsigned long flags;
1269
 
+
1270
 
+       write_lock_irqsave(&subdomain_lock, flags);
1271
 
+       list_for_each_entry_safe(node, tmp, &subdomain_list, list) {
1272
 
+               list_del_init(&node->list);
1273
 
+       }
1274
 
+       write_unlock_irqrestore(&subdomain_lock, flags);
1275
 
+}
1276
 
+
1277
 
+/* seq_file helper routines
1278
 
+ * Used by apparmorfs.c to iterate over profile_list
1279
 
+ */
1280
 
+static void *p_start(struct seq_file *f, loff_t *pos)
1281
 
+{
1282
 
+       struct aa_profile *node;
1283
 
+       loff_t l = *pos;
1284
 
+
1285
 
+       read_lock(&profile_lock);
1286
 
+       list_for_each_entry(node, &profile_list, list)
1287
 
+               if (!l--)
1288
 
+                       return node;
1289
 
+       return NULL;
1290
 
+}
1291
 
+
1292
 
+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
1293
 
+{
1294
 
+       struct list_head *lh = ((struct aa_profile *)p)->list.next;
1295
 
+       (*pos)++;
1296
 
+       return lh == &profile_list ?
1297
 
+                       NULL : list_entry(lh, struct aa_profile, list);
1298
 
+}
1299
 
+
1300
 
+static void p_stop(struct seq_file *f, void *v)
1301
 
+{
1302
 
+       read_unlock(&profile_lock);
1303
 
+}
1304
 
+
1305
 
+static int seq_show_profile(struct seq_file *f, void *v)
1306
 
+{
1307
 
+       struct aa_profile *profile = (struct aa_profile *)v;
1308
 
+       seq_printf(f, "%s (%s)\n", profile->name,
1309
 
+                  PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
1310
 
+       return 0;
1311
 
+}
1312
 
+
1313
 
+struct seq_operations apparmorfs_profiles_op = {
1314
 
+       .start =        p_start,
1315
 
+       .next =         p_next,
1316
 
+       .stop =         p_stop,
1317
 
+       .show =         seq_show_profile,
1318
 
+};
1319
 
Index: b/security/apparmor/lsm.c
1320
 
===================================================================
1321
 
--- /dev/null
1322
 
+++ b/security/apparmor/lsm.c
1323
 
@@ -0,0 +1,919 @@
1324
 
+/*
1325
 
+ *     Copyright (C) 2002-2005 Novell/SUSE
1326
 
+ *
1327
 
+ *     This program is free software; you can redistribute it and/or
1328
 
+ *     modify it under the terms of the GNU General Public License as
1329
 
+ *     published by the Free Software Foundation, version 2 of the
1330
 
+ *     License.
1331
 
+ *
1332
 
+ *     http://forge.novell.com/modules/xfmod/project/?apparmor
1333
 
+ *
1334
 
+ *     Immunix AppArmor LSM interface
1335
 
+ */
1336
 
+
1337
 
+#include <linux/security.h>
1338
 
+#include <linux/module.h>
1339
 
+#include <linux/mm.h>
1340
 
+#include <linux/mman.h>
1341
 
+#include <linux/mount.h>
1342
 
+#include <linux/namei.h>
1343
 
+
1344
 
+#include "apparmor.h"
1345
 
+#include "inline.h"
1346
 
+
1347
 
+/* struct subdomain write update lock (read side is RCU). */
1348
 
+spinlock_t sd_lock = SPIN_LOCK_UNLOCKED;
1349
 
+
1350
 
+/* Flag values, also controllable via apparmorfs/control.
1351
 
+ * We explicitly do not allow these to be modifiable when exported via
1352
 
+ * /sys/modules/parameters, as we want to do additional mediation and
1353
 
+ * don't want to add special path code. */
1354
 
+
1355
 
+/* Complain mode -- in complain mode access failures result in auditing only
1356
 
+ * and task is allowed access.  audit events are processed by userspace to
1357
 
+ * generate policy.  Default is 'enforce' (0).
1358
 
+ * Value is also togglable per profile and referenced when global value is
1359
 
+ * enforce.
1360
 
+ */
1361
 
+int apparmor_complain = 0;
1362
 
+module_param_named(complain, apparmor_complain, int, S_IRUSR);
1363
 
+MODULE_PARM_DESC(apparmor_complain, "Toggle AppArmor complain mode");
1364
 
+
1365
 
+/* Debug mode */
1366
 
+int apparmor_debug = 0;
1367
 
+module_param_named(debug, apparmor_debug, int, S_IRUSR);
1368
 
+MODULE_PARM_DESC(apparmor_debug, "Toggle AppArmor debug mode");
1369
 
+
1370
 
+/* Audit mode */
1371
 
+int apparmor_audit = 0;
1372
 
+module_param_named(audit, apparmor_audit, int, S_IRUSR);
1373
 
+MODULE_PARM_DESC(apparmor_audit, "Toggle AppArmor audit mode");
1374
 
+
1375
 
+/* Syscall logging mode */
1376
 
+int apparmor_logsyscall = 0;
1377
 
+module_param_named(logsyscall, apparmor_logsyscall, int, S_IRUSR);
1378
 
+MODULE_PARM_DESC(apparmor_logsyscall, "Toggle AppArmor logsyscall mode");
1379
 
+
1380
 
+#ifndef MODULE
1381
 
+static int __init aa_getopt_complain(char *str)
1382
 
+{
1383
 
+       get_option(&str, &apparmor_complain);
1384
 
+       return 1;
1385
 
+}
1386
 
+__setup("apparmor_complain=", aa_getopt_complain);
1387
 
+
1388
 
+static int __init aa_getopt_debug(char *str)
1389
 
+{
1390
 
+       get_option(&str, &apparmor_debug);
1391
 
+       return 1;
1392
 
+}
1393
 
+__setup("apparmor_debug=", aa_getopt_debug);
1394
 
+
1395
 
+static int __init aa_getopt_audit(char *str)
1396
 
+{
1397
 
+       get_option(&str, &apparmor_audit);
1398
 
+       return 1;
1399
 
+}
1400
 
+__setup("apparmor_audit=", aa_getopt_audit);
1401
 
+
1402
 
+static int __init aa_getopt_logsyscall(char *str)
1403
 
+{
1404
 
+       get_option(&str, &apparmor_logsyscall);
1405
 
+       return 1;
1406
 
+}
1407
 
+__setup("apparmor_logsyscall=", aa_getopt_logsyscall);
1408
 
+#endif
1409
 
+
1410
 
+static int apparmor_ptrace(struct task_struct *parent,
1411
 
+                           struct task_struct *child)
1412
 
+{
1413
 
+       int error;
1414
 
+       struct aa_profile *active;
1415
 
+
1416
 
+       error = cap_ptrace(parent, child);
1417
 
+
1418
 
+       active = get_task_active_aa_profile(parent);
1419
 
+
1420
 
+       if (!error && active)
1421
 
+               error = aa_audit_syscallreject(active, GFP_KERNEL, "ptrace");
1422
 
+
1423
 
+       put_aa_profile(active);
1424
 
+
1425
 
+       return error;
1426
 
+}
1427
 
+
1428
 
+static int apparmor_capget(struct task_struct *target,
1429
 
+                           kernel_cap_t *effective,
1430
 
+                           kernel_cap_t *inheritable,
1431
 
+                           kernel_cap_t *permitted)
1432
 
+{
1433
 
+       return cap_capget(target, effective, inheritable, permitted);
1434
 
+}
1435
 
+
1436
 
+static int apparmor_capset_check(struct task_struct *target,
1437
 
+                                 kernel_cap_t *effective,
1438
 
+                                 kernel_cap_t *inheritable,
1439
 
+                                 kernel_cap_t *permitted)
1440
 
+{
1441
 
+       return cap_capset_check(target, effective, inheritable, permitted);
1442
 
+}
1443
 
+
1444
 
+static void apparmor_capset_set(struct task_struct *target,
1445
 
+                                kernel_cap_t *effective,
1446
 
+                                kernel_cap_t *inheritable,
1447
 
+                                kernel_cap_t *permitted)
1448
 
+{
1449
 
+       cap_capset_set(target, effective, inheritable, permitted);
1450
 
+}
1451
 
+
1452
 
+static int apparmor_capable(struct task_struct *tsk, int cap)
1453
 
+{
1454
 
+       int error;
1455
 
+
1456
 
+       /* cap_capable returns 0 on success, else -EPERM */
1457
 
+       error = cap_capable(tsk, cap);
1458
 
+
1459
 
+       if (!error) {
1460
 
+               struct aa_profile *active;
1461
 
+
1462
 
+               active = get_task_active_aa_profile(tsk);
1463
 
+
1464
 
+               if (active)
1465
 
+                       error = aa_capability(active, cap);
1466
 
+
1467
 
+               put_aa_profile(active);
1468
 
+       }
1469
 
+
1470
 
+       return error;
1471
 
+}
1472
 
+
1473
 
+static int apparmor_sysctl(struct ctl_table *table, int op)
1474
 
+{
1475
 
+       int error = 0;
1476
 
+       struct aa_profile *active;
1477
 
+
1478
 
+       active = get_active_aa_profile();
1479
 
+
1480
 
+       if ((op & 002) && active && !capable(CAP_SYS_ADMIN))
1481
 
+               error = aa_audit_syscallreject(active, GFP_KERNEL,
1482
 
+                                              "sysctl (write)");
1483
 
+
1484
 
+       put_aa_profile(active);
1485
 
+
1486
 
+       return error;
1487
 
+}
1488
 
+
1489
 
+static int apparmor_syslog(int type)
1490
 
+{
1491
 
+       return cap_syslog(type);
1492
 
+}
1493
 
+
1494
 
+static int apparmor_netlink_send(struct sock *sk, struct sk_buff *skb)
1495
 
+{
1496
 
+       return cap_netlink_send(sk, skb);
1497
 
+}
1498
 
+
1499
 
+static int apparmor_netlink_recv(struct sk_buff *skb, int cap)
1500
 
+{
1501
 
+       return cap_netlink_recv(skb, cap);
1502
 
+}
1503
 
+
1504
 
+static void apparmor_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
1505
 
+{
1506
 
+       cap_bprm_apply_creds(bprm, unsafe);
1507
 
+}
1508
 
+
1509
 
+static int apparmor_bprm_set_security(struct linux_binprm *bprm)
1510
 
+{
1511
 
+       /* handle capability bits with setuid, etc */
1512
 
+       cap_bprm_set_security(bprm);
1513
 
+       /* already set based on script name */
1514
 
+       if (bprm->sh_bang)
1515
 
+               return 0;
1516
 
+       return aa_register(bprm);
1517
 
+}
1518
 
+
1519
 
+static int apparmor_bprm_secureexec(struct linux_binprm *bprm)
1520
 
+{
1521
 
+       int ret = cap_bprm_secureexec(bprm);
1522
 
+
1523
 
+       if (!ret && (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) {
1524
 
+               AA_DEBUG("%s: secureexec required for %s\n",
1525
 
+                        __FUNCTION__, bprm->filename);
1526
 
+               ret = 1;
1527
 
+       }
1528
 
+
1529
 
+       return ret;
1530
 
+}
1531
 
+
1532
 
+static int apparmor_sb_mount(char *dev_name, struct nameidata *nd, char *type,
1533
 
+                             unsigned long flags, void *data)
1534
 
+{
1535
 
+       int error = 0;
1536
 
+       struct aa_profile *active;
1537
 
+
1538
 
+       active = get_active_aa_profile();
1539
 
+
1540
 
+       if (active)
1541
 
+               error = aa_audit_syscallreject(active, GFP_KERNEL, "mount");
1542
 
+
1543
 
+       put_aa_profile(active);
1544
 
+
1545
 
+       return error;
1546
 
+}
1547
 
+
1548
 
+static int apparmor_umount(struct vfsmount *mnt, int flags)
1549
 
+{
1550
 
+       int error = 0;
1551
 
+       struct aa_profile *active;
1552
 
+
1553
 
+       active = get_active_aa_profile();
1554
 
+
1555
 
+       if (active)
1556
 
+               error = aa_audit_syscallreject(active, GFP_ATOMIC, "umount");
1557
 
+
1558
 
+       put_aa_profile(active);
1559
 
+
1560
 
+       return error;
1561
 
+}
1562
 
+
1563
 
+static int apparmor_inode_mkdir(struct inode *dir, struct dentry *dentry,
1564
 
+                               struct vfsmount *mnt, int mask)
1565
 
+{
1566
 
+       struct aa_profile *active;
1567
 
+       int error = 0;
1568
 
+
1569
 
+       if (!mnt || !mediated_filesystem(dir))
1570
 
+               goto out;
1571
 
+
1572
 
+       active = get_active_aa_profile();
1573
 
+
1574
 
+       if (active)
1575
 
+               error = aa_perm_dir(active, dentry, mnt, "mkdir", AA_MAY_WRITE);
1576
 
+
1577
 
+       put_aa_profile(active);
1578
 
+
1579
 
+out:
1580
 
+       return error;
1581
 
+}
1582
 
+
1583
 
+static int apparmor_inode_rmdir(struct inode *dir, struct dentry *dentry,
1584
 
+                               struct vfsmount *mnt)
1585
 
+{
1586
 
+       struct aa_profile *active;
1587
 
+       int error = 0;
1588
 
+
1589
 
+       if (!mnt || !mediated_filesystem(dir))
1590
 
+               goto out;
1591
 
+
1592
 
+       active = get_active_aa_profile();
1593
 
+
1594
 
+       if (active)
1595
 
+               error = aa_perm_dir(active, dentry, mnt, "rmdir", AA_MAY_WRITE);
1596
 
+
1597
 
+       put_aa_profile(active);
1598
 
+
1599
 
+out:
1600
 
+       return error;
1601
 
+}
1602
 
+
1603
 
+static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
1604
 
+                                struct vfsmount *mnt, int mask)
1605
 
+{
1606
 
+       struct aa_profile *active;
1607
 
+       int error = 0;
1608
 
+
1609
 
+       if (!mnt || !mediated_filesystem(dir))
1610
 
+               goto out;
1611
 
+
1612
 
+       active = get_active_aa_profile();
1613
 
+
1614
 
+       /* At a minimum, need write perm to create */
1615
 
+       if (active)
1616
 
+               error = aa_perm(active, dentry, mnt, MAY_WRITE);
1617
 
+
1618
 
+       put_aa_profile(active);
1619
 
+out:
1620
 
+       return error;
1621
 
+}
1622
 
+
1623
 
+static int apparmor_inode_link(struct dentry *old_dentry,
1624
 
+                              struct vfsmount *old_mnt, struct inode *dir,
1625
 
+                              struct dentry *new_dentry,
1626
 
+                              struct vfsmount *new_mnt)
1627
 
+{
1628
 
+       int error = 0;
1629
 
+       struct aa_profile *active;
1630
 
+
1631
 
+       if (!old_mnt || !new_mnt || !mediated_filesystem(dir))
1632
 
+               goto out;
1633
 
+
1634
 
+       active = get_active_aa_profile();
1635
 
+
1636
 
+       if (active)
1637
 
+               error = aa_link(active, new_dentry, new_mnt,
1638
 
+                               old_dentry, old_mnt);
1639
 
+
1640
 
+       put_aa_profile(active);
1641
 
+
1642
 
+out:
1643
 
+       return error;
1644
 
+}
1645
 
+
1646
 
+static int apparmor_inode_unlink(struct inode *dir,
1647
 
+                                struct dentry *dentry,
1648
 
+                                struct vfsmount *mnt)
1649
 
+{
1650
 
+       struct aa_profile *active;
1651
 
+       int error = 0;
1652
 
+
1653
 
+       if (!mnt || !mediated_filesystem(dir))
1654
 
+               goto out;
1655
 
+
1656
 
+       active = get_active_aa_profile();
1657
 
+
1658
 
+       if (active)
1659
 
+               error = aa_perm(active, dentry, mnt, MAY_WRITE);
1660
 
+
1661
 
+       put_aa_profile(active);
1662
 
+
1663
 
+out:
1664
 
+       return error;
1665
 
+}
1666
 
+
1667
 
+static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry,
1668
 
+                               struct vfsmount *mnt, int mode, dev_t dev)
1669
 
+{
1670
 
+       struct aa_profile *active;
1671
 
+       int error = 0;
1672
 
+
1673
 
+       if (!mnt || !mediated_filesystem(dir))
1674
 
+               goto out;
1675
 
+
1676
 
+       active = get_active_aa_profile();
1677
 
+
1678
 
+       if (active)
1679
 
+               error = aa_perm(active, dentry, mnt, MAY_WRITE);
1680
 
+
1681
 
+       put_aa_profile(active);
1682
 
+
1683
 
+out:
1684
 
+       return error;
1685
 
+}
1686
 
+
1687
 
+static int apparmor_inode_rename(struct inode *old_dir,
1688
 
+                                struct dentry *old_dentry,
1689
 
+                                struct vfsmount *old_mnt,
1690
 
+                                struct inode *new_dir,
1691
 
+                                struct dentry *new_dentry,
1692
 
+                                struct vfsmount *new_mnt)
1693
 
+{
1694
 
+       struct aa_profile *active;
1695
 
+       int error = 0;
1696
 
+
1697
 
+       if ((!old_mnt && !new_mnt) || !mediated_filesystem(old_dir))
1698
 
+               goto out;
1699
 
+
1700
 
+       active = get_active_aa_profile();
1701
 
+
1702
 
+       if (active) {
1703
 
+               if (old_mnt)
1704
 
+                       error = aa_perm(active, old_dentry, old_mnt,
1705
 
+                                       MAY_READ|MAY_WRITE);
1706
 
+
1707
 
+               if (!error && new_mnt)
1708
 
+                       error = aa_perm(active, new_dentry, new_mnt,
1709
 
+                                       MAY_WRITE);
1710
 
+       }
1711
 
+
1712
 
+       put_aa_profile(active);
1713
 
+
1714
 
+out:
1715
 
+       return error;
1716
 
+}
1717
 
+
1718
 
+static int apparmor_inode_permission(struct inode *inode, int mask,
1719
 
+                                    struct nameidata *nd)
1720
 
+{
1721
 
+       int error = 0;
1722
 
+
1723
 
+       /* Do not perform check on pipes or sockets
1724
 
+        * Same as apparmor_file_permission
1725
 
+        */
1726
 
+       if (nd && mediated_filesystem(inode)) {
1727
 
+               struct aa_profile *active;
1728
 
+
1729
 
+               active = get_active_aa_profile();
1730
 
+               if (active)
1731
 
+                       error = aa_perm(active, nd->dentry, nd->mnt, mask);
1732
 
+               put_aa_profile(active);
1733
 
+       }
1734
 
+
1735
 
+       return error;
1736
 
+}
1737
 
+
1738
 
+static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
1739
 
+                                 struct iattr *iattr)
1740
 
+{
1741
 
+       int error = 0;
1742
 
+
1743
 
+       if (!mnt)
1744
 
+               goto out;
1745
 
+
1746
 
+       if (mediated_filesystem(dentry->d_inode)) {
1747
 
+               struct aa_profile *active;
1748
 
+
1749
 
+               active = get_active_aa_profile();
1750
 
+               /*
1751
 
+                * Mediate any attempt to change attributes of a file
1752
 
+                * (chmod, chown, chgrp, etc)
1753
 
+                */
1754
 
+               if (active)
1755
 
+                       error = aa_attr(active, dentry, mnt, iattr);
1756
 
+
1757
 
+               put_aa_profile(active);
1758
 
+       }
1759
 
+
1760
 
+out:
1761
 
+       return error;
1762
 
+}
1763
 
+
1764
 
+static int apparmor_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
1765
 
+                                  char *name, void *value, size_t size,
1766
 
+                                  int flags)
1767
 
+{
1768
 
+       int error = 0;
1769
 
+
1770
 
+       if (!mnt)
1771
 
+               goto out;
1772
 
+
1773
 
+       if (mediated_filesystem(dentry->d_inode)) {
1774
 
+               struct aa_profile *active;
1775
 
+
1776
 
+               active = get_active_aa_profile();
1777
 
+               if (active)
1778
 
+                       error = aa_perm_xattr(active, dentry, mnt, name,
1779
 
+                                             "xattr set", AA_MAY_WRITE);
1780
 
+               put_aa_profile(active);
1781
 
+       }
1782
 
+
1783
 
+out:
1784
 
+       return error;
1785
 
+}
1786
 
+
1787
 
+static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
1788
 
+                                  char *name)
1789
 
+{
1790
 
+       int error = 0;
1791
 
+
1792
 
+       if (!mnt)
1793
 
+               goto out;
1794
 
+
1795
 
+       if (mediated_filesystem(dentry->d_inode)) {
1796
 
+               struct aa_profile *active;
1797
 
+
1798
 
+               active = get_active_aa_profile();
1799
 
+               if (active)
1800
 
+                       error = aa_perm_xattr(active, dentry, mnt, name,
1801
 
+                                             "xattr get", AA_MAY_READ);
1802
 
+               put_aa_profile(active);
1803
 
+       }
1804
 
+
1805
 
+out:
1806
 
+       return error;
1807
 
+}
1808
 
+static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
1809
 
+{
1810
 
+       int error = 0;
1811
 
+
1812
 
+       if (!mnt)
1813
 
+               goto out;
1814
 
+
1815
 
+       if (mediated_filesystem(dentry->d_inode)) {
1816
 
+               struct aa_profile *active;
1817
 
+
1818
 
+               active = get_active_aa_profile();
1819
 
+               if (active)
1820
 
+                       error = aa_perm_xattr(active, dentry, mnt, NULL,
1821
 
+                                             "xattr list", AA_MAY_READ);;
1822
 
+               put_aa_profile(active);
1823
 
+       }
1824
 
+
1825
 
+out:
1826
 
+       return error;
1827
 
+}
1828
 
+
1829
 
+static int apparmor_inode_removexattr(struct dentry *dentry,
1830
 
+                                     struct vfsmount *mnt, char *name)
1831
 
+{
1832
 
+       int error = 0;
1833
 
+
1834
 
+       if (!mnt)
1835
 
+               goto out;
1836
 
+
1837
 
+       if (mediated_filesystem(dentry->d_inode)) {
1838
 
+               struct aa_profile *active;
1839
 
+
1840
 
+               active = get_active_aa_profile();
1841
 
+               if (active)
1842
 
+                       error = aa_perm_xattr(active, dentry, mnt, name,
1843
 
+                                             "xattr remove", AA_MAY_WRITE);
1844
 
+               put_aa_profile(active);
1845
 
+       }
1846
 
+
1847
 
+out:
1848
 
+       return error;
1849
 
+}
1850
 
+
1851
 
+static int apparmor_file_permission(struct file *file, int mask)
1852
 
+{
1853
 
+       struct aa_profile *active;
1854
 
+       struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
1855
 
+       int error = 0;
1856
 
+
1857
 
+       /* bail out early if this isn't a mediated file */
1858
 
+       if (!file_profile || !mediated_filesystem(file->f_dentry->d_inode))
1859
 
+               goto out;
1860
 
+
1861
 
+       active = get_active_aa_profile();
1862
 
+       if (active && file_profile != active) {
1863
 
+               /* FIXME: get rid of revalidation. */
1864
 
+               error = aa_perm(active, file->f_dentry, file->f_vfsmnt,
1865
 
+                               mask & (MAY_EXEC | MAY_WRITE | MAY_READ));
1866
 
+       }
1867
 
+       put_aa_profile(active);
1868
 
+
1869
 
+out:
1870
 
+       return error;
1871
 
+}
1872
 
+
1873
 
+static int apparmor_file_alloc_security(struct file *file)
1874
 
+{
1875
 
+       struct aa_profile *active;
1876
 
+
1877
 
+       active = get_active_aa_profile();
1878
 
+       if (active) {
1879
 
+               /* FIXME: get rid of revalidation. */
1880
 
+               file->f_security = active;
1881
 
+       }
1882
 
+
1883
 
+       return 0;
1884
 
+}
1885
 
+
1886
 
+static void apparmor_file_free_security(struct file *file)
1887
 
+{
1888
 
+       struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
1889
 
+
1890
 
+       /* FIXME: get rid of revalidation. */
1891
 
+       put_aa_profile(file_profile);
1892
 
+}
1893
 
+
1894
 
+static inline int aa_mmap(struct file *file, unsigned long prot,
1895
 
+                         unsigned long flags)
1896
 
+{
1897
 
+       int error = 0, mask = 0;
1898
 
+       struct aa_profile *active;
1899
 
+
1900
 
+       active = get_active_aa_profile();
1901
 
+       if (!active || !file || !mediated_filesystem(file->f_dentry->d_inode))
1902
 
+               goto out;
1903
 
+
1904
 
+       if (prot & PROT_READ)
1905
 
+               mask |= MAY_READ;
1906
 
+
1907
 
+       /* Private mappings don't require write perms since they don't
1908
 
+        * write back to the files */
1909
 
+       if (prot & PROT_WRITE && !(flags & MAP_PRIVATE))
1910
 
+               mask |= MAY_WRITE;
1911
 
+       if (prot & PROT_EXEC)
1912
 
+               mask |= AA_EXEC_MMAP;
1913
 
+
1914
 
+       AA_DEBUG("%s: 0x%x\n", __FUNCTION__, mask);
1915
 
+
1916
 
+       if (mask)
1917
 
+               error = aa_perm(active, file->f_dentry, file->f_vfsmnt, mask);
1918
 
+
1919
 
+       put_aa_profile(active);
1920
 
+
1921
 
+out:
1922
 
+       return error;
1923
 
+}
1924
 
+
1925
 
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
1926
 
+                              unsigned long prot, unsigned long flags)
1927
 
+{
1928
 
+       return aa_mmap(file, prot, flags);
1929
 
+}
1930
 
+
1931
 
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
1932
 
+                                 unsigned long reqprot, unsigned long prot)
1933
 
+{
1934
 
+       return aa_mmap(vma->vm_file, prot,
1935
 
+                      !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
1936
 
+}
1937
 
+
1938
 
+static int apparmor_task_alloc_security(struct task_struct *p)
1939
 
+{
1940
 
+       return aa_fork(p);
1941
 
+}
1942
 
+
1943
 
+static void apparmor_task_free_security(struct task_struct *p)
1944
 
+{
1945
 
+       aa_release(p);
1946
 
+}
1947
 
+
1948
 
+static int apparmor_task_post_setuid(uid_t id0, uid_t id1, uid_t id2,
1949
 
+                                    int flags)
1950
 
+{
1951
 
+       return cap_task_post_setuid(id0, id1, id2, flags);
1952
 
+}
1953
 
+
1954
 
+static void apparmor_task_reparent_to_init(struct task_struct *p)
1955
 
+{
1956
 
+       cap_task_reparent_to_init(p);
1957
 
+}
1958
 
+
1959
 
+static int apparmor_getprocattr(struct task_struct *p, char *name, void *value,
1960
 
+                               size_t size)
1961
 
+{
1962
 
+       int error;
1963
 
+       struct aa_profile *active;
1964
 
+       char *str = value;
1965
 
+
1966
 
+       /* AppArmor only supports the "current" process attribute */
1967
 
+       if (strcmp(name, "current") != 0) {
1968
 
+               error = -EINVAL;
1969
 
+               goto out;
1970
 
+       }
1971
 
+
1972
 
+       /* must be task querying itself or admin */
1973
 
+       if (current != p && !capable(CAP_SYS_ADMIN)) {
1974
 
+               error = -EPERM;
1975
 
+               goto out;
1976
 
+       }
1977
 
+
1978
 
+       active = get_task_active_aa_profile(p);
1979
 
+       error = aa_getprocattr(active, str, size);
1980
 
+       put_aa_profile(active);
1981
 
+
1982
 
+out:
1983
 
+       return error;
1984
 
+}
1985
 
+
1986
 
+static int apparmor_setprocattr(struct task_struct *p, char *name, void *value,
1987
 
+                                size_t size)
1988
 
+{
1989
 
+       const char *cmd_changehat = "changehat ",
1990
 
+                  *cmd_setprofile = "setprofile ";
1991
 
+
1992
 
+       int error;
1993
 
+       char *cmd = (char *)value;
1994
 
+
1995
 
+       error = -EINVAL;
1996
 
+       if (strcmp(name, "current") != 0)
1997
 
+               goto out;
1998
 
+       error = -ERANGE;
1999
 
+       if (!size)
2000
 
+               goto out;
2001
 
+
2002
 
+       /* CHANGE HAT -- switch task into a subhat (subprofile) if defined */
2003
 
+       if (size > strlen(cmd_changehat) &&
2004
 
+           strncmp(cmd, cmd_changehat, strlen(cmd_changehat)) == 0) {
2005
 
+               char *hatinfo = cmd + strlen(cmd_changehat);
2006
 
+               size_t infosize = size - strlen(cmd_changehat);
2007
 
+
2008
 
+               /* Only the current process may change it's hat */
2009
 
+               if (current != p) {
2010
 
+                       AA_WARN("%s: Attempt by foreign task %s(%d) "
2011
 
+                               "[user %d] to changehat of task %s(%d)\n",
2012
 
+                               __FUNCTION__,
2013
 
+                               current->comm,
2014
 
+                               current->pid,
2015
 
+                               current->uid,
2016
 
+                               p->comm,
2017
 
+                               p->pid);
2018
 
+
2019
 
+                       error = -EACCES;
2020
 
+                       goto out;
2021
 
+               }
2022
 
+
2023
 
+               error = aa_setprocattr_changehat(hatinfo, infosize);
2024
 
+               if (!error)
2025
 
+                       error = size;
2026
 
+
2027
 
+       /* SET NEW PROFILE */
2028
 
+       } else if (size > strlen(cmd_setprofile) &&
2029
 
+                  strncmp(cmd, cmd_setprofile, strlen(cmd_setprofile)) == 0) {
2030
 
+               struct aa_profile *active;
2031
 
+
2032
 
+               /* only an unconfined process with admin capabilities
2033
 
+                * may change the profile of another task
2034
 
+                */
2035
 
+
2036
 
+               if (!capable(CAP_SYS_ADMIN)) {
2037
 
+                       AA_WARN("%s: Unprivileged attempt by task %s(%d) "
2038
 
+                               "[user %d] to assign profile to task %s(%d)\n",
2039
 
+                               __FUNCTION__,
2040
 
+                               current->comm,
2041
 
+                               current->pid,
2042
 
+                               current->uid,
2043
 
+                               p->comm,
2044
 
+                               p->pid);
2045
 
+                       error = -EACCES;
2046
 
+                       goto out;
2047
 
+               }
2048
 
+
2049
 
+               active = get_active_aa_profile();
2050
 
+               if (!active) {
2051
 
+                       char *profile = cmd + strlen(cmd_setprofile);
2052
 
+                       size_t profilesize = size - strlen(cmd_setprofile);
2053
 
+
2054
 
+                       error = aa_setprocattr_setprofile(p, profile, profilesize);
2055
 
+                       if (!error)
2056
 
+                               /* success,
2057
 
+                                * set return to #bytes in orig request
2058
 
+                                */
2059
 
+                               error = size;
2060
 
+               } else {
2061
 
+                       AA_WARN("%s: Attempt by confined task %s(%d) "
2062
 
+                               "[user %d] to assign profile to task %s(%d)\n",
2063
 
+                               __FUNCTION__,
2064
 
+                               current->comm,
2065
 
+                               current->pid,
2066
 
+                               current->uid,
2067
 
+                               p->comm,
2068
 
+                               p->pid);
2069
 
+
2070
 
+                       error = -EACCES;
2071
 
+               }
2072
 
+               put_aa_profile(active);
2073
 
+       } else {
2074
 
+               /* unknown operation */
2075
 
+               AA_WARN("%s: Unknown setprocattr command '%.*s' by task %s(%d) "
2076
 
+                       "[user %d] for task %s(%d)\n",
2077
 
+                       __FUNCTION__,
2078
 
+                       size < 16 ? (int)size : 16,
2079
 
+                       cmd,
2080
 
+                       current->comm,
2081
 
+                       current->pid,
2082
 
+                       current->uid,
2083
 
+                       p->comm,
2084
 
+                       p->pid);
2085
 
+
2086
 
+               error = -EINVAL;
2087
 
+       }
2088
 
+
2089
 
+out:
2090
 
+       return error;
2091
 
+}
2092
 
+
2093
 
+struct security_operations apparmor_ops = {
2094
 
+       .ptrace =                       apparmor_ptrace,
2095
 
+       .capget =                       apparmor_capget,
2096
 
+       .capset_check =                 apparmor_capset_check,
2097
 
+       .capset_set =                   apparmor_capset_set,
2098
 
+       .sysctl =                       apparmor_sysctl,
2099
 
+       .capable =                      apparmor_capable,
2100
 
+       .syslog =                       apparmor_syslog,
2101
 
+
2102
 
+       .netlink_send =                 apparmor_netlink_send,
2103
 
+       .netlink_recv =                 apparmor_netlink_recv,
2104
 
+
2105
 
+       .bprm_apply_creds =             apparmor_bprm_apply_creds,
2106
 
+       .bprm_set_security =            apparmor_bprm_set_security,
2107
 
+       .bprm_secureexec =              apparmor_bprm_secureexec,
2108
 
+
2109
 
+       .sb_mount =                     apparmor_sb_mount,
2110
 
+       .sb_umount =                    apparmor_umount,
2111
 
+
2112
 
+       .inode_mkdir =                  apparmor_inode_mkdir,
2113
 
+       .inode_rmdir =                  apparmor_inode_rmdir,
2114
 
+       .inode_create =                 apparmor_inode_create,
2115
 
+       .inode_link =                   apparmor_inode_link,
2116
 
+       .inode_unlink =                 apparmor_inode_unlink,
2117
 
+       .inode_mknod =                  apparmor_inode_mknod,
2118
 
+       .inode_rename =                 apparmor_inode_rename,
2119
 
+       .inode_permission =             apparmor_inode_permission,
2120
 
+       .inode_setattr =                apparmor_inode_setattr,
2121
 
+       .inode_setxattr =               apparmor_inode_setxattr,
2122
 
+       .inode_getxattr =               apparmor_inode_getxattr,
2123
 
+       .inode_listxattr =              apparmor_inode_listxattr,
2124
 
+       .inode_removexattr =            apparmor_inode_removexattr,
2125
 
+       .file_permission =              apparmor_file_permission,
2126
 
+       .file_alloc_security =          apparmor_file_alloc_security,
2127
 
+       .file_free_security =           apparmor_file_free_security,
2128
 
+       .file_mmap =                    apparmor_file_mmap,
2129
 
+       .file_mprotect =                apparmor_file_mprotect,
2130
 
+
2131
 
+       .task_alloc_security =          apparmor_task_alloc_security,
2132
 
+       .task_free_security =           apparmor_task_free_security,
2133
 
+       .task_post_setuid =             apparmor_task_post_setuid,
2134
 
+       .task_reparent_to_init =        apparmor_task_reparent_to_init,
2135
 
+
2136
 
+       .getprocattr =                  apparmor_getprocattr,
2137
 
+       .setprocattr =                  apparmor_setprocattr,
2138
 
+};
2139
 
+
2140
 
+static int __init apparmor_init(void)
2141
 
+{
2142
 
+       int error;
2143
 
+       const char *complainmsg = ": complainmode enabled";
2144
 
+
2145
 
+       if ((error = create_apparmorfs())) {
2146
 
+               AA_ERROR("Unable to activate AppArmor filesystem\n");
2147
 
+               goto createfs_out;
2148
 
+       }
2149
 
+
2150
 
+       if ((error = alloc_null_complain_profile())){
2151
 
+               AA_ERROR("Unable to allocate null complain profile\n");
2152
 
+               goto alloc_out;
2153
 
+       }
2154
 
+
2155
 
+       if ((error = register_security(&apparmor_ops))) {
2156
 
+               AA_ERROR("Unable to load AppArmor\n");
2157
 
+               goto register_security_out;
2158
 
+       }
2159
 
+
2160
 
+       AA_INFO("AppArmor initialized%s\n",
2161
 
+               apparmor_complain ? complainmsg : "");
2162
 
+       aa_audit_message(NULL, GFP_KERNEL, 0,
2163
 
+               "AppArmor initialized%s\n",
2164
 
+               apparmor_complain ? complainmsg : "");
2165
 
+
2166
 
+       return error;
2167
 
+
2168
 
+register_security_out:
2169
 
+       free_null_complain_profile();
2170
 
+
2171
 
+alloc_out:
2172
 
+       (void)destroy_apparmorfs();
2173
 
+
2174
 
+createfs_out:
2175
 
+       return error;
2176
 
+
2177
 
+}
2178
 
+
2179
 
+static int apparmor_exit_removeall_iter(struct subdomain *sd, void *cookie)
2180
 
+{
2181
 
+       /* spin_lock(&sd_lock) held here */
2182
 
+
2183
 
+       if (__aa_is_confined(sd)) {
2184
 
+               AA_DEBUG("%s: Dropping profiles %s(%d) "
2185
 
+                        "profile %s(%p) active %s(%p)\n",
2186
 
+                        __FUNCTION__,
2187
 
+                        sd->task->comm, sd->task->pid,
2188
 
+                        BASE_PROFILE(sd->active)->name,
2189
 
+                        BASE_PROFILE(sd->active),
2190
 
+                        sd->active->name, sd->active);
2191
 
+               aa_switch_unconfined(sd);
2192
 
+       }
2193
 
+
2194
 
+       return 0;
2195
 
+}
2196
 
+
2197
 
+static void __exit apparmor_exit(void)
2198
 
+{
2199
 
+       unsigned long flags;
2200
 
+
2201
 
+       /* Remove profiles from the global profile list.
2202
 
+        * This is just for tidyness as there is no way to reference this
2203
 
+        * list once the AppArmor lsm hooks are detached (below)
2204
 
+        */
2205
 
+       aa_profilelist_release();
2206
 
+
2207
 
+       /* Remove profiles from active tasks
2208
 
+        * If this is not done,  if module is reloaded after being removed,
2209
 
+        * old profiles (still refcounted in memory) will become 'magically'
2210
 
+        * reattached
2211
 
+        */
2212
 
+
2213
 
+       spin_lock_irqsave(&sd_lock, flags);
2214
 
+       aa_subdomainlist_iterate(apparmor_exit_removeall_iter, NULL);
2215
 
+       spin_unlock_irqrestore(&sd_lock, flags);
2216
 
+
2217
 
+       /* Free up list of active subdomain */
2218
 
+       aa_subdomainlist_release();
2219
 
+
2220
 
+       free_null_complain_profile();
2221
 
+
2222
 
+       destroy_apparmorfs();
2223
 
+
2224
 
+       if (unregister_security(&apparmor_ops))
2225
 
+               AA_WARN("Unable to properly unregister AppArmor\n");
2226
 
+
2227
 
+       /* delay for an rcu cycle to make ensure that profiles pending
2228
 
+        * destruction in the rcu callback are freed.
2229
 
+        */
2230
 
+       synchronize_rcu();
2231
 
+
2232
 
+       AA_INFO("AppArmor protection removed\n");
2233
 
+       aa_audit_message(NULL, GFP_KERNEL, 0,
2234
 
+               "AppArmor protection removed\n");
2235
 
+}
2236
 
+
2237
 
+module_init(apparmor_init);
2238
 
+module_exit(apparmor_exit);
2239
 
+
2240
 
+MODULE_DESCRIPTION("AppArmor process confinement");
2241
 
+MODULE_AUTHOR("Tony Jones <tonyj@suse.de>");
2242
 
+MODULE_LICENSE("GPL");
2243
 
Index: b/security/apparmor/main.c
2244
 
===================================================================
2245
 
--- /dev/null
2246
 
+++ b/security/apparmor/main.c
2247
 
@@ -0,0 +1,1256 @@
2248
 
+/*
2249
 
+ *     Copyright (C) 2002-2005 Novell/SUSE
2250
 
+ *
2251
 
+ *     This program is free software; you can redistribute it and/or
2252
 
+ *     modify it under the terms of the GNU General Public License as
2253
 
+ *     published by the Free Software Foundation, version 2 of the
2254
 
+ *     License.
2255
 
+ *
2256
 
+ *     AppArmor Core
2257
 
+ */
2258
 
+
2259
 
+#include <linux/security.h>
2260
 
+#include <linux/namei.h>
2261
 
+#include <linux/audit.h>
2262
 
+
2263
 
+#include "apparmor.h"
2264
 
+
2265
 
+#include "inline.h"
2266
 
+
2267
 
+/* NULL complain profile
2268
 
+ *
2269
 
+ * Used when in complain mode, to emit Permitting messages for non-existant
2270
 
+ * profiles and hats.  This is necessary because of selective mode, in which
2271
 
+ * case we need a complain null_profile and enforce null_profile
2272
 
+ *
2273
 
+ * The null_complain_profile cannot be statically allocated, because it
2274
 
+ * can be associated to files which keep their reference even if apparmor is
2275
 
+ * unloaded
2276
 
+ */
2277
 
+struct aa_profile *null_complain_profile;
2278
 
+
2279
 
+/***************************
2280
 
+ * Private utility functions
2281
 
+ **************************/
2282
 
+
2283
 
+/**
2284
 
+ * aa_taskattr_access
2285
 
+ * @name: name of file to check permission
2286
 
+ *
2287
 
+ * Check if name matches /proc/self/attr/current, with self resolved
2288
 
+ * to the current pid. This file is the usermode iterface for
2289
 
+ * changing one's hat.
2290
 
+ */
2291
 
+static inline int aa_taskattr_access(const char *name)
2292
 
+{
2293
 
+       unsigned long pid;
2294
 
+       char *end;
2295
 
+
2296
 
+       if (strncmp(name, "/proc/", 6) != 0)
2297
 
+               return 0;
2298
 
+       pid = simple_strtoul(name + 6, &end, 10);
2299
 
+       if (pid != current->pid)
2300
 
+               return 0;
2301
 
+       return strcmp(end, "/attr/current") == 0;
2302
 
+}
2303
 
+
2304
 
+/**
2305
 
+ * aa_file_mode - get full mode for file entry from profile
2306
 
+ * @profile: profile
2307
 
+ * @name: filename
2308
 
+ */
2309
 
+static inline int aa_file_mode(struct aa_profile *profile, const char *name)
2310
 
+{
2311
 
+       int perms = 0;
2312
 
+
2313
 
+       AA_DEBUG("%s: %s\n", __FUNCTION__, name);
2314
 
+       if (!name) {
2315
 
+               AA_DEBUG("%s: no name\n", __FUNCTION__);
2316
 
+               goto out;
2317
 
+       }
2318
 
+
2319
 
+       if (!profile) {
2320
 
+               AA_DEBUG("%s: no profile\n", __FUNCTION__);
2321
 
+               goto out;
2322
 
+       }
2323
 
+
2324
 
+       perms = aa_match(profile->file_rules, name);
2325
 
+
2326
 
+out:
2327
 
+       return perms;
2328
 
+}
2329
 
+
2330
 
+/**
2331
 
+ * aa_filter_mask
2332
 
+ * @mask: requested mask
2333
 
+ * @inode: potential directory inode
2334
 
+ *
2335
 
+ * This fn performs pre-verification of the requested mask
2336
 
+ * We ignore append. Previously we required 'w' on a dir to add a file.
2337
 
+ * No longer. Now we require 'w' on just the file itself. Traversal 'x' is
2338
 
+ * also ignored for directories.
2339
 
+ *
2340
 
+ * Returned value of %0 indicates no need to perform a perm check.
2341
 
+ */
2342
 
+static inline int aa_filter_mask(int mask, struct inode *inode)
2343
 
+{
2344
 
+       if (mask) {
2345
 
+               int elim = MAY_APPEND;
2346
 
+
2347
 
+               if (inode && S_ISDIR(inode->i_mode))
2348
 
+                       elim |= (MAY_EXEC | MAY_WRITE);
2349
 
+
2350
 
+               mask &= ~elim;
2351
 
+       }
2352
 
+
2353
 
+       return mask;
2354
 
+}
2355
 
+
2356
 
+static inline void aa_permerror2result(int perm_result, struct aa_audit *sa)
2357
 
+{
2358
 
+       if (perm_result == 0) { /* success */
2359
 
+               sa->result = 1;
2360
 
+               sa->error_code = 0;
2361
 
+       } else { /* -ve internal error code or +ve mask of denied perms */
2362
 
+               sa->result = 0;
2363
 
+               sa->error_code = perm_result;
2364
 
+       }
2365
 
+}
2366
 
+
2367
 
+/*************************
2368
 
+ * Main internal functions
2369
 
+ ************************/
2370
 
+
2371
 
+/**
2372
 
+ * aa_file_perm - calculate access mode for file
2373
 
+ * @active: profile to check against
2374
 
+ * @name: name of file to calculate mode for
2375
 
+ * @mask: permission mask requested for file
2376
 
+ *
2377
 
+ * Search the aa_entry list in @active.
2378
 
+ * Search looking to verify all permissions passed in mask.
2379
 
+ * Perform the search by looking at the partitioned list of entries, one
2380
 
+ * partition per permission bit.
2381
 
+ *
2382
 
+ * Return %0 on success, else mask of non-allowed permissions
2383
 
+ */
2384
 
+static int aa_file_perm(struct aa_profile *active, const char *name, int mask)
2385
 
+{
2386
 
+       int perms;
2387
 
+
2388
 
+       /* Always allow write access to /proc/self/attr/current. */
2389
 
+       if (mask == MAY_WRITE && aa_taskattr_access(name))
2390
 
+               return 0;
2391
 
+
2392
 
+       perms = aa_match(active->file_rules, name);
2393
 
+
2394
 
+       return mask & ~perms;  /* return permissions not satisfied */
2395
 
+}
2396
 
+
2397
 
+/**
2398
 
+ * aa_link_perm - test permission to link to a file
2399
 
+ * @active: profile to check against
2400
 
+ * @link: name of link being created
2401
 
+ * @target: name of target to be linked to
2402
 
+ *
2403
 
+ * Look up permission mode on both @link and @target.  @link must have same
2404
 
+ * permission mode as @target.  At least @link must have the link bit enabled.
2405
 
+ * Return %0 on success, else -EPERM
2406
 
+ */
2407
 
+static int aa_link_perm(struct aa_profile *active,
2408
 
+                       const char *link, const char *target)
2409
 
+{
2410
 
+       int l_mode, t_mode, ret = -EPERM;
2411
 
+
2412
 
+       l_mode = aa_file_mode(active, link);
2413
 
+       if (l_mode & AA_MAY_LINK) {
2414
 
+               /* mask off link bit */
2415
 
+               l_mode &= ~AA_MAY_LINK;
2416
 
+
2417
 
+               t_mode = aa_file_mode(active, target);
2418
 
+               t_mode &= ~AA_MAY_LINK;
2419
 
+
2420
 
+               if (l_mode == t_mode)
2421
 
+                       ret = 0;
2422
 
+       }
2423
 
+
2424
 
+       return ret;
2425
 
+}
2426
 
+
2427
 
+static int _aa_perm_vfsmount(struct aa_profile *active, struct dentry *dentry,
2428
 
+                     struct vfsmount *mnt, struct aa_audit *sa, int mask)
2429
 
+{
2430
 
+       int permerror, error;
2431
 
+
2432
 
+       sa->name = aa_get_name(dentry, mnt);
2433
 
+
2434
 
+       if (IS_ERR(sa->name)) {
2435
 
+               permerror = PTR_ERR(sa->name);
2436
 
+               sa->name = NULL;
2437
 
+       } else {
2438
 
+               permerror = aa_file_perm(active, sa->name, mask);
2439
 
+       }
2440
 
+
2441
 
+       aa_permerror2result(permerror, sa);
2442
 
+
2443
 
+       error = aa_audit(active, sa);
2444
 
+
2445
 
+       aa_put_name(sa->name);
2446
 
+
2447
 
+       return error;
2448
 
+}
2449
 
+
2450
 
+/**************************
2451
 
+ * Global utility functions
2452
 
+ *************************/
2453
 
+
2454
 
+/**
2455
 
+ * attach_nullprofile - allocate and attach a null_profile hat to profile
2456
 
+ * @profile: profile to attach a null_profile hat to.
2457
 
+ *
2458
 
+ * Return %0 (success) or error (-%ENOMEM)
2459
 
+ */
2460
 
+int attach_nullprofile(struct aa_profile *profile)
2461
 
+{
2462
 
+       struct aa_profile *hat = NULL;
2463
 
+       char *hatname = NULL;
2464
 
+
2465
 
+       hat = alloc_aa_profile();
2466
 
+       if (!hat)
2467
 
+               goto fail;
2468
 
+       if (profile->flags.complain)
2469
 
+               hatname = kstrdup("null-complain-profile", GFP_KERNEL);
2470
 
+       else
2471
 
+               hatname = kstrdup("null-profile", GFP_KERNEL);
2472
 
+       if (!hatname)
2473
 
+               goto fail;
2474
 
+
2475
 
+       hat->flags.complain = profile->flags.complain;
2476
 
+       hat->name = hatname;
2477
 
+       hat->parent = profile;
2478
 
+
2479
 
+       profile->null_profile = hat;
2480
 
+
2481
 
+       return 0;
2482
 
+
2483
 
+fail:
2484
 
+       kfree(hatname);
2485
 
+       free_aa_profile(hat);
2486
 
+
2487
 
+       return -ENOMEM;
2488
 
+}
2489
 
+
2490
 
+
2491
 
+/**
2492
 
+ * alloc_null_complain_profile - Allocate the global null_complain_profile.
2493
 
+ *
2494
 
+ * Return %0 (success) or error (-%ENOMEM)
2495
 
+ */
2496
 
+int alloc_null_complain_profile(void)
2497
 
+{
2498
 
+       null_complain_profile = alloc_aa_profile();
2499
 
+       if (!null_complain_profile)
2500
 
+               goto fail;
2501
 
+
2502
 
+       null_complain_profile->name =
2503
 
+               kstrdup("null-complain-profile", GFP_KERNEL);
2504
 
+
2505
 
+       if (!null_complain_profile->name)
2506
 
+               goto fail;
2507
 
+
2508
 
+       null_complain_profile->flags.complain = 1;
2509
 
+       if (attach_nullprofile(null_complain_profile))
2510
 
+               goto fail;
2511
 
+
2512
 
+       return 0;
2513
 
+
2514
 
+fail:
2515
 
+       /* free_aa_profile is safe for freeing partially constructed objects */
2516
 
+       free_aa_profile(null_complain_profile);
2517
 
+       null_complain_profile = NULL;
2518
 
+
2519
 
+       return -ENOMEM;
2520
 
+}
2521
 
+
2522
 
+/**
2523
 
+ * free_null_complain_profile - Free null profiles
2524
 
+ */
2525
 
+void free_null_complain_profile(void)
2526
 
+{
2527
 
+       put_aa_profile(null_complain_profile);
2528
 
+       null_complain_profile = NULL;
2529
 
+}
2530
 
+
2531
 
+/**
2532
 
+ * aa_audit_message - Log a message to the audit subsystem
2533
 
+ * @active: profile to check against
2534
 
+ * @gfp: allocation flags
2535
 
+ * @flags: audit flags
2536
 
+ * @fmt: varargs fmt
2537
 
+ */
2538
 
+int aa_audit_message(struct aa_profile *active, gfp_t gfp, int flags,
2539
 
+                    const char *fmt, ...)
2540
 
+{
2541
 
+       int ret;
2542
 
+       struct aa_audit sa;
2543
 
+
2544
 
+       sa.type = AA_AUDITTYPE_MSG;
2545
 
+       sa.name = fmt;
2546
 
+       va_start(sa.vaval, fmt);
2547
 
+       sa.flags = flags;
2548
 
+       sa.gfp_mask = gfp;
2549
 
+       sa.error_code = 0;
2550
 
+       sa.result = 0;  /* fake failure: force message to be logged */
2551
 
+
2552
 
+       ret = aa_audit(active, &sa);
2553
 
+
2554
 
+       va_end(sa.vaval);
2555
 
+
2556
 
+       return ret;
2557
 
+}
2558
 
+
2559
 
+/**
2560
 
+ * aa_audit_syscallreject - Log a syscall rejection to the audit subsystem
2561
 
+ * @active: profile to check against
2562
 
+ * @msg: string describing syscall being rejected
2563
 
+ * @gfp: memory allocation flags
2564
 
+ */
2565
 
+int aa_audit_syscallreject(struct aa_profile *active, gfp_t gfp,
2566
 
+                          const char *msg)
2567
 
+{
2568
 
+       struct aa_audit sa;
2569
 
+
2570
 
+       sa.type = AA_AUDITTYPE_SYSCALL;
2571
 
+       sa.name = msg;
2572
 
+       sa.flags = 0;
2573
 
+       sa.gfp_mask = gfp;
2574
 
+       sa.error_code = 0;
2575
 
+       sa.result = 0; /* failure */
2576
 
+
2577
 
+       return aa_audit(active, &sa);
2578
 
+}
2579
 
+
2580
 
+/**
2581
 
+ * aa_audit - Log an audit event to the audit subsystem
2582
 
+ * @active: profile to check against
2583
 
+ * @sa: audit event
2584
 
+ */
2585
 
+int aa_audit(struct aa_profile *active, const struct aa_audit *sa)
2586
 
+{
2587
 
+       struct audit_buffer *ab = NULL;
2588
 
+       struct audit_context *ctx;
2589
 
+
2590
 
+       const char *logcls;
2591
 
+       unsigned int flags;
2592
 
+       int audit = 0,
2593
 
+           complain = 0,
2594
 
+           error = -EINVAL,
2595
 
+           opspec_error = -EACCES;
2596
 
+
2597
 
+       const gfp_t gfp_mask = sa->gfp_mask;
2598
 
+
2599
 
+       WARN_ON(sa->type >= AA_AUDITTYPE__END);
2600
 
+
2601
 
+       /*
2602
 
+        * sa->result:    1 success, 0 failure
2603
 
+        * sa->error_code: success: 0
2604
 
+        *                failure: +ve mask of failed permissions or -ve
2605
 
+        *                system error
2606
 
+        */
2607
 
+
2608
 
+       if (likely(sa->result)) {
2609
 
+               if (likely(!PROFILE_AUDIT(active))) {
2610
 
+                       /* nothing to log */
2611
 
+                       error = 0;
2612
 
+                       goto out;
2613
 
+               } else {
2614
 
+                       audit = 1;
2615
 
+                       logcls = "AUDITING";
2616
 
+               }
2617
 
+       } else if (sa->error_code < 0) {
2618
 
+               audit_log(current->audit_context, gfp_mask, AUDIT_APPARMOR,
2619
 
+                       "Internal error auditing event type %d (error %d)",
2620
 
+                       sa->type, sa->error_code);
2621
 
+               AA_ERROR("Internal error auditing event type %d (error %d)\n",
2622
 
+                       sa->type, sa->error_code);
2623
 
+               error = sa->error_code;
2624
 
+               goto out;
2625
 
+       } else if (sa->type == AA_AUDITTYPE_SYSCALL) {
2626
 
+               /* Currently AA_AUDITTYPE_SYSCALL is for rejects only.
2627
 
+                * Values set by aa_audit_syscallreject will get us here.
2628
 
+                */
2629
 
+               logcls = "REJECTING";
2630
 
+       } else {
2631
 
+               complain = PROFILE_COMPLAIN(active);
2632
 
+               logcls = complain ? "PERMITTING" : "REJECTING";
2633
 
+       }
2634
 
+
2635
 
+       /* In future extend w/ per-profile flags
2636
 
+        * (flags |= sa->active->flags)
2637
 
+        */
2638
 
+       flags = sa->flags;
2639
 
+       if (apparmor_logsyscall)
2640
 
+               flags |= AA_AUDITFLAG_AUDITSS_SYSCALL;
2641
 
+
2642
 
+
2643
 
+       /* Force full audit syscall logging regardless of global setting if
2644
 
+        * we are rejecting a syscall
2645
 
+        */
2646
 
+       if (sa->type == AA_AUDITTYPE_SYSCALL) {
2647
 
+               ctx = current->audit_context;
2648
 
+       } else {
2649
 
+               ctx = (flags & AA_AUDITFLAG_AUDITSS_SYSCALL) ?
2650
 
+                       current->audit_context : NULL;
2651
 
+       }
2652
 
+
2653
 
+       ab = audit_log_start(ctx, gfp_mask, AUDIT_APPARMOR);
2654
 
+
2655
 
+       if (!ab) {
2656
 
+               AA_ERROR("Unable to log event (%d) to audit subsys\n",
2657
 
+                       sa->type);
2658
 
+               if (complain)
2659
 
+                       error = 0;
2660
 
+               goto out;
2661
 
+       }
2662
 
+
2663
 
+       /* messages get special handling */
2664
 
+       if (sa->type == AA_AUDITTYPE_MSG) {
2665
 
+               audit_log_vformat(ab, sa->name, sa->vaval);
2666
 
+               audit_log_end(ab);
2667
 
+               error = 0;
2668
 
+               goto out;
2669
 
+       }
2670
 
+
2671
 
+       /* log operation */
2672
 
+
2673
 
+       audit_log_format(ab, "%s ", logcls);    /* REJECTING/ALLOWING/etc */
2674
 
+
2675
 
+       if (sa->type == AA_AUDITTYPE_FILE) {
2676
 
+               int perm = audit ? sa->mask : sa->error_code;
2677
 
+
2678
 
+               audit_log_format(ab, "%s%s%s%s%s access to %s ",
2679
 
+                                perm & AA_EXEC_MMAP ? "m" : "",
2680
 
+                                perm & AA_MAY_READ  ? "r" : "",
2681
 
+                                perm & AA_MAY_WRITE ? "w" : "",
2682
 
+                                perm & AA_MAY_EXEC  ? "x" : "",
2683
 
+                                perm & AA_MAY_LINK  ? "l" : "",
2684
 
+                                sa->name);
2685
 
+
2686
 
+               opspec_error = -EPERM;
2687
 
+
2688
 
+       } else if (sa->type == AA_AUDITTYPE_DIR) {
2689
 
+               audit_log_format(ab, "%s on %s ", sa->operation, sa->name);
2690
 
+
2691
 
+       } else if (sa->type == AA_AUDITTYPE_ATTR) {
2692
 
+               struct iattr *iattr = (struct iattr*)sa->pval;
2693
 
+
2694
 
+               audit_log_format(ab,
2695
 
+                       "attribute (%s%s%s%s%s%s%s) change to %s ",
2696
 
+                       iattr->ia_valid & ATTR_MODE ? "mode," : "",
2697
 
+                       iattr->ia_valid & ATTR_UID ? "uid," : "",
2698
 
+                       iattr->ia_valid & ATTR_GID ? "gid," : "",
2699
 
+                       iattr->ia_valid & ATTR_SIZE ? "size," : "",
2700
 
+                       ((iattr->ia_valid & ATTR_ATIME_SET) ||
2701
 
+                        (iattr->ia_valid & ATTR_ATIME)) ? "atime," : "",
2702
 
+                       ((iattr->ia_valid & ATTR_MTIME_SET) ||
2703
 
+                        (iattr->ia_valid & ATTR_MTIME)) ? "mtime," : "",
2704
 
+                       iattr->ia_valid & ATTR_CTIME ? "ctime," : "",
2705
 
+                       sa->name);
2706
 
+
2707
 
+       } else if (sa->type == AA_AUDITTYPE_XATTR) {
2708
 
+               /* FIXME: how are special characters in sa->name escaped? */
2709
 
+               /* FIXME: check if this can be handled on the stack
2710
 
+                         with an inline varargs function. */
2711
 
+               audit_log_format(ab, "%s on %s ", sa->operation, sa->name);
2712
 
+
2713
 
+       } else if (sa->type == AA_AUDITTYPE_LINK) {
2714
 
+               audit_log_format(ab,
2715
 
+                       "link access from %s to %s ",
2716
 
+                       sa->name,
2717
 
+                       (char*)sa->pval);
2718
 
+
2719
 
+       } else if (sa->type == AA_AUDITTYPE_CAP) {
2720
 
+               audit_log_format(ab,
2721
 
+                       "access to capability '%s' ",
2722
 
+                       capability_to_name(sa->capability));
2723
 
+
2724
 
+               opspec_error = -EPERM;
2725
 
+       } else if (sa->type == AA_AUDITTYPE_SYSCALL) {
2726
 
+               audit_log_format(ab, "access to syscall '%s' ", sa->name);
2727
 
+
2728
 
+               opspec_error = -EPERM;
2729
 
+       } else {
2730
 
+               /* -EINVAL -- will WARN_ON above */
2731
 
+               goto out;
2732
 
+       }
2733
 
+
2734
 
+       audit_log_format(ab, "(%s(%d) profile %s active %s)",
2735
 
+                        current->comm, current->pid,
2736
 
+                        BASE_PROFILE(active)->name, active->name);
2737
 
+
2738
 
+       audit_log_end(ab);
2739
 
+
2740
 
+       if (complain)
2741
 
+               error = 0;
2742
 
+       else
2743
 
+               error = sa->result ? 0 : opspec_error;
2744
 
+
2745
 
+out:
2746
 
+       return error;
2747
 
+}
2748
 
+
2749
 
+/**
2750
 
+ * aa_get_name - retrieve fully qualified path name
2751
 
+ * @dentry: relative path element
2752
 
+ * @mnt: where in tree
2753
 
+ *
2754
 
+ * Returns fully qualified path name on sucess, NULL on failure.
2755
 
+ * aa_put_name must be used to free allocated buffer.
2756
 
+ */
2757
 
+char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt)
2758
 
+{
2759
 
+       char *page, *name;
2760
 
+
2761
 
+       page = (char *)__get_free_page(GFP_KERNEL);
2762
 
+       if (!page) {
2763
 
+               name = ERR_PTR(-ENOMEM);
2764
 
+               goto out;
2765
 
+       }
2766
 
+
2767
 
+       name = d_path(dentry, mnt, page, PAGE_SIZE);
2768
 
+       /* check for (deleted) that d_path appends to pathnames if the dentry
2769
 
+        * has been removed from the cache.
2770
 
+        * The size > deleted_size and strcmp checks are redundant safe guards.
2771
 
+        */
2772
 
+       if (IS_ERR(name)) {
2773
 
+               free_page((unsigned long)page);
2774
 
+       } else {
2775
 
+               const char deleted_str[] = " (deleted)";
2776
 
+               const size_t deleted_size = sizeof(deleted_str) - 1;
2777
 
+               size_t size;
2778
 
+               size = strlen(name);
2779
 
+               if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
2780
 
+                   size > deleted_size &&
2781
 
+                   strcmp(name + size - deleted_size, deleted_str) == 0)
2782
 
+                       name[size - deleted_size] = '\0';
2783
 
+               AA_DEBUG("%s: full_path=%s\n", __FUNCTION__, name);
2784
 
+       }
2785
 
+
2786
 
+out:
2787
 
+       return name;
2788
 
+}
2789
 
+
2790
 
+/***********************************
2791
 
+ * Global permission check functions
2792
 
+ ***********************************/
2793
 
+
2794
 
+/**
2795
 
+ * aa_attr - check whether attribute change allowed
2796
 
+ * @active: profile to check against
2797
 
+ * @dentry: file to check
2798
 
+ * @iattr: attribute changes requested
2799
 
+ */
2800
 
+int aa_attr(struct aa_profile *active, struct dentry *dentry,
2801
 
+           struct vfsmount *mnt, struct iattr *iattr)
2802
 
+{
2803
 
+       int error;
2804
 
+       struct aa_audit sa;
2805
 
+
2806
 
+       sa.type = AA_AUDITTYPE_ATTR;
2807
 
+       sa.pval = iattr;
2808
 
+       sa.flags = 0;
2809
 
+       sa.gfp_mask = GFP_KERNEL;
2810
 
+
2811
 
+       error = _aa_perm_vfsmount(active, dentry, mnt, &sa, MAY_WRITE);
2812
 
+
2813
 
+       return error;
2814
 
+}
2815
 
+
2816
 
+/**
2817
 
+ * aa_perm_xattr - check whether xattr attribute change allowed
2818
 
+ * @active: profile to check against
2819
 
+ * @dentry: file to check
2820
 
+ * @mnt: mount of file to check
2821
 
+ * @operation: xattr operation being done
2822
 
+ * @xattr_name: name of xattr to check
2823
 
+ * @mask: access mode requested
2824
 
+ */
2825
 
+int aa_perm_xattr(struct aa_profile *active, struct dentry *dentry,
2826
 
+                 struct vfsmount *mnt, const char *operation,
2827
 
+                 const char *xattr_name, int mask)
2828
 
+{
2829
 
+       int error;
2830
 
+       struct aa_audit sa;
2831
 
+
2832
 
+       sa.type = AA_AUDITTYPE_XATTR;
2833
 
+       sa.operation = operation;
2834
 
+       sa.pval = xattr_name;
2835
 
+       sa.flags = 0;
2836
 
+       sa.gfp_mask = GFP_KERNEL;
2837
 
+
2838
 
+       error = _aa_perm_vfsmount(active, dentry, mnt, &sa, mask);
2839
 
+
2840
 
+       return error;
2841
 
+}
2842
 
+
2843
 
+/**
2844
 
+ * aa_perm - basic apparmor permissions check
2845
 
+ * @active: profile to check against
2846
 
+ * @dentry: dentry
2847
 
+ * @mnt: mountpoint
2848
 
+ * @mask: access mode requested
2849
 
+ *
2850
 
+ * Determine if access (mask) for dentry is authorized by active
2851
 
+ * profile.  Result, %0 (success), -ve (error)
2852
 
+ */
2853
 
+int aa_perm(struct aa_profile *active, struct dentry *dentry,
2854
 
+           struct vfsmount *mnt, int mask)
2855
 
+{
2856
 
+       int error = 0;
2857
 
+       struct aa_audit sa;
2858
 
+
2859
 
+       if ((mask = aa_filter_mask(mask, dentry->d_inode)) == 0)
2860
 
+               goto out;
2861
 
+
2862
 
+       sa.type = AA_AUDITTYPE_FILE;
2863
 
+       sa.mask = mask;
2864
 
+       sa.flags = 0;
2865
 
+       sa.gfp_mask = GFP_KERNEL;
2866
 
+       error = _aa_perm_vfsmount(active, dentry, mnt, &sa, mask);
2867
 
+
2868
 
+out:
2869
 
+       return error;
2870
 
+}
2871
 
+
2872
 
+/**
2873
 
+ * aa_perm_dir
2874
 
+ * @active: profile to check against
2875
 
+ * @dentry: requested dentry
2876
 
+ * @mnt: mount of file to check
2877
 
+ * @operation: directory operation being performed
2878
 
+ * @mask: access mode requested
2879
 
+ *
2880
 
+ * Determine if directory operation (make/remove) for dentry is authorized
2881
 
+ * by @active profile.
2882
 
+ * Result, %0 (success), -ve (error)
2883
 
+ */
2884
 
+int aa_perm_dir(struct aa_profile *active, struct dentry *dentry,
2885
 
+               struct vfsmount *mnt, const char *operation, int mask)
2886
 
+{
2887
 
+       struct aa_audit sa;
2888
 
+
2889
 
+       sa.type = AA_AUDITTYPE_DIR;
2890
 
+       sa.operation = operation;
2891
 
+       sa.flags = 0;
2892
 
+       sa.gfp_mask = GFP_KERNEL;
2893
 
+
2894
 
+       return _aa_perm_vfsmount(active, dentry, mnt, &sa, mask);
2895
 
+}
2896
 
+
2897
 
+/**
2898
 
+ * aa_capability - test permission to use capability
2899
 
+ * @active: profile to check against
2900
 
+ * @cap: capability to be tested
2901
 
+ *
2902
 
+ * Look up capability in active profile capability set.
2903
 
+ * Return %0 (success), -%EPERM (error)
2904
 
+ */
2905
 
+int aa_capability(struct aa_profile *active, int cap)
2906
 
+{
2907
 
+       int error = 0;
2908
 
+       struct aa_audit sa;
2909
 
+
2910
 
+       sa.type = AA_AUDITTYPE_CAP;
2911
 
+       sa.name = NULL;
2912
 
+       sa.capability = cap;
2913
 
+       sa.flags = 0;
2914
 
+       sa.error_code = 0;
2915
 
+       sa.result = cap_raised(active->capabilities, cap);
2916
 
+       sa.gfp_mask = GFP_ATOMIC;
2917
 
+
2918
 
+       error = aa_audit(active, &sa);
2919
 
+
2920
 
+       return error;
2921
 
+}
2922
 
+
2923
 
+/**
2924
 
+ * aa_link - hard link check
2925
 
+ * @active: profile to check against
2926
 
+ * @link: dentry for link being created
2927
 
+ * @target: dentry for link target
2928
 
+ * @mnt: vfsmount (-EXDEV is link and target are not on same vfsmount)
2929
 
+ */
2930
 
+int aa_link(struct aa_profile *active,
2931
 
+           struct dentry *link, struct vfsmount *link_mnt,
2932
 
+           struct dentry *target, struct vfsmount *target_mnt)
2933
 
+{
2934
 
+       int permerror = -EPERM, error;
2935
 
+       struct aa_audit sa;
2936
 
+
2937
 
+       sa.name = aa_get_name(link, link_mnt);
2938
 
+       sa.pval = aa_get_name(target, target_mnt);
2939
 
+
2940
 
+       if (IS_ERR(sa.name)) {
2941
 
+               permerror = PTR_ERR(sa.name);
2942
 
+               sa.name = NULL;
2943
 
+       }
2944
 
+       if (IS_ERR(sa.pval)) {
2945
 
+               permerror = PTR_ERR(sa.pval);
2946
 
+               sa.pval = NULL;
2947
 
+       }
2948
 
+
2949
 
+       if (sa.name && sa.pval)
2950
 
+               permerror = aa_link_perm(active, sa.name, sa.pval);
2951
 
+
2952
 
+       aa_permerror2result(permerror, &sa);
2953
 
+
2954
 
+       sa.type = AA_AUDITTYPE_LINK;
2955
 
+       sa.flags = 0;
2956
 
+       sa.gfp_mask = GFP_KERNEL;
2957
 
+
2958
 
+       error = aa_audit(active, &sa);
2959
 
+
2960
 
+       aa_put_name(sa.name);
2961
 
+       aa_put_name(sa.pval);
2962
 
+
2963
 
+       return error;
2964
 
+}
2965
 
+
2966
 
+/*******************************
2967
 
+ * Global task related functions
2968
 
+ *******************************/
2969
 
+
2970
 
+/**
2971
 
+ * aa_fork - create a new subdomain
2972
 
+ * @p: new process
2973
 
+ *
2974
 
+ * Create a new subdomain for newly created process @p if it's parent
2975
 
+ * is already confined.  Otherwise a subdomain will be lazily allocated
2976
 
+ * will get one with NULL values.  Return 0 on sucess.
2977
 
+ * for the child if it subsequently execs (in aa_register).
2978
 
+ * Return 0 on sucess.
2979
 
+ *
2980
 
+ * The sd_lock is used to maintain consistency against profile
2981
 
+ * replacement/removal.
2982
 
+ */
2983
 
+
2984
 
+int aa_fork(struct task_struct *p)
2985
 
+{
2986
 
+       struct subdomain *sd = AA_SUBDOMAIN(current->security);
2987
 
+       struct subdomain *newsd = NULL;
2988
 
+
2989
 
+       AA_DEBUG("%s\n", __FUNCTION__);
2990
 
+
2991
 
+       if (__aa_is_confined(sd)) {
2992
 
+               unsigned long flags;
2993
 
+
2994
 
+               newsd = alloc_subdomain(p);
2995
 
+
2996
 
+               if (!newsd)
2997
 
+                       return -ENOMEM;
2998
 
+
2999
 
+               /* Use locking here instead of getting the reference
3000
 
+                * because we need both the old reference and the
3001
 
+                * new reference to be consistent.
3002
 
+                */
3003
 
+               spin_lock_irqsave(&sd_lock, flags);
3004
 
+               aa_switch(newsd, sd->active);
3005
 
+               newsd->hat_magic = sd->hat_magic;
3006
 
+               spin_unlock_irqrestore(&sd_lock, flags);
3007
 
+
3008
 
+               if (SUBDOMAIN_COMPLAIN(sd) &&
3009
 
+                   sd->active == null_complain_profile)
3010
 
+                       LOG_HINT(sd->active, GFP_KERNEL, HINT_FORK,
3011
 
+                               "pid=%d child=%d\n",
3012
 
+                               current->pid, p->pid);
3013
 
+       }
3014
 
+       p->security = newsd;
3015
 
+       return 0;
3016
 
+}
3017
 
+
3018
 
+/**
3019
 
+ * aa_register - register a new program
3020
 
+ * @bprm: binprm of program being registered
3021
 
+ *
3022
 
+ * Try to register a new program during execve().  This should give the
3023
 
+ * new program a valid subdomain.
3024
 
+ */
3025
 
+int aa_register(struct linux_binprm *bprm)
3026
 
+{
3027
 
+       char *filename;
3028
 
+       struct file *filp = bprm->file;
3029
 
+       struct aa_profile *active;
3030
 
+       struct aa_profile *newprofile = NULL, unconstrained_flag;
3031
 
+       int     error = -ENOMEM,
3032
 
+               exec_mode = 0,
3033
 
+               find_profile = 0,
3034
 
+               find_profile_mandatory = 0,
3035
 
+               complain = 0,
3036
 
+               unsafe_exec = 0;
3037
 
+
3038
 
+       AA_DEBUG("%s\n", __FUNCTION__);
3039
 
+
3040
 
+       filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt);
3041
 
+       if (IS_ERR(filename)) {
3042
 
+               AA_WARN("%s: Failed to get filename\n", __FUNCTION__);
3043
 
+               goto out;
3044
 
+       }
3045
 
+
3046
 
+       error = 0;
3047
 
+
3048
 
+       active = get_active_aa_profile();
3049
 
+
3050
 
+       if (!active) {
3051
 
+               /* Unconfined task, load profile if it exists */
3052
 
+               find_profile = 1;
3053
 
+               goto find_profile;
3054
 
+       }
3055
 
+
3056
 
+       complain = PROFILE_COMPLAIN(active);
3057
 
+
3058
 
+       /* Confined task, determine what mode inherit, unconstrained or
3059
 
+        * mandatory to load new profile
3060
 
+        */
3061
 
+       exec_mode = AA_EXEC_MASK(aa_match(active->file_rules, filename));
3062
 
+       unsafe_exec = exec_mode & AA_EXEC_UNSAFE;
3063
 
+
3064
 
+       if (exec_mode) {
3065
 
+               switch (AA_EXEC_MODIFIER_MASK(exec_mode)) {
3066
 
+               case AA_EXEC_INHERIT:
3067
 
+                       /* do nothing - setting of profile
3068
 
+                        * already handed in aa_fork
3069
 
+                        */
3070
 
+                       AA_DEBUG("%s: INHERIT %s\n",
3071
 
+                                __FUNCTION__,
3072
 
+                                filename);
3073
 
+                       break;
3074
 
+
3075
 
+               case AA_EXEC_UNCONSTRAINED:
3076
 
+                       AA_DEBUG("%s: UNCONSTRAINED %s\n",
3077
 
+                                __FUNCTION__,
3078
 
+                                filename);
3079
 
+
3080
 
+                       /* unload profile */
3081
 
+                       newprofile = &unconstrained_flag;
3082
 
+                       break;
3083
 
+
3084
 
+               case AA_EXEC_PROFILE:
3085
 
+                       AA_DEBUG("%s: PROFILE %s\n",
3086
 
+                                __FUNCTION__,
3087
 
+                                filename);
3088
 
+
3089
 
+                       find_profile = 1;
3090
 
+                       find_profile_mandatory = 1;
3091
 
+                       break;
3092
 
+
3093
 
+               case AA_MAY_EXEC:
3094
 
+                       /* this should not happen, entries
3095
 
+                        * with just EXEC only should be
3096
 
+                        * rejected at profile load time
3097
 
+                        */
3098
 
+                       AA_ERROR("%s: Rejecting exec(2) of image '%s'. "
3099
 
+                               "AA_MAY_EXEC without exec qualifier invalid "
3100
 
+                               "(%s(%d) profile %s active %s\n",
3101
 
+                                __FUNCTION__,
3102
 
+                                filename,
3103
 
+                                current->comm, current->pid,
3104
 
+                                BASE_PROFILE(active)->name, active->name);
3105
 
+                       error = -EPERM;
3106
 
+                       break;
3107
 
+
3108
 
+               default:
3109
 
+                       AA_ERROR("%s: Rejecting exec(2) of image '%s'. "
3110
 
+                                "Unknown exec qualifier %x "
3111
 
+                                "(%s (pid %d) profile %s active %s)\n",
3112
 
+                                __FUNCTION__,
3113
 
+                                filename,
3114
 
+                                exec_mode,
3115
 
+                                current->comm, current->pid,
3116
 
+                                BASE_PROFILE(active)->name, active->name);
3117
 
+                       error = -EPERM;
3118
 
+                       break;
3119
 
+               }
3120
 
+
3121
 
+       } else if (complain) {
3122
 
+               /* There was no entry in calling profile
3123
 
+                * describing mode to execute image in.
3124
 
+                * Drop into null-profile (disabling secure exec).
3125
 
+                */
3126
 
+               newprofile = get_aa_profile(null_complain_profile);
3127
 
+               unsafe_exec = 1;
3128
 
+       } else {
3129
 
+               AA_WARN("%s: Rejecting exec(2) of image '%s'. "
3130
 
+                       "Unable to determine exec qualifier "
3131
 
+                       "(%s (pid %d) profile %s active %s)\n",
3132
 
+                       __FUNCTION__,
3133
 
+                       filename,
3134
 
+                       current->comm, current->pid,
3135
 
+                       BASE_PROFILE(active)->name, active->name);
3136
 
+               error = -EPERM;
3137
 
+       }
3138
 
+
3139
 
+
3140
 
+find_profile:
3141
 
+       if (!find_profile)
3142
 
+               goto apply_profile;
3143
 
+
3144
 
+       /* Locate new profile */
3145
 
+       newprofile = aa_profilelist_find(filename);
3146
 
+       if (newprofile) {
3147
 
+               AA_DEBUG("%s: setting profile %s\n",
3148
 
+                        __FUNCTION__, newprofile->name);
3149
 
+       } else if (find_profile_mandatory) {
3150
 
+               /* Profile (mandatory) could not be found */
3151
 
+
3152
 
+               if (complain) {
3153
 
+                       LOG_HINT(active, GFP_KERNEL, HINT_MANDPROF,
3154
 
+                               "image=%s pid=%d profile=%s active=%s\n",
3155
 
+                               filename,
3156
 
+                               current->pid,
3157
 
+                               BASE_PROFILE(active)->name, active->name);
3158
 
+
3159
 
+                       newprofile = get_aa_profile(null_complain_profile);
3160
 
+               } else {
3161
 
+                       AA_WARN("REJECTING exec(2) of image '%s'. "
3162
 
+                               "Profile mandatory and not found "
3163
 
+                               "(%s(%d) profile %s active %s)\n",
3164
 
+                               filename,
3165
 
+                               current->comm, current->pid,
3166
 
+                               BASE_PROFILE(active)->name, active->name);
3167
 
+                       error = -EPERM;
3168
 
+               }
3169
 
+       } else {
3170
 
+               /* Profile (non-mandatory) could not be found */
3171
 
+
3172
 
+               /* Only way we can get into this code is if task
3173
 
+                * is unconstrained.
3174
 
+                */
3175
 
+
3176
 
+               WARN_ON(active);
3177
 
+
3178
 
+               AA_DEBUG("%s: No profile found for exec image %s\n",
3179
 
+                        __FUNCTION__,
3180
 
+                        filename);
3181
 
+       } /* newprofile */
3182
 
+
3183
 
+
3184
 
+apply_profile:
3185
 
+       /* Apply profile if necessary */
3186
 
+       if (newprofile) {
3187
 
+               struct subdomain *sd, *lazy_sd = NULL;
3188
 
+               unsigned long flags;
3189
 
+
3190
 
+               if (newprofile == &unconstrained_flag)
3191
 
+                       newprofile = NULL;
3192
 
+
3193
 
+               /* grab a lock - this is to guarentee consistency against
3194
 
+                * other writers of subdomain (replacement/removal)
3195
 
+                *
3196
 
+                * Several things may have changed since the code above
3197
 
+                *
3198
 
+                * - Task may be presently unconfined (have no sd). In which
3199
 
+                *   case we have to lazily allocate one.  Note we may be raced
3200
 
+                *   to this allocation by a setprofile.
3201
 
+                *
3202
 
+                * - If we are a confined process, active is a refcounted copy
3203
 
+                *   of the profile that was on the subdomain at entry.
3204
 
+                *   This allows us to not have to hold a lock around
3205
 
+                *   all this code.   If profile replacement has taken place
3206
 
+                *   our active may not equal sd->active any more.
3207
 
+                *   This is okay since the operation is treated as if
3208
 
+                *   the transition occured before replacement.
3209
 
+                *
3210
 
+                * - If newprofile points to an actual profile (result of
3211
 
+                *   aa_profilelist_find above), this profile may have been
3212
 
+                *   replaced.  We need to fix it up.  Doing this to avoid
3213
 
+                *   having to hold a lock around all this code.
3214
 
+                */
3215
 
+
3216
 
+               if (!active && !(sd = AA_SUBDOMAIN(current->security))) {
3217
 
+                       lazy_sd = alloc_subdomain(current);
3218
 
+                       if (!lazy_sd) {
3219
 
+                               AA_ERROR("%s: Failed to allocate subdomain\n",
3220
 
+                                        __FUNCTION__);
3221
 
+                               error = -ENOMEM;
3222
 
+                               goto cleanup;
3223
 
+                       }
3224
 
+               }
3225
 
+
3226
 
+               spin_lock_irqsave(&sd_lock, flags);
3227
 
+
3228
 
+               sd = AA_SUBDOMAIN(current->security);
3229
 
+               if (lazy_sd) {
3230
 
+                       if (sd) {
3231
 
+                               /* raced by setprofile - created sd */
3232
 
+                               free_subdomain(lazy_sd);
3233
 
+                               lazy_sd = NULL;
3234
 
+                       } else {
3235
 
+                               /* Not rcu used to get the write barrier
3236
 
+                                * correct */
3237
 
+                               rcu_assign_pointer(current->security, lazy_sd);
3238
 
+                               sd = lazy_sd;
3239
 
+                       }
3240
 
+               }
3241
 
+
3242
 
+               /* Determine if profile we found earlier is stale.
3243
 
+                * If so, reobtain it.  N.B stale flag should never be
3244
 
+                * set on null_complain profile.
3245
 
+                */
3246
 
+               if (newprofile && unlikely(newprofile->isstale)) {
3247
 
+                       WARN_ON(newprofile == null_complain_profile);
3248
 
+
3249
 
+                       /* drop refcnt obtained from earlier get_aa_profile */
3250
 
+                       put_aa_profile(newprofile);
3251
 
+
3252
 
+                       newprofile = aa_profilelist_find(filename);
3253
 
+
3254
 
+                       if (!newprofile) {
3255
 
+                               /* Race, profile was removed, not replaced.
3256
 
+                                * Redo with error checking
3257
 
+                                */
3258
 
+                               spin_unlock_irqrestore(&sd_lock, flags);
3259
 
+                               goto find_profile;
3260
 
+                       }
3261
 
+               }
3262
 
+
3263
 
+               /* Handle confined exec.
3264
 
+                * Can be at this point for the following reasons:
3265
 
+                * 1. unconfined switching to confined
3266
 
+                * 2. confined switching to different confinement
3267
 
+                * 3. confined switching to unconfined
3268
 
+                *
3269
 
+                * Cases 2 and 3 are marked as requiring secure exec
3270
 
+                * (unless policy specified "unsafe exec")
3271
 
+                */
3272
 
+               if (__aa_is_confined(sd) && !unsafe_exec) {
3273
 
+                       unsigned long bprm_flags;
3274
 
+
3275
 
+                       bprm_flags = AA_SECURE_EXEC_NEEDED;
3276
 
+                       bprm->security = (void*)
3277
 
+                               ((unsigned long)bprm->security | bprm_flags);
3278
 
+               }
3279
 
+
3280
 
+               aa_switch(sd, newprofile);
3281
 
+               put_aa_profile(newprofile);
3282
 
+
3283
 
+               if (complain && newprofile == null_complain_profile)
3284
 
+                       LOG_HINT(newprofile, GFP_ATOMIC, HINT_CHGPROF,
3285
 
+                               "pid=%d\n",
3286
 
+                               current->pid);
3287
 
+
3288
 
+               spin_unlock_irqrestore(&sd_lock, flags);
3289
 
+       }
3290
 
+
3291
 
+cleanup:
3292
 
+       aa_put_name(filename);
3293
 
+
3294
 
+       put_aa_profile(active);
3295
 
+
3296
 
+out:
3297
 
+       return error;
3298
 
+}
3299
 
+
3300
 
+/**
3301
 
+ * aa_release - release the task's subdomain
3302
 
+ * @p: task being released
3303
 
+ *
3304
 
+ * This is called after a task has exited and the parent has reaped it.
3305
 
+ * @p->security blob is freed.
3306
 
+ *
3307
 
+ * This is the one case where we don't need to hold the sd_lock before
3308
 
+ * removing a profile from a subdomain.  Once the subdomain has been
3309
 
+ * removed from the subdomain_list, we are no longer racing other writers.
3310
 
+ * There may still be other readers so we must still use aa_switch
3311
 
+ * to put the subdomain's reference safely.
3312
 
+ */
3313
 
+void aa_release(struct task_struct *p)
3314
 
+{
3315
 
+       struct subdomain *sd = AA_SUBDOMAIN(p->security);
3316
 
+       if (sd) {
3317
 
+               p->security = NULL;
3318
 
+
3319
 
+               aa_subdomainlist_remove(sd);
3320
 
+               aa_switch_unconfined(sd);
3321
 
+
3322
 
+               kfree(sd);
3323
 
+       }
3324
 
+}
3325
 
+
3326
 
+/*****************************
3327
 
+ * global subprofile functions
3328
 
+ ****************************/
3329
 
+
3330
 
+/**
3331
 
+ * do_change_hat - actually switch hats
3332
 
+ * @hat_name: name of hat to swtich to
3333
 
+ * @sd: current subdomain
3334
 
+ *
3335
 
+ * Switch to a new hat.  Return %0 on success, error otherwise.
3336
 
+ */
3337
 
+static inline int do_change_hat(const char *hat_name, struct subdomain *sd)
3338
 
+{
3339
 
+       struct aa_profile *sub;
3340
 
+       int error = 0;
3341
 
+
3342
 
+       sub = __aa_find_profile(hat_name, &BASE_PROFILE(sd->active)->sub);
3343
 
+
3344
 
+       if (sub) {
3345
 
+               /* change hat */
3346
 
+               aa_switch(sd, sub);
3347
 
+               put_aa_profile(sub);
3348
 
+       } else {
3349
 
+               /* There is no such subprofile change to a NULL profile.
3350
 
+                * The NULL profile grants no file access.
3351
 
+                *
3352
 
+                * This feature is used by changehat_apache.
3353
 
+                *
3354
 
+                * N.B from the null-profile the task can still changehat back
3355
 
+                * out to the parent profile (assuming magic != NULL)
3356
 
+                */
3357
 
+               if (SUBDOMAIN_COMPLAIN(sd)) {
3358
 
+                       LOG_HINT(sd->active, GFP_ATOMIC, HINT_UNKNOWN_HAT,
3359
 
+                               "%s pid=%d "
3360
 
+                               "profile=%s active=%s\n",
3361
 
+                               hat_name,
3362
 
+                               current->pid,
3363
 
+                               BASE_PROFILE(sd->active)->name,
3364
 
+                               sd->active->name);
3365
 
+               } else {
3366
 
+                       AA_DEBUG("%s: Unknown hatname '%s'. "
3367
 
+                               "Changing to NULL profile "
3368
 
+                               "(%s(%d) profile %s active %s)\n",
3369
 
+                                __FUNCTION__,
3370
 
+                                hat_name,
3371
 
+                                current->comm, current->pid,
3372
 
+                                BASE_PROFILE(sd->active)->name,
3373
 
+                                sd->active->name);
3374
 
+                       error = -EACCES;
3375
 
+               }
3376
 
+               aa_switch(sd, sd->active->null_profile);
3377
 
+       }
3378
 
+
3379
 
+       return error;
3380
 
+}
3381
 
+
3382
 
+/**
3383
 
+ * aa_change_hat - change hat to/from subprofile
3384
 
+ * @hat_name: specifies hat to change to
3385
 
+ * @hat_magic: token to validate hat change
3386
 
+ *
3387
 
+ * Change to new @hat_name when current hat is top level profile, and store
3388
 
+ * the @hat_magic in the current subdomain.  If the new @hat_name is
3389
 
+ * %NULL, and the @hat_magic matches that stored in the current subdomain
3390
 
+ * return to original top level profile.  Returns %0 on success, error
3391
 
+ * otherwise.
3392
 
+ */
3393
 
+int aa_change_hat(const char *hat_name, u32 hat_magic)
3394
 
+{
3395
 
+       struct subdomain *sd = AA_SUBDOMAIN(current->security);
3396
 
+       int error = 0;
3397
 
+
3398
 
+       AA_DEBUG("%s: %p, 0x%x (pid %d)\n",
3399
 
+                __FUNCTION__,
3400
 
+                hat_name, hat_magic,
3401
 
+                current->pid);
3402
 
+
3403
 
+       /* Dump out above debugging in WARN mode if we are in AUDIT mode */
3404
 
+       if (SUBDOMAIN_AUDIT(sd)) {
3405
 
+               AA_WARN("%s: %s, 0x%x (pid %d)\n",
3406
 
+                       __FUNCTION__, hat_name ? hat_name : "NULL",
3407
 
+                       hat_magic, current->pid);
3408
 
+       }
3409
 
+
3410
 
+       /* check to see if an unconfined process is doing a changehat. */
3411
 
+       if (!__aa_is_confined(sd)) {
3412
 
+               error = -EPERM;
3413
 
+               goto out;
3414
 
+       }
3415
 
+
3416
 
+       /* check to see if the confined process has any hats. */
3417
 
+       if (list_empty(&BASE_PROFILE(sd->active)->sub) &&
3418
 
+           !PROFILE_COMPLAIN(sd->active)) {
3419
 
+               error = -ECHILD;
3420
 
+               goto out;
3421
 
+       }
3422
 
+
3423
 
+       /* Check whether current domain is parent
3424
 
+        * or one of the sibling children
3425
 
+        */
3426
 
+       if (!IN_SUBPROFILE(sd->active)) {
3427
 
+               /*
3428
 
+                * parent
3429
 
+                */
3430
 
+               if (hat_name) {
3431
 
+                       AA_DEBUG("%s: switching to %s, 0x%x\n",
3432
 
+                                __FUNCTION__,
3433
 
+                                hat_name,
3434
 
+                                hat_magic);
3435
 
+
3436
 
+                       /*
3437
 
+                        * N.B hat_magic == 0 has a special meaning
3438
 
+                        * this indicates that the task may never changehat
3439
 
+                        * back to it's parent, it will stay in this subhat
3440
 
+                        * (or null-profile, if the hat doesn't exist) until
3441
 
+                        * the task terminates
3442
 
+                        */
3443
 
+                       sd->hat_magic = hat_magic;
3444
 
+                       error = do_change_hat(hat_name, sd);
3445
 
+               } else {
3446
 
+                       /* Got here via changehat(NULL, magic)
3447
 
+                        *
3448
 
+                        * We used to simply update the magic cookie.
3449
 
+                        * That's an odd behaviour, so just do nothing.
3450
 
+                        */
3451
 
+               }
3452
 
+       } else {
3453
 
+               /*
3454
 
+                * child -- check to make sure magic is same as what was
3455
 
+                * passed when we switched into this profile,
3456
 
+                * Handle special casing of NULL magic which confines task
3457
 
+                * to subprofile and prohibits further changehats
3458
 
+                */
3459
 
+               if (hat_magic == sd->hat_magic && sd->hat_magic) {
3460
 
+                       if (!hat_name) {
3461
 
+                               /*
3462
 
+                                * Got here via changehat(NULL, magic)
3463
 
+                                * Return from subprofile, back to parent
3464
 
+                                */
3465
 
+                               aa_switch(sd, sd->active->parent);
3466
 
+
3467
 
+                               /* Reset hat_magic to zero.
3468
 
+                                * New value will be passed on next changehat
3469
 
+                                */
3470
 
+                               sd->hat_magic = 0;
3471
 
+                       } else {
3472
 
+                               /* change to another (sibling) profile */
3473
 
+                               error = do_change_hat(hat_name, sd);
3474
 
+                       }
3475
 
+               } else if (sd->hat_magic) {
3476
 
+                       AA_ERROR("KILLING process %s(%d) "
3477
 
+                                "Invalid change_hat() magic# 0x%x "
3478
 
+                                "(hatname %s profile %s active %s)\n",
3479
 
+                                current->comm, current->pid,
3480
 
+                                hat_magic,
3481
 
+                                hat_name ? hat_name : "NULL",
3482
 
+                                BASE_PROFILE(sd->active)->name,
3483
 
+                                sd->active->name);
3484
 
+
3485
 
+                       /* terminate current process */
3486
 
+                       (void)send_sig_info(SIGKILL, NULL, current);
3487
 
+               } else {        /* sd->hat_magic == NULL */
3488
 
+                       AA_ERROR("KILLING process %s(%d) "
3489
 
+                                "Task was confined to current subprofile "
3490
 
+                                "(profile %s active %s)\n",
3491
 
+                                current->comm, current->pid,
3492
 
+                                BASE_PROFILE(sd->active)->name,
3493
 
+                                sd->active->name);
3494
 
+
3495
 
+                       /* terminate current process */
3496
 
+                       (void)send_sig_info(SIGKILL, NULL, current);
3497
 
+               }
3498
 
+
3499
 
+       }
3500
 
+
3501
 
+out:
3502
 
+       return error;
3503
 
+}
3504
 
Index: b/security/apparmor/module_interface.c
3505
 
===================================================================
3506
 
--- /dev/null
3507
 
+++ b/security/apparmor/module_interface.c
3508
 
@@ -0,0 +1,717 @@
3509
 
+/*
3510
 
+ *     Copyright (C) 1998-2005 Novell/SUSE
3511
 
+ *
3512
 
+ *     This program is free software; you can redistribute it and/or
3513
 
+ *     modify it under the terms of the GNU General Public License as
3514
 
+ *     published by the Free Software Foundation, version 2 of the
3515
 
+ *     License.
3516
 
+ *
3517
 
+ *     AppArmor userspace policy interface
3518
 
+ */
3519
 
+
3520
 
+#include <asm/unaligned.h>
3521
 
+
3522
 
+#include "apparmor.h"
3523
 
+#include "inline.h"
3524
 
+#include "module_interface.h"
3525
 
+
3526
 
+/* aa_code defined in module_interface.h */
3527
 
+
3528
 
+const int aa_code_datasize[] = { 1, 2, 4, 8, 2, 2, 4, 0, 0, 0, 0, 0, 0 };
3529
 
+
3530
 
+struct aa_taskreplace_data {
3531
 
+       struct aa_profile *old_profile;
3532
 
+       struct aa_profile *new_profile;
3533
 
+};
3534
 
+
3535
 
+/**
3536
 
+ * free_aa_profile_rcu - rcu callback for free profiles
3537
 
+ * @head: rcu_head struct of the profile whose reference is being put.
3538
 
+ *
3539
 
+ * the rcu callback routine, which delays the freeing of a profile when
3540
 
+ * its last reference is put.
3541
 
+ */
3542
 
+static void free_aa_profile_rcu(struct rcu_head *head)
3543
 
+{
3544
 
+       struct aa_profile *p = container_of(head, struct aa_profile, rcu);
3545
 
+       free_aa_profile(p);
3546
 
+}
3547
 
+
3548
 
+/**
3549
 
+ * task_remove - remove profile from a task's subdomain
3550
 
+ * @sd: task's subdomain
3551
 
+ *
3552
 
+ * remove the active profile from a task's subdomain, switching the task
3553
 
+ * to an unconfined state.
3554
 
+ */
3555
 
+static inline void task_remove(struct subdomain *sd)
3556
 
+{
3557
 
+       /* spin_lock(&sd_lock) held here */
3558
 
+       AA_DEBUG("%s: removing profile from task %s(%d) profile %s active %s\n",
3559
 
+                __FUNCTION__,
3560
 
+                sd->task->comm,
3561
 
+                sd->task->pid,
3562
 
+                BASE_PROFILE(sd->active)->name,
3563
 
+                sd->active->name);
3564
 
+
3565
 
+       aa_switch_unconfined(sd);
3566
 
+}
3567
 
+
3568
 
+/** taskremove_iter - Iterator to unconfine subdomains which match cookie
3569
 
+ * @sd: subdomain to consider for profile removal
3570
 
+ * @cookie: pointer to the oldprofile which is being removed
3571
 
+ *
3572
 
+ * If the subdomain's active profile matches old_profile,  then call
3573
 
+ * task_remove() to remove the profile leaving the task (subdomain) unconfined.
3574
 
+ */
3575
 
+static int taskremove_iter(struct subdomain *sd, void *cookie)
3576
 
+{
3577
 
+       struct aa_profile *old_profile = (struct aa_profile *)cookie;
3578
 
+       unsigned long flags;
3579
 
+
3580
 
+       spin_lock_irqsave(&sd_lock, flags);
3581
 
+
3582
 
+       if (__aa_is_confined(sd) && BASE_PROFILE(sd->active) == old_profile) {
3583
 
+               task_remove(sd);
3584
 
+       }
3585
 
+
3586
 
+       spin_unlock_irqrestore(&sd_lock, flags);
3587
 
+
3588
 
+       return 0;
3589
 
+}
3590
 
+
3591
 
+/** task_replace - replace subdomain's current profile with a new profile
3592
 
+ * @sd: subdomain to replace the profile on
3593
 
+ * @new: new profile
3594
 
+ *
3595
 
+ * Replace a task's (subdomain's) active profile with a new profile.  If
3596
 
+ * task was in a hat then the new profile will also be in the equivalent
3597
 
+ * hat in the new profile if it exists.  If it doesn't exist the
3598
 
+ * task will be placed in the special null_profile state.
3599
 
+ */
3600
 
+static inline void task_replace(struct subdomain *sd, struct aa_profile *new)
3601
 
+{
3602
 
+       AA_DEBUG("%s: replacing profile for task %s(%d) "
3603
 
+                "profile=%s (%p) active=%s (%p)\n",
3604
 
+                __FUNCTION__,
3605
 
+                sd->task->comm, sd->task->pid,
3606
 
+                BASE_PROFILE(sd->active)->name, BASE_PROFILE(sd->active),
3607
 
+                sd->active->name, sd->active);
3608
 
+
3609
 
+       if (!sd->active)
3610
 
+               goto out;
3611
 
+
3612
 
+       if (IN_SUBPROFILE(sd->active)) {
3613
 
+               struct aa_profile *nactive;
3614
 
+
3615
 
+               /* The old profile was in a hat, check to see if the new
3616
 
+                * profile has an equivalent hat */
3617
 
+               nactive = __aa_find_profile(sd->active->name, &new->sub);
3618
 
+
3619
 
+               if (!nactive)
3620
 
+                       nactive = get_aa_profile(new->null_profile);
3621
 
+
3622
 
+               aa_switch(sd, nactive);
3623
 
+               put_aa_profile(nactive);
3624
 
+       } else {
3625
 
+               aa_switch(sd, new);
3626
 
+       }
3627
 
+
3628
 
+ out:
3629
 
+       return;
3630
 
+}
3631
 
+
3632
 
+/** taskreplace_iter - Iterator to replace a subdomain's profile
3633
 
+ * @sd: subdomain to consider for profile replacement
3634
 
+ * @cookie: pointer to the old profile which is being replaced.
3635
 
+ *
3636
 
+ * If the subdomain's active profile matches old_profile call
3637
 
+ * task_replace() to replace with the subdomain's active profile with
3638
 
+ * the new profile.
3639
 
+ */
3640
 
+static int taskreplace_iter(struct subdomain *sd, void *cookie)
3641
 
+{
3642
 
+       struct aa_taskreplace_data *data = (struct aa_taskreplace_data *)cookie;
3643
 
+       unsigned long flags;
3644
 
+
3645
 
+       spin_lock_irqsave(&sd_lock, flags);
3646
 
+
3647
 
+       if (__aa_is_confined(sd) &&
3648
 
+           BASE_PROFILE(sd->active) == data->old_profile)
3649
 
+               task_replace(sd, data->new_profile);
3650
 
+
3651
 
+       spin_unlock_irqrestore(&sd_lock, flags);
3652
 
+
3653
 
+       return 0;
3654
 
+}
3655
 
+
3656
 
+static inline int aa_inbounds(struct aa_ext *e, size_t size)
3657
 
+{
3658
 
+       return (e->pos + size <= e->end);
3659
 
+}
3660
 
+
3661
 
+/**
3662
 
+ * aa_convert - convert trailing values of serialized type codes
3663
 
+ * @code: type code
3664
 
+ * @dest: pointer to object to receive the converted value
3665
 
+ * @src:  pointer to value to convert
3666
 
+ *
3667
 
+ * for serialized type codes which have a trailing value, convert it
3668
 
+ * and place it in @dest.  If a code does not have a trailing value nop.
3669
 
+ */
3670
 
+static void aa_convert(enum aa_code code, void *dest, void *src)
3671
 
+{
3672
 
+       switch (code) {
3673
 
+       case AA_U8:
3674
 
+               *(u8 *)dest = *(u8 *) src;
3675
 
+               break;
3676
 
+       case AA_U16:
3677
 
+       case AA_NAME:
3678
 
+       case AA_DYN_STRING:
3679
 
+               *(u16 *)dest = le16_to_cpu(get_unaligned((u16 *)src));
3680
 
+               break;
3681
 
+       case AA_U32:
3682
 
+       case AA_BLOB_LOC:
3683
 
+       case AA_STATIC_BLOB:
3684
 
+               *(u32 *)dest = le32_to_cpu(get_unaligned((u32 *)src));
3685
 
+               break;
3686
 
+       case AA_U64:
3687
 
+               *(u64 *)dest = le64_to_cpu(get_unaligned((u64 *)src));
3688
 
+               break;
3689
 
+       default:
3690
 
+               /* nop - all other type codes do not have a trailing value */
3691
 
+               ;
3692
 
+       }
3693
 
+}
3694
 
+
3695
 
+/**
3696
 
+ * aa_is_X - check if the next element is of type X
3697
 
+ * @e: serialized data extent information
3698
 
+ * @code: type code
3699
 
+ * @data: object located at @e->pos (of type @code) is written into @data
3700
 
+ *        if @data is non-null.  if data is null it means skip this
3701
 
+ *        entry
3702
 
+ * check to see if the next element in the serialized data stream is of type
3703
 
+ * X and check that it is with in bounds, if so put the associated value in
3704
 
+ * @data.
3705
 
+ * return the size of bytes associated with the returned data
3706
 
+ *        for complex object like blob and string a pointer to the allocated
3707
 
+ *        data is returned in data, but the size of the blob or string is
3708
 
+ *        returned.
3709
 
+ */
3710
 
+static u32 aa_is_X(struct aa_ext *e, enum aa_code code, void *data)
3711
 
+{
3712
 
+       void *pos = e->pos;
3713
 
+       int ret = 0;
3714
 
+       if (!aa_inbounds(e, AA_CODE_BYTE + aa_code_datasize[code]))
3715
 
+               goto fail;
3716
 
+       if (code != *(u8 *)e->pos &&
3717
 
+           !(code == AA_BLOB_LOC && AA_STATIC_BLOB == *(u8 *)e->pos))
3718
 
+               goto out;
3719
 
+       e->pos += AA_CODE_BYTE;
3720
 
+       if (code == AA_NAME) {
3721
 
+               u16 size;
3722
 
+               /* name codes are followed by X bytes */
3723
 
+               size = le16_to_cpu(get_unaligned((u16 *)e->pos));
3724
 
+               if (!aa_inbounds(e, (size_t) size))
3725
 
+                       goto fail;
3726
 
+               if (data)
3727
 
+                       *(u16 *)data = size;
3728
 
+               e->pos += aa_code_datasize[code];
3729
 
+               ret = 1 + aa_code_datasize[code];
3730
 
+       } else if (code == AA_DYN_STRING) {
3731
 
+               u16 size;
3732
 
+               char *str;
3733
 
+               /* strings codes are followed by X bytes */
3734
 
+               size = le16_to_cpu(get_unaligned((u16 *)e->pos));
3735
 
+               e->pos += aa_code_datasize[code];
3736
 
+               if (!aa_inbounds(e, (size_t) size))
3737
 
+                       goto fail;
3738
 
+               if (data) {
3739
 
+                       * (char **)data = NULL;
3740
 
+                       str = kmalloc(size, GFP_KERNEL);
3741
 
+                       if (!str)
3742
 
+                               goto fail;
3743
 
+                       memcpy(str, e->pos, (size_t) size);
3744
 
+                       str[size-1] = '\0';
3745
 
+                       * (char **)data = str;
3746
 
+               }
3747
 
+               e->pos += size;
3748
 
+               ret = size;
3749
 
+
3750
 
+       } else if (code == AA_BLOB_LOC) {
3751
 
+               u32 size;
3752
 
+               /* blobs are followed by X bytes */
3753
 
+               size = le32_to_cpu(get_unaligned((u32 *)e->pos));
3754
 
+               e->pos += aa_code_datasize[AA_STATIC_BLOB];
3755
 
+               if (!aa_inbounds(e, (size_t) size))
3756
 
+                       goto fail;
3757
 
+               if (data) {
3758
 
+                       * (char **)data = e->pos;
3759
 
+               }
3760
 
+               e->pos += size;
3761
 
+               ret = size;
3762
 
+
3763
 
+       } else if (code == AA_STATIC_BLOB) {
3764
 
+               u32 size;
3765
 
+               /* blobs are followed by X bytes, that can be 2^32 */
3766
 
+               size = le32_to_cpu(get_unaligned((u32 *)e->pos));
3767
 
+               e->pos += aa_code_datasize[code];
3768
 
+               if (!aa_inbounds(e, (size_t) size))
3769
 
+                       goto fail;
3770
 
+               if (data)
3771
 
+                       memcpy(data, e->pos, (size_t) size);
3772
 
+               e->pos += size;
3773
 
+               ret = size;
3774
 
+       } else {
3775
 
+               if (data)
3776
 
+                       aa_convert(code, data, e->pos);
3777
 
+               e->pos += aa_code_datasize[code];
3778
 
+               ret = 1 + aa_code_datasize[code];
3779
 
+       }
3780
 
+out:
3781
 
+       return ret;
3782
 
+fail:
3783
 
+       e->pos = pos;
3784
 
+       return 0;
3785
 
+}
3786
 
+
3787
 
+/**
3788
 
+ * aa_is_nameX - check is the next element is of type X with a name of @name
3789
 
+ * @e: serialized data extent information
3790
 
+ * @code: type code
3791
 
+ * @data: location to store deserialized data if match isX criteria
3792
 
+ * @name: name to match to the serialized element.
3793
 
+ *
3794
 
+ * check that the next serialized data element is of type X and has a tag
3795
 
+ * name @name.  If the code matches and name (if specified) matches then
3796
 
+ * the packed data is unpacked into *data.  (Note for strings this is the
3797
 
+ * size, and the next data in the stream is the string data)
3798
 
+ * returns %0 if either match failes
3799
 
+ */
3800
 
+static int aa_is_nameX(struct aa_ext *e, enum aa_code code, void *data,
3801
 
+                      const char *name)
3802
 
+{
3803
 
+       void *pos = e->pos;
3804
 
+       u16 size;
3805
 
+       u32 ret;
3806
 
+       /* check for presence of a tagname, and if present name size
3807
 
+        * AA_NAME tag value is a u16 */
3808
 
+       if (aa_is_X(e, AA_NAME, &size)) {
3809
 
+               /* if a name is specified it must match. otherwise skip tag */
3810
 
+               if (name && ((strlen(name) != size-1) ||
3811
 
+                            strncmp(name, (char *)e->pos, (size_t)size-1)))
3812
 
+                       goto fail;
3813
 
+               e->pos += size;
3814
 
+       } else if (name) {
3815
 
+               goto fail;
3816
 
+       }
3817
 
+
3818
 
+       /* now check if data actually matches */
3819
 
+       ret = aa_is_X(e, code, data);
3820
 
+       if (!ret)
3821
 
+               goto fail;
3822
 
+       return ret;
3823
 
+
3824
 
+fail:
3825
 
+       e->pos = pos;
3826
 
+       return 0;
3827
 
+}
3828
 
+
3829
 
+/* macro to wrap error case to make a block of reads look nicer */
3830
 
+#define AA_READ_X(E, C, D, N) \
3831
 
+       do { \
3832
 
+               u32 __ret; \
3833
 
+               __ret = aa_is_nameX((E), (C), (D), (N)); \
3834
 
+               if (!__ret) \
3835
 
+                       goto fail; \
3836
 
+       } while (0)
3837
 
+
3838
 
+/**
3839
 
+ * aa_activate_net_entry - unpacked serialized net entries
3840
 
+ * @e: serialized data extent information
3841
 
+ *
3842
 
+ * Ignore/skips net entries if they are present in the serialized data
3843
 
+ * stream.  Network confinement rules are currently unsupported but some
3844
 
+ * user side tools can generate them so they are currently ignored.
3845
 
+ */
3846
 
+static inline int aa_activate_net_entry(struct aa_ext *e)
3847
 
+{
3848
 
+       AA_READ_X(e, AA_STRUCT, NULL, "ne");
3849
 
+       AA_READ_X(e, AA_U32, NULL, NULL);
3850
 
+       AA_READ_X(e, AA_U32, NULL, NULL);
3851
 
+       AA_READ_X(e, AA_U32, NULL, NULL);
3852
 
+       AA_READ_X(e, AA_U16, NULL, NULL);
3853
 
+       AA_READ_X(e, AA_U16, NULL, NULL);
3854
 
+       AA_READ_X(e, AA_U32, NULL, NULL);
3855
 
+       AA_READ_X(e, AA_U32, NULL, NULL);
3856
 
+       AA_READ_X(e, AA_U16, NULL, NULL);
3857
 
+       AA_READ_X(e, AA_U16, NULL, NULL);
3858
 
+       /* interface name is optional so just ignore return code */
3859
 
+       aa_is_nameX(e, AA_DYN_STRING, NULL, NULL);
3860
 
+       AA_READ_X(e, AA_STRUCTEND, NULL, NULL);
3861
 
+
3862
 
+       return 1;
3863
 
+fail:
3864
 
+       return 0;
3865
 
+}
3866
 
+
3867
 
+/**
3868
 
+ * aa_activate_dfa - unpack a file rule dfa
3869
 
+ * @e: serialized data extent information
3870
 
+ *
3871
 
+ * returns dfa or ERR_PTR
3872
 
+ */
3873
 
+struct aa_dfa *aa_activate_dfa(struct aa_ext *e)
3874
 
+{
3875
 
+       char *blob = NULL;
3876
 
+       size_t size, error = 0;
3877
 
+       struct aa_dfa *dfa = NULL;
3878
 
+
3879
 
+       size = aa_is_nameX(e, AA_BLOB_LOC, &blob, "aadfa");
3880
 
+       if (size) {
3881
 
+               dfa = aa_match_alloc();
3882
 
+               if (dfa) {
3883
 
+                       error = unpack_dfa(dfa, blob, size);
3884
 
+
3885
 
+                       if (!error)
3886
 
+                               error = verify_dfa(dfa);
3887
 
+               } else {
3888
 
+                       error = -ENOMEM;
3889
 
+               }
3890
 
+
3891
 
+               if (error) {
3892
 
+                       aa_match_free(dfa);
3893
 
+                       dfa = ERR_PTR(error);
3894
 
+               }
3895
 
+       }
3896
 
+
3897
 
+       return dfa;
3898
 
+}
3899
 
+
3900
 
+/**
3901
 
+ * aa_activate_profile - unpack a serialized profile
3902
 
+ * @e: serialized data extent information
3903
 
+ * @error: error code returned if unpacking fails
3904
 
+ */
3905
 
+static struct aa_profile *aa_activate_profile(struct aa_ext *e, ssize_t *error)
3906
 
+{
3907
 
+       struct aa_profile *profile = NULL;
3908
 
+       const char *rulename = "";
3909
 
+       const char *error_string = "Invalid Profile";
3910
 
+
3911
 
+       *error = -EPROTO;
3912
 
+
3913
 
+       profile = alloc_aa_profile();
3914
 
+       if (!profile) {
3915
 
+               error_string = "Could not allocate profile";
3916
 
+               *error = -ENOMEM;
3917
 
+               goto fail;
3918
 
+       }
3919
 
+
3920
 
+       /* check that we have the right struct being passed */
3921
 
+       AA_READ_X(e, AA_STRUCT, NULL, "profile");
3922
 
+       AA_READ_X(e, AA_DYN_STRING, &profile->name, NULL);
3923
 
+
3924
 
+       error_string = "Invalid flags";
3925
 
+       /* per profile debug flags (debug, complain, audit) */
3926
 
+       AA_READ_X(e, AA_STRUCT, NULL, "flags");
3927
 
+       AA_READ_X(e, AA_U32, &(profile->flags.debug), NULL);
3928
 
+       AA_READ_X(e, AA_U32, &(profile->flags.complain), NULL);
3929
 
+       AA_READ_X(e, AA_U32, &(profile->flags.audit), NULL);
3930
 
+       AA_READ_X(e, AA_STRUCTEND, NULL, NULL);
3931
 
+
3932
 
+       error_string = "Invalid capabilities";
3933
 
+       AA_READ_X(e, AA_U32, &(profile->capabilities), NULL);
3934
 
+
3935
 
+       /* get file rules */
3936
 
+       profile->file_rules = aa_activate_dfa(e);
3937
 
+       if (IS_ERR(profile->file_rules)) {
3938
 
+               error_string = "Invalid file rule dfa\n";
3939
 
+               *error = PTR_ERR(profile->file_rules);
3940
 
+               profile->file_rules = NULL;
3941
 
+               goto fail;
3942
 
+       }
3943
 
+
3944
 
+       /* get the net entries */
3945
 
+       if (aa_is_nameX(e, AA_LIST, NULL, "net")) {
3946
 
+               error_string = "Invalid net entry";
3947
 
+               while (!aa_is_nameX(e, AA_LISTEND, NULL, NULL)) {
3948
 
+                       if (!aa_activate_net_entry(e))
3949
 
+                               goto fail;
3950
 
+               }
3951
 
+       }
3952
 
+       rulename = "";
3953
 
+
3954
 
+       /* get subprofiles */
3955
 
+       if (aa_is_nameX(e, AA_LIST, NULL, "hats")) {
3956
 
+               error_string = "Invalid profile hat";
3957
 
+               while (!aa_is_nameX(e, AA_LISTEND, NULL, NULL)) {
3958
 
+                       struct aa_profile *subprofile;
3959
 
+                       subprofile = aa_activate_profile(e, error);
3960
 
+                       if (!subprofile)
3961
 
+                               goto fail;
3962
 
+                       subprofile->parent = profile;
3963
 
+                       list_add(&subprofile->list, &profile->sub);
3964
 
+               }
3965
 
+       }
3966
 
+
3967
 
+       error_string = "Invalid end of profile";
3968
 
+       AA_READ_X(e, AA_STRUCTEND, NULL, NULL);
3969
 
+
3970
 
+       return profile;
3971
 
+
3972
 
+fail:
3973
 
+       AA_WARN("%s: %s %s in profile %s\n", INTERFACE_ID, rulename,
3974
 
+               error_string, profile && profile->name ? profile->name
3975
 
+               : "unknown");
3976
 
+
3977
 
+       if (profile) {
3978
 
+               free_aa_profile(profile);
3979
 
+               profile = NULL;
3980
 
+       }
3981
 
+
3982
 
+       return NULL;
3983
 
+}
3984
 
+
3985
 
+/**
3986
 
+ * aa_activate_top_profile - unpack a serialized base profile
3987
 
+ * @e: serialized data extent information
3988
 
+ * @error: error code returned if unpacking fails
3989
 
+ *
3990
 
+ * check interface version unpack a profile and all its hats and patch
3991
 
+ * in any extra information that the profile needs.
3992
 
+ */
3993
 
+static void *aa_activate_top_profile(struct aa_ext *e, ssize_t *error)
3994
 
+{
3995
 
+       struct aa_profile *profile = NULL;
3996
 
+
3997
 
+       /* get the interface version */
3998
 
+       if (!aa_is_nameX(e, AA_U32, &e->version, "version")) {
3999
 
+               AA_WARN("%s: version missing\n", INTERFACE_ID);
4000
 
+               *error = -EPROTONOSUPPORT;
4001
 
+               goto fail;
4002
 
+       }
4003
 
+
4004
 
+       /* check that the interface version is currently supported */
4005
 
+       if (e->version != 3) {
4006
 
+               AA_WARN("%s: unsupported interface version (%d)\n",
4007
 
+                       INTERFACE_ID, e->version);
4008
 
+               *error = -EPROTONOSUPPORT;
4009
 
+               goto fail;
4010
 
+       }
4011
 
+
4012
 
+       profile = aa_activate_profile(e, error);
4013
 
+       if (!profile)
4014
 
+               goto fail;
4015
 
+
4016
 
+       if (!list_empty(&profile->sub) || profile->flags.complain) {
4017
 
+               if (attach_nullprofile(profile))
4018
 
+                       goto fail;
4019
 
+       }
4020
 
+       return profile;
4021
 
+
4022
 
+fail:
4023
 
+       free_aa_profile(profile);
4024
 
+       return NULL;
4025
 
+}
4026
 
+
4027
 
+/**
4028
 
+ * aa_file_prof_add - add a new profile to the profile list
4029
 
+ * @data: serialized data stream
4030
 
+ * @size: size of the serialized data stream
4031
 
+ *
4032
 
+ * unpack and add a profile to the profile list.  Return %0 or error
4033
 
+ */
4034
 
+ssize_t aa_file_prof_add(void *data, size_t size)
4035
 
+{
4036
 
+       struct aa_profile *profile = NULL;
4037
 
+
4038
 
+       struct aa_ext e = {
4039
 
+               .start = data,
4040
 
+               .end = data + size,
4041
 
+               .pos = data
4042
 
+       };
4043
 
+       ssize_t error;
4044
 
+
4045
 
+       profile = aa_activate_top_profile(&e, &error);
4046
 
+       if (!profile) {
4047
 
+               AA_DEBUG("couldn't activate profile\n");
4048
 
+               goto out;
4049
 
+       }
4050
 
+
4051
 
+       /* aa_activate_top_profile allocates profile with initial 1 count
4052
 
+        * aa_profilelist_add transfers that ref to profile list without
4053
 
+        * further incrementing
4054
 
+        */
4055
 
+       if (aa_profilelist_add(profile)) {
4056
 
+               error = size;
4057
 
+       } else {
4058
 
+               AA_WARN("trying to add profile (%s) that already exists.\n",
4059
 
+                       profile->name);
4060
 
+               put_aa_profile(profile);
4061
 
+               error = -EEXIST;
4062
 
+       }
4063
 
+
4064
 
+out:
4065
 
+       return error;
4066
 
+}
4067
 
+
4068
 
+/**
4069
 
+ * aa_file_prof_repl - replace a profile on the profile list
4070
 
+ * @udata: serialized data stream
4071
 
+ * @size: size of the serialized data stream
4072
 
+ *
4073
 
+ * unpack and replace a profile on the profile list and uses of that profile
4074
 
+ * by any subdomain.  If the profile does not exist on the profile list
4075
 
+ * it is added.  Return %0 or error.
4076
 
+ */
4077
 
+ssize_t aa_file_prof_repl(void *udata, size_t size)
4078
 
+{
4079
 
+       struct aa_taskreplace_data data;
4080
 
+       struct aa_ext e = {
4081
 
+               .start = udata,
4082
 
+               .end = udata + size,
4083
 
+               .pos = udata
4084
 
+       };
4085
 
+
4086
 
+       ssize_t error;
4087
 
+
4088
 
+       data.new_profile = aa_activate_top_profile(&e, &error);
4089
 
+       if (!data.new_profile) {
4090
 
+               AA_DEBUG("couldn't activate profile\n");
4091
 
+               goto out;
4092
 
+       }
4093
 
+
4094
 
+       /* Refcount on data.new_profile is 1 (aa_activate_top_profile).
4095
 
+        *
4096
 
+        * This reference will be inherited by aa_profilelist_replace for it's
4097
 
+        * profile list reference but this isn't sufficient.
4098
 
+        *
4099
 
+        * Another replace (*for-same-profile*) may race us here.
4100
 
+        * Task A calls aa_profilelist_replace(new_profile) and is interrupted.
4101
 
+        * Task B old_profile = aa_profilelist_replace() will return task A's
4102
 
+        * new_profile with the count of 1.  If task B proceeeds to put this
4103
 
+        * profile it will dissapear from under task A.
4104
 
+        *
4105
 
+        * Grab extra reference on new_profile to prevent this
4106
 
+        */
4107
 
+
4108
 
+       get_aa_profile(data.new_profile);
4109
 
+
4110
 
+       data.old_profile = aa_profilelist_replace(data.new_profile);
4111
 
+
4112
 
+       /* If there was an old profile,  find all currently executing tasks
4113
 
+        * using this profile and replace the old profile with the new.
4114
 
+        */
4115
 
+       if (data.old_profile) {
4116
 
+               AA_DEBUG("%s: try to replace profile (%p)%s\n",
4117
 
+                        __FUNCTION__,
4118
 
+                        data.old_profile,
4119
 
+                        data.old_profile->name);
4120
 
+
4121
 
+               aa_subdomainlist_iterate(taskreplace_iter, (void *)&data);
4122
 
+
4123
 
+               /* it's off global list, and we are done replacing */
4124
 
+               put_aa_profile(data.old_profile);
4125
 
+       }
4126
 
+
4127
 
+       /* release extra reference obtained above (race) */
4128
 
+       put_aa_profile(data.new_profile);
4129
 
+
4130
 
+       error = size;
4131
 
+
4132
 
+out:
4133
 
+       return error;
4134
 
+}
4135
 
+
4136
 
+/**
4137
 
+ * aa_file_prof_remove - remove a profile from the system
4138
 
+ * @name: name of the profile to remove
4139
 
+ * @size: size of the name
4140
 
+ *
4141
 
+ * remove a profile from the profile list and all subdomain references
4142
 
+ * to said profile.  Return %0 on success, else error.
4143
 
+ */
4144
 
+ssize_t aa_file_prof_remove(const char *name, size_t size)
4145
 
+{
4146
 
+       struct aa_profile *old_profile;
4147
 
+
4148
 
+       /* if the old profile exists it will be removed from the list and
4149
 
+        * a reference is returned.
4150
 
+        */
4151
 
+       old_profile = aa_profilelist_remove(name);
4152
 
+
4153
 
+       if (old_profile) {
4154
 
+               /* remove profile from any tasks using it */
4155
 
+               aa_subdomainlist_iterate(taskremove_iter, (void *)old_profile);
4156
 
+
4157
 
+               /* drop reference obtained by aa_profilelist_remove */
4158
 
+               put_aa_profile(old_profile);
4159
 
+       } else {
4160
 
+               AA_WARN("%s: trying to remove profile (%s) that "
4161
 
+                       "doesn't exist - skipping.\n", __FUNCTION__, name);
4162
 
+               return -ENOENT;
4163
 
+       }
4164
 
+
4165
 
+       return size;
4166
 
+}
4167
 
+
4168
 
+/**
4169
 
+ * free_aa_profile_kref - free aa_profile by kref (called by put_aa_profile)
4170
 
+ * @kr: kref callback for freeing of a profile
4171
 
+ */
4172
 
+void free_aa_profile_kref(struct kref *kr)
4173
 
+{
4174
 
+       struct aa_profile *p=container_of(kr, struct aa_profile, count);
4175
 
+
4176
 
+       call_rcu(&p->rcu, free_aa_profile_rcu);
4177
 
+}
4178
 
+
4179
 
+/**
4180
 
+ * free_aa_profile - free aa_profile structure
4181
 
+ * @profile: the profile to free
4182
 
+ *
4183
 
+ * free a profile, its file entries hats and null_profile.  All references
4184
 
+ * to the profile, its hats and null_profile must have been put.
4185
 
+ * If the profile was referenced by a subdomain free_aa_profile should be
4186
 
+ * called from an rcu callback routine.
4187
 
+ */
4188
 
+void free_aa_profile(struct aa_profile *profile)
4189
 
+{
4190
 
+       struct aa_profile *p, *ptmp;
4191
 
+
4192
 
+       AA_DEBUG("%s(%p)\n", __FUNCTION__, profile);
4193
 
+
4194
 
+       if (!profile)
4195
 
+               return;
4196
 
+
4197
 
+       /* profile is still on global profile list -- invalid */
4198
 
+       if (!list_empty(&profile->list)) {
4199
 
+               AA_ERROR("%s: internal error, "
4200
 
+                        "profile '%s' still on global list\n",
4201
 
+                        __FUNCTION__,
4202
 
+                        profile->name);
4203
 
+               BUG();
4204
 
+       }
4205
 
+
4206
 
+       aa_match_free(profile->file_rules);
4207
 
+
4208
 
+       /* use free_aa_profile instead of put_aa_profile to destroy the
4209
 
+        * null_profile, because the null_profile use the same reference
4210
 
+        * counting as hats, ie. the count goes to the base profile.
4211
 
+        */
4212
 
+       free_aa_profile(profile->null_profile);
4213
 
+       list_for_each_entry_safe(p, ptmp, &profile->sub, list) {
4214
 
+               list_del_init(&p->list);
4215
 
+               p->parent = NULL;
4216
 
+               put_aa_profile(p);
4217
 
+       }
4218
 
+
4219
 
+       if (profile->name) {
4220
 
+               AA_DEBUG("%s: %s\n", __FUNCTION__, profile->name);
4221
 
+               kfree(profile->name);
4222
 
+       }
4223
 
+
4224
 
+       kfree(profile);
4225
 
+}
4226
 
Index: b/security/apparmor/module_interface.h
4227
 
===================================================================
4228
 
--- /dev/null
4229
 
+++ b/security/apparmor/module_interface.h
4230
 
@@ -0,0 +1,38 @@
4231
 
+#ifndef __MODULEINTERFACE_H
4232
 
+#define __MODULEINTERFACE_H
4233
 
+
4234
 
+/* Codes of the types of basic structures that are understood */
4235
 
+#define AA_CODE_BYTE (sizeof(u8))
4236
 
+#define INTERFACE_ID "INTERFACE"
4237
 
+
4238
 
+#define APPARMOR_INTERFACE_VERSION 2
4239
 
+
4240
 
+enum aa_code {
4241
 
+       AA_U8,
4242
 
+       AA_U16,
4243
 
+       AA_U32,
4244
 
+       AA_U64,
4245
 
+       AA_NAME,        /* same as string except it is items name */
4246
 
+       AA_DYN_STRING,
4247
 
+       AA_STATIC_BLOB,
4248
 
+       AA_STRUCT,
4249
 
+       AA_STRUCTEND,
4250
 
+       AA_LIST,
4251
 
+       AA_LISTEND,
4252
 
+       AA_OFFSET,
4253
 
+       AA_BLOB_LOC,
4254
 
+       AA_BAD
4255
 
+};
4256
 
+
4257
 
+/* aa_ext tracks the kernel buffer and read position in it.  The interface
4258
 
+ * data is copied into a kernel buffer in apparmorfs and then handed off to
4259
 
+ * the activate routines.
4260
 
+ */
4261
 
+struct aa_ext {
4262
 
+       void *start;
4263
 
+       void *end;
4264
 
+       void *pos;      /* pointer to current position in the buffer */
4265
 
+       u32 version;
4266
 
+};
4267
 
+
4268
 
+#endif /* __MODULEINTERFACE_H */
4269
 
Index: b/security/apparmor/procattr.c
4270
 
===================================================================
4271
 
--- /dev/null
4272
 
+++ b/security/apparmor/procattr.c
4273
 
@@ -0,0 +1,332 @@
4274
 
+/*
4275
 
+ *     Copyright (C) 2005 Novell/SUSE
4276
 
+ *
4277
 
+ *     This program is free software; you can redistribute it and/or
4278
 
+ *     modify it under the terms of the GNU General Public License as
4279
 
+ *     published by the Free Software Foundation, version 2 of the
4280
 
+ *     License.
4281
 
+ *
4282
 
+ *     AppArmor /proc/pid/attr handling
4283
 
+ */
4284
 
+
4285
 
+/* for isspace */
4286
 
+#include <linux/ctype.h>
4287
 
+
4288
 
+#include "apparmor.h"
4289
 
+#include "inline.h"
4290
 
+
4291
 
+size_t aa_getprocattr(struct aa_profile *active, char *str, size_t size)
4292
 
+{
4293
 
+       int error = -EACCES;    /* default to a perm denied */
4294
 
+       size_t len;
4295
 
+
4296
 
+       if (active) {
4297
 
+               size_t lena, lenm, lenp = 0;
4298
 
+               const char *enforce_str = " (enforce)";
4299
 
+               const char *complain_str = " (complain)";
4300
 
+               const char *mode_str =
4301
 
+                       PROFILE_COMPLAIN(active) ? complain_str : enforce_str;
4302
 
+
4303
 
+               lenm = strlen(mode_str);
4304
 
+
4305
 
+               lena = strlen(active->name);
4306
 
+
4307
 
+               len = lena;
4308
 
+               if (IN_SUBPROFILE(active)) {
4309
 
+                       lenp = strlen(BASE_PROFILE(active)->name);
4310
 
+                       len += (lenp + 1);      /* +1 for ^ */
4311
 
+               }
4312
 
+               /* DONT null terminate strings we output via proc */
4313
 
+               len += (lenm + 1);      /* for \n */
4314
 
+
4315
 
+               if (len <= size) {
4316
 
+                       if (lenp) {
4317
 
+                               memcpy(str, BASE_PROFILE(active)->name,
4318
 
+                                      lenp);
4319
 
+                               str += lenp;
4320
 
+                               *str++ = '^';
4321
 
+                       }
4322
 
+
4323
 
+                       memcpy(str, active->name, lena);
4324
 
+                       str += lena;
4325
 
+                       memcpy(str, mode_str, lenm);
4326
 
+                       str += lenm;
4327
 
+                       *str++ = '\n';
4328
 
+                       error = len;
4329
 
+               } else if (size == 0) {
4330
 
+                       error = len;
4331
 
+               } else {
4332
 
+                       error = -ERANGE;
4333
 
+               }
4334
 
+       } else {
4335
 
+               const char *unconstrained_str = "unconstrained\n";
4336
 
+               len = strlen(unconstrained_str);
4337
 
+
4338
 
+               /* DONT null terminate strings we output via proc */
4339
 
+               if (len <= size) {
4340
 
+                       memcpy(str, unconstrained_str, len);
4341
 
+                       error = len;
4342
 
+               } else if (size == 0) {
4343
 
+                       error = len;
4344
 
+               } else {
4345
 
+                       error = -ERANGE;
4346
 
+               }
4347
 
+       }
4348
 
+
4349
 
+       return error;
4350
 
+
4351
 
+}
4352
 
+
4353
 
+int aa_setprocattr_changehat(char *hatinfo, size_t infosize)
4354
 
+{
4355
 
+       int error = -EINVAL;
4356
 
+       char *token = NULL, *hat, *smagic, *tmp;
4357
 
+       u32 magic;
4358
 
+       int rc, len, consumed;
4359
 
+       unsigned long flags;
4360
 
+
4361
 
+       AA_DEBUG("%s: %p %zd\n", __FUNCTION__, hatinfo, infosize);
4362
 
+
4363
 
+       /* strip leading white space */
4364
 
+       while (infosize && isspace(*hatinfo)) {
4365
 
+               hatinfo++;
4366
 
+               infosize--;
4367
 
+       }
4368
 
+
4369
 
+       if (infosize == 0)
4370
 
+               goto out;
4371
 
+
4372
 
+       /*
4373
 
+        * Copy string to a new buffer so we can play with it
4374
 
+        * It may be zero terminated but we add a trailing 0
4375
 
+        * for 100% safety
4376
 
+        */
4377
 
+       token = kmalloc(infosize + 1, GFP_KERNEL);
4378
 
+
4379
 
+       if (!token) {
4380
 
+               error = -ENOMEM;
4381
 
+               goto out;
4382
 
+       }
4383
 
+
4384
 
+       memcpy(token, hatinfo, infosize);
4385
 
+       token[infosize] = 0;
4386
 
+
4387
 
+       /* error is INVAL until we have at least parsed something */
4388
 
+       error = -EINVAL;
4389
 
+
4390
 
+       tmp = token;
4391
 
+       while (*tmp && *tmp != '^') {
4392
 
+               tmp++;
4393
 
+       }
4394
 
+
4395
 
+       if (!*tmp || tmp == token) {
4396
 
+               AA_WARN("%s: Invalid input '%s'\n", __FUNCTION__, token);
4397
 
+               goto out;
4398
 
+       }
4399
 
+
4400
 
+       /* split magic and hat into two strings */
4401
 
+       *tmp = 0;
4402
 
+       smagic = token;
4403
 
+
4404
 
+       /*
4405
 
+        * Initially set consumed=strlen(magic), as if sscanf
4406
 
+        * consumes all input via the %x it will not process the %n
4407
 
+        * directive. Otherwise, if sscanf does not consume all the
4408
 
+        * input it will process the %n and update consumed.
4409
 
+        */
4410
 
+       consumed = len = strlen(smagic);
4411
 
+
4412
 
+       rc = sscanf(smagic, "%x%n", &magic, &consumed);
4413
 
+
4414
 
+       if (rc != 1 || consumed != len) {
4415
 
+               AA_WARN("%s: Invalid hex magic %s\n",
4416
 
+                       __FUNCTION__,
4417
 
+                       smagic);
4418
 
+               goto out;
4419
 
+       }
4420
 
+
4421
 
+       hat = tmp + 1;
4422
 
+
4423
 
+       if (!*hat)
4424
 
+               hat = NULL;
4425
 
+
4426
 
+       if (!hat && !magic) {
4427
 
+               AA_WARN("%s: Invalid input, NULL hat and NULL magic\n",
4428
 
+                       __FUNCTION__);
4429
 
+               goto out;
4430
 
+       }
4431
 
+
4432
 
+       AA_DEBUG("%s: Magic 0x%x Hat '%s'\n",
4433
 
+                __FUNCTION__, magic, hat ? hat : NULL);
4434
 
+
4435
 
+       spin_lock_irqsave(&sd_lock, flags);
4436
 
+       error = aa_change_hat(hat, magic);
4437
 
+       spin_unlock_irqrestore(&sd_lock, flags);
4438
 
+
4439
 
+out:
4440
 
+       if (token) {
4441
 
+               memset(token, 0, infosize);
4442
 
+               kfree(token);
4443
 
+       }
4444
 
+
4445
 
+       return error;
4446
 
+}
4447
 
+
4448
 
+int aa_setprocattr_setprofile(struct task_struct *p, char *profilename,
4449
 
+                             size_t profilesize)
4450
 
+{
4451
 
+       int error = -EINVAL;
4452
 
+       struct aa_profile *profile = NULL;
4453
 
+       struct subdomain *sd;
4454
 
+       char *name = NULL;
4455
 
+       unsigned long flags;
4456
 
+
4457
 
+       AA_DEBUG("%s: current %s(%d)\n",
4458
 
+                __FUNCTION__, current->comm, current->pid);
4459
 
+
4460
 
+       /* strip leading white space */
4461
 
+       while (profilesize && isspace(*profilename)) {
4462
 
+               profilename++;
4463
 
+               profilesize--;
4464
 
+       }
4465
 
+
4466
 
+       if (profilesize == 0)
4467
 
+               goto out;
4468
 
+
4469
 
+       /*
4470
 
+        * Copy string to a new buffer so we guarantee it is zero
4471
 
+        * terminated
4472
 
+        */
4473
 
+       name = kmalloc(profilesize + 1, GFP_KERNEL);
4474
 
+
4475
 
+       if (!name) {
4476
 
+               error = -ENOMEM;
4477
 
+               goto out;
4478
 
+       }
4479
 
+
4480
 
+       strncpy(name, profilename, profilesize);
4481
 
+       name[profilesize] = 0;
4482
 
+
4483
 
+ repeat:
4484
 
+       if (strcmp(name, "unconstrained") != 0) {
4485
 
+               profile = aa_profilelist_find(name);
4486
 
+               if (!profile) {
4487
 
+                       AA_WARN("%s: Unable to switch task %s(%d) to profile"
4488
 
+                               "'%s'. No such profile.\n",
4489
 
+                               __FUNCTION__,
4490
 
+                               p->comm, p->pid,
4491
 
+                               name);
4492
 
+
4493
 
+                       error = -EINVAL;
4494
 
+                       goto out;
4495
 
+               }
4496
 
+       }
4497
 
+
4498
 
+       spin_lock_irqsave(&sd_lock, flags);
4499
 
+
4500
 
+       sd = AA_SUBDOMAIN(p->security);
4501
 
+
4502
 
+       /* switch to unconstrained */
4503
 
+       if (!profile) {
4504
 
+               if (__aa_is_confined(sd)) {
4505
 
+                       AA_WARN("%s: Unconstraining task %s(%d) "
4506
 
+                               "profile %s active %s\n",
4507
 
+                               __FUNCTION__,
4508
 
+                               p->comm, p->pid,
4509
 
+                               BASE_PROFILE(sd->active)->name,
4510
 
+                               sd->active->name);
4511
 
+
4512
 
+                       aa_switch_unconfined(sd);
4513
 
+               } else {
4514
 
+                       AA_WARN("%s: task %s(%d) "
4515
 
+                               "is already unconstrained\n",
4516
 
+                               __FUNCTION__, p->comm, p->pid);
4517
 
+               }
4518
 
+       } else {
4519
 
+               if (!sd) {
4520
 
+                       /* this task was created before module was
4521
 
+                        * loaded, allocate a subdomain
4522
 
+                        */
4523
 
+                       AA_WARN("%s: task %s(%d) has no subdomain\n",
4524
 
+                               __FUNCTION__, p->comm, p->pid);
4525
 
+
4526
 
+                       /* unlock so we can safely GFP_KERNEL */
4527
 
+                       spin_unlock_irqrestore(&sd_lock, flags);
4528
 
+
4529
 
+                       sd = alloc_subdomain(p);
4530
 
+                       if (!sd) {
4531
 
+                               AA_WARN("%s: Unable to allocate subdomain for "
4532
 
+                                       "task %s(%d). Cannot confine task to "
4533
 
+                                       "profile %s\n",
4534
 
+                                       __FUNCTION__,
4535
 
+                                       p->comm, p->pid,
4536
 
+                                       name);
4537
 
+
4538
 
+                               error = -ENOMEM;
4539
 
+                               put_aa_profile(profile);
4540
 
+
4541
 
+                               goto out;
4542
 
+                       }
4543
 
+
4544
 
+                       spin_lock_irqsave(&sd_lock, flags);
4545
 
+                       if (!AA_SUBDOMAIN(p->security)) {
4546
 
+                               p->security = sd;
4547
 
+                       } else { /* race */
4548
 
+                               free_subdomain(sd);
4549
 
+                               sd = AA_SUBDOMAIN(p->security);
4550
 
+                       }
4551
 
+               }
4552
 
+
4553
 
+               /* ensure the profile hasn't been replaced */
4554
 
+
4555
 
+               if (unlikely(profile->isstale)) {
4556
 
+                       WARN_ON(profile == null_complain_profile);
4557
 
+
4558
 
+                       /* drop refcnt obtained from earlier get_aa_profile */
4559
 
+                       put_aa_profile(profile);
4560
 
+                       profile = aa_profilelist_find(name);
4561
 
+
4562
 
+                       if (!profile) {
4563
 
+                               /* Race, profile was removed. */
4564
 
+                               spin_unlock_irqrestore(&sd_lock, flags);
4565
 
+                               goto repeat;
4566
 
+                       }
4567
 
+               }
4568
 
+
4569
 
+               /* we do not do a normal task replace since we are not
4570
 
+                * replacing with the same profile.
4571
 
+                * If existing process is in a hat, it will be moved
4572
 
+                * into the new parent profile, even if this new
4573
 
+                * profile has a identical named hat.
4574
 
+                */
4575
 
+
4576
 
+               AA_WARN("%s: Switching task %s(%d) "
4577
 
+                       "profile %s active %s to new profile %s\n",
4578
 
+                       __FUNCTION__,
4579
 
+                       p->comm, p->pid,
4580
 
+                       sd->active ? BASE_PROFILE(sd->active)->name :
4581
 
+                               "unconstrained",
4582
 
+                       sd->active ? sd->active->name : "unconstrained",
4583
 
+                       name);
4584
 
+
4585
 
+               aa_switch(sd, profile);
4586
 
+
4587
 
+               put_aa_profile(profile); /* drop ref we obtained above
4588
 
+                                        * from aa_profilelist_find
4589
 
+                                        */
4590
 
+
4591
 
+               /* Reset magic in case we were in a subhat before
4592
 
+                * This is the only case where we zero the magic after
4593
 
+                * calling aa_switch
4594
 
+                */
4595
 
+               sd->hat_magic = 0;
4596
 
+       }
4597
 
+
4598
 
+       spin_unlock_irqrestore(&sd_lock, flags);
4599
 
+
4600
 
+       error = 0;
4601
 
+out:
4602
 
+       kfree(name);
4603
 
+
4604
 
+       return error;
4605
 
+}
4606
 
Index: b/security/apparmor/shared.h
4607
 
===================================================================
4608
 
--- /dev/null
4609
 
+++ b/security/apparmor/shared.h
4610
 
@@ -0,0 +1,51 @@
4611
 
+/*
4612
 
+ *     Copyright (C) 2000, 2001, 2004, 2005 Novell/SUSE
4613
 
+ *
4614
 
+ *     Immunix AppArmor LSM
4615
 
+ *
4616
 
+ *     This program is free software; you can redistribute it and/or
4617
 
+ *     modify it under the terms of the GNU General Public License as
4618
 
+ *     published by the Free Software Foundation, version 2 of the
4619
 
+ *     License.
4620
 
+ */
4621
 
+
4622
 
+#ifndef _SHARED_H
4623
 
+#define _SHARED_H
4624
 
+
4625
 
+/* start of system offsets */
4626
 
+#define POS_AA_FILE_MIN                        0
4627
 
+#define POS_AA_MAY_EXEC                        POS_AA_FILE_MIN
4628
 
+#define POS_AA_MAY_WRITE               (POS_AA_MAY_EXEC + 1)
4629
 
+#define POS_AA_MAY_READ                        (POS_AA_MAY_WRITE + 1)
4630
 
+#define POS_AA_MAY_APPEND              (POS_AA_MAY_READ + 1)
4631
 
+/* end of system offsets */
4632
 
+
4633
 
+#define POS_AA_MAY_LINK                        (POS_AA_MAY_APPEND + 1)
4634
 
+#define POS_AA_EXEC_INHERIT            (POS_AA_MAY_LINK + 1)
4635
 
+#define POS_AA_EXEC_UNCONSTRAINED      (POS_AA_EXEC_INHERIT + 1)
4636
 
+#define POS_AA_EXEC_PROFILE            (POS_AA_EXEC_UNCONSTRAINED + 1)
4637
 
+#define POS_AA_EXEC_MMAP               (POS_AA_EXEC_PROFILE + 1)
4638
 
+#define POS_AA_EXEC_UNSAFE             (POS_AA_EXEC_MMAP + 1)
4639
 
+#define POS_AA_FILE_MAX                        POS_AA_EXEC_UNSAFE
4640
 
+
4641
 
+/* Invalid perm permission */
4642
 
+#define POS_AA_INVALID_POS             31
4643
 
+
4644
 
+/* Modeled after MAY_READ, MAY_WRITE, MAY_EXEC def'ns */
4645
 
+#define AA_MAY_EXEC                    (0x01 << POS_AA_MAY_EXEC)
4646
 
+#define AA_MAY_WRITE                   (0x01 << POS_AA_MAY_WRITE)
4647
 
+#define AA_MAY_READ                    (0x01 << POS_AA_MAY_READ)
4648
 
+#define AA_MAY_LINK                    (0x01 << POS_AA_MAY_LINK)
4649
 
+#define AA_EXEC_INHERIT                        (0x01 << POS_AA_EXEC_INHERIT)
4650
 
+#define AA_EXEC_UNCONSTRAINED          (0x01 << POS_AA_EXEC_UNCONSTRAINED)
4651
 
+#define AA_EXEC_PROFILE                        (0x01 << POS_AA_EXEC_PROFILE)
4652
 
+#define AA_EXEC_MMAP                   (0x01 << POS_AA_EXEC_MMAP)
4653
 
+#define AA_EXEC_UNSAFE                 (0x01 << POS_AA_EXEC_UNSAFE)
4654
 
+#define AA_INVALID_PERM                        (0x01 << POS_AA_INVALID_POS)
4655
 
+
4656
 
+#define AA_EXEC_MODIFIERS              (AA_EXEC_INHERIT | \
4657
 
+                                        AA_EXEC_UNCONSTRAINED | \
4658
 
+                                        AA_EXEC_PROFILE)
4659
 
+#define AA_VALID_PERM_MASK             ((1 << (POS_AA_FILE_MAX + 1)) - 1)
4660
 
+
4661
 
+#endif /* _SHARED_H */
4662
 
Index: b/security/apparmor/match.c
4663
 
===================================================================
4664
 
--- /dev/null
4665
 
+++ b/security/apparmor/match.c
4666
 
@@ -0,0 +1,274 @@
4667
 
+/*
4668
 
+ *     Copyright (C) 2002-2005 Novell/SUSE
4669
 
+ *
4670
 
+ *     This program is free software; you can redistribute it and/or
4671
 
+ *     modify it under the terms of the GNU General Public License as
4672
 
+ *     published by the Free Software Foundation, version 2 of the
4673
 
+ *     License.
4674
 
+ *
4675
 
+ *     http://forge.novell.com/modules/xfmod/project/?apparmor
4676
 
+ *
4677
 
+ *     AppArmor aa_match submodule (w/ pattern expansion).
4678
 
+ *
4679
 
+ */
4680
 
+
4681
 
+#include <asm/unaligned.h>
4682
 
+#include <linux/module.h>
4683
 
+#include "match.h"
4684
 
+
4685
 
+static const char *features="pattern=aadfa";
4686
 
+
4687
 
+static struct table_header *unpack_table(void *blob, size_t bsize)
4688
 
+{
4689
 
+       struct table_header *table = NULL;
4690
 
+       struct table_header th;
4691
 
+       size_t tsize;
4692
 
+
4693
 
+       if (bsize < sizeof(struct table_header))
4694
 
+               goto out;
4695
 
+
4696
 
+       th.td_id = ntohs(get_unaligned((u16 *) (blob)));
4697
 
+       th.td_flags = ntohs(get_unaligned((u16 *) (blob + 2)));
4698
 
+       th.td_lolen = ntohl(get_unaligned((u32 *) (blob + 8)));
4699
 
+       blob += sizeof(struct table_header);
4700
 
+
4701
 
+       if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
4702
 
+               th.td_flags == YYTD_DATA8))
4703
 
+               goto out;
4704
 
+
4705
 
+       tsize = table_size(th.td_lolen, th.td_flags);
4706
 
+       if (bsize < tsize)
4707
 
+               goto out;
4708
 
+
4709
 
+       table = kmalloc(tsize, GFP_KERNEL);
4710
 
+       if (table) {
4711
 
+               *table = th;
4712
 
+               if (th.td_flags == YYTD_DATA8)
4713
 
+                       UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
4714
 
+                                    u8, ntohb);
4715
 
+               else if (th.td_flags == YYTD_DATA16)
4716
 
+                       UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
4717
 
+                                    u16, ntohs);
4718
 
+               else
4719
 
+                       UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
4720
 
+                                    u32, ntohl);
4721
 
+       }
4722
 
+
4723
 
+out:
4724
 
+       return table;
4725
 
+}
4726
 
+
4727
 
+int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size)
4728
 
+{
4729
 
+       int i;
4730
 
+       int error = -ENOMEM;
4731
 
+
4732
 
+       /* get dfa table set header */
4733
 
+       if (size < sizeof(struct table_set_header))
4734
 
+               goto fail;
4735
 
+
4736
 
+       dfa->th.th_magic = ntohl(get_unaligned((u32 *) (blob + 0)));
4737
 
+       dfa->th.th_hsize = ntohl(get_unaligned((u32 *) (blob + 4)));
4738
 
+       dfa->th.th_ssize = ntohl(get_unaligned((u32 *) (blob + 8)));
4739
 
+       dfa->th.th_flags = ntohs(get_unaligned((u16 *) (blob + 12)));
4740
 
+
4741
 
+       if (dfa->th.th_magic != YYTH_MAGIC)
4742
 
+               goto fail;
4743
 
+
4744
 
+       if (size < dfa->th.th_hsize)
4745
 
+               goto fail;
4746
 
+
4747
 
+       blob += dfa->th.th_hsize;
4748
 
+       size -= dfa->th.th_hsize;
4749
 
+
4750
 
+       while (size > 0) {
4751
 
+               struct table_header *table;
4752
 
+               table = unpack_table(blob, size);
4753
 
+               if (!table)
4754
 
+                       goto fail;
4755
 
+
4756
 
+               switch(table->td_id) {
4757
 
+               case YYTD_ID_ACCEPT:
4758
 
+               case YYTD_ID_BASE:
4759
 
+                       dfa->tables[table->td_id - 1] = table;
4760
 
+                       if (table->td_flags != YYTD_DATA32)
4761
 
+                               goto fail_proto;
4762
 
+                       break;
4763
 
+               case YYTD_ID_DEF:
4764
 
+               case YYTD_ID_NXT:
4765
 
+               case YYTD_ID_CHK:
4766
 
+                       dfa->tables[table->td_id - 1] = table;
4767
 
+                       if (table->td_flags != YYTD_DATA16)
4768
 
+                               goto fail_proto;
4769
 
+                       break;
4770
 
+               case YYTD_ID_EC:
4771
 
+                       dfa->tables[table->td_id - 1] = table;
4772
 
+                       if (table->td_flags != YYTD_DATA8)
4773
 
+                               goto fail_proto;
4774
 
+                       break;
4775
 
+               default:
4776
 
+                       kfree(table);
4777
 
+                       goto fail_proto;
4778
 
+               }
4779
 
+
4780
 
+               blob += table_size(table->td_lolen, table->td_flags);
4781
 
+               size -= table_size(table->td_lolen, table->td_flags);
4782
 
+       }
4783
 
+
4784
 
+       error = 0;
4785
 
+
4786
 
+       return error;
4787
 
+
4788
 
+fail_proto:
4789
 
+       error = -EPROTO;
4790
 
+fail:
4791
 
+       for (i = 0; i < YYTD_ID_NXT; i++) {
4792
 
+               if (dfa->tables[i]) {
4793
 
+                       kfree(dfa->tables[i]);
4794
 
+                       dfa->tables[i] = NULL;
4795
 
+               }
4796
 
+       }
4797
 
+       return error;
4798
 
+}
4799
 
+
4800
 
+/**
4801
 
+ * verify_dfa - verify that all the transitions and states in the dfa tables
4802
 
+ *              are in bounds.
4803
 
+ * @dfa: dfa to test
4804
 
+ *
4805
 
+ * assumes dfa has gone through the verification done by unpacking
4806
 
+ */
4807
 
+int verify_dfa(struct aa_dfa *dfa)
4808
 
+{
4809
 
+       size_t i, state_count, trans_count;
4810
 
+       int error = -EPROTO;
4811
 
+
4812
 
+       /* check that required tables exist */
4813
 
+       if (!(dfa->tables[YYTD_ID_ACCEPT -1 ] &&
4814
 
+             dfa->tables[YYTD_ID_DEF - 1] &&
4815
 
+             dfa->tables[YYTD_ID_BASE - 1] &&
4816
 
+             dfa->tables[YYTD_ID_NXT - 1] &&
4817
 
+             dfa->tables[YYTD_ID_CHK - 1]))
4818
 
+               goto out;
4819
 
+
4820
 
+       /* accept.size == default.size == base.size */
4821
 
+       state_count = dfa->tables[YYTD_ID_BASE - 1]->td_lolen;
4822
 
+       if (!(state_count == dfa->tables[YYTD_ID_DEF - 1]->td_lolen &&
4823
 
+             state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen))
4824
 
+               goto out;
4825
 
+
4826
 
+       /* next.size == chk.size */
4827
 
+       trans_count = dfa->tables[YYTD_ID_NXT - 1]->td_lolen;
4828
 
+       if (trans_count != dfa->tables[YYTD_ID_CHK - 1]->td_lolen)
4829
 
+               goto out;
4830
 
+
4831
 
+       /* if equivalence classes then its table must be 256 */
4832
 
+       if (dfa->tables[YYTD_ID_EC - 1] &&
4833
 
+           dfa->tables[YYTD_ID_EC - 1]->td_lolen != 256)
4834
 
+               goto out;
4835
 
+
4836
 
+       for (i = 0; i < state_count; i++) {
4837
 
+               if (DEFAULT_TABLE(dfa)[i] >= state_count)
4838
 
+                       goto out;
4839
 
+               if (BASE_TABLE(dfa)[i] >= trans_count + 256)
4840
 
+                       goto out;
4841
 
+       }
4842
 
+
4843
 
+       for (i = 0; i < trans_count ; i++) {
4844
 
+               if (NEXT_TABLE(dfa)[i] >= state_count)
4845
 
+                       goto out;
4846
 
+               if (CHECK_TABLE(dfa)[i] >= state_count)
4847
 
+                       goto out;
4848
 
+       }
4849
 
+
4850
 
+       error = 0;
4851
 
+out:
4852
 
+       return error;
4853
 
+}
4854
 
+
4855
 
+struct aa_dfa *aa_match_alloc(void)
4856
 
+{
4857
 
+       return kzalloc(sizeof(struct aa_dfa), GFP_KERNEL);
4858
 
+}
4859
 
+
4860
 
+void aa_match_free(struct aa_dfa *dfa)
4861
 
+{
4862
 
+       if (dfa) {
4863
 
+               int i;
4864
 
+               for (i = 0; i < YYTD_ID_NXT; i++) {
4865
 
+                       kfree(dfa->tables[i]);
4866
 
+               }
4867
 
+       }
4868
 
+       kfree(dfa);
4869
 
+}
4870
 
+
4871
 
+const char *aa_match_features(void)
4872
 
+{
4873
 
+       return features;
4874
 
+}
4875
 
+
4876
 
+/**
4877
 
+ * aadfa_label - return the permissions associated with @state
4878
 
+ * @dfa: dfa to get state permission from
4879
 
+ * @state: state in the dfa for which to get a label
4880
 
+ *
4881
 
+ * Assumes that state is a valid state of the dfa
4882
 
+ *
4883
 
+ * Returns the label associated with @state.  0 indicates the state
4884
 
+ * is no-accepting/provides no permissions.
4885
 
+ */
4886
 
+inline unsigned int aadfa_label(struct aa_dfa *dfa, int state)
4887
 
+{
4888
 
+       return ACCEPT_TABLE(dfa)[state];
4889
 
+}
4890
 
+
4891
 
+/**
4892
 
+ * aa_dfa_match - match @path against @dfa starting in @state
4893
 
+ * @dfa: the dfa to match @path against
4894
 
+ * @state: the state to start matching in
4895
 
+ * @path: the path to match against the dfa
4896
 
+ *
4897
 
+ * aa_dfa_match will match the full path length and return the state it
4898
 
+ * finished matching in.  The final state returned can be used to
4899
 
+ * lookup the accepting label or as a starting point to continue matching
4900
 
+ * with a new string if the path has been broken into multiple components.
4901
 
+ */
4902
 
+inline unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int state,
4903
 
+                               const char *path)
4904
 
+{
4905
 
+       u8 *s = (u8 *) path;
4906
 
+       u16 *def = DEFAULT_TABLE(dfa);
4907
 
+       u32 *base = BASE_TABLE(dfa);
4908
 
+       u16 *next = NEXT_TABLE(dfa);
4909
 
+       u16 *check = CHECK_TABLE(dfa);
4910
 
+       unsigned int pos;
4911
 
+
4912
 
+       /* current state is <state>, matching character *s */
4913
 
+       if (dfa->tables[YYTD_ID_EC - 1]) {
4914
 
+               u8 *equiv = EQUIV_TABLE(dfa);
4915
 
+               for ( ; *s; ++s) {
4916
 
+                       pos = base[state] + equiv[*s];
4917
 
+                       if (check[pos] == state)
4918
 
+                               state = next[pos];
4919
 
+                       else
4920
 
+                               state = def[state];
4921
 
+               }
4922
 
+       } else {
4923
 
+               for ( ; *s; ++s) {
4924
 
+                       pos = base[state] + *s;
4925
 
+                       if (check[pos] == state)
4926
 
+                               state = next[pos];
4927
 
+                       else
4928
 
+                               state = def[state];
4929
 
+               }
4930
 
+       }
4931
 
+       return state;
4932
 
+}
4933
 
+
4934
 
+unsigned int aa_match(struct aa_dfa *dfa, const char *pathname)
4935
 
+{
4936
 
+       if (dfa)
4937
 
+               return aadfa_label(dfa, aa_dfa_match(dfa, 1, pathname));
4938
 
+
4939
 
+       return 0;
4940
 
+}
4941
 
Index: b/security/apparmor/match.h
4942
 
===================================================================
4943
 
--- /dev/null
4944
 
+++ b/security/apparmor/match.h
4945
 
@@ -0,0 +1,80 @@
4946
 
+/*
4947
 
+ *     Copyright (C) 2002-2005 Novell/SUSE
4948
 
+ *
4949
 
+ *     This program is free software; you can redistribute it and/or
4950
 
+ *     modify it under the terms of the GNU General Public License as
4951
 
+ *     published by the Free Software Foundation, version 2 of the
4952
 
+ *     License.
4953
 
+ *
4954
 
+ *     AppArmor submodule (match) prototypes
4955
 
+ */
4956
 
+
4957
 
+#ifndef __MATCH_H
4958
 
+#define __MATCH_H
4959
 
+
4960
 
+#define YYTH_MAGIC     0x1B5E783D
4961
 
+
4962
 
+struct table_set_header {
4963
 
+       u32             th_magic;       /* TH_MAGIC */
4964
 
+       u32             th_hsize;
4965
 
+       u32             th_ssize;
4966
 
+       u16             th_flags;
4967
 
+       char            th_version[];
4968
 
+};
4969
 
+
4970
 
+#define        YYTD_ID_ACCEPT  1 /* 1 */
4971
 
+#define YYTD_ID_BASE   2 /* 2 */
4972
 
+#define YYTD_ID_CHK    3 /* 3 */
4973
 
+#define YYTD_ID_DEF    4 /* 4 */
4974
 
+#define YYTD_ID_EC     5 /* 5 */
4975
 
+#define YYTD_ID_NXT    6 /* 8 */
4976
 
+#define YYTD_ID_META   7 /* 6 */
4977
 
+
4978
 
+#define YYTD_DATA8     1
4979
 
+#define YYTD_DATA16    2
4980
 
+#define YYTD_DATA32    4
4981
 
+
4982
 
+struct table_header {
4983
 
+       u16             td_id;
4984
 
+       u16             td_flags;
4985
 
+       u32             td_hilen;
4986
 
+       u32             td_lolen;
4987
 
+       char            td_data[];
4988
 
+};
4989
 
+
4990
 
+#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF - 1]->td_data))
4991
 
+#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE - 1]->td_data))
4992
 
+#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT - 1]->td_data))
4993
 
+#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK - 1]->td_data))
4994
 
+#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC - 1]->td_data))
4995
 
+#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT - 1]->td_data))
4996
 
+
4997
 
+struct aa_dfa {
4998
 
+       struct table_header *tables[YYTD_ID_NXT];
4999
 
+
5000
 
+       struct table_set_header th;
5001
 
+};
5002
 
+
5003
 
+#define ntohb(X) (X)
5004
 
+
5005
 
+#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
5006
 
+       do { \
5007
 
+               typeof(LEN) __i; \
5008
 
+               TYPE *__t = (TYPE *) TABLE; \
5009
 
+               TYPE *__b = (TYPE *) BLOB; \
5010
 
+               for (__i = 0; __i < LEN; __i++) { \
5011
 
+                       __t[__i] = NTOHX(__b[__i]); \
5012
 
+               } \
5013
 
+       } while (0)
5014
 
+
5015
 
+static inline size_t pad64(size_t i)
5016
 
+{
5017
 
+       return (i + (size_t)7) & ~(size_t)7;
5018
 
+}
5019
 
+
5020
 
+static inline size_t table_size(size_t len, size_t el_size)
5021
 
+{
5022
 
+       return pad64(sizeof(struct table_header) + len * el_size);
5023
 
+}
5024
 
+
5025
 
+#endif /* __MATCH_H */