[Devel] [PATCH RHEL10 COMMIT] block/blk-cbt: don't copy_to_user() under RCU in cbt_ioc_list()

Konstantin Khorenko khorenko at virtuozzo.com
Mon Jun 15 17:14:06 MSK 2026


The commit is pushed to "branch-rh10-6.12.0-211.16.1.12.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-211.16.1.el10
------>
commit 6b717bc8e58846e6bf2e5dcd10233170510611a9
Author: Konstantin Khorenko <khorenko at virtuozzo.com>
Date:   Wed Jun 3 23:58:30 2026 +0200

    block/blk-cbt: don't copy_to_user() under RCU in cbt_ioc_list()
    
    cbt_ioc_list() walked q->cbt_list under rcu_read_lock() and called
    copy_to_user() for each entry inside that section. copy_to_user() may
    fault and sleep, which is illegal in an RCU read-side critical section
    ("BUG: scheduling while atomic" / sleeping-in-atomic). In addition the
    copy_to_user() failure path did "return -EFAULT" without
    rcu_read_unlock(), leaking the RCU read lock.
    
    q->cbt_list is added to / removed from under cbt_mutex (see
    blk_cbt_add() and the BLKCBTGET show path which already walks the list
    with plain list_for_each_entry() under cbt_mutex). Take cbt_mutex here
    too: it stabilises the list, allows the sleeping copy_to_user(), and the
    error path now drops the mutex.
    
    Fixes: 6a6e88ab5fc2 ("block/blk-cbt: add BLKCBTLIST ioctl")
    https://virtuozzo.atlassian.net/browse/VSTOR-132310
    Feature: cbt: changed block tracking (for backup)
    Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 block/blk-cbt.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/block/blk-cbt.c b/block/blk-cbt.c
index 8d243562161f..90219f58f1ae 100644
--- a/block/blk-cbt.c
+++ b/block/blk-cbt.c
@@ -1001,16 +1001,18 @@ static int cbt_ioc_list(struct block_device *bdev, void __user *arg)
 		       lst.count * CBT_NAME_LENGTH))
 		return -EFAULT;
 
-	rcu_read_lock();
-	list_for_each_entry_rcu(cbt, &q->cbt_list, list) {
+	mutex_lock(&cbt_mutex);
+	list_for_each_entry(cbt, &q->cbt_list, list) {
 		if (total < lst.count) {
-			if (copy_to_user(name_ptr, cbt->name, CBT_NAME_LENGTH))
+			if (copy_to_user(name_ptr, cbt->name, CBT_NAME_LENGTH)) {
+				mutex_unlock(&cbt_mutex);
 				return -EFAULT;
+			}
 			name_ptr = (void *)((size_t)name_ptr + CBT_NAME_LENGTH);
 		}
 		total++;
 	}
-	rcu_read_unlock();
+	mutex_unlock(&cbt_mutex);
 
 	lst.count = total;
 


More information about the Devel mailing list