[PATCH 3.16 096/202] s390/qeth: fix use-after-free in error path

From: Ben Hutchings
Date: Sat Apr 27 2019 - 11:31:22 EST


3.16.66-rc1 review patch. If anyone has any objections, please let me know.

------------------

From: Julian Wiedmann <jwi@xxxxxxxxxxxxx>

commit afa0c5904ba16d59b0454f7ee4c807dae350f432 upstream.

The error path in qeth_alloc_qdio_buffers() that takes care of
cleaning up the Output Queues is buggy. It first frees the queue, but
then calls qeth_clear_outq_buffers() with that very queue struct.

Make the call to qeth_clear_outq_buffers() part of the free action
(in the correct order), and while at it fix the naming of the helper.

Fixes: 0da9581ddb0f ("qeth: exploit asynchronous delivery of storage blocks")
Signed-off-by: Julian Wiedmann <jwi@xxxxxxxxxxxxx>
Reviewed-by: Alexandra Winter <wintera@xxxxxxxxxxxxx>
Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
[bwh: Backported to 3.16:
- Add the qeth_free_output_queue() function, which didn't exist here
- Keep using kfree() to free to free the qeth_qdio_out_q structure]
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
---
drivers/s390/net/qeth_core_main.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)

--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -1288,6 +1288,15 @@ static void qeth_free_buffer_pool(struct
}
}

+static void qeth_free_output_queue(struct qeth_qdio_out_q *q)
+{
+ if (!q)
+ return;
+
+ qeth_clear_outq_buffers(q, 1);
+ kfree(q);
+}
+
static void qeth_free_qdio_buffers(struct qeth_card *card)
{
int i, j;
@@ -1308,10 +1317,8 @@ static void qeth_free_qdio_buffers(struc
qeth_free_buffer_pool(card);
/* free outbound qdio_qs */
if (card->qdio.out_qs) {
- for (i = 0; i < card->qdio.no_out_queues; ++i) {
- qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
- kfree(card->qdio.out_qs[i]);
- }
+ for (i = 0; i < card->qdio.no_out_queues; i++)
+ qeth_free_output_queue(card->qdio.out_qs[i]);
kfree(card->qdio.out_qs);
card->qdio.out_qs = NULL;
}
@@ -2483,10 +2490,8 @@ out_freeoutqbufs:
card->qdio.out_qs[i]->bufs[j] = NULL;
}
out_freeoutq:
- while (i > 0) {
- kfree(card->qdio.out_qs[--i]);
- qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
- }
+ while (i > 0)
+ qeth_free_output_queue(card->qdio.out_qs[--i]);
kfree(card->qdio.out_qs);
card->qdio.out_qs = NULL;
out_freepool: