This patch doesn't apply to the .36 stable tree If someone wants it applied there, please email the backport to [email protected]
thanks, greg k-h > commit: a1f805e5e73a8fe166b71c6592d3837df0cd5e2e > From: Clemens Ladisch <[email protected]> > Date: Mon, 25 Oct 2010 11:42:20 +0200 > Subject: [PATCH] firewire: ohci: fix race in AR split packet handling > > When handling an AR buffer that has been completely filled, we assumed > that its descriptor will not be read by the controller and can be > overwritten. However, when the last received packet happens to end at > the end of the buffer, the controller might not yet have moved on to the > next buffer and might read the branch address later. If we overwrite > and free the page before that, the DMA context will either go dead > because of an invalid Z value, or go off into some random memory. > > To fix this, ensure that the descriptor does not get overwritten by > using only the actual buffer instead of the entire page for reassembling > the split packet. Furthermore, to avoid freeing the page too early, > move on to the next buffer only when some data in it guarantees that the > controller has moved on. > > This should eliminate the remaining firewire-net problems. > > Signed-off-by: Clemens Ladisch <[email protected]> > Cc: 2.6.22-2.6.36 <[email protected]> > Tested-by: Maxim Levitsky <[email protected]> > Signed-off-by: Stefan Richter <[email protected]> > --- > drivers/firewire/ohci.c | 35 +++++++++++++++++++++-------------- > 1 files changed, 21 insertions(+), 14 deletions(-) > > diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c > index 5826ae3..7570b71 100644 > --- a/drivers/firewire/ohci.c > +++ b/drivers/firewire/ohci.c > @@ -750,20 +750,19 @@ static void ar_context_tasklet(unsigned long data) > */ > > offset = offsetof(struct ar_buffer, data); > - start = buffer = ab; > + start = ab; > start_bus = le32_to_cpu(ab->descriptor.data_address) - offset; > + buffer = ab->data; > > ab = ab->next; > d = &ab->descriptor; > - size = buffer + PAGE_SIZE - ctx->pointer; > + size = start + PAGE_SIZE - ctx->pointer; > /* valid buffer data in the next page */ > rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count); > /* what actually fits in this page */ > - size2 = min(rest, (size_t)PAGE_SIZE - size); > + size2 = min(rest, (size_t)PAGE_SIZE - offset - size); > memmove(buffer, ctx->pointer, size); > memcpy(buffer + size, ab->data, size2); > - ctx->current_buffer = ab; > - ctx->pointer = (void *) ab->data + rest; > > while (size > 0) { > void *next = handle_ar_packet(ctx, buffer); > @@ -782,22 +781,30 @@ static void ar_context_tasklet(unsigned long data) > size -= pktsize; > /* fill up this page again */ > size3 = min(rest - size2, > - (size_t)PAGE_SIZE - size - size2); > + (size_t)PAGE_SIZE - offset - size - size2); > memcpy(buffer + size + size2, > (void *) ab->data + size2, size3); > size2 += size3; > } > > - /* handle the packets that are fully in the next page */ > - buffer = (void *) ab->data + (buffer - (start + size)); > - end = (void *) ab->data + rest; > + if (rest > 0) { > + /* handle the packets that are fully in the next page */ > + buffer = (void *) ab->data + > + (buffer - (start + offset + size)); > + end = (void *) ab->data + rest; > > - while (buffer < end) > - buffer = handle_ar_packet(ctx, buffer); > + while (buffer < end) > + buffer = handle_ar_packet(ctx, buffer); > + > + ctx->current_buffer = ab; > + ctx->pointer = end; > > - dma_free_coherent(ohci->card.device, PAGE_SIZE, > - start, start_bus); > - ar_context_add_page(ctx); > + dma_free_coherent(ohci->card.device, PAGE_SIZE, > + start, start_bus); > + ar_context_add_page(ctx); > + } else { > + ctx->pointer = start + PAGE_SIZE; > + } > } else { > buffer = ctx->pointer; > ctx->pointer = end = > > _______________________________________________ > stable mailing list > [email protected] > http://linux.kernel.org/mailman/listinfo/stable _______________________________________________ stable mailing list [email protected] http://linux.kernel.org/mailman/listinfo/stable
