Skip to content

Commit fd8958e

Browse files
Patrick Kelseyjgunthorpe
authored andcommitted
IB/hfi1: Fix sdma.h tx->num_descs off-by-one errors
Fix three sources of error involving struct sdma_txreq.num_descs. When _extend_sdma_tx_descs() extends the descriptor array, it uses the value of tx->num_descs to determine how many existing entries from the tx's original, internal descriptor array to copy to the newly allocated one. As this value was incremented before the call, the copy loop will access one entry past the internal descriptor array, copying its contents into the corresponding slot in the new array. If the call to _extend_sdma_tx_descs() fails, _pad_smda_tx_descs() then invokes __sdma_tx_clean() which uses the value of tx->num_desc to drive a loop that unmaps all descriptor entries in use. As this value was incremented before the call, the unmap loop will invoke sdma_unmap_desc() on a descriptor entry whose contents consist of whatever random data was copied into it during (1), leading to cascading further calls into the kernel and driver using arbitrary data. _sdma_close_tx() was using tx->num_descs instead of tx->num_descs - 1. Fix all of the above by: - Only increment .num_descs after .descp is extended. - Use .num_descs - 1 instead of .num_descs for last .descp entry. Fixes: f4d26d8 ("staging/rdma/hfi1: Add coalescing support for SDMA TX descriptors") Link: https://lore.kernel.org/r/167656658879.2223096.10026561343022570690.stgit@awfm-02.cornelisnetworks.com Signed-off-by: Brendan Cunningham <[email protected]> Signed-off-by: Patrick Kelsey <[email protected]> Signed-off-by: Dennis Dalessandro <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent a0d198f commit fd8958e

File tree

2 files changed

+9
-10
lines changed

2 files changed

+9
-10
lines changed

drivers/infiniband/hw/hfi1/sdma.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3160,8 +3160,7 @@ int _pad_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
31603160
{
31613161
int rval = 0;
31623162

3163-
tx->num_desc++;
3164-
if ((unlikely(tx->num_desc == tx->desc_limit))) {
3163+
if ((unlikely(tx->num_desc + 1 == tx->desc_limit))) {
31653164
rval = _extend_sdma_tx_descs(dd, tx);
31663165
if (rval) {
31673166
__sdma_txclean(dd, tx);
@@ -3174,6 +3173,7 @@ int _pad_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
31743173
SDMA_MAP_NONE,
31753174
dd->sdma_pad_phys,
31763175
sizeof(u32) - (tx->packet_len & (sizeof(u32) - 1)));
3176+
tx->num_desc++;
31773177
_sdma_close_tx(dd, tx);
31783178
return rval;
31793179
}

drivers/infiniband/hw/hfi1/sdma.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -631,14 +631,13 @@ static inline void sdma_txclean(struct hfi1_devdata *dd, struct sdma_txreq *tx)
631631
static inline void _sdma_close_tx(struct hfi1_devdata *dd,
632632
struct sdma_txreq *tx)
633633
{
634-
tx->descp[tx->num_desc].qw[0] |=
635-
SDMA_DESC0_LAST_DESC_FLAG;
636-
tx->descp[tx->num_desc].qw[1] |=
637-
dd->default_desc1;
634+
u16 last_desc = tx->num_desc - 1;
635+
636+
tx->descp[last_desc].qw[0] |= SDMA_DESC0_LAST_DESC_FLAG;
637+
tx->descp[last_desc].qw[1] |= dd->default_desc1;
638638
if (tx->flags & SDMA_TXREQ_F_URGENT)
639-
tx->descp[tx->num_desc].qw[1] |=
640-
(SDMA_DESC1_HEAD_TO_HOST_FLAG |
641-
SDMA_DESC1_INT_REQ_FLAG);
639+
tx->descp[last_desc].qw[1] |= (SDMA_DESC1_HEAD_TO_HOST_FLAG |
640+
SDMA_DESC1_INT_REQ_FLAG);
642641
}
643642

644643
static inline int _sdma_txadd_daddr(
@@ -655,6 +654,7 @@ static inline int _sdma_txadd_daddr(
655654
type,
656655
addr, len);
657656
WARN_ON(len > tx->tlen);
657+
tx->num_desc++;
658658
tx->tlen -= len;
659659
/* special cases for last */
660660
if (!tx->tlen) {
@@ -666,7 +666,6 @@ static inline int _sdma_txadd_daddr(
666666
_sdma_close_tx(dd, tx);
667667
}
668668
}
669-
tx->num_desc++;
670669
return rval;
671670
}
672671

0 commit comments

Comments
 (0)