* [PATCH blktests] nvme/071: add a test for fcloop LS request use-after-free
@ 2026-09-21 14:56 Nguyen Ngoc Thang
2026-09-23 8:33 ` Shin'ichiro Kawasaki
2026-09-23 13:49 ` [PATCH blktests v2] " Nguyen Ngoc Thang
0 siblings, 2 replies; 4+ messages in thread
From: Nguyen Ngoc Thang @ 2026-09-21 14:56 UTC (permalink / raw)
To: linux-block
Cc: Shin'ichiro Kawasaki, Daniel Wagner, Hannes Reinecke,
linux-nvme
Delete the fcloop remote port and then the target port while an
association is being deleted. The Disconnect Association LS is completed
from a work item that can run after nvmet_fc_unregister_targetport() freed
the pending request, which KASAN reports as a use-after-free in
fcloop_tport_lsrqst_work().
Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
---
tests/nvme/071 | 70 ++++++++++++++++++++++++++++++++++++++++++++++
tests/nvme/071.out | 2 ++
2 files changed, 72 insertions(+)
create mode 100755 tests/nvme/071
create mode 100644 tests/nvme/071.out
diff --git a/tests/nvme/071 b/tests/nvme/071
new file mode 100755
index 0000000..d17ef18
--- /dev/null
+++ b/tests/nvme/071
@@ -0,0 +1,70 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-3.0+
+# Copyright (C) 2026 Nguyen Ngoc Thang
+#
+# Regression test for a use-after-free in fcloop when the target port is
+# deleted right after the remote port. Deleting the association sends a
+# Disconnect Association LS whose completion is queued while
+# nvmet_fc_unregister_targetport() is flushing nvmet_wq. The pending LS request
+# was freed before that completion ran.
+
+. tests/nvme/rc
+
+DESCRIPTION="delete fcloop target port right after remote port"
+QUICK=1
+
+requires() {
+ _nvme_requires
+ _have_loop
+ _require_nvme_trtype fc
+}
+
+set_conditions() {
+ _set_nvme_trtype "$@"
+}
+
+test() {
+ echo "Running ${TEST_NAME}"
+
+ _setup_nvmet
+
+ local i ports port host_port
+
+ _nvmet_target_setup
+
+ _get_nvmet_ports "${def_subsysnqn}" ports
+ port="${ports[0]}"
+ host_port="${ports_to_hosts[${port}]}"
+
+ for ((i = 0; i < 20; i++)); do
+ _nvme_connect_subsys
+ sleep 0.05
+
+ # Deleting the association sends a Disconnect Association LS.
+ _remove_nvmet_subsystem_from_port "${port}" "${def_subsysnqn}"
+ sleep "0.00$(printf "%02d" "${i}")"
+
+ # Remote port first, so the LS can't reach the host anymore.
+ _nvme_fcloop_del_rport "$(_host_wwnn "${host_port}")" \
+ "$(_host_wwpn "${host_port}")" \
+ "$(_remote_wwnn "${port}")" \
+ "$(_remote_wwpn "${port}")"
+ _nvme_fcloop_del_tport "$(_remote_wwnn "${port}")" \
+ "$(_remote_wwpn "${port}")"
+
+ # The host keeps trying to reconnect, drop the controller.
+ _nvme_disconnect_subsys >> "${FULL}" 2>&1
+
+ _nvme_fcloop_add_tport "$(_remote_wwnn "${port}")" \
+ "$(_remote_wwpn "${port}")"
+ _nvme_fcloop_add_rport "$(_host_wwnn "${host_port}")" \
+ "$(_host_wwpn "${host_port}")" \
+ "$(_remote_wwnn "${port}")" \
+ "$(_remote_wwpn "${port}")"
+ _add_nvmet_subsys_to_port "${port}" "${def_subsysnqn}"
+ done
+
+ _nvmet_target_cleanup
+
+ echo "Test complete"
+}
diff --git a/tests/nvme/071.out b/tests/nvme/071.out
new file mode 100644
index 0000000..146809b
--- /dev/null
+++ b/tests/nvme/071.out
@@ -0,0 +1,2 @@
+Running nvme/071
+Test complete
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH blktests] nvme/071: add a test for fcloop LS request use-after-free
2026-09-21 14:56 [PATCH blktests] nvme/071: add a test for fcloop LS request use-after-free Nguyen Ngoc Thang
@ 2026-09-23 8:33 ` Shin'ichiro Kawasaki
2026-09-23 13:53 ` Nguyen Ngoc Thang
2026-09-23 13:49 ` [PATCH blktests v2] " Nguyen Ngoc Thang
1 sibling, 1 reply; 4+ messages in thread
From: Shin'ichiro Kawasaki @ 2026-09-23 8:33 UTC (permalink / raw)
To: Nguyen Ngoc Thang; +Cc: linux-block, Daniel Wagner, Hannes Reinecke, linux-nvme
On Sep 21, 2026 / 21:56, Nguyen Ngoc Thang wrote:
> Delete the fcloop remote port and then the target port while an
> association is being deleted. The Disconnect Association LS is completed
> from a work item that can run after nvmet_fc_unregister_targetport() freed
> the pending request, which KASAN reports as a use-after-free in
> fcloop_tport_lsrqst_work().
It is the better to note which kernel side fix is related to this test case.
I suggest to note the commit title of the kernel fix here.
If its git hash could be noted, it would be the best, but the fix is not
yet applied, so we can not do that yet.
When I tried to run this test case, I often observed the test run hanged.
The hang was observed with v7.3-rc4 kernel. It was observed even with the
v2 fix patch [*]. Do you observe hangs on your test systems?
[*] https://lore.kernel.org/linux-nvme/20260921145651.17131-1-ngocthang2710.1999@gmail.com/
Also, please find my comments in line. Thanks!
>
> Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
> ---
> tests/nvme/071 | 70 ++++++++++++++++++++++++++++++++++++++++++++++
> tests/nvme/071.out | 2 ++
> 2 files changed, 72 insertions(+)
> create mode 100755 tests/nvme/071
> create mode 100644 tests/nvme/071.out
>
> diff --git a/tests/nvme/071 b/tests/nvme/071
> new file mode 100755
> index 0000000..d17ef18
> --- /dev/null
> +++ b/tests/nvme/071
> @@ -0,0 +1,70 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-3.0+
> +# Copyright (C) 2026 Nguyen Ngoc Thang
> +#
> +# Regression test for a use-after-free in fcloop when the target port is
> +# deleted right after the remote port. Deleting the association sends a
> +# Disconnect Association LS whose completion is queued while
> +# nvmet_fc_unregister_targetport() is flushing nvmet_wq. The pending LS request
> +# was freed before that completion ran.
I suggest to the note the kernel side fix commit here too.
> +
> +. tests/nvme/rc
> +
> +DESCRIPTION="delete fcloop target port right after remote port"
> +QUICK=1
> +
> +requires() {
> + _nvme_requires
> + _have_loop
> + _require_nvme_trtype fc
> +}
> +
> +set_conditions() {
> + _set_nvme_trtype "$@"
> +}
> +
> +test() {
> + echo "Running ${TEST_NAME}"
> +
> + _setup_nvmet
> +
> + local i ports port host_port
Nit: ports is an array, so I suggest to seprarte it from other variables and
declare it as an array:
local -a ports
> +
> + _nvmet_target_setup
> +
> + _get_nvmet_ports "${def_subsysnqn}" ports
> + port="${ports[0]}"
> + host_port="${ports_to_hosts[${port}]}"
common/nvme provides _get_fc_host_port(). Let's use it to avoid the
reference to the global variable.
> +
> + for ((i = 0; i < 20; i++)); do
> + _nvme_connect_subsys
> + sleep 0.05
> +
> + # Deleting the association sends a Disconnect Association LS.
> + _remove_nvmet_subsystem_from_port "${port}" "${def_subsysnqn}"
> + sleep "0.00$(printf "%02d" "${i}")"
Is there any reason to variate the sleep time here?
I tried to recreate the KASAN use-after-free using v7.3-rc4 kernel, but I was
not able to do it on my test node. I modified the above line to "sleep 0", then
I was able to recreate the failure. I guess the sleep lengths f
r KASAN recreation could be test system dependent.
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH blktests v2] nvme/071: add a test for fcloop LS request use-after-free
2026-09-21 14:56 [PATCH blktests] nvme/071: add a test for fcloop LS request use-after-free Nguyen Ngoc Thang
2026-09-23 8:33 ` Shin'ichiro Kawasaki
@ 2026-09-23 13:49 ` Nguyen Ngoc Thang
1 sibling, 0 replies; 4+ messages in thread
From: Nguyen Ngoc Thang @ 2026-09-23 13:49 UTC (permalink / raw)
To: linux-block
Cc: Shin'ichiro Kawasaki, Daniel Wagner, Hannes Reinecke,
linux-nvme
Delete the fcloop remote port and then the target port while an
association is being deleted. The Disconnect Association LS is completed
from a work item that can run after nvmet_fc_unregister_targetport() freed
the pending request, which KASAN reports as a use-after-free in
fcloop_tport_lsrqst_work().
Kernel fix: "nvmet-fc: flush nvmet_wq twice on targetport unregister"
Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
---
Changes in v2 (thanks Shin'ichiro for the review):
- Note the kernel fix's commit title in the file header.
- local -a ports, and use _get_fc_host_port() instead of reading
ports_to_hosts directly.
- Connect with --ctrl-loss-tmo 0. Without it, the host can spend up to
NVMF_DEF_CTRL_LOSS_TMO (600s) retrying reconnect after we pull the
remote port, which is likely the hang you saw; disconnecting it
cleanly then has to wait on that reconnect state first.
- Drop the swept delay before pulling the ports. I could not tell it
apart from a fixed "sleep 0" here either (KASAN UAF + list_debug BUG,
both with and without it), so it wasn't earning its complexity.
- v1: https://lore.kernel.org/linux-block/20260921145659.17151-1-ngocthang2710.1999@gmail.com/
tests/nvme/071 | 75 ++++++++++++++++++++++++++++++++++++++++++++++
tests/nvme/071.out | 2 ++
2 files changed, 77 insertions(+)
create mode 100755 tests/nvme/071
create mode 100644 tests/nvme/071.out
diff --git a/tests/nvme/071 b/tests/nvme/071
new file mode 100755
index 0000000..406a841
--- /dev/null
+++ b/tests/nvme/071
@@ -0,0 +1,75 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-3.0+
+# Copyright (C) 2026 Nguyen Ngoc Thang
+#
+# Regression test for a use-after-free in fcloop when the target port is
+# deleted right after the remote port. Deleting the association sends a
+# Disconnect Association LS whose completion is queued while
+# nvmet_fc_unregister_targetport() is flushing nvmet_wq. The pending LS request
+# was freed before that completion ran.
+#
+# Kernel fix: "nvmet-fc: flush nvmet_wq twice on targetport unregister"
+
+. tests/nvme/rc
+
+DESCRIPTION="delete fcloop target port right after remote port"
+QUICK=1
+
+requires() {
+ _nvme_requires
+ _have_loop
+ _require_nvme_trtype fc
+}
+
+set_conditions() {
+ _set_nvme_trtype "$@"
+}
+
+test() {
+ echo "Running ${TEST_NAME}"
+
+ _setup_nvmet
+
+ local -a ports
+ local i port host_port
+
+ _nvmet_target_setup
+
+ _get_nvmet_ports "${def_subsysnqn}" ports
+ port="${ports[0]}"
+ host_port="$(_get_fc_host_port "${port}")"
+
+ for ((i = 0; i < 20; i++)); do
+ # ctrl-loss-tmo=0 so the host drops the controller on the first
+ # failed reconnect instead of retrying for NVMF_DEF_CTRL_LOSS_TMO
+ # (600s), which would make each iteration look like it hangs.
+ _nvme_connect_subsys --ctrl-loss-tmo 0
+ sleep 0.05
+
+ # Deleting the association sends a Disconnect Association LS.
+ _remove_nvmet_subsystem_from_port "${port}" "${def_subsysnqn}"
+
+ # Remote port first, so the LS can't reach the host anymore.
+ _nvme_fcloop_del_rport "$(_host_wwnn "${host_port}")" \
+ "$(_host_wwpn "${host_port}")" \
+ "$(_remote_wwnn "${port}")" \
+ "$(_remote_wwpn "${port}")"
+ _nvme_fcloop_del_tport "$(_remote_wwnn "${port}")" \
+ "$(_remote_wwpn "${port}")"
+
+ # The host keeps trying to reconnect, drop the controller.
+ _nvme_disconnect_subsys >> "${FULL}" 2>&1
+
+ _nvme_fcloop_add_tport "$(_remote_wwnn "${port}")" \
+ "$(_remote_wwpn "${port}")"
+ _nvme_fcloop_add_rport "$(_host_wwnn "${host_port}")" \
+ "$(_host_wwpn "${host_port}")" \
+ "$(_remote_wwnn "${port}")" \
+ "$(_remote_wwpn "${port}")"
+ _add_nvmet_subsys_to_port "${port}" "${def_subsysnqn}"
+ done
+
+ _nvmet_target_cleanup
+
+ echo "Test complete"
+}
diff --git a/tests/nvme/071.out b/tests/nvme/071.out
new file mode 100644
index 0000000..146809b
--- /dev/null
+++ b/tests/nvme/071.out
@@ -0,0 +1,2 @@
+Running nvme/071
+Test complete
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH blktests] nvme/071: add a test for fcloop LS request use-after-free
2026-09-23 8:33 ` Shin'ichiro Kawasaki
@ 2026-09-23 13:53 ` Nguyen Ngoc Thang
0 siblings, 0 replies; 4+ messages in thread
From: Nguyen Ngoc Thang @ 2026-09-23 13:53 UTC (permalink / raw)
To: Shin'ichiro Kawasaki
Cc: linux-block, Daniel Wagner, Hannes Reinecke, linux-nvme
Hi Shin'ichiro,
Thanks for testing and the review, v2 is sent:
[PATCH blktests v2] nvme/071: add a test for fcloop LS request use-after-free
Message-ID: <20260923134938.12673-1-ngocthang2710.1999@gmail.com>
- Noted the kernel fix's commit title in the file header, since it's not
applied yet and has no hash.
- local -a ports, and use _get_fc_host_port() instead of reading
ports_to_hosts directly.
- On the hang: I couldn't reproduce a real hang, but I think I found the
cause. _nvme_connect_subsys() doesn't pass --ctrl-loss-tmo, so it
defaults to NVMF_DEF_CTRL_LOSS_TMO (600s). After we pull the remote
port the host has nothing to reconnect to, and the following
_nvme_disconnect_subsys() has to wait on that reconnect state before
it can remove the controller, up to 10 minutes if it lands there.
v2 connects with --ctrl-loss-tmo 0 so the host gives up on the first
failed reconnect instead. Let me know if you still see it hang with
this.
- On the swept delay: I tried a fixed "sleep 0" here too and got the
same KASAN UAF + list_debug BUG as with the sweep, so it wasn't
earning its complexity. Dropped it in v2.
Thanks,
Thang
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-23 13:53 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-21 14:56 [PATCH blktests] nvme/071: add a test for fcloop LS request use-after-free Nguyen Ngoc Thang
2026-09-23 8:33 ` Shin'ichiro Kawasaki
2026-09-23 13:53 ` Nguyen Ngoc Thang
2026-09-23 13:49 ` [PATCH blktests v2] " Nguyen Ngoc Thang
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).