xt_qtaguid: fix a race condition in if_tag_stat_update
authorliping.zhang <liping.zhang@spreadtrum.com>
Mon, 11 Jan 2016 05:31:01 +0000 (13:31 +0800)
committerJohn Stultz <john.stultz@linaro.org>
Tue, 16 Feb 2016 21:51:41 +0000 (13:51 -0800)
Miss a lock protection in if_tag_stat_update while doing get_iface_entry. So if
one CPU is doing iface_stat_create while another CPU is doing if_tag_stat_update,
race will happened.

Change-Id: Ib8d98e542f4e385685499f5b7bb7354f08654a75
Signed-off-by: Liping Zhang <liping.zhang@spreadtrum.com>
net/netfilter/xt_qtaguid.c

index 62ddd6cd1ee8ae0a0be6af1160f208590ec9e3ce..04bb081adde87168ff685e888fb52d95c6617dfe 100644 (file)
@@ -1291,11 +1291,12 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
                "uid=%u sk=%p dir=%d proto=%d bytes=%d)\n",
                 ifname, uid, sk, direction, proto, bytes);
 
-
+       spin_lock_bh(&iface_stat_list_lock);
        iface_entry = get_iface_entry(ifname);
        if (!iface_entry) {
                pr_err_ratelimited("qtaguid: iface_stat: stat_update() "
                                   "%s not found\n", ifname);
+               spin_unlock_bh(&iface_stat_list_lock);
                return;
        }
        /* It is ok to process data when an iface_entry is inactive */
@@ -1331,8 +1332,7 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
                 * {0, uid_tag} will also get updated.
                 */
                tag_stat_update(tag_stat_entry, direction, proto, bytes);
-               spin_unlock_bh(&iface_entry->tag_stat_list_lock);
-               return;
+               goto unlock;
        }
 
        /* Loop over tag list under this interface for {0,uid_tag} */
@@ -1372,6 +1372,7 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
        tag_stat_update(new_tag_stat, direction, proto, bytes);
 unlock:
        spin_unlock_bh(&iface_entry->tag_stat_list_lock);
+       spin_unlock_bh(&iface_stat_list_lock);
 }
 
 static int iface_netdev_event_handler(struct notifier_block *nb,