[PATCH] osst: don't doublefree pages from scatterlist

From: Hugh Dickins
Date: Fri Feb 03 2006 - 14:54:51 EST


On some architectures, mapping the scatterlist may coalesce entries:
if that coalesced list is then used for freeing the pages afterwards,
there's a danger that pages may be doubly freed (and others leaked).

Fix OnStream SCSI Tape's normalize_buffer by freeing from a second list
beyond the I/O scatterlist, saving page pointers with their lengths.

Signed-off-by: Hugh Dickins <hugh@xxxxxxxxxxx>
---
Warning: untested!

drivers/scsi/osst.c | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)

--- 2.6.16-rc2/drivers/scsi/osst.c 2006-01-03 03:21:10.000000000 +0000
+++ linux/drivers/scsi/osst.c 2006-02-03 09:59:37.000000000 +0000
@@ -5152,7 +5152,8 @@ static struct osst_buffer * new_tape_buf
else
priority = GFP_KERNEL;

- i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
+ i = sizeof(struct osst_buffer) +
+ (2 * osst_max_sg_segs - 1) * sizeof(struct scatterlist);
tb = (struct osst_buffer *)kmalloc(i, priority);
if (!tb) {
printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
@@ -5227,6 +5228,8 @@ static int enlarge_buffer(struct osst_bu
#if DEBUG
STbuffer->buffer_size = got;
#endif
+ memcpy(STbuffer->sg + STbuffer->sg_segs, STbuffer->sg,
+ STbuffer->sg_segs * sizeof(STbuffer->sg[0]));
normalize_buffer(STbuffer);
return 0;
}
@@ -5235,6 +5238,9 @@ static int enlarge_buffer(struct osst_bu
STbuffer->buffer_size = got;
STbuffer->sg_segs = ++segs;
}
+ /* Save uncoalesced scatterlist of pages to be freed */
+ memcpy(STbuffer->sg + STbuffer->sg_segs, STbuffer->sg,
+ STbuffer->sg_segs * sizeof(STbuffer->sg[0]));
#if DEBUG
if (debugging) {
printk(OSST_DEB_MSG
@@ -5254,9 +5260,10 @@ static int enlarge_buffer(struct osst_bu
/* Release the segments */
static void normalize_buffer(struct osst_buffer *STbuffer)
{
- int i, order, b_size;
+ int i, order, b_size;

- for (i=0; i < STbuffer->sg_segs; i++) {
+ /* Scatterlist entries may have been coalesced: free saved pagelist */
+ for (i = STbuffer->sg_segs; i < 2*STbuffer->sg_segs; i++) {

for (b_size = PAGE_SIZE, order = 0;
b_size < STbuffer->sg[i].length;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/