From 1269a2ec89a9c7ecc729705db5391991d08967e7 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 27 Mar 2019 23:03:22 +0800 Subject: [PATCH] ata: fix a race condition when internal cmd time out euler inclusion category: bugfix bugzilla: NA CVE: NA --------------------------- For internal cmds, we will unmap DMA memory associated with the cmd before we abort the cmd. If DMA transferring data before the aborting, bus error will occur. ata_exec_internal_sg ->ata_port_freeze if timeout ->ata_qc_complete ->ata_sg_clean dma transferring data = bus error ->ap->ops->post_internal_cmd ->sas_ata_post_internal ->sas_ata_internal_abort ->abort the cmd Fix this by moving post_internal_cmd() before unmapping the DMA memory when time out. Notice that we have to set ATA_QCFLAG_FAILED flag before calling post_internal_cmd() so that the aborting will work. Reported-by: luojian Signed-off-by: Jason Yan Reviewed-by: zhengbin Signed-off-by: Yang Yingliang --- drivers/ata/libata-core.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 15ad766f1cf3..a0eea7ac0027 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1665,6 +1665,13 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, */ if (qc->flags & ATA_QCFLAG_ACTIVE) { qc->err_mask |= AC_ERR_TIMEOUT; + qc->flags |= ATA_QCFLAG_FAILED; + + spin_unlock_irqrestore(ap->lock, flags); + /* do post_internal_cmd */ + if (ap->ops->post_internal_cmd) + ap->ops->post_internal_cmd(qc); + spin_lock_irqsave(ap->lock, flags); if (ap->ops->error_handler) ata_port_freeze(ap); @@ -1679,9 +1686,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, spin_unlock_irqrestore(ap->lock, flags); } - /* do post_internal_cmd */ - if (ap->ops->post_internal_cmd) - ap->ops->post_internal_cmd(qc); + if (!(qc->err_mask & AC_ERR_TIMEOUT)) + /* do post_internal_cmd */ + if (ap->ops->post_internal_cmd) + ap->ops->post_internal_cmd(qc); /* perform minimal error analysis */ if (qc->flags & ATA_QCFLAG_FAILED) { -- GitLab