]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.36.2/firewire-ohci-fix-race-in-ar-split-packet-handling.patch
Fixes for 5.10
[thirdparty/kernel/stable-queue.git] / releases / 2.6.36.2 / firewire-ohci-fix-race-in-ar-split-packet-handling.patch
1 From a1f805e5e73a8fe166b71c6592d3837df0cd5e2e Mon Sep 17 00:00:00 2001
2 From: Clemens Ladisch <clemens@ladisch.de>
3 Date: Mon, 25 Oct 2010 11:42:20 +0200
4 Subject: firewire: ohci: fix race in AR split packet handling
5
6 From: Clemens Ladisch <clemens@ladisch.de>
7
8 commit a1f805e5e73a8fe166b71c6592d3837df0cd5e2e upstream.
9
10 When handling an AR buffer that has been completely filled, we assumed
11 that its descriptor will not be read by the controller and can be
12 overwritten. However, when the last received packet happens to end at
13 the end of the buffer, the controller might not yet have moved on to the
14 next buffer and might read the branch address later. If we overwrite
15 and free the page before that, the DMA context will either go dead
16 because of an invalid Z value, or go off into some random memory.
17
18 To fix this, ensure that the descriptor does not get overwritten by
19 using only the actual buffer instead of the entire page for reassembling
20 the split packet. Furthermore, to avoid freeing the page too early,
21 move on to the next buffer only when some data in it guarantees that the
22 controller has moved on.
23
24 This should eliminate the remaining firewire-net problems.
25
26 Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
27 Tested-by: Maxim Levitsky <maximlevitsky@gmail.com>
28 Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
29 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
30
31 ---
32 drivers/firewire/ohci.c | 39 +++++++++++++++++++++++----------------
33 1 file changed, 23 insertions(+), 16 deletions(-)
34
35 --- a/drivers/firewire/ohci.c
36 +++ b/drivers/firewire/ohci.c
37 @@ -750,20 +750,19 @@ static void ar_context_tasklet(unsigned
38 */
39
40 offset = offsetof(struct ar_buffer, data);
41 - start = buffer = ab;
42 + start = ab;
43 start_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
44 + buffer = ab->data;
45
46 ab = ab->next;
47 d = &ab->descriptor;
48 - size = buffer + PAGE_SIZE - ctx->pointer;
49 + size = start + PAGE_SIZE - ctx->pointer;
50 /* valid buffer data in the next page */
51 rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count);
52 /* what actually fits in this page */
53 - size2 = min(rest, (size_t)PAGE_SIZE - size);
54 + size2 = min(rest, (size_t)PAGE_SIZE - offset - size);
55 memmove(buffer, ctx->pointer, size);
56 memcpy(buffer + size, ab->data, size2);
57 - ctx->current_buffer = ab;
58 - ctx->pointer = (void *) ab->data + rest;
59
60 while (size > 0) {
61 void *next = handle_ar_packet(ctx, buffer);
62 @@ -782,22 +781,30 @@ static void ar_context_tasklet(unsigned
63 size -= pktsize;
64 /* fill up this page again */
65 size3 = min(rest - size2,
66 - (size_t)PAGE_SIZE - size - size2);
67 + (size_t)PAGE_SIZE - offset - size - size2);
68 memcpy(buffer + size + size2,
69 (void *) ab->data + size2, size3);
70 size2 += size3;
71 }
72
73 - /* handle the packets that are fully in the next page */
74 - buffer = (void *) ab->data + (buffer - (start + size));
75 - end = (void *) ab->data + rest;
76 -
77 - while (buffer < end)
78 - buffer = handle_ar_packet(ctx, buffer);
79 -
80 - dma_free_coherent(ohci->card.device, PAGE_SIZE,
81 - start, start_bus);
82 - ar_context_add_page(ctx);
83 + if (rest > 0) {
84 + /* handle the packets that are fully in the next page */
85 + buffer = (void *) ab->data +
86 + (buffer - (start + offset + size));
87 + end = (void *) ab->data + rest;
88 +
89 + while (buffer < end)
90 + buffer = handle_ar_packet(ctx, buffer);
91 +
92 + ctx->current_buffer = ab;
93 + ctx->pointer = end;
94 +
95 + dma_free_coherent(ohci->card.device, PAGE_SIZE,
96 + start, start_bus);
97 + ar_context_add_page(ctx);
98 + } else {
99 + ctx->pointer = start + PAGE_SIZE;
100 + }
101 } else {
102 buffer = ctx->pointer;
103 ctx->pointer = end =