1
Index: linux-2.6-apparmor/security/apparmor/apparmor.h
2
===================================================================
3
--- linux-2.6-apparmor.orig/security/apparmor/apparmor.h
4
+++ linux-2.6-apparmor/security/apparmor/apparmor.h
5
@@ -88,7 +88,7 @@ static inline int mediated_filesystem(st
6
* @sub: profiles list of subprofiles (HATS)
7
* @flags: flags controlling profile behavior
8
* @null_profile: if needed per profile learning and null confinement profile
9
- * @isstale: flag to indicate the profile is stale
10
+ * @isstale: flag indicating profile is stale by pointing to its replacement
11
* @capabilities: capabilities granted by the process
12
* @count: reference count of the profile
14
@@ -114,7 +114,7 @@ struct aa_profile {
17
struct aa_profile *null_profile;
19
+ struct aa_profile *isstale;
21
kernel_cap_t capabilities;
23
Index: linux-2.6-apparmor/security/apparmor/lsm.c
24
===================================================================
25
--- linux-2.6-apparmor.orig/security/apparmor/lsm.c
26
+++ linux-2.6-apparmor/security/apparmor/lsm.c
27
@@ -806,16 +806,8 @@ static void __exit apparmor_exit(void)
29
/* Remove the profile from each task context it is on. */
30
lock_profile(profile);
31
- profile->isstale = 1;
32
- while (!list_empty(&profile->task_contexts)) {
33
- struct task_struct *task =
34
- list_entry(profile->task_contexts.next,
35
- struct aa_task_context, list)->task;
38
- aa_change_task_context(task, NULL, NULL, 0);
41
+ profile->isstale = ERR_PTR(-ENOENT);
42
+ remove_tasks_on_context_list(profile);
43
unlock_profile(profile);
45
/* Release the profile itself. */
46
Index: linux-2.6-apparmor/security/apparmor/module_interface.c
47
===================================================================
48
--- linux-2.6-apparmor.orig/security/apparmor/module_interface.c
49
+++ linux-2.6-apparmor/security/apparmor/module_interface.c
54
-static DEFINE_MUTEX(aa_interface_lock);
56
/* The AppArmor interface treats data as a type byte followed by the
57
* actual data. The interface has the notion of a a named entry
58
* which has a name (AA_NAME typecode followed by name string) followed by
59
@@ -364,18 +362,15 @@ ssize_t aa_file_prof_add(void *data, siz
61
return PTR_ERR(profile);
63
- mutex_lock(&aa_interface_lock);
64
write_lock(&profile_list_lock);
65
if (__aa_find_profile(profile->name, &profile_list)) {
66
/* A profile with this name exists already. */
67
write_unlock(&profile_list_lock);
68
- mutex_unlock(&aa_interface_lock);
69
aa_put_profile(profile);
72
list_add(&profile->list, &profile_list);
73
write_unlock(&profile_list_lock);
74
- mutex_unlock(&aa_interface_lock);
78
@@ -446,13 +441,13 @@ ssize_t aa_file_prof_replace(void *udata
79
if (IS_ERR(new_profile))
80
return PTR_ERR(new_profile);
82
- mutex_lock(&aa_interface_lock);
83
write_lock(&profile_list_lock);
84
old_profile = __aa_find_profile(new_profile->name, &profile_list);
86
- old_profile->isstale = 1;
87
+ old_profile->isstale = aa_dup_profile(new_profile);
88
list_del_init(&old_profile->list);
90
+ aa_dup_profile(new_profile);
91
list_add(&new_profile->list, &profile_list);
92
write_unlock(&profile_list_lock);
94
@@ -460,9 +455,18 @@ ssize_t aa_file_prof_replace(void *udata
98
- * FIXME: this loop is confusing. Can't we simply allocate the new
99
- * task context under the profile locks after checking that we
100
- * actually need it?
101
+ * Replacement needs to allocate a new aa_task_context for each
102
+ * task confined by old_profile. To do this the profile locks
103
+ * are only held when the actual switch is done per task. While
104
+ * looping to allocate a new aa_task_context the old_task list
105
+ * may get shorter if tasks exist/change their profile but will
106
+ * not get longer as new task will not use old_profile detecting
108
+ * The new_profile could be removed/replaced becoming stale itself.
109
+ * In this case replacement switches to using new_profile->isstale
110
+ * forwarding pointer for replacement of any remaining tasks.
111
+ * The replacement that made new_profile stale will take care of
112
+ * replacing any tasks that were already moved to new_profile.
115
new_cxt = aa_alloc_task_context(GFP_KERNEL | __GFP_NOFAIL);
116
@@ -474,7 +478,22 @@ ssize_t aa_file_prof_replace(void *udata
117
* profile (updating the list) and replacement updating
121
lock_both_profiles(old_profile, new_profile);
122
+ if (new_profile->isstale) {
123
+ struct aa_profile *profile;
124
+ if (IS_ERR(new_profile->isstale)) {
125
+ /* new_profile was removed so become removal */
126
+ remove_tasks_on_context_list(old_profile);
127
+ unlock_both_profiles(old_profile, new_profile);
130
+ profile = aa_dup_profile(new_profile->isstale);
131
+ unlock_both_profiles(old_profile, new_profile);
132
+ aa_put_profile(new_profile);
133
+ new_profile = profile;
136
if (!list_empty(&old_profile->task_contexts)) {
137
struct task_struct *task =
138
list_entry(old_profile->task_contexts.next,
139
@@ -488,9 +507,8 @@ ssize_t aa_file_prof_replace(void *udata
141
aa_free_task_context(new_cxt);
142
aa_put_profile(old_profile);
144
+ aa_put_profile(new_profile);
146
- mutex_unlock(&aa_interface_lock);
150
@@ -507,29 +525,19 @@ ssize_t aa_file_prof_remove(const char *
152
struct aa_profile *profile;
154
- mutex_lock(&aa_interface_lock);
155
write_lock(&profile_list_lock);
156
profile = __aa_find_profile(name, &profile_list);
158
write_unlock(&profile_list_lock);
159
- mutex_unlock(&aa_interface_lock);
162
- profile->isstale = 1;
163
+ profile->isstale = ERR_PTR(-ENOENT);
164
list_del_init(&profile->list);
165
write_unlock(&profile_list_lock);
167
lock_profile(profile);
168
- while (!list_empty(&profile->task_contexts)) {
169
- struct task_struct *task =
170
- list_entry(profile->task_contexts.next,
171
- struct aa_task_context, list)->task;
173
- aa_change_task_context(task, NULL, NULL, 0);
176
+ remove_tasks_on_context_list(profile);
177
unlock_profile(profile);
178
- mutex_unlock(&aa_interface_lock);
179
aa_put_profile(profile);
182
@@ -573,6 +581,8 @@ void free_aa_profile(struct aa_profile *
186
+ if (!IS_ERR(profile->isstale))
187
+ aa_put_profile(profile->isstale);
188
aa_match_free(profile->file_rules);
190
/* use free_aa_profile instead of aa_put_profile to destroy the
191
Index: linux-2.6-apparmor/security/apparmor/inline.h
192
===================================================================
193
--- linux-2.6-apparmor.orig/security/apparmor/inline.h
194
+++ linux-2.6-apparmor/security/apparmor/inline.h
195
@@ -104,6 +104,24 @@ static inline struct aa_profile *alloc_a
199
+ * remove_tasks_on_context_list - remove tasks on @profiles task_contexts list
200
+ * @profile: profile to remove associated tasks
202
+ * Assumes that @profile lock is held
204
+static inline void remove_tasks_on_context_list(struct aa_profile *profile)
206
+ while (!list_empty(&profile->task_contexts)) {
207
+ struct task_struct *task =
208
+ list_entry(profile->task_contexts.next,
209
+ struct aa_task_context, list)->task;
211
+ aa_change_task_context(task, NULL, NULL, 0);
217
* lock_profile - lock a profile
218
* @profile: the profile to lock