mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 16:35:02 +01:00
158 lines
5.4 KiB
Diff
158 lines
5.4 KiB
Diff
Index: linux-2.6-apparmor/security/apparmor/apparmor.h
|
|
===================================================================
|
|
--- linux-2.6-apparmor.orig/security/apparmor/apparmor.h
|
|
+++ linux-2.6-apparmor/security/apparmor/apparmor.h
|
|
@@ -257,6 +257,7 @@ extern ssize_t aa_file_prof_replace(void
|
|
extern ssize_t aa_file_prof_remove(const char *, size_t);
|
|
extern void free_aa_profile(struct aa_profile *profile);
|
|
extern void free_aa_profile_kref(struct kref *kref);
|
|
+extern void aa_unconfine_tasks(struct aa_profile *profile);
|
|
|
|
/* procattr.c */
|
|
extern int aa_getprocattr(struct aa_profile *profile, char **string,
|
|
Index: linux-2.6-apparmor/security/apparmor/lsm.c
|
|
===================================================================
|
|
--- linux-2.6-apparmor.orig/security/apparmor/lsm.c
|
|
+++ linux-2.6-apparmor/security/apparmor/lsm.c
|
|
@@ -807,7 +807,7 @@ static void __exit apparmor_exit(void)
|
|
/* Remove the profile from each task context it is on. */
|
|
lock_profile(profile);
|
|
profile->isstale = ERR_PTR(-ENOENT);
|
|
- remove_tasks_on_context_list(profile);
|
|
+ aa_unconfine_tasks(profile);
|
|
unlock_profile(profile);
|
|
|
|
/* Release the profile itself. */
|
|
Index: linux-2.6-apparmor/security/apparmor/module_interface.c
|
|
===================================================================
|
|
--- linux-2.6-apparmor.orig/security/apparmor/module_interface.c
|
|
+++ linux-2.6-apparmor/security/apparmor/module_interface.c
|
|
@@ -444,7 +444,9 @@ ssize_t aa_file_prof_replace(void *udata
|
|
write_lock(&profile_list_lock);
|
|
old_profile = __aa_find_profile(new_profile->name, &profile_list);
|
|
if (old_profile) {
|
|
- old_profile->isstale = aa_dup_profile(new_profile);
|
|
+ lock_profile(old_profile);
|
|
+ old_profile->isstale = new_profile;
|
|
+ unlock_profile(old_profile);
|
|
list_del_init(&old_profile->list);
|
|
}
|
|
aa_dup_profile(new_profile);
|
|
@@ -471,20 +473,14 @@ ssize_t aa_file_prof_replace(void *udata
|
|
do {
|
|
new_cxt = aa_alloc_task_context(GFP_KERNEL | __GFP_NOFAIL);
|
|
|
|
- /*
|
|
- * new_profile needs to be locked in the case that there
|
|
- * are multiple tasks on old_profile->list, this avoids
|
|
- * a race between an already replaced task changing its
|
|
- * profile (updating the list) and replacement updating
|
|
- * the list
|
|
- */
|
|
repeat:
|
|
lock_both_profiles(old_profile, new_profile);
|
|
if (new_profile->isstale) {
|
|
struct aa_profile *profile;
|
|
+
|
|
if (IS_ERR(new_profile->isstale)) {
|
|
/* new_profile was removed so become removal */
|
|
- remove_tasks_on_context_list(old_profile);
|
|
+ aa_unconfine_tasks(old_profile);
|
|
unlock_both_profiles(old_profile, new_profile);
|
|
break;
|
|
}
|
|
@@ -531,14 +527,17 @@ ssize_t aa_file_prof_remove(const char *
|
|
write_unlock(&profile_list_lock);
|
|
return -ENOENT;
|
|
}
|
|
- profile->isstale = ERR_PTR(-ENOENT);
|
|
- list_del_init(&profile->list);
|
|
- write_unlock(&profile_list_lock);
|
|
|
|
+ /* Remove the profile from each task context it is on. */
|
|
lock_profile(profile);
|
|
- remove_tasks_on_context_list(profile);
|
|
+ profile->isstale = ERR_PTR(-ENOENT);
|
|
+ aa_unconfine_tasks(profile);
|
|
unlock_profile(profile);
|
|
+
|
|
+ /* Release the profile itself. */
|
|
+ list_del_init(&profile->list);
|
|
aa_put_profile(profile);
|
|
+ write_unlock(&profile_list_lock);
|
|
|
|
return size;
|
|
}
|
|
@@ -581,8 +580,6 @@ void free_aa_profile(struct aa_profile *
|
|
BUG();
|
|
}
|
|
|
|
- if (!IS_ERR(profile->isstale))
|
|
- aa_put_profile(profile->isstale);
|
|
aa_match_free(profile->file_rules);
|
|
|
|
/* use free_aa_profile instead of aa_put_profile to destroy the
|
|
@@ -603,3 +600,21 @@ void free_aa_profile(struct aa_profile *
|
|
|
|
kfree(profile);
|
|
}
|
|
+
|
|
+/**
|
|
+ * aa_unconfine_tasks - remove tasks on @profiles task_contexts list
|
|
+ * @profile: profile to remove associated tasks
|
|
+ *
|
|
+ * Assumes that @profile lock is held
|
|
+ */
|
|
+void aa_unconfine_tasks(struct aa_profile *profile)
|
|
+{
|
|
+ while (!list_empty(&profile->task_contexts)) {
|
|
+ struct task_struct *task =
|
|
+ list_entry(profile->task_contexts.next,
|
|
+ struct aa_task_context, list)->task;
|
|
+ task_lock(task);
|
|
+ aa_change_task_context(task, NULL, NULL, 0);
|
|
+ task_unlock(task);
|
|
+ }
|
|
+}
|
|
Index: linux-2.6-apparmor/security/apparmor/inline.h
|
|
===================================================================
|
|
--- linux-2.6-apparmor.orig/security/apparmor/inline.h
|
|
+++ linux-2.6-apparmor/security/apparmor/inline.h
|
|
@@ -104,24 +104,6 @@ static inline struct aa_profile *alloc_a
|
|
}
|
|
|
|
/**
|
|
- * remove_tasks_on_context_list - remove tasks on @profiles task_contexts list
|
|
- * @profile: profile to remove associated tasks
|
|
- *
|
|
- * Assumes that @profile lock is held
|
|
- */
|
|
-static inline void remove_tasks_on_context_list(struct aa_profile *profile)
|
|
-{
|
|
- while (!list_empty(&profile->task_contexts)) {
|
|
- struct task_struct *task =
|
|
- list_entry(profile->task_contexts.next,
|
|
- struct aa_task_context, list)->task;
|
|
- task_lock(task);
|
|
- aa_change_task_context(task, NULL, NULL, 0);
|
|
- task_unlock(task);
|
|
- }
|
|
-}
|
|
-
|
|
-/**
|
|
* lock_profile - lock a profile
|
|
* @profile: the profile to lock
|
|
*
|
|
Index: linux-2.6-apparmor/security/apparmor/main.c
|
|
===================================================================
|
|
--- linux-2.6-apparmor.orig/security/apparmor/main.c
|
|
+++ linux-2.6-apparmor/security/apparmor/main.c
|
|
@@ -1201,7 +1201,7 @@ struct aa_profile *aa_replace_profile(st
|
|
}
|
|
|
|
cxt = lock_task_and_profiles(task, profile);
|
|
- if (profile && profile->isstale) {
|
|
+ if (unlikely(profile && profile->isstale)) {
|
|
task_unlock(task);
|
|
unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
|
|
aa_free_task_context(new_cxt);
|