mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 16:35:02 +01:00
333 lines
10 KiB
Diff
333 lines
10 KiB
Diff
Index: b/security/apparmor/apparmor.h
|
|
===================================================================
|
|
--- a/security/apparmor/apparmor.h
|
|
+++ b/security/apparmor/apparmor.h
|
|
@@ -128,6 +128,9 @@ struct aa_profile {
|
|
extern struct list_head profile_list;
|
|
extern rwlock_t profile_list_lock;
|
|
|
|
+extern struct list_head task_context_list;
|
|
+extern rwlock_t task_context_list_lock;
|
|
+
|
|
/**
|
|
* struct aa_task_context - primary label for confined tasks
|
|
* @profile: the current profile
|
|
@@ -147,8 +150,6 @@ struct aa_task_context {
|
|
kernel_cap_t caps_logged;
|
|
};
|
|
|
|
-typedef int (*aa_iter) (struct aa_task_context *, void *);
|
|
-
|
|
static inline struct aa_task_context *aa_task_context(struct task_struct *task)
|
|
{
|
|
return (struct aa_task_context *)task->security;
|
|
@@ -236,7 +237,6 @@ extern int aa_fork(struct task_struct *t
|
|
extern int aa_register(struct linux_binprm *bprm);
|
|
extern void aa_release(struct task_struct *task);
|
|
extern int aa_change_hat(const char *id, u32 hat_magic);
|
|
-extern int aa_associate_filp(struct file *filp);
|
|
extern struct aa_profile *__aa_find_profile(const char *name,
|
|
struct list_head *list);
|
|
|
|
@@ -244,8 +244,6 @@ extern struct aa_profile *__aa_find_prof
|
|
extern void aa_profilelist_release(void);
|
|
extern void aa_task_context_list_add(struct aa_task_context *);
|
|
extern void aa_task_context_list_remove(struct aa_task_context *);
|
|
-extern void aa_task_context_list_iterate(aa_iter, void *);
|
|
-extern void aa_task_context_list_iterateremove(aa_iter, void *);
|
|
extern void aa_task_context_list_release(void);
|
|
|
|
/* module_interface.c */
|
|
Index: b/security/apparmor/list.c
|
|
===================================================================
|
|
--- a/security/apparmor/list.c
|
|
+++ b/security/apparmor/list.c
|
|
@@ -18,8 +18,8 @@ LIST_HEAD(profile_list);
|
|
rwlock_t profile_list_lock = RW_LOCK_UNLOCKED;
|
|
|
|
/* list of all task_contexts and lock */
|
|
-static LIST_HEAD(task_context_list);
|
|
-static rwlock_t task_context_list_lock = RW_LOCK_UNLOCKED;
|
|
+LIST_HEAD(task_context_list);
|
|
+rwlock_t task_context_list_lock = RW_LOCK_UNLOCKED;
|
|
|
|
/**
|
|
* __aa_find_profile - look up a profile on the profile list
|
|
@@ -93,29 +93,6 @@ void aa_task_context_list_remove(struct
|
|
}
|
|
|
|
/**
|
|
- * aa_task_context_list_iterate - apply @func over the task_context_list
|
|
- * @func: method to be called for each element
|
|
- * @cookie: user passed data
|
|
- *
|
|
- * Iterate over aa_task_context list applying @func, stop when @func returns
|
|
- * non zero
|
|
- */
|
|
-void aa_task_context_list_iterate(aa_iter func, void *cookie)
|
|
-{
|
|
- struct aa_task_context *node;
|
|
- int ret = 0;
|
|
- unsigned long flags;
|
|
-
|
|
- read_lock_irqsave(&task_context_list_lock, flags);
|
|
- list_for_each_entry(node, &task_context_list, list) {
|
|
- ret = (*func) (node, cookie);
|
|
- if (ret != 0)
|
|
- break;
|
|
- }
|
|
- read_unlock_irqrestore(&task_context_list_lock, flags);
|
|
-}
|
|
-
|
|
-/**
|
|
* aa_task_context_list_release - Remove all aa_task_contexts from
|
|
* task_context_list
|
|
*/
|
|
Index: b/security/apparmor/lsm.c
|
|
===================================================================
|
|
--- a/security/apparmor/lsm.c
|
|
+++ b/security/apparmor/lsm.c
|
|
@@ -747,27 +747,9 @@ createfs_out:
|
|
|
|
}
|
|
|
|
-static int apparmor_exit_removeall_iter(struct aa_task_context *cxt,
|
|
- void *cookie)
|
|
-{
|
|
- /* spin_lock(&cxt_lock) held here */
|
|
-
|
|
- if (cxt->profile) {
|
|
- AA_DEBUG("%s: Dropping profiles %s(%d) "
|
|
- "profile %s(%p) active %s(%p)\n",
|
|
- __FUNCTION__,
|
|
- cxt->task->comm, cxt->task->pid,
|
|
- cxt->profile->parent->name,
|
|
- cxt->profile->parent,
|
|
- cxt->profile->name, cxt->profile);
|
|
- aa_switch_to_profile(cxt, NULL, 0);
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
static void __exit apparmor_exit(void)
|
|
{
|
|
+ struct aa_task_context *cxt;
|
|
unsigned long flags;
|
|
|
|
/* Remove profiles from the global profile list.
|
|
@@ -782,8 +764,17 @@ static void __exit apparmor_exit(void)
|
|
* reattached
|
|
*/
|
|
|
|
+ /*
|
|
+ * FIXME: We have a lock inversion here (cp. aa_file_prof_repl,
|
|
+ * aa_file_prof_remove).
|
|
+ */
|
|
spin_lock_irqsave(&cxt_lock, flags);
|
|
- aa_task_context_list_iterate(apparmor_exit_removeall_iter, NULL);
|
|
+ read_lock(&task_context_list_lock);
|
|
+ list_for_each_entry(cxt, &task_context_list, list) {
|
|
+ if (cxt->profile)
|
|
+ aa_switch_to_profile(cxt, NULL, 0);
|
|
+ }
|
|
+ read_unlock(&task_context_list_lock);
|
|
spin_unlock_irqrestore(&cxt_lock, flags);
|
|
|
|
/* Free up list of profile aa_task_context */
|
|
Index: b/security/apparmor/module_interface.c
|
|
===================================================================
|
|
--- a/security/apparmor/module_interface.c
|
|
+++ b/security/apparmor/module_interface.c
|
|
@@ -19,11 +19,6 @@
|
|
|
|
const int aa_code_datasize[] = { 1, 2, 4, 8, 2, 2, 4, 0, 0, 0, 0, 0, 0 };
|
|
|
|
-struct aa_taskreplace_data {
|
|
- struct aa_profile *old_profile;
|
|
- struct aa_profile *new_profile;
|
|
-};
|
|
-
|
|
/**
|
|
* free_aa_profile_rcu - rcu callback for free profiles
|
|
* @head: rcu_head struct of the profile whose reference is being put.
|
|
@@ -37,49 +32,6 @@ static void free_aa_profile_rcu(struct r
|
|
free_aa_profile(p);
|
|
}
|
|
|
|
-/**
|
|
- * task_remove - remove profile from a task's aa_task_context
|
|
- * @cxt: task's aa_task_context
|
|
- *
|
|
- * remove the profile from a task's aa_task_context, switching the task
|
|
- * to an unconfined state.
|
|
- */
|
|
-static inline void task_remove(struct aa_task_context *cxt)
|
|
-{
|
|
- /* spin_lock(&cxt_lock) held here */
|
|
- AA_DEBUG("%s: removing profile from task %s(%d) profile %s active %s\n",
|
|
- __FUNCTION__,
|
|
- cxt->task->comm,
|
|
- cxt->task->pid,
|
|
- cxt->profile->parent->name,
|
|
- cxt->profile->name);
|
|
-
|
|
- aa_switch_to_profile(cxt, NULL, 0);
|
|
-}
|
|
-
|
|
-/** taskremove_iter - Iterator to unconfine aa_task_contexts which match cookie
|
|
- * @cxt: aa_task_context to consider for profile removal
|
|
- * @cookie: pointer to the oldprofile which is being removed
|
|
- *
|
|
- * If the aa_task_context's profile matches old_profile, then call
|
|
- * task_remove() to remove the profile leaving the task (aa_task_context) unconfined.
|
|
- */
|
|
-static int taskremove_iter(struct aa_task_context *cxt, void *cookie)
|
|
-{
|
|
- struct aa_profile *old_profile = (struct aa_profile *)cookie;
|
|
- unsigned long flags;
|
|
-
|
|
- spin_lock_irqsave(&cxt_lock, flags);
|
|
-
|
|
- if (cxt->profile && cxt->profile->parent == old_profile) {
|
|
- task_remove(cxt);
|
|
- }
|
|
-
|
|
- spin_unlock_irqrestore(&cxt_lock, flags);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
/** task_replace - replace aa_task_context's current profile with a new profile
|
|
* @cxt: aa_task_context to replace the profile on
|
|
* @new: new profile
|
|
@@ -99,9 +51,6 @@ static inline void task_replace(struct a
|
|
cxt->profile->parent->name, cxt->profile->parent,
|
|
cxt->profile->name, cxt->profile);
|
|
|
|
- if (!cxt->profile)
|
|
- return;
|
|
-
|
|
if (cxt->profile != cxt->profile->parent) {
|
|
struct aa_profile *nactive;
|
|
|
|
@@ -118,29 +67,6 @@ static inline void task_replace(struct a
|
|
aa_switch_to_profile(cxt, new, cxt->hat_magic);
|
|
}
|
|
|
|
-/** taskreplace_iter - Iterator to replace a aa_task_context's profile
|
|
- * @cxt: aa_task_context to consider for profile replacement
|
|
- * @cookie: pointer to the old profile which is being replaced.
|
|
- *
|
|
- * If the aa_task_context's profile matches old_profile call
|
|
- * task_replace() to replace with the aa_task_context's profile with
|
|
- * the new profile.
|
|
- */
|
|
-static int taskreplace_iter(struct aa_task_context *cxt, void *cookie)
|
|
-{
|
|
- struct aa_taskreplace_data *data = (struct aa_taskreplace_data *)cookie;
|
|
- unsigned long flags;
|
|
-
|
|
- spin_lock_irqsave(&cxt_lock, flags);
|
|
-
|
|
- if (cxt->profile && cxt->profile->parent == data->old_profile)
|
|
- task_replace(cxt, data->new_profile);
|
|
-
|
|
- spin_unlock_irqrestore(&cxt_lock, flags);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
static inline int aa_inbounds(struct aa_ext *e, size_t size)
|
|
{
|
|
return (e->pos + size <= e->end);
|
|
@@ -518,7 +444,7 @@ ssize_t aa_file_prof_add(void *data, siz
|
|
*/
|
|
ssize_t aa_file_prof_repl(void *udata, size_t size)
|
|
{
|
|
- struct aa_taskreplace_data data;
|
|
+ struct aa_profile *old_profile, *new_profile;
|
|
struct aa_ext e = {
|
|
.start = udata,
|
|
.end = udata + size,
|
|
@@ -526,28 +452,40 @@ ssize_t aa_file_prof_repl(void *udata, s
|
|
};
|
|
ssize_t error;
|
|
|
|
- data.new_profile = aa_activate_top_profile(&e, &error);
|
|
- if (!data.new_profile)
|
|
+ new_profile = aa_activate_top_profile(&e, &error);
|
|
+ if (!new_profile)
|
|
return error;
|
|
|
|
write_lock(&profile_list_lock);
|
|
- data.old_profile = __aa_find_profile(data.new_profile->name,
|
|
- &profile_list);
|
|
- if (data.old_profile) {
|
|
- list_del_init(&data.old_profile->list);
|
|
-
|
|
- lock_profile(data.old_profile);
|
|
- data.old_profile->isstale = 1;
|
|
- unlock_profile(data.old_profile);
|
|
+ old_profile = __aa_find_profile(new_profile->name, &profile_list);
|
|
+ if (old_profile) {
|
|
+ struct aa_task_context *cxt;
|
|
+ unsigned long flags;
|
|
+
|
|
+ list_del_init(&old_profile->list);
|
|
+
|
|
+ lock_profile(old_profile);
|
|
+ old_profile->isstale = 1;
|
|
+ unlock_profile(old_profile);
|
|
|
|
/*
|
|
* Find all tasks using the old profile and replace the old
|
|
* profile with the new.
|
|
*/
|
|
- aa_task_context_list_iterate(taskreplace_iter, &data);
|
|
- aa_put_profile(data.old_profile);
|
|
+ read_lock_irqsave(&task_context_list_lock, flags);
|
|
+ list_for_each_entry(cxt, &task_context_list, list) {
|
|
+ spin_lock_irqsave(&cxt_lock, flags);
|
|
+
|
|
+ if (cxt->profile &&
|
|
+ cxt->profile->parent == old_profile)
|
|
+ task_replace(cxt, new_profile);
|
|
+
|
|
+ spin_unlock_irqrestore(&cxt_lock, flags);
|
|
+ }
|
|
+ read_unlock_irqrestore(&task_context_list_lock, flags);
|
|
+ aa_put_profile(old_profile);
|
|
}
|
|
- list_add(&data.new_profile->list, &profile_list);
|
|
+ list_add(&new_profile->list, &profile_list);
|
|
write_unlock(&profile_list_lock);
|
|
|
|
return size;
|
|
@@ -564,6 +502,8 @@ ssize_t aa_file_prof_repl(void *udata, s
|
|
ssize_t aa_file_prof_remove(const char *name, size_t size)
|
|
{
|
|
struct aa_profile *profile;
|
|
+ struct aa_task_context *cxt;
|
|
+ unsigned long flags;
|
|
|
|
write_lock(&profile_list_lock);
|
|
profile = __aa_find_profile(name, &profile_list);
|
|
@@ -578,7 +518,16 @@ ssize_t aa_file_prof_remove(const char *
|
|
profile->isstale = 1;
|
|
unlock_profile(profile);
|
|
|
|
- aa_task_context_list_iterate(taskremove_iter, profile);
|
|
+ read_lock_irqsave(&task_context_list_lock, flags);
|
|
+ list_for_each_entry(cxt, &task_context_list, list) {
|
|
+ if (cxt->profile && cxt->profile->parent == profile) {
|
|
+ spin_lock(&cxt_lock);
|
|
+ aa_switch_to_profile(cxt, NULL, 0);
|
|
+ spin_unlock(&cxt_lock);
|
|
+ }
|
|
+ }
|
|
+ read_unlock_irqrestore(&task_context_list_lock, flags);
|
|
+
|
|
aa_put_profile(profile);
|
|
write_unlock(&profile_list_lock);
|
|
|