Patch "rcu: Protect rcu_print_task_exp_stall() ->exp_tasks access" has been added to the 6.1-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    rcu: Protect rcu_print_task_exp_stall() ->exp_tasks access

to the 6.1-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     rcu-protect-rcu_print_task_exp_stall-exp_tasks-acces.patch
and it can be found in the queue-6.1 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 7478071e20761b4d1a13cd2c640be413f44fe8fa
Author: Zqiang <qiang1.zhang@xxxxxxxxx>
Date:   Sat Dec 24 13:25:53 2022 +0800

    rcu: Protect rcu_print_task_exp_stall() ->exp_tasks access
    
    [ Upstream commit 3c1566bca3f8349f12b75d0a2d5e4a20ad6262ec ]
    
    For kernels built with CONFIG_PREEMPT_RCU=y, the following scenario can
    result in a NULL-pointer dereference:
    
               CPU1                                           CPU2
    rcu_preempt_deferred_qs_irqrestore                rcu_print_task_exp_stall
      if (special.b.blocked)                            READ_ONCE(rnp->exp_tasks) != NULL
        raw_spin_lock_rcu_node
        np = rcu_next_node_entry(t, rnp)
        if (&t->rcu_node_entry == rnp->exp_tasks)
          WRITE_ONCE(rnp->exp_tasks, np)
          ....
          raw_spin_unlock_irqrestore_rcu_node
                                                        raw_spin_lock_irqsave_rcu_node
                                                        t = list_entry(rnp->exp_tasks->prev,
                                                            struct task_struct, rcu_node_entry)
                                                        (if rnp->exp_tasks is NULL, this
                                                           will dereference a NULL pointer)
    
    The problem is that CPU2 accesses the rcu_node structure's->exp_tasks
    field without holding the rcu_node structure's ->lock and CPU2 did
    not observe CPU1's change to rcu_node structure's ->exp_tasks in time.
    Therefore, if CPU1 sets rcu_node structure's->exp_tasks pointer to NULL,
    then CPU2 might dereference that NULL pointer.
    
    This commit therefore holds the rcu_node structure's ->lock while
    accessing that structure's->exp_tasks field.
    
    [ paulmck: Apply Frederic Weisbecker feedback. ]
    
    Acked-by: Joel Fernandes (Google) <joel@xxxxxxxxxxxxxxxxx>
    Signed-off-by: Zqiang <qiang1.zhang@xxxxxxxxx>
    Signed-off-by: Paul E. McKenney <paulmck@xxxxxxxxxx>
    Signed-off-by: Joel Fernandes (Google) <joel@xxxxxxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h
index 60732264a7d0b..e25321dbb068e 100644
--- a/kernel/rcu/tree_exp.h
+++ b/kernel/rcu/tree_exp.h
@@ -800,9 +800,11 @@ static int rcu_print_task_exp_stall(struct rcu_node *rnp)
 	int ndetected = 0;
 	struct task_struct *t;
 
-	if (!READ_ONCE(rnp->exp_tasks))
-		return 0;
 	raw_spin_lock_irqsave_rcu_node(rnp, flags);
+	if (!rnp->exp_tasks) {
+		raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
+		return 0;
+	}
 	t = list_entry(rnp->exp_tasks->prev,
 		       struct task_struct, rcu_node_entry);
 	list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) {



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux