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

« back to all changes in this revision

Viewing changes to kernel-patches/for-mainline/rcu-stale-forward-ptr.diff

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
Index: 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
13
 
  *
14
 
@@ -114,7 +114,7 @@ struct aa_profile {
15
 
                int audit;
16
 
        } flags;
17
 
        struct aa_profile *null_profile;
18
 
-       int isstale;
19
 
+       struct aa_profile *isstale;
20
 
 
21
 
        kernel_cap_t capabilities;
22
 
        struct kref count;
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)
28
 
 
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;
36
 
-
37
 
-                       task_lock(task);
38
 
-                       aa_change_task_context(task, NULL, NULL, 0);
39
 
-                       task_unlock(task);
40
 
-               }
41
 
+               profile->isstale = ERR_PTR(-ENOENT);
42
 
+               remove_tasks_on_context_list(profile);
43
 
                unlock_profile(profile);
44
 
 
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
50
 
@@ -14,8 +14,6 @@
51
 
 #include "apparmor.h"
52
 
 #include "inline.h"
53
 
 
54
 
-static DEFINE_MUTEX(aa_interface_lock);
55
 
-
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
60
 
        if (IS_ERR(profile))
61
 
                return PTR_ERR(profile);
62
 
 
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);
70
 
                return -EEXIST;
71
 
        }
72
 
        list_add(&profile->list, &profile_list);
73
 
        write_unlock(&profile_list_lock);
74
 
-       mutex_unlock(&aa_interface_lock);
75
 
 
76
 
        return size;
77
 
 }
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);
81
 
 
82
 
-       mutex_lock(&aa_interface_lock);
83
 
        write_lock(&profile_list_lock);
84
 
        old_profile = __aa_find_profile(new_profile->name, &profile_list);
85
 
        if (old_profile) {
86
 
-               old_profile->isstale = 1;
87
 
+               old_profile->isstale = aa_dup_profile(new_profile);
88
 
                list_del_init(&old_profile->list);
89
 
        }
90
 
+       aa_dup_profile(new_profile);
91
 
        list_add(&new_profile->list, &profile_list);
92
 
        write_unlock(&profile_list_lock);
93
 
 
94
 
@@ -460,9 +455,18 @@ ssize_t aa_file_prof_replace(void *udata
95
 
                goto out;
96
 
 
97
 
        /*
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
107
 
+        * that is stale.
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.
113
 
         */
114
 
        do {
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
118
 
                 * the list
119
 
                 */
120
 
+       repeat:
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);
128
 
+                               break;
129
 
+                       }
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;
134
 
+                       goto repeat;
135
 
+               }
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
140
 
        } while (!new_cxt);
141
 
        aa_free_task_context(new_cxt);
142
 
        aa_put_profile(old_profile);
143
 
-
144
 
+       aa_put_profile(new_profile);
145
 
 out:
146
 
-       mutex_unlock(&aa_interface_lock);
147
 
 
148
 
        return size;
149
 
 }
150
 
@@ -507,29 +525,19 @@ ssize_t aa_file_prof_remove(const char *
151
 
 {
152
 
        struct aa_profile *profile;
153
 
 
154
 
-       mutex_lock(&aa_interface_lock);
155
 
        write_lock(&profile_list_lock);
156
 
        profile = __aa_find_profile(name, &profile_list);
157
 
        if (!profile) {
158
 
                write_unlock(&profile_list_lock);
159
 
-               mutex_unlock(&aa_interface_lock);
160
 
                return -ENOENT;
161
 
        }
162
 
-       profile->isstale = 1;
163
 
+       profile->isstale = ERR_PTR(-ENOENT);
164
 
        list_del_init(&profile->list);
165
 
        write_unlock(&profile_list_lock);
166
 
 
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;
172
 
-               task_lock(task);
173
 
-               aa_change_task_context(task, NULL, NULL, 0);
174
 
-               task_unlock(task);
175
 
-       }
176
 
+       remove_tasks_on_context_list(profile);
177
 
        unlock_profile(profile);
178
 
-       mutex_unlock(&aa_interface_lock);
179
 
        aa_put_profile(profile);
180
 
 
181
 
        return size;
182
 
@@ -573,6 +581,8 @@ void free_aa_profile(struct aa_profile *
183
 
                BUG();
184
 
        }
185
 
 
186
 
+       if (!IS_ERR(profile->isstale))
187
 
+               aa_put_profile(profile->isstale);
188
 
        aa_match_free(profile->file_rules);
189
 
 
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
196
 
 }
197
 
 
198
 
 /**
199
 
+ * remove_tasks_on_context_list - remove tasks on @profiles task_contexts list
200
 
+ * @profile: profile to remove associated tasks
201
 
+ *
202
 
+ * Assumes that @profile lock is held
203
 
+ */
204
 
+static inline void remove_tasks_on_context_list(struct aa_profile *profile)
205
 
+{
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;
210
 
+               task_lock(task);
211
 
+               aa_change_task_context(task, NULL, NULL, 0);
212
 
+               task_unlock(task);
213
 
+       }
214
 
+}
215
 
+
216
 
+/**
217
 
  * lock_profile - lock a profile
218
 
  * @profile: the profile to lock
219
 
  *