--- /dev/null
+From 6f5d51148921c242680a7a1d9913384a30ab3cbe Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@ZenIV.linux.org.uk>
+Date: Sat, 19 Dec 2009 15:59:45 +0000
+Subject: fix braindamage in audit_tree.c untag_chunk()
+
+From: Al Viro <viro@ZenIV.linux.org.uk>
+
+commit 6f5d51148921c242680a7a1d9913384a30ab3cbe upstream.
+
+... aka "Al had badly fscked up when writing that thing and nobody
+noticed until Eric had fixed leaks that used to mask the breakage".
+
+The function essentially creates a copy of old array sans one element
+and replaces the references to elements of original (they are on cyclic
+lists) with those to corresponding elements of new one. After that the
+old one is fair game for freeing.
+
+First of all, there's a dumb braino: when we get to list_replace_init we
+use indices for wrong arrays - position in new one with the old array
+and vice versa.
+
+Another bug is more subtle - termination condition is wrong if the
+element to be excluded happens to be the last one. We shouldn't go
+until we fill the new array, we should go until we'd finished the old
+one. Otherwise the element we are trying to kill will remain on the
+cyclic lists...
+
+That crap used to be masked by several leaks, so it was not quite
+trivial to hit. Eric had fixed some of those leaks a while ago and the
+shit had hit the fan...
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ kernel/audit_tree.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/kernel/audit_tree.c
++++ b/kernel/audit_tree.c
+@@ -277,7 +277,7 @@ static void untag_chunk(struct node *p)
+ owner->root = NULL;
+ }
+
+- for (i = j = 0; i < size; i++, j++) {
++ for (i = j = 0; j <= size; i++, j++) {
+ struct audit_tree *s;
+ if (&chunk->owners[j] == p) {
+ list_del_init(&p->list);
+@@ -290,7 +290,7 @@ static void untag_chunk(struct node *p)
+ if (!s) /* result of earlier fallback */
+ continue;
+ get_tree(s);
+- list_replace_init(&chunk->owners[i].list, &new->owners[j].list);
++ list_replace_init(&chunk->owners[j].list, &new->owners[i].list);
+ }
+
+ list_replace_rcu(&chunk->hash, &new->hash);
--- /dev/null
+From b4c30aad39805902cf5b855aa8a8b22d728ad057 Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@ZenIV.linux.org.uk>
+Date: Sat, 19 Dec 2009 16:03:30 +0000
+Subject: fix more leaks in audit_tree.c tag_chunk()
+
+From: Al Viro <viro@ZenIV.linux.org.uk>
+
+commit b4c30aad39805902cf5b855aa8a8b22d728ad057 upstream.
+
+Several leaks in audit_tree didn't get caught by commit
+318b6d3d7ddbcad3d6867e630711b8a705d873d7, including the leak on normal
+exit in case of multiple rules refering to the same chunk.
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ kernel/audit_tree.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/kernel/audit_tree.c
++++ b/kernel/audit_tree.c
+@@ -373,15 +373,17 @@ static int tag_chunk(struct inode *inode
+ for (n = 0; n < old->count; n++) {
+ if (old->owners[n].owner == tree) {
+ spin_unlock(&hash_lock);
+- put_inotify_watch(watch);
++ put_inotify_watch(&old->watch);
+ return 0;
+ }
+ }
+ spin_unlock(&hash_lock);
+
+ chunk = alloc_chunk(old->count + 1);
+- if (!chunk)
++ if (!chunk) {
++ put_inotify_watch(&old->watch);
+ return -ENOMEM;
++ }
+
+ mutex_lock(&inode->inotify_mutex);
+ if (inotify_clone_watch(&old->watch, &chunk->watch) < 0) {
+@@ -425,7 +427,8 @@ static int tag_chunk(struct inode *inode
+ spin_unlock(&hash_lock);
+ inotify_evict_watch(&old->watch);
+ mutex_unlock(&inode->inotify_mutex);
+- put_inotify_watch(&old->watch);
++ put_inotify_watch(&old->watch); /* pair to inotify_find_watch */
++ put_inotify_watch(&old->watch); /* and kill it */
+ return 0;
+ }
+