From 410ef5f9f09c14b3fcc7a3652ea3d2f52081bebd Mon Sep 17 00:00:00 2001
From: JP Abgrall <jpa@google.com>
Date: Wed, 6 Jul 2011 20:09:38 -0700
Subject: [PATCH 353/696] netfitler: xt_qtaguid: add another missing spin_unlock.

This time the symptom is caused by tagging the same socket twice
without untagging it in between.
This would cause it to not unlock, and return.

Signed-off-by: JP Abgrall <jpa@google.com>
---
 net/netfilter/xt_qtaguid.c |   12 +++++++++++-
 1 files changed, 11 insertions(+), 1 deletions(-)

diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 3cacec0..49ed432 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -997,11 +997,13 @@ static int qtaguid_ctrl_parse(const char *input, int count)
 		sock_tag_entry = get_sock_stat_nl(el_socket->sk);
 		if (!sock_tag_entry)
 			spin_unlock_irqrestore(&sock_tag_list_lock, flags);
+		/* HERE: The lock is held if there was a matching sock tag entry */
 		break;
 	default:
 		res = -EINVAL;
 		goto err;
 	}
+	/* HERE: The lock is held if there was a matching sock tag entry */
 
 	/* Process commands */
 	switch (cmd) {
@@ -1009,17 +1011,23 @@ static int qtaguid_ctrl_parse(const char *input, int count)
 	case 't':
 		if (argc < 2) {
 			res = -EINVAL;
+			/* HERE: The lock is held if there was a matching sock
+			 * tag entry */
 			goto err_unlock;
 		}
 		if (argc < 3) {
 			acct_tag = 0;
 		} else if (!valid_atag(acct_tag)) {
 			res = -EINVAL;
+			/* HERE: The lock is held if there was a matching sock
+			 * tag entry */
 			goto err_unlock;
 		}
 		if (argc < 4)
 			uid = current_fsuid();
 		if (!sock_tag_entry) {
+			/* HERE: There is no lock held because there was no
+			 * sock tag entry */
 			sock_tag_entry = kmalloc(sizeof(*sock_tag_entry),
 						GFP_KERNEL);
 			if (!sock_tag_entry) {
@@ -1034,13 +1042,15 @@ static int qtaguid_ctrl_parse(const char *input, int count)
 								uid);
 			spin_lock_irqsave(&sock_tag_list_lock, flags);
 			sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree);
-			spin_unlock_irqrestore(&sock_tag_list_lock, flags);
 		} else {
+			/* HERE: The lock is held because there is a matching
+			 * sock tag entry */
 			/* Just update the acct_tag portion. */
 			uid_t orig_uid = get_uid_from_tag(sock_tag_entry->tag);
 			sock_tag_entry->tag = combine_atag_with_uid(acct_tag,
 								orig_uid);
 		}
+		spin_unlock_irqrestore(&sock_tag_list_lock, flags);
 		pr_debug("xt_qtaguid: tag: sock_tag_entry->sk=%p "
 			"...->tag=0x%llx (uid=%u)\n",
 			sock_tag_entry->sk, sock_tag_entry->tag,
-- 
1.7.1


