Skip to content

Commit 4ec24e9

Browse files
committed
spi: spi-qpic-snand: avoid memory corruption
Merge series from Gabor Juhos <[email protected]>: The 'spi-qpic-nand' driver may cause memory corruption under some circumstances. The first patch in the series changes the driver to avoid that, whereas the second adds some sanity checks to the common QPIC code in order to make detecting such errors easier in the future.
2 parents fa60c09 + ddaad4a commit 4ec24e9

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

drivers/mtd/nand/qpic_common.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,15 @@ qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc)
5757
bam_txn_buf += sizeof(*bam_txn);
5858

5959
bam_txn->bam_ce = bam_txn_buf;
60-
bam_txn_buf +=
61-
sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
60+
bam_txn->bam_ce_nitems = QPIC_PER_CW_CMD_ELEMENTS * num_cw;
61+
bam_txn_buf += sizeof(*bam_txn->bam_ce) * bam_txn->bam_ce_nitems;
6262

6363
bam_txn->cmd_sgl = bam_txn_buf;
64-
bam_txn_buf +=
65-
sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
64+
bam_txn->cmd_sgl_nitems = QPIC_PER_CW_CMD_SGL * num_cw;
65+
bam_txn_buf += sizeof(*bam_txn->cmd_sgl) * bam_txn->cmd_sgl_nitems;
6666

6767
bam_txn->data_sgl = bam_txn_buf;
68+
bam_txn->data_sgl_nitems = QPIC_PER_CW_DATA_SGL * num_cw;
6869

6970
init_completion(&bam_txn->txn_done);
7071

@@ -238,6 +239,11 @@ int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
238239
struct bam_transaction *bam_txn = nandc->bam_txn;
239240
u32 offset;
240241

242+
if (bam_txn->bam_ce_pos + size > bam_txn->bam_ce_nitems) {
243+
dev_err(nandc->dev, "BAM %s array is full\n", "CE");
244+
return -EINVAL;
245+
}
246+
241247
bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
242248

243249
/* fill the command desc */
@@ -258,6 +264,12 @@ int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
258264

259265
/* use the separate sgl after this command */
260266
if (flags & NAND_BAM_NEXT_SGL) {
267+
if (bam_txn->cmd_sgl_pos >= bam_txn->cmd_sgl_nitems) {
268+
dev_err(nandc->dev, "BAM %s array is full\n",
269+
"CMD sgl");
270+
return -EINVAL;
271+
}
272+
261273
bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
262274
bam_ce_size = (bam_txn->bam_ce_pos -
263275
bam_txn->bam_ce_start) *
@@ -297,10 +309,20 @@ int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
297309
struct bam_transaction *bam_txn = nandc->bam_txn;
298310

299311
if (read) {
312+
if (bam_txn->rx_sgl_pos >= bam_txn->data_sgl_nitems) {
313+
dev_err(nandc->dev, "BAM %s array is full\n", "RX sgl");
314+
return -EINVAL;
315+
}
316+
300317
sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
301318
vaddr, size);
302319
bam_txn->rx_sgl_pos++;
303320
} else {
321+
if (bam_txn->tx_sgl_pos >= bam_txn->data_sgl_nitems) {
322+
dev_err(nandc->dev, "BAM %s array is full\n", "TX sgl");
323+
return -EINVAL;
324+
}
325+
304326
sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
305327
vaddr, size);
306328
bam_txn->tx_sgl_pos++;

drivers/spi/spi-qpic-snand.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,22 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
315315

316316
mtd_set_ooblayout(mtd, &qcom_spi_ooblayout);
317317

318+
/*
319+
* Free the temporary BAM transaction allocated initially by
320+
* qcom_nandc_alloc(), and allocate a new one based on the
321+
* updated max_cwperpage value.
322+
*/
323+
qcom_free_bam_transaction(snandc);
324+
325+
snandc->max_cwperpage = cwperpage;
326+
327+
snandc->bam_txn = qcom_alloc_bam_transaction(snandc);
328+
if (!snandc->bam_txn) {
329+
dev_err(snandc->dev, "failed to allocate BAM transaction\n");
330+
ret = -ENOMEM;
331+
goto err_free_ecc_cfg;
332+
}
333+
318334
ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
319335
FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) |
320336
FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) |

include/linux/mtd/nand-qpic-common.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@
237237
* @last_data_desc - last DMA desc in data channel (tx/rx).
238238
* @last_cmd_desc - last DMA desc in command channel.
239239
* @txn_done - completion for NAND transfer.
240+
* @bam_ce_nitems - the number of elements in the @bam_ce array
241+
* @cmd_sgl_nitems - the number of elements in the @cmd_sgl array
242+
* @data_sgl_nitems - the number of elements in the @data_sgl array
240243
* @bam_ce_pos - the index in bam_ce which is available for next sgl
241244
* @bam_ce_start - the index in bam_ce which marks the start position ce
242245
* for current sgl. It will be used for size calculation
@@ -255,6 +258,11 @@ struct bam_transaction {
255258
struct dma_async_tx_descriptor *last_data_desc;
256259
struct dma_async_tx_descriptor *last_cmd_desc;
257260
struct completion txn_done;
261+
262+
unsigned int bam_ce_nitems;
263+
unsigned int cmd_sgl_nitems;
264+
unsigned int data_sgl_nitems;
265+
258266
struct_group(bam_positions,
259267
u32 bam_ce_pos;
260268
u32 bam_ce_start;

0 commit comments

Comments
 (0)