]> Pileus Git - ~andy/linux/commitdiff
tipc: protect handler_enabled variable with qitem_lock spin lock
authorYing Xue <ying.xue@windriver.com>
Tue, 10 Dec 2013 06:54:47 +0000 (22:54 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 11 Dec 2013 03:35:49 +0000 (22:35 -0500)
'handler_enabled' is a global flag indicating whether the TIPC
signal handling service is enabled or not. The lack of lock
protection for this flag incurs a risk for contention, so that
a tipc_k_signal() call might queue a signal handler to a destroyed
signal queue, with unpredictable results. To correct this, we let
the already existing 'qitem_lock' protect the flag, as it already
does with the queue itself. This way, we ensure that the flag
always is consistent across all cores.

Signed-off-by: Ying Xue <ying.xue@windriver.com>
Reviewed-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/tipc/handler.c

index b36f0fcd9bdfe76d04adf287687190ada3e9ccca..e4bc8a2967447fbde1f39d0d19146f2c7848ac99 100644 (file)
@@ -56,12 +56,13 @@ unsigned int tipc_k_signal(Handler routine, unsigned long argument)
 {
        struct queue_item *item;
 
+       spin_lock_bh(&qitem_lock);
        if (!handler_enabled) {
                pr_err("Signal request ignored by handler\n");
+               spin_unlock_bh(&qitem_lock);
                return -ENOPROTOOPT;
        }
 
-       spin_lock_bh(&qitem_lock);
        item = kmem_cache_alloc(tipc_queue_item_cache, GFP_ATOMIC);
        if (!item) {
                pr_err("Signal queue out of memory\n");
@@ -112,10 +113,14 @@ void tipc_handler_stop(void)
        struct list_head *l, *n;
        struct queue_item *item;
 
-       if (!handler_enabled)
+       spin_lock_bh(&qitem_lock);
+       if (!handler_enabled) {
+               spin_unlock_bh(&qitem_lock);
                return;
-
+       }
        handler_enabled = 0;
+       spin_unlock_bh(&qitem_lock);
+
        tasklet_kill(&tipc_tasklet);
 
        spin_lock_bh(&qitem_lock);