* [PATCH] tcmu: avoid use-after-free after command timeout
@ 2019-08-10 21:19 Dmitry Fomichev
2019-08-10 23:55 ` Mike Christie
0 siblings, 1 reply; 3+ messages in thread
From: Dmitry Fomichev @ 2019-08-10 21:19 UTC (permalink / raw)
To: linux-scsi, Martin K . Petersen, target-devel, Mike Christie,
Bart Van Assche
Cc: Damien Le Moal
In tcmu_handle_completion() function, the variable called read_len is
always initialized with a value taken from se_cmd structure. If this
function is called to complete an expired (timed out) out command, the
session command pointed by se_cmd is likely to be already deallocated by
the target core at that moment. As the result, this access triggers a
use-after-free warning from KASAN.
This patch fixes the code not to touch se_cmd when completing timed out
TCMU commands. It also resets the pointer to se_cmd at the time when the
TCMU_CMD_BIT_EXPIRED flag is set because it is going to become invalid
after calling target_complete_cmd() later in the same function,
tcmu_check_expired_cmd().
Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
drivers/target/target_core_user.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 04eda111920e..a0231491fa36 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -1132,14 +1132,16 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
struct se_cmd *se_cmd = cmd->se_cmd;
struct tcmu_dev *udev = cmd->tcmu_dev;
bool read_len_valid = false;
- uint32_t read_len = se_cmd->data_length;
+ uint32_t read_len;
/*
* cmd has been completed already from timeout, just reclaim
* data area space and free cmd
*/
- if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags))
+ if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
+ WARN_ON_ONCE(se_cmd);
goto out;
+ }
list_del_init(&cmd->queue_entry);
@@ -1152,6 +1154,7 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
goto done;
}
+ read_len = se_cmd->data_length;
if (se_cmd->data_direction == DMA_FROM_DEVICE &&
(entry->hdr.uflags & TCMU_UFLAG_READ_LEN) && entry->rsp.read_len) {
read_len_valid = true;
@@ -1307,6 +1310,7 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data)
*/
scsi_status = SAM_STAT_CHECK_CONDITION;
list_del_init(&cmd->queue_entry);
+ cmd->se_cmd = NULL;
} else {
list_del_init(&cmd->queue_entry);
idr_remove(&udev->commands, id);
--
2.21.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] tcmu: avoid use-after-free after command timeout
2019-08-10 21:19 [PATCH] tcmu: avoid use-after-free after command timeout Dmitry Fomichev
@ 2019-08-10 23:55 ` Mike Christie
2019-08-11 17:49 ` Dmitry Fomichev
0 siblings, 1 reply; 3+ messages in thread
From: Mike Christie @ 2019-08-10 23:55 UTC (permalink / raw)
To: Dmitry Fomichev, linux-scsi, Martin K . Petersen, target-devel,
Bart Van Assche
Cc: Damien Le Moal
On 08/10/2019 04:19 PM, Dmitry Fomichev wrote:
> In tcmu_handle_completion() function, the variable called read_len is
> always initialized with a value taken from se_cmd structure. If this
> function is called to complete an expired (timed out) out command, the
> session command pointed by se_cmd is likely to be already deallocated by
> the target core at that moment. As the result, this access triggers a
> use-after-free warning from KASAN.
>
> This patch fixes the code not to touch se_cmd when completing timed out
> TCMU commands. It also resets the pointer to se_cmd at the time when the
> TCMU_CMD_BIT_EXPIRED flag is set because it is going to become invalid
> after calling target_complete_cmd() later in the same function,
> tcmu_check_expired_cmd().
>
> Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> ---
> drivers/target/target_core_user.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
> index 04eda111920e..a0231491fa36 100644
> --- a/drivers/target/target_core_user.c
> +++ b/drivers/target/target_core_user.c
> @@ -1132,14 +1132,16 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
> struct se_cmd *se_cmd = cmd->se_cmd;
> struct tcmu_dev *udev = cmd->tcmu_dev;
> bool read_len_valid = false;
> - uint32_t read_len = se_cmd->data_length;
> + uint32_t read_len;
>
> /*
> * cmd has been completed already from timeout, just reclaim
> * data area space and free cmd
> */
> - if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags))
> + if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
> + WARN_ON_ONCE(se_cmd);
If you are adding a warn here, I think you want to also add a warn in
tcmu_reset_ring where there is another code path we do the same sequence
of operations where we check the bit then access the se_cmd after if not
set.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] tcmu: avoid use-after-free after command timeout
2019-08-10 23:55 ` Mike Christie
@ 2019-08-11 17:49 ` Dmitry Fomichev
0 siblings, 0 replies; 3+ messages in thread
From: Dmitry Fomichev @ 2019-08-11 17:49 UTC (permalink / raw)
To: linux-scsi, mchristi, target-devel, bvanassche, martin.petersen
Cc: Damien Le Moal
On Sat, 2019-08-10 at 18:55 -0500, Mike Christie wrote:
> On 08/10/2019 04:19 PM, Dmitry Fomichev wrote:
> > In tcmu_handle_completion() function, the variable called read_len is
> > always initialized with a value taken from se_cmd structure. If this
> > function is called to complete an expired (timed out) out command, the
> > session command pointed by se_cmd is likely to be already deallocated by
> > the target core at that moment. As the result, this access triggers a
> > use-after-free warning from KASAN.
> >
> > This patch fixes the code not to touch se_cmd when completing timed out
> > TCMU commands. It also resets the pointer to se_cmd at the time when the
> > TCMU_CMD_BIT_EXPIRED flag is set because it is going to become invalid
> > after calling target_complete_cmd() later in the same function,
> > tcmu_check_expired_cmd().
> >
> > Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> > ---
> > drivers/target/target_core_user.c | 8 ++++++--
> > 1 file changed, 6 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
> > index 04eda111920e..a0231491fa36 100644
> > --- a/drivers/target/target_core_user.c
> > +++ b/drivers/target/target_core_user.c
> > @@ -1132,14 +1132,16 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
> > struct se_cmd *se_cmd = cmd->se_cmd;
> > struct tcmu_dev *udev = cmd->tcmu_dev;
> > bool read_len_valid = false;
> > - uint32_t read_len = se_cmd->data_length;
> > + uint32_t read_len;
> >
> > /*
> > * cmd has been completed already from timeout, just reclaim
> > * data area space and free cmd
> > */
> > - if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags))
> > + if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
> > + WARN_ON_ONCE(se_cmd);
>
> If you are adding a warn here, I think you want to also add a warn in
> tcmu_reset_ring where there is another code path we do the same sequence
> of operations where we check the bit then access the se_cmd after if not
> set.
>
Mike,
Good point, thanks. I am going to send out the updated version of the patch.
Dmitry
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2019-08-11 17:49 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-10 21:19 [PATCH] tcmu: avoid use-after-free after command timeout Dmitry Fomichev
2019-08-10 23:55 ` Mike Christie
2019-08-11 17:49 ` Dmitry Fomichev
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).