* [PATCH] nvmet: Fix a use-after-free
@ 2022-08-12 21:03 Bart Van Assche
2022-08-14 11:45 ` Sagi Grimberg
2022-09-05 13:03 ` Christoph Hellwig
0 siblings, 2 replies; 6+ messages in thread
From: Bart Van Assche @ 2022-08-12 21:03 UTC (permalink / raw)
To: Keith Busch, Sagi Grimberg
Cc: Christoph Hellwig, linux-nvme, Bart Van Assche, stable
Fix the following use-after-free complaint triggered by blktests nvme/004:
BUG: KASAN: user-memory-access in blk_mq_complete_request_remote+0xac/0x350
Read of size 4 at addr 0000607bd1835943 by task kworker/13:1/460
Workqueue: nvmet-wq nvme_loop_execute_work [nvme_loop]
Call Trace:
show_stack+0x52/0x58
dump_stack_lvl+0x49/0x5e
print_report.cold+0x36/0x1e2
kasan_report+0xb9/0xf0
__asan_load4+0x6b/0x80
blk_mq_complete_request_remote+0xac/0x350
nvme_loop_queue_response+0x1df/0x275 [nvme_loop]
__nvmet_req_complete+0x132/0x4f0 [nvmet]
nvmet_req_complete+0x15/0x40 [nvmet]
nvmet_execute_io_connect+0x18a/0x1f0 [nvmet]
nvme_loop_execute_work+0x20/0x30 [nvme_loop]
process_one_work+0x56e/0xa70
worker_thread+0x2d1/0x640
kthread+0x183/0x1c0
ret_from_fork+0x1f/0x30
Cc: stable@vger.kernel.org
Fixes: a07b4970f464 ("nvmet: add a generic NVMe target")
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/nvme/target/core.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index a1345790005f..7f4083cf953a 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -735,6 +735,8 @@ static void nvmet_set_error(struct nvmet_req *req, u16 status)
static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
{
+ struct nvmet_ns *ns = req->ns;
+
if (!req->sq->sqhd_disabled)
nvmet_update_sq_head(req);
req->cqe->sq_id = cpu_to_le16(req->sq->qid);
@@ -745,9 +747,9 @@ static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
trace_nvmet_req_complete(req);
- if (req->ns)
- nvmet_put_namespace(req->ns);
req->ops->queue_response(req);
+ if (ns)
+ nvmet_put_namespace(ns);
}
void nvmet_req_complete(struct nvmet_req *req, u16 status)
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] nvmet: Fix a use-after-free
2022-08-12 21:03 [PATCH] nvmet: Fix a use-after-free Bart Van Assche
@ 2022-08-14 11:45 ` Sagi Grimberg
2022-08-14 14:24 ` Bart Van Assche
2022-09-05 13:03 ` Christoph Hellwig
1 sibling, 1 reply; 6+ messages in thread
From: Sagi Grimberg @ 2022-08-14 11:45 UTC (permalink / raw)
To: Bart Van Assche, Keith Busch; +Cc: Christoph Hellwig, linux-nvme, stable
On 8/13/22 00:03, Bart Van Assche wrote:
> Fix the following use-after-free complaint triggered by blktests nvme/004:
>
> BUG: KASAN: user-memory-access in blk_mq_complete_request_remote+0xac/0x350
> Read of size 4 at addr 0000607bd1835943 by task kworker/13:1/460
> Workqueue: nvmet-wq nvme_loop_execute_work [nvme_loop]
> Call Trace:
> show_stack+0x52/0x58
> dump_stack_lvl+0x49/0x5e
> print_report.cold+0x36/0x1e2
> kasan_report+0xb9/0xf0
> __asan_load4+0x6b/0x80
> blk_mq_complete_request_remote+0xac/0x350
> nvme_loop_queue_response+0x1df/0x275 [nvme_loop]
> __nvmet_req_complete+0x132/0x4f0 [nvmet]
> nvmet_req_complete+0x15/0x40 [nvmet]
> nvmet_execute_io_connect+0x18a/0x1f0 [nvmet]
> nvme_loop_execute_work+0x20/0x30 [nvme_loop]
> process_one_work+0x56e/0xa70
> worker_thread+0x2d1/0x640
> kthread+0x183/0x1c0
> ret_from_fork+0x1f/0x30
>
> Cc: stable@vger.kernel.org
> Fixes: a07b4970f464 ("nvmet: add a generic NVMe target")
> Signed-off-by: Bart Van Assche <bvanassche@acm.org>
> ---
> drivers/nvme/target/core.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
> index a1345790005f..7f4083cf953a 100644
> --- a/drivers/nvme/target/core.c
> +++ b/drivers/nvme/target/core.c
> @@ -735,6 +735,8 @@ static void nvmet_set_error(struct nvmet_req *req, u16 status)
>
> static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
> {
> + struct nvmet_ns *ns = req->ns;
> +
> if (!req->sq->sqhd_disabled)
> nvmet_update_sq_head(req);
> req->cqe->sq_id = cpu_to_le16(req->sq->qid);
> @@ -745,9 +747,9 @@ static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
>
> trace_nvmet_req_complete(req);
>
> - if (req->ns)
> - nvmet_put_namespace(req->ns);
> req->ops->queue_response(req);
> + if (ns)
> + nvmet_put_namespace(ns);
Why did the put change position?
I'm not exactly clear what was used-after-free here..
> }
>
> void nvmet_req_complete(struct nvmet_req *req, u16 status)
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] nvmet: Fix a use-after-free
2022-08-14 11:45 ` Sagi Grimberg
@ 2022-08-14 14:24 ` Bart Van Assche
2022-08-17 10:09 ` Sagi Grimberg
0 siblings, 1 reply; 6+ messages in thread
From: Bart Van Assche @ 2022-08-14 14:24 UTC (permalink / raw)
To: Sagi Grimberg, Keith Busch; +Cc: Christoph Hellwig, linux-nvme, stable
On 8/14/22 04:45, Sagi Grimberg wrote:
> On 8/13/22 00:03, Bart Van Assche wrote:
>> @@ -745,9 +747,9 @@ static void __nvmet_req_complete(struct nvmet_req
>> *req, u16 status)
>> trace_nvmet_req_complete(req);
>> - if (req->ns)
>> - nvmet_put_namespace(req->ns);
>> req->ops->queue_response(req);
>> + if (ns)
>> + nvmet_put_namespace(ns);
>
> Why did the put change position?
> I'm not exactly clear what was used-after-free here..
Hi Sagi,
Is my understanding correct that the NVMe target namespace owns the
block device `req` is associated with and hence that the namespace
reference count must only be dropped after dereferencing the `req`
pointer has finished?
This is what I found in the NVMe target code:
* nvmet_put_namespace() decreases ns->ref.
* Dropping the last ns->ref causes nvmet_destroy_namespace() to be
called. That function completes ns->disable_done.
* nvmet_ns_disable() waits on that completion and calls
nvmet_ns_dev_disable().
* For a block device, nvmet_ns_dev_disable() calls blkdev_put().
* The last blkdev_put() call calls disk_release().
* disk_release() calls blk_put_queue().
* The last blk_put_queue() call calls blk_release_queue().
* blk_release_queue() frees struct request_queue.
* blk_mq_complete_request_remote() dereferences req->q.
Thanks,
Bart.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] nvmet: Fix a use-after-free
2022-08-14 14:24 ` Bart Van Assche
@ 2022-08-17 10:09 ` Sagi Grimberg
2022-08-17 10:17 ` Sagi Grimberg
0 siblings, 1 reply; 6+ messages in thread
From: Sagi Grimberg @ 2022-08-17 10:09 UTC (permalink / raw)
To: Bart Van Assche, Keith Busch; +Cc: Christoph Hellwig, linux-nvme, stable
>>> @@ -745,9 +747,9 @@ static void __nvmet_req_complete(struct nvmet_req
>>> *req, u16 status)
>>> trace_nvmet_req_complete(req);
>>> - if (req->ns)
>>> - nvmet_put_namespace(req->ns);
>>> req->ops->queue_response(req);
>>> + if (ns)
>>> + nvmet_put_namespace(ns);
>>
>> Why did the put change position?
>> I'm not exactly clear what was used-after-free here..
>
> Hi Sagi,
>
> Is my understanding correct that the NVMe target namespace owns the
> block device `req` is associated with and hence that the namespace
> reference count must only be dropped after dereferencing the `req`
> pointer has finished?
>
> This is what I found in the NVMe target code:
> * nvmet_put_namespace() decreases ns->ref.
> * Dropping the last ns->ref causes nvmet_destroy_namespace() to be
> called. That function completes ns->disable_done.
> * nvmet_ns_disable() waits on that completion and calls
> nvmet_ns_dev_disable().
> * For a block device, nvmet_ns_dev_disable() calls blkdev_put().
> * The last blkdev_put() call calls disk_release().
> * disk_release() calls blk_put_queue().
> * The last blk_put_queue() call calls blk_release_queue().
> * blk_release_queue() frees struct request_queue.
> * blk_mq_complete_request_remote() dereferences req->q.
The analysis is correct, specifically for loop transport, but it is not
the same request_queue...
blk_mq_complete_request_remote references the initiator block device
created from the namespace, but nvmet_ns_dev_disable puts the backend
blockdev, which is a separate blockdev...
Maybe I'm misunderstanding your point?
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] nvmet: Fix a use-after-free
2022-08-17 10:09 ` Sagi Grimberg
@ 2022-08-17 10:17 ` Sagi Grimberg
0 siblings, 0 replies; 6+ messages in thread
From: Sagi Grimberg @ 2022-08-17 10:17 UTC (permalink / raw)
To: Bart Van Assche, Keith Busch; +Cc: Christoph Hellwig, linux-nvme, stable
>>>> nvmet_req *req, u16 status)
>>>> trace_nvmet_req_complete(req);
>>>> - if (req->ns)
>>>> - nvmet_put_namespace(req->ns);
>>>> req->ops->queue_response(req);
>>>> + if (ns)
>>>> + nvmet_put_namespace(ns);
>>>
>>> Why did the put change position?
>>> I'm not exactly clear what was used-after-free here..
>>
>> Hi Sagi,
>>
>> Is my understanding correct that the NVMe target namespace owns the
>> block device `req` is associated with and hence that the namespace
>> reference count must only be dropped after dereferencing the `req`
>> pointer has finished?
>>
>> This is what I found in the NVMe target code:
>> * nvmet_put_namespace() decreases ns->ref.
>> * Dropping the last ns->ref causes nvmet_destroy_namespace() to be
>> called. That function completes ns->disable_done.
>> * nvmet_ns_disable() waits on that completion and calls
>> nvmet_ns_dev_disable().
>> * For a block device, nvmet_ns_dev_disable() calls blkdev_put().
>> * The last blkdev_put() call calls disk_release().
>> * disk_release() calls blk_put_queue().
>> * The last blk_put_queue() call calls blk_release_queue().
>> * blk_release_queue() frees struct request_queue.
>> * blk_mq_complete_request_remote() dereferences req->q.
>
> The analysis is correct, specifically for loop transport, but it is not
> the same request_queue...
>
> blk_mq_complete_request_remote references the initiator block device
> created from the namespace, but nvmet_ns_dev_disable puts the backend
> blockdev, which is a separate blockdev...
>
> Maybe I'm misunderstanding your point?
And specifically your stack trace references nvmet_execute_io_connect
which is not addressed to a namespace... This I think that the
request_queue is actually the ctrl->connect_q, which is used for
io_connect commands.
It is unclear to me how this one ended up with a use-after-free...
Maybe we have a stray io_connect command lingering after we teardown
the controller?
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] nvmet: Fix a use-after-free
2022-08-12 21:03 [PATCH] nvmet: Fix a use-after-free Bart Van Assche
2022-08-14 11:45 ` Sagi Grimberg
@ 2022-09-05 13:03 ` Christoph Hellwig
1 sibling, 0 replies; 6+ messages in thread
From: Christoph Hellwig @ 2022-09-05 13:03 UTC (permalink / raw)
To: Bart Van Assche
Cc: Keith Busch, Sagi Grimberg, Christoph Hellwig, linux-nvme, stable
Thanks,
applied to nvme-6.0.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2022-09-05 13:03 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-12 21:03 [PATCH] nvmet: Fix a use-after-free Bart Van Assche
2022-08-14 11:45 ` Sagi Grimberg
2022-08-14 14:24 ` Bart Van Assche
2022-08-17 10:09 ` Sagi Grimberg
2022-08-17 10:17 ` Sagi Grimberg
2022-09-05 13:03 ` Christoph Hellwig
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.