linux-block.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).