aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2010-10-25 05:43:05 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-10-30 17:37:20 -0400
commit693fa7792e9db9f32da9436e633976fbacd04b55 (patch)
tree227078047db9c8f3497133769b1b9b1f7b681fa1 /drivers/firewire
parent837596a61ba8f9bb53bb7aa27d17328ff9b2bcd5 (diff)
firewire: ohci: fix race when reading count in AR descriptor
If the controller is storing a split packet and therefore changing d->res_count to zero between the two reads by the driver, we end up with an end pointer that is not at a packet boundary, and therefore overflow the buffer when handling the split packet. To fix this, read the field once, atomically. The compiler usually merges the two reads anyway, but for correctness, we have to enforce it. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Tested-by: Maxim Levitsky <maximlevitsky@gmail.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/ohci.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index b5ba66656c6c..84eb607d6c03 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -740,11 +740,13 @@ static void ar_context_tasklet(unsigned long data)
740 struct ar_buffer *ab; 740 struct ar_buffer *ab;
741 struct descriptor *d; 741 struct descriptor *d;
742 void *buffer, *end; 742 void *buffer, *end;
743 __le16 res_count;
743 744
744 ab = ctx->current_buffer; 745 ab = ctx->current_buffer;
745 d = &ab->descriptor; 746 d = &ab->descriptor;
746 747
747 if (d->res_count == 0) { 748 res_count = ACCESS_ONCE(d->res_count);
749 if (res_count == 0) {
748 size_t size, size2, rest, pktsize, size3, offset; 750 size_t size, size2, rest, pktsize, size3, offset;
749 dma_addr_t start_bus; 751 dma_addr_t start_bus;
750 void *start; 752 void *start;
@@ -812,7 +814,7 @@ static void ar_context_tasklet(unsigned long data)
812 } else { 814 } else {
813 buffer = ctx->pointer; 815 buffer = ctx->pointer;
814 ctx->pointer = end = 816 ctx->pointer = end =
815 (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count); 817 (void *) ab + PAGE_SIZE - le16_to_cpu(res_count);
816 818
817 while (buffer < end) 819 while (buffer < end)
818 buffer = handle_ar_packet(ctx, buffer); 820 buffer = handle_ar_packet(ctx, buffer);