lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20080414142019.GG16584@beardog.cca.cpqcorp.net>
Date:	Mon, 14 Apr 2008 09:20:19 -0500
From:	scameron@...rdog.cca.cpqcorp.net
To:	linux-kernel@...r.kernel.org, axboe@...nel.dk, mike.miller@...com,
	mikem@...rdog.cca.cpqcorp.net
Subject: [patch] cciss: Fix race between disk-adding code and interrupt handler



Fix race condition between cciss_init_one(), cciss_update_drive_info(),
and cciss_check_queues().  cciss_softirq_done would try to start
queues which were not quite ready to be started, as its checks for
readiness were not sufficiently synchronized with the queue initializing
code in cciss_init_one and cciss_update_drive_info.  Slow cpu and
large numbers of logical drives seem to make the race more likely 
to cause a problem.


Signed-off-by: Stephen M. Cameron <scameron@...rdog.cca.cpqcorp.net>

---

 linux-2.6.25-rc9/drivers/block/cciss.c |   25 ++++++++++++++++++++++++-
 linux-2.6.25-rc9/drivers/block/cciss.h |    3 +++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff -puN linux-2.6.25-rc9/drivers/block/cciss.c~cciss_init_one_race linux-2.6.25-rc9/drivers/block/cciss.c
--- linux-2.6.25-rc9/linux-2.6.25-rc9/drivers/block/cciss.c~cciss_init_one_race	2008-04-14 08:21:03.000000000 -0500
+++ linux-2.6.25-rc9-scameron/linux-2.6.25-rc9/drivers/block/cciss.c	2008-04-14 08:22:04.000000000 -0500
@@ -1270,7 +1270,9 @@ static void cciss_check_queues(ctlr_info
 		/* make sure the disk has been added and the drive is real
 		 * because this can be called from the middle of init_one.
 		 */
-		if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
+		if (!(h->drv[curr_queue].queue) ||
+			!(h->drv[curr_queue].heads) ||
+			!h->drv[curr_queue].queue_ready)
 			continue;
 		blk_start_queue(h->gendisk[curr_queue]->queue);
 
@@ -1394,6 +1396,11 @@ geo_inq:
 
 	/* if it's the controller it's already added */
 	if (drv_index) {
+
+		/* Prevent race with interrupt handler's queue starting code. */
+		h->drv[drv_index].queue_ready = 0;
+		wmb();
+
 		disk->queue = blk_init_queue(do_cciss_request, &h->lock);
 		sprintf(disk->disk_name, "cciss/c%dd%d", ctlr, drv_index);
 		disk->major = h->major;
@@ -1420,6 +1427,11 @@ geo_inq:
 					hba[ctlr]->drv[drv_index].block_size);
 
 		h->drv[drv_index].queue = disk->queue;
+
+		/* Prevent race with interrupt handler's queue starting code. */
+		wmb();
+		h->drv[drv_index].queue_ready = 1;
+
 		add_disk(disk);
 	}
 
@@ -3473,6 +3485,11 @@ static int __devinit cciss_init_one(stru
 		struct gendisk *disk = hba[i]->gendisk[j];
 		struct request_queue *q;
 
+		/* prevent race with interrupt handler's */
+		/* queue starting code. */
+		drv->queue_ready = 0;
+		wmb();
+
 		/* Check if the disk was allocated already */
 		if (!disk){
 			hba[i]->gendisk[j] = alloc_disk(1 << NWD_SHIFT);
@@ -3520,6 +3537,12 @@ static int __devinit cciss_init_one(stru
 			continue;
 		blk_queue_hardsect_size(q, drv->block_size);
 		set_capacity(disk, drv->nr_blocks);
+
+		/* prevent race with interrupt handler's */
+		/* queue starting code. */
+		wmb();
+		drv->queue_ready = 1;
+
 		add_disk(disk);
 		j++;
 	} while (j <= hba[i]->highest_lun);
diff -puN linux-2.6.25-rc9/drivers/block/cciss.h~cciss_init_one_race linux-2.6.25-rc9/drivers/block/cciss.h
--- linux-2.6.25-rc9/linux-2.6.25-rc9/drivers/block/cciss.h~cciss_init_one_race	2008-04-14 08:21:06.000000000 -0500
+++ linux-2.6.25-rc9-scameron/linux-2.6.25-rc9/drivers/block/cciss.h	2008-04-14 08:21:58.000000000 -0500
@@ -39,6 +39,9 @@ typedef struct _drive_info_struct
 				   *to prevent it from being opened or it's queue
 				   *from being started.
 				  */
+	int queue_ready; /* This is used to prevent the interrupt handler */
+			 /* from racing (while starting up queues) with */
+			 /* cciss_init_one() (while setting up new queues) */
 } drive_info_struct;
 
 #ifdef CONFIG_CISS_SCSI_TAPE
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ