apparmor/kernel-patches/for-mainline/rewrite-profile-list-functions.diff
2007-02-21 01:08:46 +00:00

475 lines
14 KiB
Diff

Index: b/security/apparmor/apparmor.h
===================================================================
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -119,6 +119,9 @@ struct aa_profile {
struct kref count;
};
+extern struct list_head profile_list;
+extern rwlock_t profile_list_lock;
+
/**
* struct aa_task_context - primary label for confined tasks
* @profile: the current profile
@@ -231,15 +234,11 @@ extern int aa_register(struct linux_binp
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);
/* list.c */
-extern struct aa_profile *aa_profilelist_find(const char *name);
-extern int aa_profilelist_add(struct aa_profile *profile);
-extern struct aa_profile *aa_profilelist_remove(const char *name);
extern void aa_profilelist_release(void);
-extern struct aa_profile *aa_profilelist_replace(struct aa_profile *profile);
-extern void aa_profile_dump(struct aa_profile *);
-extern void aa_profilelist_dump(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 *);
Index: b/security/apparmor/list.c
===================================================================
--- a/security/apparmor/list.c
+++ b/security/apparmor/list.c
@@ -14,125 +14,31 @@
#include "inline.h"
/* list of all profiles and lock */
-static LIST_HEAD(profile_list);
-static rwlock_t profile_list_lock = RW_LOCK_UNLOCKED;
+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;
/**
- * aa_profilelist_find
- * @name: profile name (program name)
+ * __aa_find_profile - look up a profile on the profile list
+ * @name: name of profile to find
+ * @head: list to search
*
- * Search the profile list for profile @name. Return refcounted profile on
- * success, NULL on failure.
+ * Returns a pointer to the profile on the list, or NULL if no profile
+ * called @name exists. The caller must hold the profile_list_lock.
*/
-struct aa_profile *aa_profilelist_find(const char *name)
+struct aa_profile *__aa_find_profile(const char *name, struct list_head *head)
{
- struct aa_profile *p = NULL;
- if (name) {
- read_lock(&profile_list_lock);
- p = __aa_find_profile(name, &profile_list);
- read_unlock(&profile_list_lock);
- }
- return p;
-}
-
-/**
- * aa_profilelist_add - add new profile to list
- * @profile: new profile to add to list
- *
- * NOTE: Caller must allocate necessary reference count that will be used
- * by the profile_list. This is because profile allocation alloc_aa_profile()
- * returns an unreferenced object with a initial count of %1.
- *
- * Return %1 on success, %0 on failure (already exists)
- */
-int aa_profilelist_add(struct aa_profile *profile)
-{
- struct aa_profile *old_profile;
- int ret = 0;
-
- if (!profile)
- goto out;
-
- write_lock(&profile_list_lock);
- old_profile = __aa_find_profile(profile->name, &profile_list);
- if (old_profile) {
- aa_put_profile(old_profile);
- goto out;
- }
-
- list_add(&profile->list, &profile_list);
- ret = 1;
- out:
- write_unlock(&profile_list_lock);
- return ret;
-}
-
-/**
- * aa_profilelist_remove - remove a profile from the list by name
- * @name: name of profile to be removed
- *
- * If the profile exists remove profile from list and return its reference.
- * The reference count on profile is not decremented and should be decremented
- * when the profile is no longer needed
- */
-struct aa_profile *aa_profilelist_remove(const char *name)
-{
- struct aa_profile *profile = NULL;
- struct aa_profile *p, *tmp;
-
- if (!name)
- goto out;
+ struct aa_profile *profile;
- write_lock(&profile_list_lock);
- list_for_each_entry_safe(p, tmp, &profile_list, list) {
- if (!strcmp(p->name, name)) {
- list_del_init(&p->list);
- /* mark old profile as stale */
- p->isstale = 1;
- profile = p;
- break;
- }
+ list_for_each_entry(profile, head, list) {
+ if (!strcmp(profile->name, name))
+ return profile;
}
- write_unlock(&profile_list_lock);
-out:
- return profile;
-}
-
-/**
- * aa_profilelist_replace - replace a profile on the list
- * @profile: new profile
- *
- * Replace a profile on the profile list. Find the old profile by name in
- * the list, and replace it with the new profile. NOTE: Caller must allocate
- * necessary initial reference count for new profile as aa_profilelist_add().
- *
- * This is an atomic list operation. Returns the old profile (which is still
- * refcounted) if there was one, or NULL.
- */
-struct aa_profile *aa_profilelist_replace(struct aa_profile *profile)
-{
- struct aa_profile *oldprofile;
-
- write_lock(&profile_list_lock);
- oldprofile = __aa_find_profile(profile->name, &profile_list);
- if (oldprofile) {
- list_del_init(&oldprofile->list);
- /* mark old profile as stale */
- oldprofile->isstale = 1;
-
- /* __aa_find_profile incremented count, so adjust down */
- aa_put_profile(oldprofile);
- }
-
- list_add(&profile->list, &profile_list);
- write_unlock(&profile_list_lock);
-
- return oldprofile;
+ return NULL;
}
/**
Index: b/security/apparmor/inline.h
===================================================================
--- a/security/apparmor/inline.h
+++ b/security/apparmor/inline.h
@@ -50,6 +50,17 @@ static inline struct aa_profile *aa_get_
return profile;
}
+static inline struct aa_profile *aa_find_profile(const char *name)
+{
+ struct aa_profile *profile = NULL;
+
+ read_lock(&profile_list_lock);
+ profile = aa_dup_profile(__aa_find_profile(name, &profile_list));
+ read_unlock(&profile_list_lock);
+
+ return profile;
+}
+
/**
* aa_switch_to_profile - change aa_task_context to use a new profile
* @cxt: aa_task_context to switch the profile on
@@ -132,32 +143,4 @@ static inline struct aa_profile *alloc_a
}
return profile;
}
-
-/** __aa_find_profile
- * @name: name of profile to find
- * @head: list to search
- *
- * Return reference counted handle to profile. NULL if not found
- * Caller must hold any necessary locks
- */
-static inline struct aa_profile *__aa_find_profile(const char *name,
- struct list_head *head)
-{
- struct aa_profile *p;
-
- if (!name || !head)
- return NULL;
-
- AA_DEBUG("%s: finding profile %s\n", __FUNCTION__, name);
- list_for_each_entry(p, head, list) {
- if (!strcmp(p->name, name)) {
- /* return refcounted object */
- p = aa_dup_profile(p);
- return p;
- } else {
- AA_DEBUG("%s: skipping %s\n", __FUNCTION__, p->name);
- }
- }
- return NULL;
-}
#endif /* __INLINE_H__ */
Index: b/security/apparmor/main.c
===================================================================
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -778,7 +778,7 @@ aa_register_find(const char *name, int m
struct aa_profile *profile;
/* Locate new profile */
- profile = aa_profilelist_find(name);
+ profile = aa_find_profile(name);
if (profile) {
AA_DEBUG("%s: setting profile %s\n",
__FUNCTION__, profile->name);
@@ -931,7 +931,7 @@ repeat:
* the transition occured before replacement.
*
* - If newprofile points to an actual profile (result of
- * aa_profilelist_find above), this profile may have been
+ * aa_find_profile above), this profile may have been
* replaced. We need to fix it up. Doing this to avoid
* having to hold a lock around all this code.
*/
@@ -972,7 +972,7 @@ repeat:
/* drop refcnt obtained from earlier aa_dup_profile */
aa_put_profile(newprofile);
- newprofile = aa_profilelist_find(filename);
+ newprofile = aa_find_profile(filename);
if (!newprofile) {
/* Race, profile was removed, not replaced.
@@ -1063,12 +1063,14 @@ static inline int do_change_hat(const ch
struct aa_profile *sub;
int error = 0;
+ /*
+ * Note: the profile and sub-profiles cannot go away under us here;
+ * no need to grab an additional reference count.
+ */
sub = __aa_find_profile(hat_name, &BASE_PROFILE(cxt->profile)->sub);
-
if (sub) {
/* change hat */
aa_switch_to_profile(cxt, sub, hat_magic);
- aa_put_profile(sub);
} else {
if (APPARMOR_COMPLAIN(cxt)) {
LOG_HINT(cxt->profile, GFP_ATOMIC, HINT_UNKNOWN_HAT,
Index: b/security/apparmor/procattr.c
===================================================================
--- a/security/apparmor/procattr.c
+++ b/security/apparmor/procattr.c
@@ -208,7 +208,7 @@ int aa_setprocattr_setprofile(struct tas
repeat:
if (strcmp(name, "unconstrained") != 0) {
- profile = aa_profilelist_find(name);
+ profile = aa_find_profile(name);
if (!profile) {
AA_WARN("%s: Unable to switch task %s(%d) to profile"
"'%s'. No such profile.\n",
@@ -283,7 +283,7 @@ int aa_setprocattr_setprofile(struct tas
/* drop refcnt obtained from earlier aa_dup_profile */
aa_put_profile(profile);
- profile = aa_profilelist_find(name);
+ profile = aa_find_profile(name);
if (!profile) {
/* Race, profile was removed. */
Index: b/security/apparmor/module_interface.c
===================================================================
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -476,16 +476,13 @@ fail:
}
/**
- * aa_file_prof_add - add a new profile to the profile list
+ * aa_file_prof_add - Unpack and add a new profile to the profile list
* @data: serialized data stream
* @size: size of the serialized data stream
- *
- * unpack and add a profile to the profile list. Return %0 or error
*/
ssize_t aa_file_prof_add(void *data, size_t size)
{
struct aa_profile *profile = NULL;
-
struct aa_ext e = {
.start = data,
.end = data + size,
@@ -494,26 +491,20 @@ ssize_t aa_file_prof_add(void *data, siz
ssize_t error;
profile = aa_activate_top_profile(&e, &error);
- if (!profile) {
- AA_DEBUG("couldn't activate profile\n");
- goto out;
- }
+ if (!profile)
+ return error;
- /* aa_activate_top_profile allocates profile with initial 1 count
- * aa_profilelist_add transfers that ref to profile list without
- * further incrementing
- */
- if (aa_profilelist_add(profile)) {
- error = size;
- } else {
- AA_WARN("trying to add profile (%s) that already exists.\n",
- profile->name);
+ write_lock(&profile_list_lock);
+ if (__aa_find_profile(profile->name, &profile_list)) {
+ /* A profile with this name exists already. */
+ write_unlock(&profile_list_lock);
aa_put_profile(profile);
- error = -EEXIST;
+ return -EEXIST;
}
+ list_add(&profile->list, &profile_list);
+ write_unlock(&profile_list_lock);
-out:
- return error;
+ return size;
}
/**
@@ -533,55 +524,31 @@ ssize_t aa_file_prof_repl(void *udata, s
.end = udata + size,
.pos = udata
};
-
ssize_t error;
data.new_profile = aa_activate_top_profile(&e, &error);
- if (!data.new_profile) {
- AA_DEBUG("couldn't activate profile\n");
- goto out;
- }
-
- /* Refcount on data.new_profile is 1 (aa_activate_top_profile).
- *
- * This reference will be inherited by aa_profilelist_replace for it's
- * profile list reference but this isn't sufficient.
- *
- * Another replace (*for-same-profile*) may race us here.
- * Task A calls aa_profilelist_replace(new_profile) and is interrupted.
- * Task B old_profile = aa_profilelist_replace() will return task A's
- * new_profile with the count of 1. If task B proceeeds to put this
- * profile it will dissapear from under task A.
- *
- * Grab extra reference on new_profile to prevent this
- */
-
- aa_dup_profile(data.new_profile);
-
- data.old_profile = aa_profilelist_replace(data.new_profile);
+ if (!data.new_profile)
+ return error;
- /* If there was an old profile, find all currently executing tasks
- * using this profile and replace the old profile with the new.
- */
+ write_lock(&profile_list_lock);
+ data.old_profile = __aa_find_profile(data.new_profile->name,
+ &profile_list);
if (data.old_profile) {
- AA_DEBUG("%s: try to replace profile (%p)%s\n",
- __FUNCTION__,
- data.old_profile,
- data.old_profile->name);
+ list_del_init(&data.old_profile->list);
- aa_task_context_list_iterate(taskreplace_iter, (void *)&data);
+ data.old_profile->isstale = 1;
- /* it's off global list, and we are done replacing */
+ /*
+ * 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);
}
+ list_add(&data.new_profile->list, &profile_list);
+ write_unlock(&profile_list_lock);
- /* release extra reference obtained above (race) */
- aa_put_profile(data.new_profile);
-
- error = size;
-
-out:
- return error;
+ return size;
}
/**
@@ -590,30 +557,27 @@ out:
* @size: size of the name
*
* remove a profile from the profile list and all aa_task_context references
- * to said profile. Return %0 on success, else error.
+ * to said profile.
*/
ssize_t aa_file_prof_remove(const char *name, size_t size)
{
- struct aa_profile *old_profile;
+ struct aa_profile *profile;
- /* if the old profile exists it will be removed from the list and
- * a reference is returned.
- */
- old_profile = aa_profilelist_remove(name);
-
- if (old_profile) {
- /* remove profile from any tasks using it */
- aa_task_context_list_iterate(taskremove_iter,
- (void *)old_profile);
-
- /* drop reference obtained by aa_profilelist_remove */
- aa_put_profile(old_profile);
- } else {
- AA_WARN("%s: trying to remove profile (%s) that "
- "doesn't exist - skipping.\n", __FUNCTION__, name);
+ write_lock(&profile_list_lock);
+ profile = __aa_find_profile(name, &profile_list);
+ if (!profile) {
+ write_unlock(&profile_list_lock);
return -ENOENT;
}
+ list_del_init(&profile->list);
+
+ profile->isstale = 1;
+
+ aa_task_context_list_iterate(taskremove_iter, profile);
+ aa_put_profile(profile);
+ write_unlock(&profile_list_lock);
+
return size;
}