~ubuntu-branches/ubuntu/oneiric/apparmor/oneiric-security

« back to all changes in this revision

Viewing changes to kernel-patches/for-mainline/rework-locking.diff

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
Index: b/security/apparmor/apparmor.h
2
 
===================================================================
3
 
--- a/security/apparmor/apparmor.h
4
 
+++ b/security/apparmor/apparmor.h
5
 
@@ -128,9 +128,6 @@ struct aa_profile {
6
 
 extern struct list_head profile_list;
7
 
 extern rwlock_t profile_list_lock;
8
 
 
9
 
-extern struct list_head task_context_list;
10
 
-extern rwlock_t task_context_list_lock;
11
 
-
12
 
 /**
13
 
  * struct aa_task_context - primary label for confined tasks
14
 
  * @profile: the current profile
15
 
@@ -155,9 +152,6 @@ static inline struct aa_task_context *aa
16
 
        return (struct aa_task_context *)task->security;
17
 
 }
18
 
 
19
 
-/* Lock protecting access to 'struct aa_task_context' accesses */
20
 
-extern spinlock_t cxt_lock;
21
 
-
22
 
 extern struct aa_profile *null_complain_profile;
23
 
 
24
 
 /* aa_audit - AppArmor auditing structure
25
 
@@ -242,9 +236,6 @@ extern struct aa_profile *__aa_find_prof
26
 
 
27
 
 /* list.c */
28
 
 extern void aa_profilelist_release(void);
29
 
-extern void aa_task_context_list_add(struct aa_task_context *);
30
 
-extern void aa_task_context_list_remove(struct aa_task_context *);
31
 
-extern void aa_task_context_list_release(void);
32
 
 
33
 
 /* module_interface.c */
34
 
 extern ssize_t aa_file_prof_add(void *, size_t);
35
 
Index: b/security/apparmor/inline.h
36
 
===================================================================
37
 
--- a/security/apparmor/inline.h
38
 
+++ b/security/apparmor/inline.h
39
 
@@ -42,7 +42,7 @@ static inline struct aa_profile *aa_get_
40
 
        rcu_read_lock();
41
 
        cxt = aa_task_context(task);
42
 
        if (cxt) {
43
 
-               profile = (struct aa_profile *)rcu_dereference(cxt->profile);
44
 
+               profile = rcu_dereference(cxt->profile);
45
 
                aa_dup_profile(profile);
46
 
        }
47
 
        rcu_read_unlock();
48
 
@@ -79,41 +79,22 @@ static inline void aa_change_profile(str
49
 
        aa_put_profile(old_profile);
50
 
 }
51
 
 
52
 
-/**
53
 
- * alloc_aa_task_context - allocate a new aa_task_context
54
 
- * @task: task struct
55
 
- *
56
 
- * Allocate a new aa_task_context including a backpointer to it's referring
57
 
- * task.
58
 
- */
59
 
-static inline struct aa_task_context *alloc_aa_task_context(struct task_struct *task)
60
 
+static inline struct aa_task_context *
61
 
+aa_alloc_task_context(struct task_struct *task)
62
 
 {
63
 
        struct aa_task_context *cxt;
64
 
 
65
 
        cxt = kzalloc(sizeof(struct aa_task_context), GFP_KERNEL);
66
 
-       if (!cxt)
67
 
-               goto out;
68
 
-
69
 
-       /* back pointer to task */
70
 
-       cxt->task = task;
71
 
-
72
 
-       /* any readers of the list must make sure that they can handle
73
 
-        * case where cxt->profile is not yet set (null)
74
 
-        */
75
 
-       aa_task_context_list_add(cxt);
76
 
+       if (cxt) {
77
 
+               INIT_LIST_HEAD(&cxt->list);
78
 
+               cxt->task = task;
79
 
+       }
80
 
 
81
 
-out:
82
 
        return cxt;
83
 
 }
84
 
 
85
 
-/**
86
 
- * free_aa_task_context - Free a aa_task_context previously allocated by
87
 
- *                        alloc_aa_task_context
88
 
- * @cxt: aa_task_context
89
 
- */
90
 
-static inline void free_aa_task_context(struct aa_task_context *cxt)
91
 
+static inline void aa_free_task_context(struct aa_task_context *cxt)
92
 
 {
93
 
-       aa_task_context_list_remove(cxt);
94
 
        kfree(cxt);
95
 
 }
96
 
 
97
 
Index: b/security/apparmor/list.c
98
 
===================================================================
99
 
--- a/security/apparmor/list.c
100
 
+++ b/security/apparmor/list.c
101
 
@@ -17,10 +17,6 @@
102
 
 LIST_HEAD(profile_list);
103
 
 rwlock_t profile_list_lock = RW_LOCK_UNLOCKED;
104
 
 
105
 
-/* list of all task_contexts and lock */
106
 
-LIST_HEAD(task_context_list);
107
 
-rwlock_t task_context_list_lock = RW_LOCK_UNLOCKED;
108
 
-
109
 
 /**
110
 
  * __aa_find_profile  -  look up a profile on the profile list
111
 
  * @name: name of profile to find
112
 
@@ -56,58 +52,6 @@ void aa_profilelist_release(void)
113
 
        write_unlock(&profile_list_lock);
114
 
 }
115
 
 
116
 
-/**
117
 
- * aa_task_context_list_add - Add aa_task_context to task_context_list
118
 
- * @cxt: new aa_task_context
119
 
- */
120
 
-void aa_task_context_list_add(struct aa_task_context *cxt)
121
 
-{
122
 
-       unsigned long flags;
123
 
-
124
 
-       if (!cxt) {
125
 
-               AA_INFO("%s: bad aa_task_context\n", __FUNCTION__);
126
 
-               return;
127
 
-       }
128
 
-
129
 
-       write_lock_irqsave(&task_context_list_lock, flags);
130
 
-       /* new aa_task_contexts must be added to the end of the list due to a
131
 
-        * subtle interaction between fork and profile replacement.
132
 
-        */
133
 
-       list_add_tail(&cxt->list, &task_context_list);
134
 
-       write_unlock_irqrestore(&task_context_list_lock, flags);
135
 
-}
136
 
-
137
 
-/**
138
 
- * aa_task_context_list_remove - Remove aa_task_context from task_context_list
139
 
- * @cxt: aa_task_context to be removed
140
 
- */
141
 
-void aa_task_context_list_remove(struct aa_task_context *cxt)
142
 
-{
143
 
-       unsigned long flags;
144
 
-
145
 
-       if (cxt) {
146
 
-               write_lock_irqsave(&task_context_list_lock, flags);
147
 
-               list_del_init(&cxt->list);
148
 
-               write_unlock_irqrestore(&task_context_list_lock, flags);
149
 
-       }
150
 
-}
151
 
-
152
 
-/**
153
 
- * aa_task_context_list_release - Remove all aa_task_contexts from
154
 
- *                               task_context_list
155
 
- */
156
 
-void aa_task_context_list_release(void)
157
 
-{
158
 
-       struct aa_task_context *node, *tmp;
159
 
-       unsigned long flags;
160
 
-
161
 
-       write_lock_irqsave(&task_context_list_lock, flags);
162
 
-       list_for_each_entry_safe(node, tmp, &task_context_list, list) {
163
 
-               list_del_init(&node->list);
164
 
-       }
165
 
-       write_unlock_irqrestore(&task_context_list_lock, flags);
166
 
-}
167
 
-
168
 
 /* seq_file helper routines
169
 
  * Used by apparmorfs.c to iterate over profile_list
170
 
  */
171
 
Index: b/security/apparmor/lsm.c
172
 
===================================================================
173
 
--- a/security/apparmor/lsm.c
174
 
+++ b/security/apparmor/lsm.c
175
 
@@ -21,9 +21,6 @@
176
 
 #include "apparmor.h"
177
 
 #include "inline.h"
178
 
 
179
 
-/* struct aa_task_context write update lock (read side is RCU). */
180
 
-spinlock_t cxt_lock = SPIN_LOCK_UNLOCKED;
181
 
-
182
 
 /* Flag values, also controllable via apparmorfs/control.
183
 
  * We explicitly do not allow these to be modifiable when exported via
184
 
  * /sys/modules/parameters, as we want to do additional mediation and
185
 
@@ -749,49 +746,68 @@ createfs_out:
186
 
 
187
 
 static void __exit apparmor_exit(void)
188
 
 {
189
 
-       struct aa_task_context *cxt;
190
 
-       unsigned long flags;
191
 
+       LIST_HEAD(task_contexts_bucket);
192
 
 
193
 
-       /* Remove profiles from the global profile list.
194
 
-        * This is just for tidyness as there is no way to reference this
195
 
-        * list once the AppArmor lsm hooks are detached (below)
196
 
-        */
197
 
-       aa_profilelist_release();
198
 
+       /* Remove and release all the profiles on the profile list. */
199
 
+       write_lock(&profile_list_lock);
200
 
+       while (!list_empty(&profile_list)) {
201
 
+               struct aa_profile *profile =
202
 
+                       list_entry(profile_list.next, struct aa_profile, list);
203
 
+
204
 
+               /* Remove the profile from each task context it is on. */
205
 
+               lock_profile(profile);
206
 
+               while (!list_empty(&profile->task_contexts)) {
207
 
+                       struct aa_task_context *cxt =
208
 
+                               list_entry(profile->task_contexts.next,
209
 
+                                          struct aa_task_context, list);
210
 
+
211
 
+                       /*
212
 
+                        * Detach the task context from the task. Protect
213
 
+                        * from races by taking the task lock here.
214
 
+                        */
215
 
+                       task_lock(cxt->task);
216
 
+                       rcu_assign_pointer(cxt->task->security, NULL);
217
 
+                       task_unlock(cxt->task);
218
 
+                       aa_change_profile(cxt, NULL, 0);
219
 
 
220
 
-       /* Remove profiles from profiled tasks
221
 
-        * If this is not done,  if module is reloaded after being removed,
222
 
-        * old profiles (still refcounted in memory) will become 'magically'
223
 
-        * reattached
224
 
-        */
225
 
+                       /*
226
 
+                        * Defer release: the task context may still have
227
 
+                        * active readers.
228
 
+                        */
229
 
+                       list_move(&cxt->list, &task_contexts_bucket);
230
 
+               }
231
 
+               unlock_profile(profile);
232
 
 
233
 
-       /*
234
 
-        * FIXME: We have a lock inversion here (cp. aa_file_prof_repl,
235
 
-        * aa_file_prof_remove).
236
 
-        */
237
 
-       spin_lock_irqsave(&cxt_lock, flags);
238
 
-       read_lock(&task_context_list_lock);
239
 
-       list_for_each_entry(cxt, &task_context_list, list) {
240
 
-               if (cxt->profile)
241
 
-                       aa_change_profile(cxt, NULL, 0);
242
 
+               /* Release the profile itself. */
243
 
+               list_del_init(&profile->list);
244
 
+               aa_put_profile(profile);
245
 
        }
246
 
-       read_unlock(&task_context_list_lock);
247
 
-       spin_unlock_irqrestore(&cxt_lock, flags);
248
 
-
249
 
-       /* Free up list of profile aa_task_context */
250
 
-       aa_task_context_list_release();
251
 
+       write_unlock(&profile_list_lock);
252
 
 
253
 
        free_null_complain_profile();
254
 
 
255
 
+       /**
256
 
+        * Delay for an rcu cycle to make sure that all active task
257
 
+        * context readers have finished, and all profiles have been
258
 
+        * freed by their rcu callbacks.
259
 
+        */
260
 
+       synchronize_rcu();
261
 
+
262
 
+       /* Now we can safely free all remaining task contexts. */
263
 
+       while (!list_empty(&task_contexts_bucket)) {
264
 
+               struct aa_task_context *cxt =
265
 
+                       list_entry(task_contexts_bucket.next,
266
 
+                                  struct aa_task_context, list);
267
 
+
268
 
+               list_del(&cxt->list);
269
 
+               kfree(cxt);
270
 
+       }
271
 
+
272
 
        destroy_apparmorfs();
273
 
 
274
 
        if (unregister_security(&apparmor_ops))
275
 
                AA_WARN("Unable to properly unregister AppArmor\n");
276
 
 
277
 
-       /* delay for an rcu cycle to make ensure that profiles pending
278
 
-        * destruction in the rcu callback are freed.
279
 
-        */
280
 
-       synchronize_rcu();
281
 
-
282
 
        AA_INFO("AppArmor protection removed\n");
283
 
        aa_audit_message(NULL, GFP_KERNEL, 0,
284
 
                "AppArmor protection removed\n");
285
 
Index: b/security/apparmor/main.c
286
 
===================================================================
287
 
--- a/security/apparmor/main.c
288
 
+++ b/security/apparmor/main.c
289
 
@@ -717,19 +717,9 @@ int aa_link(struct aa_profile *profile,
290
 
  *******************************/
291
 
 
292
 
 /**
293
 
- * aa_fork - create a new aa_task_context
294
 
- * @task: new process
295
 
- *
296
 
- * Create a new aa_task_context for newly created process @task if it's parent
297
 
- * is already confined.  Otherwise a aa_task_context will be lazily allocated
298
 
- * will get one with NULL values.  Return 0 on sucess.
299
 
- * for the child if it subsequently execs (in aa_register).
300
 
- * Return 0 on sucess.
301
 
- *
302
 
- * The cxt_lock is used to maintain consistency against profile
303
 
- * replacement/removal.
304
 
+ * aa_fork - initialize the task context for a new task
305
 
+ * @task: task that is being created
306
 
  */
307
 
-
308
 
 int aa_fork(struct task_struct *task)
309
 
 {
310
 
        struct aa_task_context *cxt = aa_task_context(current);
311
 
@@ -738,9 +728,7 @@ int aa_fork(struct task_struct *task)
312
 
        AA_DEBUG("%s\n", __FUNCTION__);
313
 
 
314
 
        if (cxt && cxt->profile) {
315
 
-               unsigned long flags;
316
 
-
317
 
-               newcxt = alloc_aa_task_context(task);
318
 
+               newcxt = aa_alloc_task_context(task);
319
 
 
320
 
                /* FIXME: The alloc above is a blocking operation, so
321
 
                 *        cxt->profile may have vanished by now.
322
 
@@ -758,9 +746,7 @@ int aa_fork(struct task_struct *task)
323
 
                 * race with profile replacement or removal here, and
324
 
                 * he new task would end up with an obsolete profile.
325
 
                 */
326
 
-               spin_lock_irqsave(&cxt_lock, flags);
327
 
                aa_change_profile(newcxt, cxt->profile, cxt->hat_magic);
328
 
-               spin_unlock_irqrestore(&cxt_lock, flags);
329
 
 
330
 
                if (APPARMOR_COMPLAIN(cxt) &&
331
 
                    cxt->profile == null_complain_profile)
332
 
@@ -910,7 +896,6 @@ repeat:
333
 
        /* Apply the new profile, or switch to unconfined if NULL. */
334
 
        if (!IS_ERR(newprofile)) {
335
 
                struct aa_task_context *cxt, *lazy_cxt = NULL;
336
 
-               unsigned long flags;
337
 
 
338
 
                /* grab a lock - this is to guarentee consistency against
339
 
                 * other writers of aa_task_context (replacement/removal)
340
 
@@ -936,7 +921,7 @@ repeat:
341
 
                 */
342
 
 
343
 
                if (!profile && !(cxt = aa_task_context(current))) {
344
 
-                       lazy_cxt = alloc_aa_task_context(current);
345
 
+                       lazy_cxt = aa_alloc_task_context(current);
346
 
                        if (!lazy_cxt) {
347
 
                                AA_ERROR("%s: Failed to allocate aa_task_context\n",
348
 
                                         __FUNCTION__);
349
 
@@ -945,13 +930,11 @@ repeat:
350
 
                        }
351
 
                }
352
 
 
353
 
-               spin_lock_irqsave(&cxt_lock, flags);
354
 
-
355
 
                cxt = aa_task_context(current);
356
 
                if (lazy_cxt) {
357
 
                        if (cxt) {
358
 
                                /* raced by setprofile - created cxt */
359
 
-                               free_aa_task_context(lazy_cxt);
360
 
+                               aa_free_task_context(lazy_cxt);
361
 
                                lazy_cxt = NULL;
362
 
                        } else {
363
 
                                /* Not rcu used to get the write barrier
364
 
@@ -977,7 +960,6 @@ repeat:
365
 
                                /* Race, profile was removed, not replaced.
366
 
                                 * Redo with error checking
367
 
                                 */
368
 
-                               spin_unlock_irqrestore(&cxt_lock, flags);
369
 
                                goto repeat;
370
 
                        }
371
 
                }
372
 
@@ -1005,8 +987,6 @@ repeat:
373
 
                        LOG_HINT(newprofile, GFP_ATOMIC, HINT_CHGPROF,
374
 
                                "pid=%d\n",
375
 
                                current->pid);
376
 
-
377
 
-               spin_unlock_irqrestore(&cxt_lock, flags);
378
 
        }
379
 
 
380
 
 cleanup:
381
 
@@ -1019,28 +999,51 @@ cleanup:
382
 
 }
383
 
 
384
 
 /**
385
 
- * aa_release - release the task's aa_task_context
386
 
+ * aa_release - release a task context
387
 
  * @task: task being released
388
 
  *
389
 
  * This is called after a task has exited and the parent has reaped it.
390
 
- * @task->security blob is freed.
391
 
- *
392
 
- * This is the one case where we don't need to hold the cxt_lock before
393
 
- * removing a profile from a aa_task_context.  Once the aa_task_context has
394
 
- * been removed from the aa_task_context_list, we are no longer racing other
395
 
- * writers. There may still be other readers so we must still use
396
 
- * aa_change_profile to put the aa_task_context's reference safely.
397
 
  */
398
 
 void aa_release(struct task_struct *task)
399
 
 {
400
 
-       struct aa_task_context *cxt = aa_task_context(task);
401
 
-       if (cxt) {
402
 
-               task->security = NULL;
403
 
+       struct aa_task_context *cxt = NULL;
404
 
+       struct aa_profile *profile;
405
 
 
406
 
-               aa_task_context_list_remove(cxt);
407
 
-               aa_change_profile(cxt, NULL, 0);
408
 
+       /*
409
 
+        * While the task context is still on a profile's task context
410
 
+        * list, another process could replace the profile under us,
411
 
+        * leaving us with a locked profile that is no longer attached
412
 
+        * to this task. So after locking the profile, we lock the task
413
 
+        * to make sure that the profile is still attached. (We must
414
 
+        * lock the profile first to avoid lock inversion.)
415
 
+        *
416
 
+        * If the task does not have a profile attached at this point,
417
 
+        * we are safe.
418
 
+        */
419
 
 
420
 
+repeat:
421
 
+       profile = aa_get_profile(task);
422
 
+       if (profile) {
423
 
+               lock_profile(profile);
424
 
+               task_lock(task);
425
 
+               cxt = aa_task_context(task);
426
 
+               if (unlikely(profile != cxt->profile)) {
427
 
+                       task_unlock(task);
428
 
+                       unlock_profile(profile);
429
 
+                       aa_put_profile(profile);
430
 
+                       goto repeat;
431
 
+               }
432
 
+               /*
433
 
+                * There may still be other profile readers, so we must
434
 
+                * put the profile reference safely.
435
 
+                */
436
 
+               aa_change_profile(cxt, NULL, 0);
437
 
+               task_unlock(task);
438
 
+               list_del(&cxt->list);
439
 
+               unlock_profile(profile);
440
 
+               aa_put_profile(profile);
441
 
                kfree(cxt);
442
 
+               task->security = NULL;
443
 
        }
444
 
 }
445
 
 
446
 
Index: b/security/apparmor/procattr.c
447
 
===================================================================
448
 
--- a/security/apparmor/procattr.c
449
 
+++ b/security/apparmor/procattr.c
450
 
@@ -82,7 +82,6 @@ int aa_setprocattr_changehat(char *hatin
451
 
        char *token = NULL, *hat, *smagic, *tmp;
452
 
        u32 magic;
453
 
        int rc, len, consumed;
454
 
-       unsigned long flags;
455
 
 
456
 
        AA_DEBUG("%s: %p %zd\n", __FUNCTION__, hatinfo, infosize);
457
 
 
458
 
@@ -158,9 +157,7 @@ int aa_setprocattr_changehat(char *hatin
459
 
        AA_DEBUG("%s: Magic 0x%x Hat '%s'\n",
460
 
                 __FUNCTION__, magic, hat ? hat : NULL);
461
 
 
462
 
-       spin_lock_irqsave(&cxt_lock, flags);
463
 
        error = aa_change_hat(hat, magic);
464
 
-       spin_unlock_irqrestore(&cxt_lock, flags);
465
 
 
466
 
 out:
467
 
        if (token) {
468
 
@@ -178,7 +175,6 @@ int aa_setprocattr_setprofile(struct tas
469
 
        struct aa_profile *profile = NULL;
470
 
        struct aa_task_context *cxt;
471
 
        char *name = NULL;
472
 
-       unsigned long flags;
473
 
 
474
 
        AA_DEBUG("%s: current %s(%d)\n",
475
 
                 __FUNCTION__, current->comm, current->pid);
476
 
@@ -221,8 +217,6 @@ int aa_setprocattr_setprofile(struct tas
477
 
                }
478
 
        }
479
 
 
480
 
-       spin_lock_irqsave(&cxt_lock, flags);
481
 
-
482
 
        cxt = aa_task_context(task);
483
 
 
484
 
        /* switch to unconstrained */
485
 
@@ -249,10 +243,7 @@ int aa_setprocattr_setprofile(struct tas
486
 
                        AA_WARN("%s: task %s(%d) has no aa_task_context\n",
487
 
                                __FUNCTION__, task->comm, task->pid);
488
 
 
489
 
-                       /* unlock so we can safely GFP_KERNEL */
490
 
-                       spin_unlock_irqrestore(&cxt_lock, flags);
491
 
-
492
 
-                       cxt = alloc_aa_task_context(task);
493
 
+                       cxt = aa_alloc_task_context(task);
494
 
                        if (!cxt) {
495
 
                                AA_WARN("%s: Unable to allocate "
496
 
                                        "aa_task_context for task %s(%d). "
497
 
@@ -267,11 +258,10 @@ int aa_setprocattr_setprofile(struct tas
498
 
                                goto out;
499
 
                        }
500
 
 
501
 
-                       spin_lock_irqsave(&cxt_lock, flags);
502
 
                        if (!aa_task_context(task)) {
503
 
                                task->security = cxt;
504
 
                        } else { /* race */
505
 
-                               free_aa_task_context(cxt);
506
 
+                               aa_free_task_context(cxt);
507
 
                                cxt = aa_task_context(task);
508
 
                        }
509
 
                }
510
 
@@ -287,7 +277,6 @@ int aa_setprocattr_setprofile(struct tas
511
 
 
512
 
                        if (!profile) {
513
 
                                /* Race, profile was removed. */
514
 
-                               spin_unlock_irqrestore(&cxt_lock, flags);
515
 
                                goto repeat;
516
 
                        }
517
 
                }
518
 
@@ -312,8 +301,6 @@ int aa_setprocattr_setprofile(struct tas
519
 
                aa_put_profile(profile);
520
 
        }
521
 
 
522
 
-       spin_unlock_irqrestore(&cxt_lock, flags);
523
 
-
524
 
        error = 0;
525
 
 out:
526
 
        kfree(name);
527
 
Index: b/security/apparmor/module_interface.c
528
 
===================================================================
529
 
--- a/security/apparmor/module_interface.c
530
 
+++ b/security/apparmor/module_interface.c
531
 
@@ -460,29 +460,24 @@ ssize_t aa_file_prof_repl(void *udata, s
532
 
        old_profile = __aa_find_profile(new_profile->name, &profile_list);
533
 
        if (old_profile) {
534
 
                struct aa_task_context *cxt;
535
 
-               unsigned long flags;
536
 
-
537
 
-               list_del_init(&old_profile->list);
538
 
 
539
 
                lock_profile(old_profile);
540
 
                old_profile->isstale = 1;
541
 
-               unlock_profile(old_profile);
542
 
-
543
 
-               /*
544
 
-                * Find all tasks using the old profile and replace the old
545
 
-                * profile with the new.
546
 
-                */
547
 
-               read_lock_irqsave(&task_context_list_lock, flags);
548
 
-               list_for_each_entry(cxt, &task_context_list, list) {
549
 
-                       spin_lock_irqsave(&cxt_lock, flags);
550
 
-
551
 
-                       if (cxt->profile &&
552
 
-                           cxt->profile->parent == old_profile)
553
 
-                               task_replace(cxt, new_profile);
554
 
 
555
 
-                       spin_unlock_irqrestore(&cxt_lock, flags);
556
 
+               list_for_each_entry(cxt, &old_profile->task_contexts, list) {
557
 
+                       /*
558
 
+                        * Protect from racing with aa_release by taking
559
 
+                        * the task lock here.
560
 
+                        */
561
 
+                       task_lock(cxt->task);
562
 
+                       task_replace(cxt, new_profile);
563
 
+                       task_unlock(cxt->task);
564
 
                }
565
 
-               read_unlock_irqrestore(&task_context_list_lock, flags);
566
 
+               list_splice_init(&old_profile->task_contexts,
567
 
+                                &new_profile->task_contexts);
568
 
+               unlock_profile(old_profile);
569
 
+
570
 
+               list_del_init(&old_profile->list);
571
 
                aa_put_profile(old_profile);
572
 
        }
573
 
        list_add(&new_profile->list, &profile_list);
574
 
@@ -502,8 +497,6 @@ ssize_t aa_file_prof_repl(void *udata, s
575
 
 ssize_t aa_file_prof_remove(const char *name, size_t size)
576
 
 {
577
 
        struct aa_profile *profile;
578
 
-       struct aa_task_context *cxt;
579
 
-       unsigned long flags;
580
 
 
581
 
        write_lock(&profile_list_lock);
582
 
        profile = __aa_find_profile(name, &profile_list);
583
 
@@ -512,24 +505,22 @@ ssize_t aa_file_prof_remove(const char *
584
 
                return -ENOENT;
585
 
        }
586
 
 
587
 
-       list_del_init(&profile->list);
588
 
-
589
 
        lock_profile(profile);
590
 
        profile->isstale = 1;
591
 
-       unlock_profile(profile);
592
 
-
593
 
-       read_lock_irqsave(&task_context_list_lock, flags);
594
 
-       list_for_each_entry(cxt, &task_context_list, list) {
595
 
-               if (cxt->profile && cxt->profile->parent == profile) {
596
 
-                       spin_lock(&cxt_lock);
597
 
-                       aa_change_profile(cxt, NULL, 0);
598
 
-                       spin_unlock(&cxt_lock);
599
 
-               }
600
 
+       while (!list_empty(&profile->task_contexts)) {
601
 
+               struct aa_task_context *cxt =
602
 
+                       list_entry(profile->task_contexts.next,
603
 
+                                  struct aa_task_context, list);
604
 
+               task_lock(cxt->task);
605
 
+               aa_change_profile(cxt, NULL, 0);
606
 
+               task_unlock(cxt->task);
607
 
+               list_del_init(&cxt->list);
608
 
        }
609
 
-       read_unlock_irqrestore(&task_context_list_lock, flags);
610
 
+       unlock_profile(profile);
611
 
 
612
 
-       aa_put_profile(profile);
613
 
+       list_del_init(&profile->list);
614
 
        write_unlock(&profile_list_lock);
615
 
+       aa_put_profile(profile);
616
 
 
617
 
        return size;
618
 
 }