[PATCH AUTOSEL 6.18-5.15] nvme-tcp: look up host_iface in the current netns

sashiko-bot at kernel.org sashiko-bot at kernel.org
Mon Oct 19 07:43:52 PDT 2026


Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] nvme-tcp: use-after-free in nvme_tcp_alloc_ctrl() via __dev_get_by_name()
--

commit 04aa71fe23c7dec86f240fa7773c4020c75d2bb7
Author: Geliang Tang <geliang at kernel.org>

nvme-tcp: look up host_iface in the current netns

This commit changes nvme_tcp_alloc_ctrl() to look up opts->host_iface in
current->nsproxy->net_ns rather than init_net so that interfaces in the
calling task's network namespace can be found.

> diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
> index 9a96df1a511c0..fb6858023f19d 100644
> --- a/drivers/nvme/host/tcp.c
> +++ b/drivers/nvme/host/tcp.c
> @@ -2935,7 +2935,8 @@ static struct nvme_tcp_ctrl *nvme_tcp_alloc_ctrl(struct device *dev,
>  	}
>  
>  	if (opts->mask & NVMF_OPT_HOST_IFACE) {
> -		if (!__dev_get_by_name(&init_net, opts->host_iface)) {
> +		if (!__dev_get_by_name(current->nsproxy->net_ns,
> +				       opts->host_iface)) {

[Severity: Critical]
Is it safe to call __dev_get_by_name() here without holding rtnl_lock()?

When userspace writes connection parameters with host_iface=<name> to
/dev/nvme-fabrics, the call chain:

  nvmf_dev_write()
    -> nvmf_create_ctrl()
      -> nvme_tcp_create_ctrl()
        -> nvme_tcp_alloc_ctrl()

runs in sleepable process context holding only nvmf_dev_mutex, with
neither rtnl_lock() nor rcu_read_lock() held.

In net/core/dev.c, __dev_get_by_name() requires the RTNL semaphore and
calls netdev_name_node_lookup(), which traverses the per-netns hash bucket
with non-RCU list primitives:

net/core/dev.c:netdev_name_node_lookup() {
	struct hlist_head *head = dev_name_hash(net, name);
	struct netdev_name_node *name_node;

	hlist_for_each_entry(name_node, head, hlist)
		if (!strcmp(name_node->name, name))
			return name_node;
	return NULL;
}

net/core/dev.c:__dev_get_by_name() {
	struct netdev_name_node *node_name;

	node_name = netdev_name_node_lookup(net, name);
	return node_name ? node_name->dev : NULL;
}

If a network device in current->nsproxy->net_ns is concurrently
unregistered via unregister_netdevice_many_notify() ->
rollback_registered_many() (which unlinks the node in unlist_netdevice(),
waits for an RCU grace period via synchronize_net(), and then frees the
nodes via netdev_name_node_alt_flush() and netdev_name_node_free()), has an
altname deleted via netdev_name_node_alt_destroy() ->
__netdev_name_node_alt_destroy(), or is renamed via dev_change_name(),
neither synchronize_net() nor call_rcu() will wait for a preempted reader
in nvme_tcp_alloc_ctrl().

Could this trigger a use-after-free on name_node or name_node->name during
the hash list traversal, and should this lookup use dev_get_by_name_rcu()
under rcu_read_lock() (or netdev_name_in_use()) instead?

>  			pr_err("invalid interface passed: %s\n",
>  			       opts->host_iface);
>  			ret = -ENODEV;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-231-sashal@kernel.org?part=1



More information about the Linux-nvme mailing list