1
Index: b/security/apparmor/Kconfig
2
===================================================================
4
+++ b/security/apparmor/Kconfig
6
+config SECURITY_APPARMOR
7
+ tristate "AppArmor support"
8
+ depends on SECURITY!=n
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
===================================================================
18
+++ b/security/apparmor/Makefile
20
+# Makefile for AppArmor Linux Security Module
22
+obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
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
===================================================================
29
+++ b/security/apparmor/apparmor.h
32
+ * Copyright (C) 1998-2005 Novell/SUSE
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
39
+ * AppArmor internal prototypes
45
+#include <linux/fs.h> /* Include for defn of iattr */
46
+#include <linux/binfmts.h> /* defn of linux_binprm */
47
+#include <linux/rcupdate.h>
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;
59
+static inline int mediated_filesystem(struct inode *inode)
61
+ return !(inode->i_sb->s_flags & MS_NOUSER);
64
+#define PROFILE_COMPLAIN(_profile) \
65
+ (apparmor_complain == 1 || ((_profile) && (_profile)->flags.complain))
67
+#define SUBDOMAIN_COMPLAIN(_sd) \
68
+ (apparmor_complain == 1 || \
69
+ ((_sd) && (_sd)->active && (_sd)->active->flags.complain))
71
+#define PROFILE_AUDIT(_profile) \
72
+ (apparmor_audit == 1 || ((_profile) && (_profile)->flags.audit))
74
+#define SUBDOMAIN_AUDIT(_sd) \
75
+ (apparmor_audit == 1 || \
76
+ ((_sd) && (_sd)->active && (_sd)->active->flags.audit))
79
+ * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
80
+ * which is not related to profile accesses.
83
+#define AA_DEBUG(fmt, args...) \
85
+ if (apparmor_debug) \
86
+ printk(KERN_DEBUG "AppArmor: " fmt, ##args); \
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)
92
+/* basic AppArmor data structures */
100
+#define AA_SECURE_EXEC_NEEDED 0x00000001
102
+#define AA_EXEC_MODIFIER_MASK(mask) ((mask) & AA_EXEC_MODIFIERS)
103
+#define AA_EXEC_MASK(mask) ((mask) & (AA_EXEC_MODIFIERS | AA_EXEC_UNSAFE))
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
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
123
+ struct aa_profile *parent;
126
+ struct aa_dfa *file_rules;
128
+ struct list_head list;
129
+ struct list_head sub;
130
+ struct flagval flags;
131
+ struct aa_profile *null_profile;
134
+ kernel_cap_t capabilities;
136
+ struct rcu_head rcu;
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
148
+ * Contains the tasks current active profile (which could change due to
149
+ * change_hat). Plus the hat_magic needed during change_hat.
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).
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;
161
+typedef int (*aa_iter) (struct subdomain *, void *);
163
+#define AA_SUBDOMAIN(sec) ((struct subdomain*)(sec))
164
+#define AA_PROFILE(sec) ((struct aa_profile*)(sec))
166
+/* Lock protecting access to 'struct subdomain' accesses */
167
+extern spinlock_t sd_lock;
169
+extern struct aa_profile *null_complain_profile;
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.
177
+ unsigned short type, flags;
178
+ unsigned int result;
182
+ const char *operation;
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
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 */
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"
215
+#define LOG_HINT(p, gfp, hint, fmt, args...) \
217
+ aa_audit_message(p, gfp, 0, \
218
+ "LOGPROF-HINT " hint " " fmt, ##args);\
221
+#define BASE_PROFILE(p) ((p)->parent ? (p)->parent : (p))
222
+#define IN_SUBPROFILE(p) ((p)->parent)
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,
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);
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);
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);
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);
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);
282
+extern int create_apparmorfs(void);
283
+extern void destroy_apparmorfs(void);
285
+/* capabilities.c */
286
+extern const char *capability_to_name(unsigned int cap);
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);
296
+#endif /* __APPARMOR_H */
297
Index: b/security/apparmor/apparmorfs.c
298
===================================================================
300
+++ b/security/apparmor/apparmorfs.c
303
+ * Copyright (C) 2005 Novell/SUSE
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
310
+ * AppArmor filesystem (part of securityfs)
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>
319
+#include "apparmor.h"
322
+#define SECFS_AA "apparmor"
323
+static struct dentry *aa_fs_dentry = NULL;
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);
330
+static struct file_operations apparmorfs_profiles_fops = {
331
+ .open = aa_prof_open,
333
+ .llseek = seq_lseek,
334
+ .release = aa_prof_release,
338
+static ssize_t aa_matching_read(struct file *file, char __user *buf,
339
+ size_t size, loff_t *ppos);
341
+static struct file_operations apparmorfs_matching_fops = {
342
+ .read = aa_matching_read,
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);
354
+static struct file_operations apparmorfs_profile_load = {
355
+ .write = aa_profile_load
358
+static struct file_operations apparmorfs_profile_replace = {
359
+ .write = aa_profile_replace
362
+static struct file_operations apparmorfs_profile_remove = {
363
+ .write = aa_profile_remove
368
+static u64 aa_control_get(void *data);
369
+static void aa_control_set(void *data, u64 val);
371
+DEFINE_SIMPLE_ATTRIBUTE(apparmorfs_control_fops, aa_control_get,
372
+ aa_control_set, "%lld\n");
376
+/* table of static entries */
378
+static struct root_entry {
382
+ struct file_operations *fops;
385
+ /* internal fields */
386
+ struct dentry *dentry;
388
+} root_entries[] = {
389
+ /* our root, normally /sys/kernel/security/apparmor */
390
+ {SECFS_AA, S_IFDIR, 0550}, /* DO NOT EDIT/MOVE */
392
+ /* interface for obtaining list of profiles currently loaded */
393
+ {"profiles", S_IFREG, 0440, &apparmorfs_profiles_fops,
396
+ /* interface for obtaining matching features supported */
397
+ {"matching", S_IFREG, 0440, &apparmorfs_matching_fops,
400
+ /* interface for loading/removing/replacing profiles */
401
+ {".load", S_IFREG, 0640, &apparmorfs_profile_load,
403
+ {".replace", S_IFREG, 0640, &apparmorfs_profile_replace,
405
+ {".remove", S_IFREG, 0640, &apparmorfs_profile_remove,
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,
414
+ {"debug", S_IFREG, 0640, &apparmorfs_control_fops,
416
+ {"logsyscall", S_IFREG, 0640, &apparmorfs_control_fops,
417
+ &apparmor_logsyscall},
418
+ {NULL, S_IFDIR, 0},
424
+#define AA_FS_DENTRY root_entries[0].dentry
426
+static const unsigned int num_entries =
427
+ sizeof(root_entries) / sizeof(struct root_entry);
431
+static int aa_prof_open(struct inode *inode, struct file *file)
433
+ return seq_open(file, &apparmorfs_profiles_op);
437
+static int aa_prof_release(struct inode *inode, struct file *file)
439
+ return seq_release(inode, file);
442
+static ssize_t aa_matching_read(struct file *file, char __user *buf,
443
+ size_t size, loff_t *ppos)
445
+ const char *matching = aa_match_features();
447
+ return simple_read_from_buffer(buf, size, ppos, matching,
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)
455
+ struct aa_profile *active;
459
+ /* only writes from pos 0, that is complete writes */
460
+ data = ERR_PTR(-ESPIPE);
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.
469
+ active = get_activeptr_rcu();
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);
476
+ data = ERR_PTR(-EPERM);
481
+ data = vmalloc(alloc_size);
482
+ if (data == NULL) {
483
+ data = ERR_PTR(-ENOMEM);
487
+ if (copy_from_user(data, userbuf, copy_size)) {
489
+ data = ERR_PTR(-EFAULT);
497
+static ssize_t aa_profile_load(struct file *f, const char __user *buf,
498
+ size_t size, loff_t *pos)
503
+ data = aa_simple_write_to_buffer(buf, size, size, pos, "load");
505
+ if (!IS_ERR(data)) {
506
+ error = aa_file_prof_add(data, size);
509
+ error = PTR_ERR(data);
515
+static ssize_t aa_profile_replace(struct file *f, const char __user *buf,
516
+ size_t size, loff_t *pos)
521
+ data = aa_simple_write_to_buffer(buf, size, size, pos, "replacement");
523
+ if (!IS_ERR(data)) {
524
+ error = aa_file_prof_repl(data, size);
527
+ error = PTR_ERR(data);
533
+static ssize_t aa_profile_remove(struct file *f, const char __user *buf,
534
+ size_t size, loff_t *pos)
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
542
+ data = aa_simple_write_to_buffer(buf, size+1, size, pos, "removal");
544
+ if (!IS_ERR(data)) {
546
+ error = aa_file_prof_remove(data, size);
549
+ error = PTR_ERR(data);
555
+static u64 aa_control_get(void *data)
557
+ return *(int *)data;
560
+static void aa_control_set(void *data, u64 val)
565
+ *(int*)data = (int)val;
568
+static void clear_apparmorfs(void)
572
+ for (i=0; i < num_entries;i++) {
573
+ unsigned int index;
575
+ if (root_entries[i].mode == S_IFDIR) {
576
+ if (root_entries[i].name)
577
+ /* defer dir free till all sub-entries freed */
580
+ /* cleanup parent */
581
+ index = root_entries[i].parent_index;
586
+ if (root_entries[index].dentry) {
587
+ securityfs_remove(root_entries[index].dentry);
589
+ AA_DEBUG("%s: deleted apparmorfs entry name=%s "
592
+ root_entries[index].name,
593
+ root_entries[index].dentry);
595
+ root_entries[index].dentry = NULL;
596
+ root_entries[index].parent_index = 0;
601
+static int populate_apparmorfs(struct dentry *root)
603
+ unsigned int i, parent_index, depth;
605
+ for (i = 0; i < num_entries; i++) {
606
+ root_entries[i].dentry = NULL;
607
+ root_entries[i].parent_index = 0;
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",
620
+ /* 2. Build back pointers */
624
+ for (i = 1; i < num_entries; i++) {
625
+ root_entries[i].parent_index = parent_index;
627
+ if (root_entries[i].name &&
628
+ root_entries[i].mode == S_IFDIR) {
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)",
635
+ root_entries[i].mode,
636
+ root_entries[i].parent_index);
641
+ parent_index = root_entries[parent_index].parent_index;
646
+ AA_ERROR("%s: root_entry table not correctly terminated\n",
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,
658
+ if (IS_ERR(root_entries[0].dentry))
661
+ AA_DEBUG("%s: created securityfs/apparmor [dentry=%p]\n",
662
+ __FUNCTION__, root_entries[0].dentry);
665
+ /* 4. create remaining nodes */
666
+ for (i = 1; i < num_entries; i++) {
667
+ struct dentry *parent;
669
+ struct file_operations *fops = NULL;
671
+ /* end of directory ? */
672
+ if (!root_entries[i].name)
675
+ parent = root_entries[root_entries[i].parent_index].dentry;
677
+ if (root_entries[i].mode != S_IFDIR) {
678
+ data = root_entries[i].data;
679
+ fops = root_entries[i].fops;
682
+ root_entries[i].dentry = securityfs_create_file(
683
+ root_entries[i].name,
684
+ root_entries[i].mode |
685
+ root_entries[i].access,
690
+ if (IS_ERR(root_entries[i].dentry))
691
+ goto cleanup_error;
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);
703
+ clear_apparmorfs();
709
+int create_apparmorfs(void)
713
+ if (AA_FS_DENTRY) {
715
+ AA_ERROR("%s: AppArmor securityfs already exists\n",
718
+ error = populate_apparmorfs(aa_fs_dentry);
720
+ AA_ERROR("%s: Error populating AppArmor securityfs\n",
728
+void destroy_apparmorfs(void)
731
+ clear_apparmorfs();
733
Index: b/security/apparmor/capabilities.c
734
===================================================================
736
+++ b/security/apparmor/capabilities.c
739
+ * Copyright (C) 2005 Novell/SUSE
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
746
+ * AppArmor capability definitions
749
+#include "apparmor.h"
751
+static const char *cap_names[] = {
762
+ "net_bind_service",
783
+const char *capability_to_name(unsigned int cap)
787
+ name = (cap < (sizeof(cap_names) / sizeof(char *))
788
+ ? cap_names[cap] : "invalid-capability");
792
Index: b/security/apparmor/inline.h
793
===================================================================
795
+++ b/security/apparmor/inline.h
798
+ * Copyright (C) 2005 Novell/SUSE
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
809
+#include <linux/sched.h>
811
+static inline int __aa_is_confined(struct subdomain *sd)
813
+ return (sd && sd->active);
818
+ * Determine whether current task contains a valid profile (confined).
819
+ * Return %1 if confined, %0 otherwise.
821
+static inline int aa_is_confined(void)
823
+ struct subdomain *sd = AA_SUBDOMAIN(current->security);
824
+ return __aa_is_confined(sd);
827
+static inline int __aa_sub_defined(struct subdomain *sd)
829
+ return __aa_is_confined(sd) && !list_empty(&BASE_PROFILE(sd->active)->sub);
833
+ * aa_sub_defined - check to see if current task has any subprofiles
834
+ * Return 1 if true, 0 otherwise
836
+static inline int aa_sub_defined(void)
838
+ struct subdomain *sd = AA_SUBDOMAIN(current->security);
839
+ return __aa_sub_defined(sd);
843
+ * get_aa_profile - increment refcount on profile @p
846
+static inline struct aa_profile *get_aa_profile(struct aa_profile *p)
849
+ kref_get(&(BASE_PROFILE(p)->count));
855
+ * put_aa_profile - decrement refcount on profile @p
858
+static inline void put_aa_profile(struct aa_profile *p)
861
+ kref_put(&BASE_PROFILE(p)->count, free_aa_profile_kref);
865
+ * get_task_activeptr_rcu - get pointer to @tsk's active profile.
866
+ * @tsk: task to get active profile from
868
+ * Requires rcu_read_lock is held
870
+static inline struct aa_profile *get_task_activeptr_rcu(struct task_struct *tsk)
872
+ struct subdomain *sd = AA_SUBDOMAIN(tsk->security);
873
+ struct aa_profile *active = NULL;
876
+ active = (struct aa_profile *) rcu_dereference(sd->active);
882
+ * get_activeptr_rcu - get pointer to current task's active profile
883
+ * Requires rcu_read_lock is held
885
+static inline struct aa_profile *get_activeptr_rcu(void)
887
+ return get_task_activeptr_rcu(current);
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
894
+static inline struct aa_profile *get_task_active_aa_profile(struct task_struct *tsk)
896
+ struct aa_profile *active;
899
+ active = get_aa_profile(get_task_activeptr_rcu(tsk));
906
+ * get_active_aa_profile - get a reference to the current tasks active profile
908
+static inline struct aa_profile *get_active_aa_profile(void)
910
+ return get_task_active_aa_profile(current);
914
+ * aa_switch - change subdomain to use a new profile
915
+ * @sd: subdomain to switch the active profile on
916
+ * @newactive: new active profile
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
925
+static inline void aa_switch(struct subdomain *sd, struct aa_profile *newactive)
927
+ struct aa_profile *oldactive = sd->active;
930
+ rcu_assign_pointer(sd->active, get_aa_profile(newactive));
931
+ put_aa_profile(oldactive);
935
+ * aa_switch_unconfined - change subdomain to be unconfined (no profile)
936
+ * @sd: subdomain to switch
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.
942
+static inline void aa_switch_unconfined(struct subdomain *sd)
944
+ aa_switch(sd, NULL);
946
+ /* reset magic in case we were in a subhat before */
951
+ * alloc_subdomain - allocate a new subdomain
952
+ * @tsk: task struct
954
+ * Allocate a new subdomain including a backpointer to it's referring task.
956
+static inline struct subdomain *alloc_subdomain(struct task_struct *tsk)
958
+ struct subdomain *sd;
960
+ sd = kzalloc(sizeof(struct subdomain), GFP_KERNEL);
964
+ /* back pointer to task */
967
+ /* any readers of the list must make sure that they can handle
968
+ * case where sd->active is not yet set (null)
970
+ aa_subdomainlist_add(sd);
977
+ * free_subdomain - Free a subdomain previously allocated by alloc_subdomain
980
+static inline void free_subdomain(struct subdomain *sd)
982
+ aa_subdomainlist_remove(sd);
987
+ * alloc_aa_profile - Allocate, initialize and return a new zeroed profile.
988
+ * Returns NULL on failure.
990
+static inline struct aa_profile *alloc_aa_profile(void)
992
+ struct aa_profile *profile;
994
+ profile = (struct aa_profile *)kzalloc(sizeof(struct aa_profile),
996
+ AA_DEBUG("%s(%p)\n", __FUNCTION__, profile);
998
+ INIT_LIST_HEAD(&profile->list);
999
+ INIT_LIST_HEAD(&profile->sub);
1000
+ INIT_RCU_HEAD(&profile->rcu);
1001
+ kref_init(&profile->count);
1008
+ * @name: name to release.
1010
+ * Release space (free_page) allocated to hold pathname
1011
+ * name may be NULL (checked for by free_page)
1013
+static inline void aa_put_name(const char *name)
1015
+ free_page((unsigned long)name);
1018
+/** __aa_find_profile
1019
+ * @name: name of profile to find
1020
+ * @head: list to search
1022
+ * Return reference counted copy of profile. NULL if not found
1023
+ * Caller must hold any necessary locks
1025
+static inline struct aa_profile *__aa_find_profile(const char *name,
1026
+ struct list_head *head)
1028
+ struct aa_profile *p;
1030
+ if (!name || !head)
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);
1040
+ AA_DEBUG("%s: skipping %s\n", __FUNCTION__, p->name);
1045
+#endif /* __INLINE_H__ */
1046
Index: b/security/apparmor/list.c
1047
===================================================================
1049
+++ b/security/apparmor/list.c
1052
+ * Copyright (C) 1998-2005 Novell/SUSE
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
1059
+ * AppArmor Profile List Management
1062
+#include <linux/seq_file.h>
1063
+#include "apparmor.h"
1064
+#include "inline.h"
1066
+/* list of all profiles and lock */
1067
+static LIST_HEAD(profile_list);
1068
+static rwlock_t profile_lock = RW_LOCK_UNLOCKED;
1070
+/* list of all subdomains and lock */
1071
+static LIST_HEAD(subdomain_list);
1072
+static rwlock_t subdomain_lock = RW_LOCK_UNLOCKED;
1075
+ * aa_profilelist_find
1076
+ * @name: profile name (program name)
1078
+ * Search the profile list for profile @name. Return refcounted profile on
1079
+ * success, NULL on failure.
1081
+struct aa_profile *aa_profilelist_find(const char *name)
1083
+ struct aa_profile *p = NULL;
1085
+ read_lock(&profile_lock);
1086
+ p = __aa_find_profile(name, &profile_list);
1087
+ read_unlock(&profile_lock);
1093
+ * aa_profilelist_add - add new profile to list
1094
+ * @profile: new profile to add to list
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.
1100
+ * Return %1 on success, %0 on failure (already exists)
1102
+int aa_profilelist_add(struct aa_profile *profile)
1104
+ struct aa_profile *old_profile;
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);
1117
+ list_add(&profile->list, &profile_list);
1120
+ write_unlock(&profile_lock);
1125
+ * aa_profilelist_remove - remove a profile from the list by name
1126
+ * @name: name of profile to be removed
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
1132
+struct aa_profile *aa_profilelist_remove(const char *name)
1134
+ struct aa_profile *profile = NULL;
1135
+ struct aa_profile *p, *tmp;
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 */
1150
+ write_unlock(&profile_lock);
1157
+ * aa_profilelist_replace - replace a profile on the list
1158
+ * @profile: new profile
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().
1164
+ * This is an atomic list operation. Returns the old profile (which is still
1165
+ * refcounted) if there was one, or NULL.
1167
+struct aa_profile *aa_profilelist_replace(struct aa_profile *profile)
1169
+ struct aa_profile *oldprofile;
1171
+ write_lock(&profile_lock);
1172
+ oldprofile = __aa_find_profile(profile->name, &profile_list);
1174
+ list_del_init(&oldprofile->list);
1175
+ /* mark old profile as stale */
1176
+ oldprofile->isstale = 1;
1178
+ /* __aa_find_profile incremented count, so adjust down */
1179
+ put_aa_profile(oldprofile);
1182
+ list_add(&profile->list, &profile_list);
1183
+ write_unlock(&profile_lock);
1185
+ return oldprofile;
1189
+ * aa_profilelist_release - Remove all profiles from profile_list
1191
+void aa_profilelist_release(void)
1193
+ struct aa_profile *p, *tmp;
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);
1200
+ write_unlock(&profile_lock);
1204
+ * aa_subdomainlist_add - Add subdomain to subdomain_list
1205
+ * @sd: new subdomain
1207
+void aa_subdomainlist_add(struct subdomain *sd)
1209
+ unsigned long flags;
1212
+ AA_INFO("%s: bad subdomain\n", __FUNCTION__);
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.
1220
+ list_add_tail(&sd->list, &subdomain_list);
1221
+ write_unlock_irqrestore(&subdomain_lock, flags);
1225
+ * aa_subdomainlist_remove - Remove subdomain from subdomain_list
1226
+ * @sd: subdomain to be removed
1228
+void aa_subdomainlist_remove(struct subdomain *sd)
1230
+ unsigned long flags;
1233
+ write_lock_irqsave(&subdomain_lock, flags);
1234
+ list_del_init(&sd->list);
1235
+ write_unlock_irqrestore(&subdomain_lock, flags);
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
1244
+ * Iterate over subdomain list applying @func, stop when @func returns
1247
+void aa_subdomainlist_iterate(aa_iter func, void *cookie)
1249
+ struct subdomain *node;
1251
+ unsigned long flags;
1253
+ read_lock_irqsave(&subdomain_lock, flags);
1254
+ list_for_each_entry(node, &subdomain_list, list) {
1255
+ ret = (*func) (node, cookie);
1259
+ read_unlock_irqrestore(&subdomain_lock, flags);
1263
+ * aa_subdomainlist_release - Remove all subdomains from subdomain_list
1265
+void aa_subdomainlist_release(void)
1267
+ struct subdomain *node, *tmp;
1268
+ unsigned long flags;
1270
+ write_lock_irqsave(&subdomain_lock, flags);
1271
+ list_for_each_entry_safe(node, tmp, &subdomain_list, list) {
1272
+ list_del_init(&node->list);
1274
+ write_unlock_irqrestore(&subdomain_lock, flags);
1277
+/* seq_file helper routines
1278
+ * Used by apparmorfs.c to iterate over profile_list
1280
+static void *p_start(struct seq_file *f, loff_t *pos)
1282
+ struct aa_profile *node;
1285
+ read_lock(&profile_lock);
1286
+ list_for_each_entry(node, &profile_list, list)
1292
+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
1294
+ struct list_head *lh = ((struct aa_profile *)p)->list.next;
1296
+ return lh == &profile_list ?
1297
+ NULL : list_entry(lh, struct aa_profile, list);
1300
+static void p_stop(struct seq_file *f, void *v)
1302
+ read_unlock(&profile_lock);
1305
+static int seq_show_profile(struct seq_file *f, void *v)
1307
+ struct aa_profile *profile = (struct aa_profile *)v;
1308
+ seq_printf(f, "%s (%s)\n", profile->name,
1309
+ PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
1313
+struct seq_operations apparmorfs_profiles_op = {
1317
+ .show = seq_show_profile,
1319
Index: b/security/apparmor/lsm.c
1320
===================================================================
1322
+++ b/security/apparmor/lsm.c
1325
+ * Copyright (C) 2002-2005 Novell/SUSE
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
1332
+ * http://forge.novell.com/modules/xfmod/project/?apparmor
1334
+ * Immunix AppArmor LSM interface
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>
1344
+#include "apparmor.h"
1345
+#include "inline.h"
1347
+/* struct subdomain write update lock (read side is RCU). */
1348
+spinlock_t sd_lock = SPIN_LOCK_UNLOCKED;
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. */
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
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");
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");
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");
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");
1381
+static int __init aa_getopt_complain(char *str)
1383
+ get_option(&str, &apparmor_complain);
1386
+__setup("apparmor_complain=", aa_getopt_complain);
1388
+static int __init aa_getopt_debug(char *str)
1390
+ get_option(&str, &apparmor_debug);
1393
+__setup("apparmor_debug=", aa_getopt_debug);
1395
+static int __init aa_getopt_audit(char *str)
1397
+ get_option(&str, &apparmor_audit);
1400
+__setup("apparmor_audit=", aa_getopt_audit);
1402
+static int __init aa_getopt_logsyscall(char *str)
1404
+ get_option(&str, &apparmor_logsyscall);
1407
+__setup("apparmor_logsyscall=", aa_getopt_logsyscall);
1410
+static int apparmor_ptrace(struct task_struct *parent,
1411
+ struct task_struct *child)
1414
+ struct aa_profile *active;
1416
+ error = cap_ptrace(parent, child);
1418
+ active = get_task_active_aa_profile(parent);
1420
+ if (!error && active)
1421
+ error = aa_audit_syscallreject(active, GFP_KERNEL, "ptrace");
1423
+ put_aa_profile(active);
1428
+static int apparmor_capget(struct task_struct *target,
1429
+ kernel_cap_t *effective,
1430
+ kernel_cap_t *inheritable,
1431
+ kernel_cap_t *permitted)
1433
+ return cap_capget(target, effective, inheritable, permitted);
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)
1441
+ return cap_capset_check(target, effective, inheritable, permitted);
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)
1449
+ cap_capset_set(target, effective, inheritable, permitted);
1452
+static int apparmor_capable(struct task_struct *tsk, int cap)
1456
+ /* cap_capable returns 0 on success, else -EPERM */
1457
+ error = cap_capable(tsk, cap);
1460
+ struct aa_profile *active;
1462
+ active = get_task_active_aa_profile(tsk);
1465
+ error = aa_capability(active, cap);
1467
+ put_aa_profile(active);
1473
+static int apparmor_sysctl(struct ctl_table *table, int op)
1476
+ struct aa_profile *active;
1478
+ active = get_active_aa_profile();
1480
+ if ((op & 002) && active && !capable(CAP_SYS_ADMIN))
1481
+ error = aa_audit_syscallreject(active, GFP_KERNEL,
1482
+ "sysctl (write)");
1484
+ put_aa_profile(active);
1489
+static int apparmor_syslog(int type)
1491
+ return cap_syslog(type);
1494
+static int apparmor_netlink_send(struct sock *sk, struct sk_buff *skb)
1496
+ return cap_netlink_send(sk, skb);
1499
+static int apparmor_netlink_recv(struct sk_buff *skb, int cap)
1501
+ return cap_netlink_recv(skb, cap);
1504
+static void apparmor_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
1506
+ cap_bprm_apply_creds(bprm, unsafe);
1509
+static int apparmor_bprm_set_security(struct linux_binprm *bprm)
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)
1516
+ return aa_register(bprm);
1519
+static int apparmor_bprm_secureexec(struct linux_binprm *bprm)
1521
+ int ret = cap_bprm_secureexec(bprm);
1523
+ if (!ret && (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) {
1524
+ AA_DEBUG("%s: secureexec required for %s\n",
1525
+ __FUNCTION__, bprm->filename);
1532
+static int apparmor_sb_mount(char *dev_name, struct nameidata *nd, char *type,
1533
+ unsigned long flags, void *data)
1536
+ struct aa_profile *active;
1538
+ active = get_active_aa_profile();
1541
+ error = aa_audit_syscallreject(active, GFP_KERNEL, "mount");
1543
+ put_aa_profile(active);
1548
+static int apparmor_umount(struct vfsmount *mnt, int flags)
1551
+ struct aa_profile *active;
1553
+ active = get_active_aa_profile();
1556
+ error = aa_audit_syscallreject(active, GFP_ATOMIC, "umount");
1558
+ put_aa_profile(active);
1563
+static int apparmor_inode_mkdir(struct inode *dir, struct dentry *dentry,
1564
+ struct vfsmount *mnt, int mask)
1566
+ struct aa_profile *active;
1569
+ if (!mnt || !mediated_filesystem(dir))
1572
+ active = get_active_aa_profile();
1575
+ error = aa_perm_dir(active, dentry, mnt, "mkdir", AA_MAY_WRITE);
1577
+ put_aa_profile(active);
1583
+static int apparmor_inode_rmdir(struct inode *dir, struct dentry *dentry,
1584
+ struct vfsmount *mnt)
1586
+ struct aa_profile *active;
1589
+ if (!mnt || !mediated_filesystem(dir))
1592
+ active = get_active_aa_profile();
1595
+ error = aa_perm_dir(active, dentry, mnt, "rmdir", AA_MAY_WRITE);
1597
+ put_aa_profile(active);
1603
+static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
1604
+ struct vfsmount *mnt, int mask)
1606
+ struct aa_profile *active;
1609
+ if (!mnt || !mediated_filesystem(dir))
1612
+ active = get_active_aa_profile();
1614
+ /* At a minimum, need write perm to create */
1616
+ error = aa_perm(active, dentry, mnt, MAY_WRITE);
1618
+ put_aa_profile(active);
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)
1629
+ struct aa_profile *active;
1631
+ if (!old_mnt || !new_mnt || !mediated_filesystem(dir))
1634
+ active = get_active_aa_profile();
1637
+ error = aa_link(active, new_dentry, new_mnt,
1638
+ old_dentry, old_mnt);
1640
+ put_aa_profile(active);
1646
+static int apparmor_inode_unlink(struct inode *dir,
1647
+ struct dentry *dentry,
1648
+ struct vfsmount *mnt)
1650
+ struct aa_profile *active;
1653
+ if (!mnt || !mediated_filesystem(dir))
1656
+ active = get_active_aa_profile();
1659
+ error = aa_perm(active, dentry, mnt, MAY_WRITE);
1661
+ put_aa_profile(active);
1667
+static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry,
1668
+ struct vfsmount *mnt, int mode, dev_t dev)
1670
+ struct aa_profile *active;
1673
+ if (!mnt || !mediated_filesystem(dir))
1676
+ active = get_active_aa_profile();
1679
+ error = aa_perm(active, dentry, mnt, MAY_WRITE);
1681
+ put_aa_profile(active);
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)
1694
+ struct aa_profile *active;
1697
+ if ((!old_mnt && !new_mnt) || !mediated_filesystem(old_dir))
1700
+ active = get_active_aa_profile();
1704
+ error = aa_perm(active, old_dentry, old_mnt,
1705
+ MAY_READ|MAY_WRITE);
1707
+ if (!error && new_mnt)
1708
+ error = aa_perm(active, new_dentry, new_mnt,
1712
+ put_aa_profile(active);
1718
+static int apparmor_inode_permission(struct inode *inode, int mask,
1719
+ struct nameidata *nd)
1723
+ /* Do not perform check on pipes or sockets
1724
+ * Same as apparmor_file_permission
1726
+ if (nd && mediated_filesystem(inode)) {
1727
+ struct aa_profile *active;
1729
+ active = get_active_aa_profile();
1731
+ error = aa_perm(active, nd->dentry, nd->mnt, mask);
1732
+ put_aa_profile(active);
1738
+static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
1739
+ struct iattr *iattr)
1746
+ if (mediated_filesystem(dentry->d_inode)) {
1747
+ struct aa_profile *active;
1749
+ active = get_active_aa_profile();
1751
+ * Mediate any attempt to change attributes of a file
1752
+ * (chmod, chown, chgrp, etc)
1755
+ error = aa_attr(active, dentry, mnt, iattr);
1757
+ put_aa_profile(active);
1764
+static int apparmor_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
1765
+ char *name, void *value, size_t size,
1773
+ if (mediated_filesystem(dentry->d_inode)) {
1774
+ struct aa_profile *active;
1776
+ active = get_active_aa_profile();
1778
+ error = aa_perm_xattr(active, dentry, mnt, name,
1779
+ "xattr set", AA_MAY_WRITE);
1780
+ put_aa_profile(active);
1787
+static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
1795
+ if (mediated_filesystem(dentry->d_inode)) {
1796
+ struct aa_profile *active;
1798
+ active = get_active_aa_profile();
1800
+ error = aa_perm_xattr(active, dentry, mnt, name,
1801
+ "xattr get", AA_MAY_READ);
1802
+ put_aa_profile(active);
1808
+static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
1815
+ if (mediated_filesystem(dentry->d_inode)) {
1816
+ struct aa_profile *active;
1818
+ active = get_active_aa_profile();
1820
+ error = aa_perm_xattr(active, dentry, mnt, NULL,
1821
+ "xattr list", AA_MAY_READ);;
1822
+ put_aa_profile(active);
1829
+static int apparmor_inode_removexattr(struct dentry *dentry,
1830
+ struct vfsmount *mnt, char *name)
1837
+ if (mediated_filesystem(dentry->d_inode)) {
1838
+ struct aa_profile *active;
1840
+ active = get_active_aa_profile();
1842
+ error = aa_perm_xattr(active, dentry, mnt, name,
1843
+ "xattr remove", AA_MAY_WRITE);
1844
+ put_aa_profile(active);
1851
+static int apparmor_file_permission(struct file *file, int mask)
1853
+ struct aa_profile *active;
1854
+ struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
1857
+ /* bail out early if this isn't a mediated file */
1858
+ if (!file_profile || !mediated_filesystem(file->f_dentry->d_inode))
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));
1867
+ put_aa_profile(active);
1873
+static int apparmor_file_alloc_security(struct file *file)
1875
+ struct aa_profile *active;
1877
+ active = get_active_aa_profile();
1879
+ /* FIXME: get rid of revalidation. */
1880
+ file->f_security = active;
1886
+static void apparmor_file_free_security(struct file *file)
1888
+ struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
1890
+ /* FIXME: get rid of revalidation. */
1891
+ put_aa_profile(file_profile);
1894
+static inline int aa_mmap(struct file *file, unsigned long prot,
1895
+ unsigned long flags)
1897
+ int error = 0, mask = 0;
1898
+ struct aa_profile *active;
1900
+ active = get_active_aa_profile();
1901
+ if (!active || !file || !mediated_filesystem(file->f_dentry->d_inode))
1904
+ if (prot & PROT_READ)
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;
1914
+ AA_DEBUG("%s: 0x%x\n", __FUNCTION__, mask);
1917
+ error = aa_perm(active, file->f_dentry, file->f_vfsmnt, mask);
1919
+ put_aa_profile(active);
1925
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
1926
+ unsigned long prot, unsigned long flags)
1928
+ return aa_mmap(file, prot, flags);
1931
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
1932
+ unsigned long reqprot, unsigned long prot)
1934
+ return aa_mmap(vma->vm_file, prot,
1935
+ !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
1938
+static int apparmor_task_alloc_security(struct task_struct *p)
1940
+ return aa_fork(p);
1943
+static void apparmor_task_free_security(struct task_struct *p)
1948
+static int apparmor_task_post_setuid(uid_t id0, uid_t id1, uid_t id2,
1951
+ return cap_task_post_setuid(id0, id1, id2, flags);
1954
+static void apparmor_task_reparent_to_init(struct task_struct *p)
1956
+ cap_task_reparent_to_init(p);
1959
+static int apparmor_getprocattr(struct task_struct *p, char *name, void *value,
1963
+ struct aa_profile *active;
1964
+ char *str = value;
1966
+ /* AppArmor only supports the "current" process attribute */
1967
+ if (strcmp(name, "current") != 0) {
1972
+ /* must be task querying itself or admin */
1973
+ if (current != p && !capable(CAP_SYS_ADMIN)) {
1978
+ active = get_task_active_aa_profile(p);
1979
+ error = aa_getprocattr(active, str, size);
1980
+ put_aa_profile(active);
1986
+static int apparmor_setprocattr(struct task_struct *p, char *name, void *value,
1989
+ const char *cmd_changehat = "changehat ",
1990
+ *cmd_setprofile = "setprofile ";
1993
+ char *cmd = (char *)value;
1996
+ if (strcmp(name, "current") != 0)
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);
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",
2023
+ error = aa_setprocattr_changehat(hatinfo, infosize);
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;
2032
+ /* only an unconfined process with admin capabilities
2033
+ * may change the profile of another task
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",
2049
+ active = get_active_aa_profile();
2051
+ char *profile = cmd + strlen(cmd_setprofile);
2052
+ size_t profilesize = size - strlen(cmd_setprofile);
2054
+ error = aa_setprocattr_setprofile(p, profile, profilesize);
2057
+ * set return to #bytes in orig request
2061
+ AA_WARN("%s: Attempt by confined task %s(%d) "
2062
+ "[user %d] to assign profile to task %s(%d)\n",
2072
+ put_aa_profile(active);
2074
+ /* unknown operation */
2075
+ AA_WARN("%s: Unknown setprocattr command '%.*s' by task %s(%d) "
2076
+ "[user %d] for task %s(%d)\n",
2078
+ size < 16 ? (int)size : 16,
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,
2102
+ .netlink_send = apparmor_netlink_send,
2103
+ .netlink_recv = apparmor_netlink_recv,
2105
+ .bprm_apply_creds = apparmor_bprm_apply_creds,
2106
+ .bprm_set_security = apparmor_bprm_set_security,
2107
+ .bprm_secureexec = apparmor_bprm_secureexec,
2109
+ .sb_mount = apparmor_sb_mount,
2110
+ .sb_umount = apparmor_umount,
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,
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,
2136
+ .getprocattr = apparmor_getprocattr,
2137
+ .setprocattr = apparmor_setprocattr,
2140
+static int __init apparmor_init(void)
2143
+ const char *complainmsg = ": complainmode enabled";
2145
+ if ((error = create_apparmorfs())) {
2146
+ AA_ERROR("Unable to activate AppArmor filesystem\n");
2147
+ goto createfs_out;
2150
+ if ((error = alloc_null_complain_profile())){
2151
+ AA_ERROR("Unable to allocate null complain profile\n");
2155
+ if ((error = register_security(&apparmor_ops))) {
2156
+ AA_ERROR("Unable to load AppArmor\n");
2157
+ goto register_security_out;
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 : "");
2168
+register_security_out:
2169
+ free_null_complain_profile();
2172
+ (void)destroy_apparmorfs();
2179
+static int apparmor_exit_removeall_iter(struct subdomain *sd, void *cookie)
2181
+ /* spin_lock(&sd_lock) held here */
2183
+ if (__aa_is_confined(sd)) {
2184
+ AA_DEBUG("%s: Dropping profiles %s(%d) "
2185
+ "profile %s(%p) active %s(%p)\n",
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);
2197
+static void __exit apparmor_exit(void)
2199
+ unsigned long flags;
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)
2205
+ aa_profilelist_release();
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'
2213
+ spin_lock_irqsave(&sd_lock, flags);
2214
+ aa_subdomainlist_iterate(apparmor_exit_removeall_iter, NULL);
2215
+ spin_unlock_irqrestore(&sd_lock, flags);
2217
+ /* Free up list of active subdomain */
2218
+ aa_subdomainlist_release();
2220
+ free_null_complain_profile();
2222
+ destroy_apparmorfs();
2224
+ if (unregister_security(&apparmor_ops))
2225
+ AA_WARN("Unable to properly unregister AppArmor\n");
2227
+ /* delay for an rcu cycle to make ensure that profiles pending
2228
+ * destruction in the rcu callback are freed.
2230
+ synchronize_rcu();
2232
+ AA_INFO("AppArmor protection removed\n");
2233
+ aa_audit_message(NULL, GFP_KERNEL, 0,
2234
+ "AppArmor protection removed\n");
2237
+module_init(apparmor_init);
2238
+module_exit(apparmor_exit);
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
===================================================================
2246
+++ b/security/apparmor/main.c
2249
+ * Copyright (C) 2002-2005 Novell/SUSE
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
2259
+#include <linux/security.h>
2260
+#include <linux/namei.h>
2261
+#include <linux/audit.h>
2263
+#include "apparmor.h"
2265
+#include "inline.h"
2267
+/* NULL complain profile
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
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
2277
+struct aa_profile *null_complain_profile;
2279
+/***************************
2280
+ * Private utility functions
2281
+ **************************/
2284
+ * aa_taskattr_access
2285
+ * @name: name of file to check permission
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.
2291
+static inline int aa_taskattr_access(const char *name)
2293
+ unsigned long pid;
2296
+ if (strncmp(name, "/proc/", 6) != 0)
2298
+ pid = simple_strtoul(name + 6, &end, 10);
2299
+ if (pid != current->pid)
2301
+ return strcmp(end, "/attr/current") == 0;
2305
+ * aa_file_mode - get full mode for file entry from profile
2306
+ * @profile: profile
2309
+static inline int aa_file_mode(struct aa_profile *profile, const char *name)
2313
+ AA_DEBUG("%s: %s\n", __FUNCTION__, name);
2315
+ AA_DEBUG("%s: no name\n", __FUNCTION__);
2320
+ AA_DEBUG("%s: no profile\n", __FUNCTION__);
2324
+ perms = aa_match(profile->file_rules, name);
2332
+ * @mask: requested mask
2333
+ * @inode: potential directory inode
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.
2340
+ * Returned value of %0 indicates no need to perform a perm check.
2342
+static inline int aa_filter_mask(int mask, struct inode *inode)
2345
+ int elim = MAY_APPEND;
2347
+ if (inode && S_ISDIR(inode->i_mode))
2348
+ elim |= (MAY_EXEC | MAY_WRITE);
2356
+static inline void aa_permerror2result(int perm_result, struct aa_audit *sa)
2358
+ if (perm_result == 0) { /* success */
2360
+ sa->error_code = 0;
2361
+ } else { /* -ve internal error code or +ve mask of denied perms */
2363
+ sa->error_code = perm_result;
2367
+/*************************
2368
+ * Main internal functions
2369
+ ************************/
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
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.
2382
+ * Return %0 on success, else mask of non-allowed permissions
2384
+static int aa_file_perm(struct aa_profile *active, const char *name, int mask)
2388
+ /* Always allow write access to /proc/self/attr/current. */
2389
+ if (mask == MAY_WRITE && aa_taskattr_access(name))
2392
+ perms = aa_match(active->file_rules, name);
2394
+ return mask & ~perms; /* return permissions not satisfied */
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
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
2407
+static int aa_link_perm(struct aa_profile *active,
2408
+ const char *link, const char *target)
2410
+ int l_mode, t_mode, ret = -EPERM;
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;
2417
+ t_mode = aa_file_mode(active, target);
2418
+ t_mode &= ~AA_MAY_LINK;
2420
+ if (l_mode == t_mode)
2427
+static int _aa_perm_vfsmount(struct aa_profile *active, struct dentry *dentry,
2428
+ struct vfsmount *mnt, struct aa_audit *sa, int mask)
2430
+ int permerror, error;
2432
+ sa->name = aa_get_name(dentry, mnt);
2434
+ if (IS_ERR(sa->name)) {
2435
+ permerror = PTR_ERR(sa->name);
2438
+ permerror = aa_file_perm(active, sa->name, mask);
2441
+ aa_permerror2result(permerror, sa);
2443
+ error = aa_audit(active, sa);
2445
+ aa_put_name(sa->name);
2450
+/**************************
2451
+ * Global utility functions
2452
+ *************************/
2455
+ * attach_nullprofile - allocate and attach a null_profile hat to profile
2456
+ * @profile: profile to attach a null_profile hat to.
2458
+ * Return %0 (success) or error (-%ENOMEM)
2460
+int attach_nullprofile(struct aa_profile *profile)
2462
+ struct aa_profile *hat = NULL;
2463
+ char *hatname = NULL;
2465
+ hat = alloc_aa_profile();
2468
+ if (profile->flags.complain)
2469
+ hatname = kstrdup("null-complain-profile", GFP_KERNEL);
2471
+ hatname = kstrdup("null-profile", GFP_KERNEL);
2475
+ hat->flags.complain = profile->flags.complain;
2476
+ hat->name = hatname;
2477
+ hat->parent = profile;
2479
+ profile->null_profile = hat;
2485
+ free_aa_profile(hat);
2492
+ * alloc_null_complain_profile - Allocate the global null_complain_profile.
2494
+ * Return %0 (success) or error (-%ENOMEM)
2496
+int alloc_null_complain_profile(void)
2498
+ null_complain_profile = alloc_aa_profile();
2499
+ if (!null_complain_profile)
2502
+ null_complain_profile->name =
2503
+ kstrdup("null-complain-profile", GFP_KERNEL);
2505
+ if (!null_complain_profile->name)
2508
+ null_complain_profile->flags.complain = 1;
2509
+ if (attach_nullprofile(null_complain_profile))
2515
+ /* free_aa_profile is safe for freeing partially constructed objects */
2516
+ free_aa_profile(null_complain_profile);
2517
+ null_complain_profile = NULL;
2523
+ * free_null_complain_profile - Free null profiles
2525
+void free_null_complain_profile(void)
2527
+ put_aa_profile(null_complain_profile);
2528
+ null_complain_profile = NULL;
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
2538
+int aa_audit_message(struct aa_profile *active, gfp_t gfp, int flags,
2539
+ const char *fmt, ...)
2542
+ struct aa_audit sa;
2544
+ sa.type = AA_AUDITTYPE_MSG;
2546
+ va_start(sa.vaval, fmt);
2548
+ sa.gfp_mask = gfp;
2549
+ sa.error_code = 0;
2550
+ sa.result = 0; /* fake failure: force message to be logged */
2552
+ ret = aa_audit(active, &sa);
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
2565
+int aa_audit_syscallreject(struct aa_profile *active, gfp_t gfp,
2568
+ struct aa_audit sa;
2570
+ sa.type = AA_AUDITTYPE_SYSCALL;
2573
+ sa.gfp_mask = gfp;
2574
+ sa.error_code = 0;
2575
+ sa.result = 0; /* failure */
2577
+ return aa_audit(active, &sa);
2581
+ * aa_audit - Log an audit event to the audit subsystem
2582
+ * @active: profile to check against
2583
+ * @sa: audit event
2585
+int aa_audit(struct aa_profile *active, const struct aa_audit *sa)
2587
+ struct audit_buffer *ab = NULL;
2588
+ struct audit_context *ctx;
2590
+ const char *logcls;
2591
+ unsigned int flags;
2595
+ opspec_error = -EACCES;
2597
+ const gfp_t gfp_mask = sa->gfp_mask;
2599
+ WARN_ON(sa->type >= AA_AUDITTYPE__END);
2602
+ * sa->result: 1 success, 0 failure
2603
+ * sa->error_code: success: 0
2604
+ * failure: +ve mask of failed permissions or -ve
2608
+ if (likely(sa->result)) {
2609
+ if (likely(!PROFILE_AUDIT(active))) {
2610
+ /* nothing to log */
2615
+ logcls = "AUDITING";
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;
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.
2629
+ logcls = "REJECTING";
2631
+ complain = PROFILE_COMPLAIN(active);
2632
+ logcls = complain ? "PERMITTING" : "REJECTING";
2635
+ /* In future extend w/ per-profile flags
2636
+ * (flags |= sa->active->flags)
2638
+ flags = sa->flags;
2639
+ if (apparmor_logsyscall)
2640
+ flags |= AA_AUDITFLAG_AUDITSS_SYSCALL;
2643
+ /* Force full audit syscall logging regardless of global setting if
2644
+ * we are rejecting a syscall
2646
+ if (sa->type == AA_AUDITTYPE_SYSCALL) {
2647
+ ctx = current->audit_context;
2649
+ ctx = (flags & AA_AUDITFLAG_AUDITSS_SYSCALL) ?
2650
+ current->audit_context : NULL;
2653
+ ab = audit_log_start(ctx, gfp_mask, AUDIT_APPARMOR);
2656
+ AA_ERROR("Unable to log event (%d) to audit subsys\n",
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);
2671
+ /* log operation */
2673
+ audit_log_format(ab, "%s ", logcls); /* REJECTING/ALLOWING/etc */
2675
+ if (sa->type == AA_AUDITTYPE_FILE) {
2676
+ int perm = audit ? sa->mask : sa->error_code;
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" : "",
2686
+ opspec_error = -EPERM;
2688
+ } else if (sa->type == AA_AUDITTYPE_DIR) {
2689
+ audit_log_format(ab, "%s on %s ", sa->operation, sa->name);
2691
+ } else if (sa->type == AA_AUDITTYPE_ATTR) {
2692
+ struct iattr *iattr = (struct iattr*)sa->pval;
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," : "",
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);
2713
+ } else if (sa->type == AA_AUDITTYPE_LINK) {
2714
+ audit_log_format(ab,
2715
+ "link access from %s to %s ",
2719
+ } else if (sa->type == AA_AUDITTYPE_CAP) {
2720
+ audit_log_format(ab,
2721
+ "access to capability '%s' ",
2722
+ capability_to_name(sa->capability));
2724
+ opspec_error = -EPERM;
2725
+ } else if (sa->type == AA_AUDITTYPE_SYSCALL) {
2726
+ audit_log_format(ab, "access to syscall '%s' ", sa->name);
2728
+ opspec_error = -EPERM;
2730
+ /* -EINVAL -- will WARN_ON above */
2734
+ audit_log_format(ab, "(%s(%d) profile %s active %s)",
2735
+ current->comm, current->pid,
2736
+ BASE_PROFILE(active)->name, active->name);
2738
+ audit_log_end(ab);
2743
+ error = sa->result ? 0 : opspec_error;
2750
+ * aa_get_name - retrieve fully qualified path name
2751
+ * @dentry: relative path element
2752
+ * @mnt: where in tree
2754
+ * Returns fully qualified path name on sucess, NULL on failure.
2755
+ * aa_put_name must be used to free allocated buffer.
2757
+char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt)
2759
+ char *page, *name;
2761
+ page = (char *)__get_free_page(GFP_KERNEL);
2763
+ name = ERR_PTR(-ENOMEM);
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.
2772
+ if (IS_ERR(name)) {
2773
+ free_page((unsigned long)page);
2775
+ const char deleted_str[] = " (deleted)";
2776
+ const size_t deleted_size = sizeof(deleted_str) - 1;
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);
2790
+/***********************************
2791
+ * Global permission check functions
2792
+ ***********************************/
2795
+ * aa_attr - check whether attribute change allowed
2796
+ * @active: profile to check against
2797
+ * @dentry: file to check
2798
+ * @iattr: attribute changes requested
2800
+int aa_attr(struct aa_profile *active, struct dentry *dentry,
2801
+ struct vfsmount *mnt, struct iattr *iattr)
2804
+ struct aa_audit sa;
2806
+ sa.type = AA_AUDITTYPE_ATTR;
2809
+ sa.gfp_mask = GFP_KERNEL;
2811
+ error = _aa_perm_vfsmount(active, dentry, mnt, &sa, MAY_WRITE);
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
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)
2830
+ struct aa_audit sa;
2832
+ sa.type = AA_AUDITTYPE_XATTR;
2833
+ sa.operation = operation;
2834
+ sa.pval = xattr_name;
2836
+ sa.gfp_mask = GFP_KERNEL;
2838
+ error = _aa_perm_vfsmount(active, dentry, mnt, &sa, mask);
2844
+ * aa_perm - basic apparmor permissions check
2845
+ * @active: profile to check against
2847
+ * @mnt: mountpoint
2848
+ * @mask: access mode requested
2850
+ * Determine if access (mask) for dentry is authorized by active
2851
+ * profile. Result, %0 (success), -ve (error)
2853
+int aa_perm(struct aa_profile *active, struct dentry *dentry,
2854
+ struct vfsmount *mnt, int mask)
2857
+ struct aa_audit sa;
2859
+ if ((mask = aa_filter_mask(mask, dentry->d_inode)) == 0)
2862
+ sa.type = AA_AUDITTYPE_FILE;
2865
+ sa.gfp_mask = GFP_KERNEL;
2866
+ error = _aa_perm_vfsmount(active, dentry, mnt, &sa, mask);
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
2880
+ * Determine if directory operation (make/remove) for dentry is authorized
2881
+ * by @active profile.
2882
+ * Result, %0 (success), -ve (error)
2884
+int aa_perm_dir(struct aa_profile *active, struct dentry *dentry,
2885
+ struct vfsmount *mnt, const char *operation, int mask)
2887
+ struct aa_audit sa;
2889
+ sa.type = AA_AUDITTYPE_DIR;
2890
+ sa.operation = operation;
2892
+ sa.gfp_mask = GFP_KERNEL;
2894
+ return _aa_perm_vfsmount(active, dentry, mnt, &sa, mask);
2898
+ * aa_capability - test permission to use capability
2899
+ * @active: profile to check against
2900
+ * @cap: capability to be tested
2902
+ * Look up capability in active profile capability set.
2903
+ * Return %0 (success), -%EPERM (error)
2905
+int aa_capability(struct aa_profile *active, int cap)
2908
+ struct aa_audit sa;
2910
+ sa.type = AA_AUDITTYPE_CAP;
2912
+ sa.capability = cap;
2914
+ sa.error_code = 0;
2915
+ sa.result = cap_raised(active->capabilities, cap);
2916
+ sa.gfp_mask = GFP_ATOMIC;
2918
+ error = aa_audit(active, &sa);
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)
2930
+int aa_link(struct aa_profile *active,
2931
+ struct dentry *link, struct vfsmount *link_mnt,
2932
+ struct dentry *target, struct vfsmount *target_mnt)
2934
+ int permerror = -EPERM, error;
2935
+ struct aa_audit sa;
2937
+ sa.name = aa_get_name(link, link_mnt);
2938
+ sa.pval = aa_get_name(target, target_mnt);
2940
+ if (IS_ERR(sa.name)) {
2941
+ permerror = PTR_ERR(sa.name);
2944
+ if (IS_ERR(sa.pval)) {
2945
+ permerror = PTR_ERR(sa.pval);
2949
+ if (sa.name && sa.pval)
2950
+ permerror = aa_link_perm(active, sa.name, sa.pval);
2952
+ aa_permerror2result(permerror, &sa);
2954
+ sa.type = AA_AUDITTYPE_LINK;
2956
+ sa.gfp_mask = GFP_KERNEL;
2958
+ error = aa_audit(active, &sa);
2960
+ aa_put_name(sa.name);
2961
+ aa_put_name(sa.pval);
2966
+/*******************************
2967
+ * Global task related functions
2968
+ *******************************/
2971
+ * aa_fork - create a new subdomain
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.
2980
+ * The sd_lock is used to maintain consistency against profile
2981
+ * replacement/removal.
2984
+int aa_fork(struct task_struct *p)
2986
+ struct subdomain *sd = AA_SUBDOMAIN(current->security);
2987
+ struct subdomain *newsd = NULL;
2989
+ AA_DEBUG("%s\n", __FUNCTION__);
2991
+ if (__aa_is_confined(sd)) {
2992
+ unsigned long flags;
2994
+ newsd = alloc_subdomain(p);
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.
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);
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);
3014
+ p->security = newsd;
3019
+ * aa_register - register a new program
3020
+ * @bprm: binprm of program being registered
3022
+ * Try to register a new program during execve(). This should give the
3023
+ * new program a valid subdomain.
3025
+int aa_register(struct linux_binprm *bprm)
3028
+ struct file *filp = bprm->file;
3029
+ struct aa_profile *active;
3030
+ struct aa_profile *newprofile = NULL, unconstrained_flag;
3031
+ int error = -ENOMEM,
3034
+ find_profile_mandatory = 0,
3038
+ AA_DEBUG("%s\n", __FUNCTION__);
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__);
3048
+ active = get_active_aa_profile();
3051
+ /* Unconfined task, load profile if it exists */
3053
+ goto find_profile;
3056
+ complain = PROFILE_COMPLAIN(active);
3058
+ /* Confined task, determine what mode inherit, unconstrained or
3059
+ * mandatory to load new profile
3061
+ exec_mode = AA_EXEC_MASK(aa_match(active->file_rules, filename));
3062
+ unsafe_exec = exec_mode & AA_EXEC_UNSAFE;
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
3070
+ AA_DEBUG("%s: INHERIT %s\n",
3075
+ case AA_EXEC_UNCONSTRAINED:
3076
+ AA_DEBUG("%s: UNCONSTRAINED %s\n",
3080
+ /* unload profile */
3081
+ newprofile = &unconstrained_flag;
3084
+ case AA_EXEC_PROFILE:
3085
+ AA_DEBUG("%s: PROFILE %s\n",
3090
+ find_profile_mandatory = 1;
3094
+ /* this should not happen, entries
3095
+ * with just EXEC only should be
3096
+ * rejected at profile load time
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",
3103
+ current->comm, current->pid,
3104
+ BASE_PROFILE(active)->name, active->name);
3109
+ AA_ERROR("%s: Rejecting exec(2) of image '%s'. "
3110
+ "Unknown exec qualifier %x "
3111
+ "(%s (pid %d) profile %s active %s)\n",
3115
+ current->comm, current->pid,
3116
+ BASE_PROFILE(active)->name, active->name);
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).
3126
+ newprofile = get_aa_profile(null_complain_profile);
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",
3134
+ current->comm, current->pid,
3135
+ BASE_PROFILE(active)->name, active->name);
3141
+ if (!find_profile)
3142
+ goto apply_profile;
3144
+ /* Locate new profile */
3145
+ newprofile = aa_profilelist_find(filename);
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 */
3153
+ LOG_HINT(active, GFP_KERNEL, HINT_MANDPROF,
3154
+ "image=%s pid=%d profile=%s active=%s\n",
3157
+ BASE_PROFILE(active)->name, active->name);
3159
+ newprofile = get_aa_profile(null_complain_profile);
3161
+ AA_WARN("REJECTING exec(2) of image '%s'. "
3162
+ "Profile mandatory and not found "
3163
+ "(%s(%d) profile %s active %s)\n",
3165
+ current->comm, current->pid,
3166
+ BASE_PROFILE(active)->name, active->name);
3170
+ /* Profile (non-mandatory) could not be found */
3172
+ /* Only way we can get into this code is if task
3173
+ * is unconstrained.
3178
+ AA_DEBUG("%s: No profile found for exec image %s\n",
3181
+ } /* newprofile */
3185
+ /* Apply profile if necessary */
3187
+ struct subdomain *sd, *lazy_sd = NULL;
3188
+ unsigned long flags;
3190
+ if (newprofile == &unconstrained_flag)
3191
+ newprofile = NULL;
3193
+ /* grab a lock - this is to guarentee consistency against
3194
+ * other writers of subdomain (replacement/removal)
3196
+ * Several things may have changed since the code above
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.
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.
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.
3216
+ if (!active && !(sd = AA_SUBDOMAIN(current->security))) {
3217
+ lazy_sd = alloc_subdomain(current);
3219
+ AA_ERROR("%s: Failed to allocate subdomain\n",
3226
+ spin_lock_irqsave(&sd_lock, flags);
3228
+ sd = AA_SUBDOMAIN(current->security);
3231
+ /* raced by setprofile - created sd */
3232
+ free_subdomain(lazy_sd);
3235
+ /* Not rcu used to get the write barrier
3237
+ rcu_assign_pointer(current->security, lazy_sd);
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.
3246
+ if (newprofile && unlikely(newprofile->isstale)) {
3247
+ WARN_ON(newprofile == null_complain_profile);
3249
+ /* drop refcnt obtained from earlier get_aa_profile */
3250
+ put_aa_profile(newprofile);
3252
+ newprofile = aa_profilelist_find(filename);
3254
+ if (!newprofile) {
3255
+ /* Race, profile was removed, not replaced.
3256
+ * Redo with error checking
3258
+ spin_unlock_irqrestore(&sd_lock, flags);
3259
+ goto find_profile;
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
3269
+ * Cases 2 and 3 are marked as requiring secure exec
3270
+ * (unless policy specified "unsafe exec")
3272
+ if (__aa_is_confined(sd) && !unsafe_exec) {
3273
+ unsigned long bprm_flags;
3275
+ bprm_flags = AA_SECURE_EXEC_NEEDED;
3276
+ bprm->security = (void*)
3277
+ ((unsigned long)bprm->security | bprm_flags);
3280
+ aa_switch(sd, newprofile);
3281
+ put_aa_profile(newprofile);
3283
+ if (complain && newprofile == null_complain_profile)
3284
+ LOG_HINT(newprofile, GFP_ATOMIC, HINT_CHGPROF,
3288
+ spin_unlock_irqrestore(&sd_lock, flags);
3292
+ aa_put_name(filename);
3294
+ put_aa_profile(active);
3301
+ * aa_release - release the task's subdomain
3302
+ * @p: task being released
3304
+ * This is called after a task has exited and the parent has reaped it.
3305
+ * @p->security blob is freed.
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.
3313
+void aa_release(struct task_struct *p)
3315
+ struct subdomain *sd = AA_SUBDOMAIN(p->security);
3317
+ p->security = NULL;
3319
+ aa_subdomainlist_remove(sd);
3320
+ aa_switch_unconfined(sd);
3326
+/*****************************
3327
+ * global subprofile functions
3328
+ ****************************/
3331
+ * do_change_hat - actually switch hats
3332
+ * @hat_name: name of hat to swtich to
3333
+ * @sd: current subdomain
3335
+ * Switch to a new hat. Return %0 on success, error otherwise.
3337
+static inline int do_change_hat(const char *hat_name, struct subdomain *sd)
3339
+ struct aa_profile *sub;
3342
+ sub = __aa_find_profile(hat_name, &BASE_PROFILE(sd->active)->sub);
3346
+ aa_switch(sd, sub);
3347
+ put_aa_profile(sub);
3349
+ /* There is no such subprofile change to a NULL profile.
3350
+ * The NULL profile grants no file access.
3352
+ * This feature is used by changehat_apache.
3354
+ * N.B from the null-profile the task can still changehat back
3355
+ * out to the parent profile (assuming magic != NULL)
3357
+ if (SUBDOMAIN_COMPLAIN(sd)) {
3358
+ LOG_HINT(sd->active, GFP_ATOMIC, HINT_UNKNOWN_HAT,
3360
+ "profile=%s active=%s\n",
3363
+ BASE_PROFILE(sd->active)->name,
3364
+ sd->active->name);
3366
+ AA_DEBUG("%s: Unknown hatname '%s'. "
3367
+ "Changing to NULL profile "
3368
+ "(%s(%d) profile %s active %s)\n",
3371
+ current->comm, current->pid,
3372
+ BASE_PROFILE(sd->active)->name,
3373
+ sd->active->name);
3376
+ aa_switch(sd, sd->active->null_profile);
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
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
3393
+int aa_change_hat(const char *hat_name, u32 hat_magic)
3395
+ struct subdomain *sd = AA_SUBDOMAIN(current->security);
3398
+ AA_DEBUG("%s: %p, 0x%x (pid %d)\n",
3400
+ hat_name, hat_magic,
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);
3410
+ /* check to see if an unconfined process is doing a changehat. */
3411
+ if (!__aa_is_confined(sd)) {
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)) {
3423
+ /* Check whether current domain is parent
3424
+ * or one of the sibling children
3426
+ if (!IN_SUBPROFILE(sd->active)) {
3431
+ AA_DEBUG("%s: switching to %s, 0x%x\n",
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
3443
+ sd->hat_magic = hat_magic;
3444
+ error = do_change_hat(hat_name, sd);
3446
+ /* Got here via changehat(NULL, magic)
3448
+ * We used to simply update the magic cookie.
3449
+ * That's an odd behaviour, so just do nothing.
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
3459
+ if (hat_magic == sd->hat_magic && sd->hat_magic) {
3462
+ * Got here via changehat(NULL, magic)
3463
+ * Return from subprofile, back to parent
3465
+ aa_switch(sd, sd->active->parent);
3467
+ /* Reset hat_magic to zero.
3468
+ * New value will be passed on next changehat
3470
+ sd->hat_magic = 0;
3472
+ /* change to another (sibling) profile */
3473
+ error = do_change_hat(hat_name, sd);
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,
3481
+ hat_name ? hat_name : "NULL",
3482
+ BASE_PROFILE(sd->active)->name,
3483
+ sd->active->name);
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);
3495
+ /* terminate current process */
3496
+ (void)send_sig_info(SIGKILL, NULL, current);
3504
Index: b/security/apparmor/module_interface.c
3505
===================================================================
3507
+++ b/security/apparmor/module_interface.c
3510
+ * Copyright (C) 1998-2005 Novell/SUSE
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
3517
+ * AppArmor userspace policy interface
3520
+#include <asm/unaligned.h>
3522
+#include "apparmor.h"
3523
+#include "inline.h"
3524
+#include "module_interface.h"
3526
+/* aa_code defined in module_interface.h */
3528
+const int aa_code_datasize[] = { 1, 2, 4, 8, 2, 2, 4, 0, 0, 0, 0, 0, 0 };
3530
+struct aa_taskreplace_data {
3531
+ struct aa_profile *old_profile;
3532
+ struct aa_profile *new_profile;
3536
+ * free_aa_profile_rcu - rcu callback for free profiles
3537
+ * @head: rcu_head struct of the profile whose reference is being put.
3539
+ * the rcu callback routine, which delays the freeing of a profile when
3540
+ * its last reference is put.
3542
+static void free_aa_profile_rcu(struct rcu_head *head)
3544
+ struct aa_profile *p = container_of(head, struct aa_profile, rcu);
3545
+ free_aa_profile(p);
3549
+ * task_remove - remove profile from a task's subdomain
3550
+ * @sd: task's subdomain
3552
+ * remove the active profile from a task's subdomain, switching the task
3553
+ * to an unconfined state.
3555
+static inline void task_remove(struct subdomain *sd)
3557
+ /* spin_lock(&sd_lock) held here */
3558
+ AA_DEBUG("%s: removing profile from task %s(%d) profile %s active %s\n",
3562
+ BASE_PROFILE(sd->active)->name,
3563
+ sd->active->name);
3565
+ aa_switch_unconfined(sd);
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
3572
+ * If the subdomain's active profile matches old_profile, then call
3573
+ * task_remove() to remove the profile leaving the task (subdomain) unconfined.
3575
+static int taskremove_iter(struct subdomain *sd, void *cookie)
3577
+ struct aa_profile *old_profile = (struct aa_profile *)cookie;
3578
+ unsigned long flags;
3580
+ spin_lock_irqsave(&sd_lock, flags);
3582
+ if (__aa_is_confined(sd) && BASE_PROFILE(sd->active) == old_profile) {
3586
+ spin_unlock_irqrestore(&sd_lock, flags);
3591
+/** task_replace - replace subdomain's current profile with a new profile
3592
+ * @sd: subdomain to replace the profile on
3593
+ * @new: new profile
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.
3600
+static inline void task_replace(struct subdomain *sd, struct aa_profile *new)
3602
+ AA_DEBUG("%s: replacing profile for task %s(%d) "
3603
+ "profile=%s (%p) active=%s (%p)\n",
3605
+ sd->task->comm, sd->task->pid,
3606
+ BASE_PROFILE(sd->active)->name, BASE_PROFILE(sd->active),
3607
+ sd->active->name, sd->active);
3612
+ if (IN_SUBPROFILE(sd->active)) {
3613
+ struct aa_profile *nactive;
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);
3620
+ nactive = get_aa_profile(new->null_profile);
3622
+ aa_switch(sd, nactive);
3623
+ put_aa_profile(nactive);
3625
+ aa_switch(sd, new);
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.
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.
3640
+static int taskreplace_iter(struct subdomain *sd, void *cookie)
3642
+ struct aa_taskreplace_data *data = (struct aa_taskreplace_data *)cookie;
3643
+ unsigned long flags;
3645
+ spin_lock_irqsave(&sd_lock, flags);
3647
+ if (__aa_is_confined(sd) &&
3648
+ BASE_PROFILE(sd->active) == data->old_profile)
3649
+ task_replace(sd, data->new_profile);
3651
+ spin_unlock_irqrestore(&sd_lock, flags);
3656
+static inline int aa_inbounds(struct aa_ext *e, size_t size)
3658
+ return (e->pos + size <= e->end);
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
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.
3670
+static void aa_convert(enum aa_code code, void *dest, void *src)
3674
+ *(u8 *)dest = *(u8 *) src;
3678
+ case AA_DYN_STRING:
3679
+ *(u16 *)dest = le16_to_cpu(get_unaligned((u16 *)src));
3683
+ case AA_STATIC_BLOB:
3684
+ *(u32 *)dest = le32_to_cpu(get_unaligned((u32 *)src));
3687
+ *(u64 *)dest = le64_to_cpu(get_unaligned((u64 *)src));
3690
+ /* nop - all other type codes do not have a trailing value */
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
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
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
3710
+static u32 aa_is_X(struct aa_ext *e, enum aa_code code, void *data)
3712
+ void *pos = e->pos;
3714
+ if (!aa_inbounds(e, AA_CODE_BYTE + aa_code_datasize[code]))
3716
+ if (code != *(u8 *)e->pos &&
3717
+ !(code == AA_BLOB_LOC && AA_STATIC_BLOB == *(u8 *)e->pos))
3719
+ e->pos += AA_CODE_BYTE;
3720
+ if (code == AA_NAME) {
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))
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) {
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))
3739
+ * (char **)data = NULL;
3740
+ str = kmalloc(size, GFP_KERNEL);
3743
+ memcpy(str, e->pos, (size_t) size);
3744
+ str[size-1] = '\0';
3745
+ * (char **)data = str;
3750
+ } else if (code == AA_BLOB_LOC) {
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))
3758
+ * (char **)data = e->pos;
3763
+ } else if (code == AA_STATIC_BLOB) {
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))
3771
+ memcpy(data, e->pos, (size_t) size);
3776
+ aa_convert(code, data, e->pos);
3777
+ e->pos += aa_code_datasize[code];
3778
+ ret = 1 + aa_code_datasize[code];
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.
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
3800
+static int aa_is_nameX(struct aa_ext *e, enum aa_code code, void *data,
3803
+ void *pos = e->pos;
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)))
3814
+ } else if (name) {
3818
+ /* now check if data actually matches */
3819
+ ret = aa_is_X(e, code, data);
3829
+/* macro to wrap error case to make a block of reads look nicer */
3830
+#define AA_READ_X(E, C, D, N) \
3833
+ __ret = aa_is_nameX((E), (C), (D), (N)); \
3839
+ * aa_activate_net_entry - unpacked serialized net entries
3840
+ * @e: serialized data extent information
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.
3846
+static inline int aa_activate_net_entry(struct aa_ext *e)
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);
3868
+ * aa_activate_dfa - unpack a file rule dfa
3869
+ * @e: serialized data extent information
3871
+ * returns dfa or ERR_PTR
3873
+struct aa_dfa *aa_activate_dfa(struct aa_ext *e)
3875
+ char *blob = NULL;
3876
+ size_t size, error = 0;
3877
+ struct aa_dfa *dfa = NULL;
3879
+ size = aa_is_nameX(e, AA_BLOB_LOC, &blob, "aadfa");
3881
+ dfa = aa_match_alloc();
3883
+ error = unpack_dfa(dfa, blob, size);
3886
+ error = verify_dfa(dfa);
3892
+ aa_match_free(dfa);
3893
+ dfa = ERR_PTR(error);
3901
+ * aa_activate_profile - unpack a serialized profile
3902
+ * @e: serialized data extent information
3903
+ * @error: error code returned if unpacking fails
3905
+static struct aa_profile *aa_activate_profile(struct aa_ext *e, ssize_t *error)
3907
+ struct aa_profile *profile = NULL;
3908
+ const char *rulename = "";
3909
+ const char *error_string = "Invalid Profile";
3913
+ profile = alloc_aa_profile();
3915
+ error_string = "Could not allocate profile";
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);
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);
3932
+ error_string = "Invalid capabilities";
3933
+ AA_READ_X(e, AA_U32, &(profile->capabilities), NULL);
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;
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))
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);
3962
+ subprofile->parent = profile;
3963
+ list_add(&subprofile->list, &profile->sub);
3967
+ error_string = "Invalid end of profile";
3968
+ AA_READ_X(e, AA_STRUCTEND, NULL, NULL);
3973
+ AA_WARN("%s: %s %s in profile %s\n", INTERFACE_ID, rulename,
3974
+ error_string, profile && profile->name ? profile->name
3978
+ free_aa_profile(profile);
3986
+ * aa_activate_top_profile - unpack a serialized base profile
3987
+ * @e: serialized data extent information
3988
+ * @error: error code returned if unpacking fails
3990
+ * check interface version unpack a profile and all its hats and patch
3991
+ * in any extra information that the profile needs.
3993
+static void *aa_activate_top_profile(struct aa_ext *e, ssize_t *error)
3995
+ struct aa_profile *profile = NULL;
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;
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;
4012
+ profile = aa_activate_profile(e, error);
4016
+ if (!list_empty(&profile->sub) || profile->flags.complain) {
4017
+ if (attach_nullprofile(profile))
4023
+ free_aa_profile(profile);
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
4032
+ * unpack and add a profile to the profile list. Return %0 or error
4034
+ssize_t aa_file_prof_add(void *data, size_t size)
4036
+ struct aa_profile *profile = NULL;
4038
+ struct aa_ext e = {
4040
+ .end = data + size,
4045
+ profile = aa_activate_top_profile(&e, &error);
4047
+ AA_DEBUG("couldn't activate profile\n");
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
4055
+ if (aa_profilelist_add(profile)) {
4058
+ AA_WARN("trying to add profile (%s) that already exists.\n",
4060
+ put_aa_profile(profile);
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
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.
4077
+ssize_t aa_file_prof_repl(void *udata, size_t size)
4079
+ struct aa_taskreplace_data data;
4080
+ struct aa_ext e = {
4082
+ .end = udata + size,
4088
+ data.new_profile = aa_activate_top_profile(&e, &error);
4089
+ if (!data.new_profile) {
4090
+ AA_DEBUG("couldn't activate profile\n");
4094
+ /* Refcount on data.new_profile is 1 (aa_activate_top_profile).
4096
+ * This reference will be inherited by aa_profilelist_replace for it's
4097
+ * profile list reference but this isn't sufficient.
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.
4105
+ * Grab extra reference on new_profile to prevent this
4108
+ get_aa_profile(data.new_profile);
4110
+ data.old_profile = aa_profilelist_replace(data.new_profile);
4112
+ /* If there was an old profile, find all currently executing tasks
4113
+ * using this profile and replace the old profile with the new.
4115
+ if (data.old_profile) {
4116
+ AA_DEBUG("%s: try to replace profile (%p)%s\n",
4119
+ data.old_profile->name);
4121
+ aa_subdomainlist_iterate(taskreplace_iter, (void *)&data);
4123
+ /* it's off global list, and we are done replacing */
4124
+ put_aa_profile(data.old_profile);
4127
+ /* release extra reference obtained above (race) */
4128
+ put_aa_profile(data.new_profile);
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
4141
+ * remove a profile from the profile list and all subdomain references
4142
+ * to said profile. Return %0 on success, else error.
4144
+ssize_t aa_file_prof_remove(const char *name, size_t size)
4146
+ struct aa_profile *old_profile;
4148
+ /* if the old profile exists it will be removed from the list and
4149
+ * a reference is returned.
4151
+ old_profile = aa_profilelist_remove(name);
4153
+ if (old_profile) {
4154
+ /* remove profile from any tasks using it */
4155
+ aa_subdomainlist_iterate(taskremove_iter, (void *)old_profile);
4157
+ /* drop reference obtained by aa_profilelist_remove */
4158
+ put_aa_profile(old_profile);
4160
+ AA_WARN("%s: trying to remove profile (%s) that "
4161
+ "doesn't exist - skipping.\n", __FUNCTION__, name);
4169
+ * free_aa_profile_kref - free aa_profile by kref (called by put_aa_profile)
4170
+ * @kr: kref callback for freeing of a profile
4172
+void free_aa_profile_kref(struct kref *kr)
4174
+ struct aa_profile *p=container_of(kr, struct aa_profile, count);
4176
+ call_rcu(&p->rcu, free_aa_profile_rcu);
4180
+ * free_aa_profile - free aa_profile structure
4181
+ * @profile: the profile to free
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.
4188
+void free_aa_profile(struct aa_profile *profile)
4190
+ struct aa_profile *p, *ptmp;
4192
+ AA_DEBUG("%s(%p)\n", __FUNCTION__, profile);
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",
4206
+ aa_match_free(profile->file_rules);
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.
4212
+ free_aa_profile(profile->null_profile);
4213
+ list_for_each_entry_safe(p, ptmp, &profile->sub, list) {
4214
+ list_del_init(&p->list);
4216
+ put_aa_profile(p);
4219
+ if (profile->name) {
4220
+ AA_DEBUG("%s: %s\n", __FUNCTION__, profile->name);
4221
+ kfree(profile->name);
4226
Index: b/security/apparmor/module_interface.h
4227
===================================================================
4229
+++ b/security/apparmor/module_interface.h
4231
+#ifndef __MODULEINTERFACE_H
4232
+#define __MODULEINTERFACE_H
4234
+/* Codes of the types of basic structures that are understood */
4235
+#define AA_CODE_BYTE (sizeof(u8))
4236
+#define INTERFACE_ID "INTERFACE"
4238
+#define APPARMOR_INTERFACE_VERSION 2
4245
+ AA_NAME, /* same as string except it is items name */
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.
4264
+ void *pos; /* pointer to current position in the buffer */
4268
+#endif /* __MODULEINTERFACE_H */
4269
Index: b/security/apparmor/procattr.c
4270
===================================================================
4272
+++ b/security/apparmor/procattr.c
4275
+ * Copyright (C) 2005 Novell/SUSE
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
4282
+ * AppArmor /proc/pid/attr handling
4286
+#include <linux/ctype.h>
4288
+#include "apparmor.h"
4289
+#include "inline.h"
4291
+size_t aa_getprocattr(struct aa_profile *active, char *str, size_t size)
4293
+ int error = -EACCES; /* default to a perm denied */
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;
4303
+ lenm = strlen(mode_str);
4305
+ lena = strlen(active->name);
4308
+ if (IN_SUBPROFILE(active)) {
4309
+ lenp = strlen(BASE_PROFILE(active)->name);
4310
+ len += (lenp + 1); /* +1 for ^ */
4312
+ /* DONT null terminate strings we output via proc */
4313
+ len += (lenm + 1); /* for \n */
4315
+ if (len <= size) {
4317
+ memcpy(str, BASE_PROFILE(active)->name,
4323
+ memcpy(str, active->name, lena);
4325
+ memcpy(str, mode_str, lenm);
4329
+ } else if (size == 0) {
4335
+ const char *unconstrained_str = "unconstrained\n";
4336
+ len = strlen(unconstrained_str);
4338
+ /* DONT null terminate strings we output via proc */
4339
+ if (len <= size) {
4340
+ memcpy(str, unconstrained_str, len);
4342
+ } else if (size == 0) {
4353
+int aa_setprocattr_changehat(char *hatinfo, size_t infosize)
4355
+ int error = -EINVAL;
4356
+ char *token = NULL, *hat, *smagic, *tmp;
4358
+ int rc, len, consumed;
4359
+ unsigned long flags;
4361
+ AA_DEBUG("%s: %p %zd\n", __FUNCTION__, hatinfo, infosize);
4363
+ /* strip leading white space */
4364
+ while (infosize && isspace(*hatinfo)) {
4369
+ if (infosize == 0)
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
4377
+ token = kmalloc(infosize + 1, GFP_KERNEL);
4384
+ memcpy(token, hatinfo, infosize);
4385
+ token[infosize] = 0;
4387
+ /* error is INVAL until we have at least parsed something */
4391
+ while (*tmp && *tmp != '^') {
4395
+ if (!*tmp || tmp == token) {
4396
+ AA_WARN("%s: Invalid input '%s'\n", __FUNCTION__, token);
4400
+ /* split magic and hat into two strings */
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.
4410
+ consumed = len = strlen(smagic);
4412
+ rc = sscanf(smagic, "%x%n", &magic, &consumed);
4414
+ if (rc != 1 || consumed != len) {
4415
+ AA_WARN("%s: Invalid hex magic %s\n",
4426
+ if (!hat && !magic) {
4427
+ AA_WARN("%s: Invalid input, NULL hat and NULL magic\n",
4432
+ AA_DEBUG("%s: Magic 0x%x Hat '%s'\n",
4433
+ __FUNCTION__, magic, hat ? hat : NULL);
4435
+ spin_lock_irqsave(&sd_lock, flags);
4436
+ error = aa_change_hat(hat, magic);
4437
+ spin_unlock_irqrestore(&sd_lock, flags);
4441
+ memset(token, 0, infosize);
4448
+int aa_setprocattr_setprofile(struct task_struct *p, char *profilename,
4449
+ size_t profilesize)
4451
+ int error = -EINVAL;
4452
+ struct aa_profile *profile = NULL;
4453
+ struct subdomain *sd;
4454
+ char *name = NULL;
4455
+ unsigned long flags;
4457
+ AA_DEBUG("%s: current %s(%d)\n",
4458
+ __FUNCTION__, current->comm, current->pid);
4460
+ /* strip leading white space */
4461
+ while (profilesize && isspace(*profilename)) {
4466
+ if (profilesize == 0)
4470
+ * Copy string to a new buffer so we guarantee it is zero
4473
+ name = kmalloc(profilesize + 1, GFP_KERNEL);
4480
+ strncpy(name, profilename, profilesize);
4481
+ name[profilesize] = 0;
4484
+ if (strcmp(name, "unconstrained") != 0) {
4485
+ profile = aa_profilelist_find(name);
4487
+ AA_WARN("%s: Unable to switch task %s(%d) to profile"
4488
+ "'%s'. No such profile.\n",
4498
+ spin_lock_irqsave(&sd_lock, flags);
4500
+ sd = AA_SUBDOMAIN(p->security);
4502
+ /* switch to unconstrained */
4504
+ if (__aa_is_confined(sd)) {
4505
+ AA_WARN("%s: Unconstraining task %s(%d) "
4506
+ "profile %s active %s\n",
4509
+ BASE_PROFILE(sd->active)->name,
4510
+ sd->active->name);
4512
+ aa_switch_unconfined(sd);
4514
+ AA_WARN("%s: task %s(%d) "
4515
+ "is already unconstrained\n",
4516
+ __FUNCTION__, p->comm, p->pid);
4520
+ /* this task was created before module was
4521
+ * loaded, allocate a subdomain
4523
+ AA_WARN("%s: task %s(%d) has no subdomain\n",
4524
+ __FUNCTION__, p->comm, p->pid);
4526
+ /* unlock so we can safely GFP_KERNEL */
4527
+ spin_unlock_irqrestore(&sd_lock, flags);
4529
+ sd = alloc_subdomain(p);
4531
+ AA_WARN("%s: Unable to allocate subdomain for "
4532
+ "task %s(%d). Cannot confine task to "
4539
+ put_aa_profile(profile);
4544
+ spin_lock_irqsave(&sd_lock, flags);
4545
+ if (!AA_SUBDOMAIN(p->security)) {
4547
+ } else { /* race */
4548
+ free_subdomain(sd);
4549
+ sd = AA_SUBDOMAIN(p->security);
4553
+ /* ensure the profile hasn't been replaced */
4555
+ if (unlikely(profile->isstale)) {
4556
+ WARN_ON(profile == null_complain_profile);
4558
+ /* drop refcnt obtained from earlier get_aa_profile */
4559
+ put_aa_profile(profile);
4560
+ profile = aa_profilelist_find(name);
4563
+ /* Race, profile was removed. */
4564
+ spin_unlock_irqrestore(&sd_lock, flags);
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.
4576
+ AA_WARN("%s: Switching task %s(%d) "
4577
+ "profile %s active %s to new profile %s\n",
4580
+ sd->active ? BASE_PROFILE(sd->active)->name :
4582
+ sd->active ? sd->active->name : "unconstrained",
4585
+ aa_switch(sd, profile);
4587
+ put_aa_profile(profile); /* drop ref we obtained above
4588
+ * from aa_profilelist_find
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
4595
+ sd->hat_magic = 0;
4598
+ spin_unlock_irqrestore(&sd_lock, flags);
4606
Index: b/security/apparmor/shared.h
4607
===================================================================
4609
+++ b/security/apparmor/shared.h
4612
+ * Copyright (C) 2000, 2001, 2004, 2005 Novell/SUSE
4614
+ * Immunix AppArmor LSM
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
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 */
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
4641
+/* Invalid perm permission */
4642
+#define POS_AA_INVALID_POS 31
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)
4656
+#define AA_EXEC_MODIFIERS (AA_EXEC_INHERIT | \
4657
+ AA_EXEC_UNCONSTRAINED | \
4659
+#define AA_VALID_PERM_MASK ((1 << (POS_AA_FILE_MAX + 1)) - 1)
4661
+#endif /* _SHARED_H */
4662
Index: b/security/apparmor/match.c
4663
===================================================================
4665
+++ b/security/apparmor/match.c
4668
+ * Copyright (C) 2002-2005 Novell/SUSE
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
4675
+ * http://forge.novell.com/modules/xfmod/project/?apparmor
4677
+ * AppArmor aa_match submodule (w/ pattern expansion).
4681
+#include <asm/unaligned.h>
4682
+#include <linux/module.h>
4685
+static const char *features="pattern=aadfa";
4687
+static struct table_header *unpack_table(void *blob, size_t bsize)
4689
+ struct table_header *table = NULL;
4690
+ struct table_header th;
4693
+ if (bsize < sizeof(struct table_header))
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);
4701
+ if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
4702
+ th.td_flags == YYTD_DATA8))
4705
+ tsize = table_size(th.td_lolen, th.td_flags);
4706
+ if (bsize < tsize)
4709
+ table = kmalloc(tsize, GFP_KERNEL);
4712
+ if (th.td_flags == YYTD_DATA8)
4713
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
4715
+ else if (th.td_flags == YYTD_DATA16)
4716
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
4719
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
4727
+int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size)
4730
+ int error = -ENOMEM;
4732
+ /* get dfa table set header */
4733
+ if (size < sizeof(struct table_set_header))
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)));
4741
+ if (dfa->th.th_magic != YYTH_MAGIC)
4744
+ if (size < dfa->th.th_hsize)
4747
+ blob += dfa->th.th_hsize;
4748
+ size -= dfa->th.th_hsize;
4750
+ while (size > 0) {
4751
+ struct table_header *table;
4752
+ table = unpack_table(blob, size);
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)
4766
+ dfa->tables[table->td_id - 1] = table;
4767
+ if (table->td_flags != YYTD_DATA16)
4771
+ dfa->tables[table->td_id - 1] = table;
4772
+ if (table->td_flags != YYTD_DATA8)
4780
+ blob += table_size(table->td_lolen, table->td_flags);
4781
+ size -= table_size(table->td_lolen, table->td_flags);
4791
+ for (i = 0; i < YYTD_ID_NXT; i++) {
4792
+ if (dfa->tables[i]) {
4793
+ kfree(dfa->tables[i]);
4794
+ dfa->tables[i] = NULL;
4801
+ * verify_dfa - verify that all the transitions and states in the dfa tables
4803
+ * @dfa: dfa to test
4805
+ * assumes dfa has gone through the verification done by unpacking
4807
+int verify_dfa(struct aa_dfa *dfa)
4809
+ size_t i, state_count, trans_count;
4810
+ int error = -EPROTO;
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]))
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))
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)
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)
4836
+ for (i = 0; i < state_count; i++) {
4837
+ if (DEFAULT_TABLE(dfa)[i] >= state_count)
4839
+ if (BASE_TABLE(dfa)[i] >= trans_count + 256)
4843
+ for (i = 0; i < trans_count ; i++) {
4844
+ if (NEXT_TABLE(dfa)[i] >= state_count)
4846
+ if (CHECK_TABLE(dfa)[i] >= state_count)
4855
+struct aa_dfa *aa_match_alloc(void)
4857
+ return kzalloc(sizeof(struct aa_dfa), GFP_KERNEL);
4860
+void aa_match_free(struct aa_dfa *dfa)
4864
+ for (i = 0; i < YYTD_ID_NXT; i++) {
4865
+ kfree(dfa->tables[i]);
4871
+const char *aa_match_features(void)
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
4881
+ * Assumes that state is a valid state of the dfa
4883
+ * Returns the label associated with @state. 0 indicates the state
4884
+ * is no-accepting/provides no permissions.
4886
+inline unsigned int aadfa_label(struct aa_dfa *dfa, int state)
4888
+ return ACCEPT_TABLE(dfa)[state];
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
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.
4902
+inline unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int state,
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);
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];
4920
+ state = def[state];
4923
+ for ( ; *s; ++s) {
4924
+ pos = base[state] + *s;
4925
+ if (check[pos] == state)
4926
+ state = next[pos];
4928
+ state = def[state];
4934
+unsigned int aa_match(struct aa_dfa *dfa, const char *pathname)
4937
+ return aadfa_label(dfa, aa_dfa_match(dfa, 1, pathname));
4941
Index: b/security/apparmor/match.h
4942
===================================================================
4944
+++ b/security/apparmor/match.h
4947
+ * Copyright (C) 2002-2005 Novell/SUSE
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
4954
+ * AppArmor submodule (match) prototypes
4960
+#define YYTH_MAGIC 0x1B5E783D
4962
+struct table_set_header {
4963
+ u32 th_magic; /* TH_MAGIC */
4967
+ char th_version[];
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 */
4978
+#define YYTD_DATA8 1
4979
+#define YYTD_DATA16 2
4980
+#define YYTD_DATA32 4
4982
+struct table_header {
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))
4998
+ struct table_header *tables[YYTD_ID_NXT];
5000
+ struct table_set_header th;
5003
+#define ntohb(X) (X)
5005
+#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
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]); \
5015
+static inline size_t pad64(size_t i)
5017
+ return (i + (size_t)7) & ~(size_t)7;
5020
+static inline size_t table_size(size_t len, size_t el_size)
5022
+ return pad64(sizeof(struct table_header) + len * el_size);
5025
+#endif /* __MATCH_H */