Linux SCSI subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Tyrel Datwyler" <tyreld@linux.ibm.com>
Cc: linux-scsi@vger.kernel.org
Subject: Re: [PATCH v2 10/33] ibmvfc: add logic for protocol specific fabric logins
Date: Thu, 23 Jul 2026 00:28:57 +0000	[thread overview]
Message-ID: <20260723002857.BB7FA1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260723000149.969416-11-tyreld@linux.ibm.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:

New issues:
- [High] The host initialization state machine permanently stalls if NPIV login completes while `vhost->do_enquiry` is false.
- [High] NVMe fabric login is entirely skipped if the VIOS advertises NVMe support but not SCSI support, or if SCSI fabric login is disabled.
- [High] Concurrent transmission of SCSI and NVMe discovery MADs causes state machine transitions to be lost, resulting in dropped targets.
- [High] If NVMe is disabled by the guest but supported by the VIOS, `ibmvfc_channel_setup()` unconditionally dereferences a NULL `nvme->scrqs` pointer.
- [Medium] Unintended switch fallthrough in `ibmvfc_fabric_login_scsi_done` default case sends NVMe MAD on a dead link.

Pre-existing issues:
- [High] Missing validation of hypervisor-provided `active_queues` in `ibmvfc_channel_setup_done` leads to out-of-bounds heap writes.
- [High] Integer overflow of `max_cmds` when calculating queue depths for NPIV login.
--

--- Patch [10]: [PATCH v2 10/33] ibmvfc: add logic for protocol specific fabric logins ---
commit bffd16f5906104e27c687d661ecee756b7747318
Author: Tyrel Datwyler <tyreld@linux.ibm.com>

    ibmvfc: add logic for protocol specific fabric logins

    Add support for the protocol-specific fabric login flow introduced by
    the updated client/VIOS interface. Track whether SCSI and NVMe/FC fabric
    login are needed, extend channel enquiry/setup handling to negotiate both
    SCSI and NVMe queue counts, and issue the appropriate fabric login MADs
    before target discovery begins.

> diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ibmvfc-core.c
> index d8c2b56258eeb..e0edd71e9fd4b 100644
> --- a/drivers/scsi/ibmvscsi/ibmvfc-core.c
> +++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c

[ ... ]

> @@ -1512,7 +1520,7 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
>  	max_cmds = scsi_qdepth + IBMVFC_NUM_INTERNAL_REQ;
>  	if (mq_enabled)
>  		max_cmds += (scsi_qdepth + IBMVFC_NUM_INTERNAL_SUBQ_REQ) *
> -			vhost->scsi_scrqs.desired_queues;
> +			(vhost->scsi_scrqs.desired_queues + vhost->nvme_scrqs.desired_queues);

[Severity: High]
This isn't a bug introduced by this patch, but does calculating the queue
depth this way risk an integer overflow?

In ibmvfc_set_login_info(), max_cmds is declared as a 16-bit unsigned integer
(u16). If large values are configured for module parameters like scsi_qdepth,
this calculation could silently exceed 65,535 and wrap around.

Could this overflow submit a corrupted max_cmds limit to the VIOS?

[ ... ]

> +static void ibmvfc_fabric_login_scsi_done(struct ibmvfc_event *evt)
> +{
> +	struct ibmvfc_host *vhost = evt->vhost;
> +	struct ibmvfc_fabric_login_mad *rsp = &evt->xfer_iu->fabric_login;
> +	u32 mad_status = be16_to_cpu(rsp->common.status);
> +	int level = IBMVFC_DEFAULT_LOG_LEVEL;
> +
> +	switch (mad_status) {
> +	case IBMVFC_MAD_SUCCESS:
> +		ibmvfc_dbg(vhost, "SCSI fabric login succeeded\n");
> +		break;
> +	case IBMVFC_MAD_FAILED:

[ ... ]

> +	case IBMVFC_MAD_DRIVER_FAILED:
> +		ibmvfc_free_event(evt);
> +		return;
> +	default:
> +		dev_err(vhost->dev, "Invalid SCSI fabric login response: 0x%x\n", mad_status);
> +		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
> +		break;
> +	}
> +
> +	ibmvfc_free_event(evt);
> +
> +	if (vhost->do_nvme_login) {
> +		ibmvfc_fabric_login_nvme(vhost);

[Severity: Medium]
Does the break statement in the default case above cause an unintended switch
fallthrough?

If SCSI fabric login fails with an unrecognized status, the default case calls
ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD). However, unlike the other error
cases which return, it breaks out of the switch.

Will this cause execution to fall through and improperly invoke
ibmvfc_fabric_login_nvme() on a dead link?

> +	} else {
> +		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
> +		wake_up(&vhost->work_wait_q);
> +	}
> +}

[ ... ]

> @@ -5068,22 +5211,28 @@ static void ibmvfc_channel_setup_done(struct ibmvfc_event *evt)
>  		ibmvfc_dbg(vhost, "Channel Setup succeeded\n");
>  		flags = be32_to_cpu(setup->flags);
>  		vhost->do_enquiry = 0;
> -		active_queues = be32_to_cpu(setup->num_scsi_subq_channels);
> -		scrqs->active_queues = active_queues;
> +		scsi->active_queues = be32_to_cpu(setup->num_scsi_subq_channels);
> +		nvme->active_queues = be32_to_cpu(setup->num_nvme_subq_channels);

[Severity: High]
This is a pre-existing issue, but are these hypervisor-provided counts
validated against the array bounds?

The counts are taken directly from the untrusted 32-bit values returned by
the VIOS.

If the VIOS returns values larger than the dynamically allocated array sizes
(max_queues), will the subsequent loops that initialize vios_cookie corrupt
the guest kernel heap by writing out-of-bounds?

>  
>  		if (flags & IBMVFC_CHANNELS_CANCELED) {
>  			ibmvfc_dbg(vhost, "Channels Canceled\n");
>  			vhost->using_channels = 0;
> -		} else {
> -			if (active_queues)
> -				vhost->using_channels = 1;
> -			for (i = 0; i < active_queues; i++)
> -				scrqs->scrqs[i].vios_cookie =
> -					be64_to_cpu(setup->channel_handles[i]);
> -
> -			ibmvfc_dbg(vhost, "Using %u channels\n",
> -				   vhost->scsi_scrqs.active_queues);
> +			break;
>  		}
> +
> +		if (scsi->active_queues || nvme->active_queues)
> +			vhost->using_channels = 1;
> +		for (i = 0; i < scsi->active_queues; i++)
> +			scsi->scrqs[i].vios_cookie =
> +				be64_to_cpu(setup->channel_handles[i]);
> +		for (i = 0; i < nvme->active_queues; i++)
> +			nvme->scrqs[i].vios_cookie =
> +				be64_to_cpu(setup->channel_handles[scsi->active_queues + i]);

[ ... ]

> @@ -5098,8 +5247,12 @@ static void ibmvfc_channel_setup_done(struct ibmvfc_event *evt)
>  		return;
>  	}
>  
> -	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
> -	wake_up(&vhost->work_wait_q);
> +	if (vhost->do_scsi_login) {
> +		ibmvfc_fabric_login_scsi(vhost);
> +	} else {
> +		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
> +		wake_up(&vhost->work_wait_q);
> +	}
>  }

[Severity: High]
Does this bypass NVMe fabric login if SCSI fabric login is disabled?

If vhost->do_scsi_login is false, the code immediately transitions the host
state to IBMVFC_HOST_ACTION_QUERY.

Since NVMe login is sequentially chained from the SCSI login completion
callback (ibmvfc_fabric_login_scsi_done), if the VIOS advertises NVMe support
but not SCSI support, will NVMe initialization fail because it is entirely
skipped?

>  
>  static void ibmvfc_channel_setup(struct ibmvfc_host *vhost)
> @@ -5120,12 +5276,17 @@ static void ibmvfc_channel_setup(struct ibmvfc_host *vhost)
>  	}
>  
>  	memset(setup_buf, 0, sizeof(*setup_buf));
> -	if (num_channels == 0)
> +	if (!scsi_channels && !nvme_channels)
>  		setup_buf->flags = cpu_to_be32(IBMVFC_CANCEL_CHANNELS);
>  	else {
> -		setup_buf->num_scsi_subq_channels = cpu_to_be32(num_channels);
> -		for (i = 0; i < num_channels; i++)
> -			setup_buf->channel_handles[i] = cpu_to_be64(scrqs->scrqs[i].cookie);
> +		setup_buf->num_scsi_subq_channels = cpu_to_be32(scsi_channels);
> +		setup_buf->num_nvme_subq_channels = cpu_to_be32(nvme_channels);
> +		for (i = 0; i < scsi_channels; i++)
> +			setup_buf->channel_handles[i] =
> +				cpu_to_be64(scsi->scrqs[i].cookie);
> +		for (i = 0; i < nvme_channels; i++)
> +			setup_buf->channel_handles[scsi_channels + i] =
> +				cpu_to_be64(nvme->scrqs[i].cookie);

[Severity: High]
Can nvme->scrqs be a NULL pointer here?

If the guest disables NVMe (e.g., via module parameter),
ibmvfc_alloc_channels() for NVMe is skipped, leaving nvme->scrqs as NULL.

When ibmvfc_channel_enquiry_done() executes, if the VIOS reports
num_nvme_subq_channels > 0, nvme_channels calculates to > 0.

Will the loop above then unconditionally dereference the NULL nvme->scrqs
pointer?

>  	}
>  
>  	ibmvfc_init_event(evt, ibmvfc_channel_setup_done, IBMVFC_MAD_FORMAT);

[ ... ]

> @@ -5290,8 +5452,14 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
>  	vhost->host->can_queue = be32_to_cpu(rsp->max_cmds) - IBMVFC_NUM_INTERNAL_REQ;
>  	vhost->host->max_sectors = npiv_max_sectors;
>  
> -	if (ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPORT_CHANNELS) && vhost->do_enquiry) {
> -		ibmvfc_channel_enquiry(vhost);
> +
> +	if (ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPORT_CHANNELS)) {
> +		if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_SCSI))
> +			vhost->do_scsi_login = 1;
> +		if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_NVMEOF))
> +			vhost->do_nvme_login = 1;
> +		if (vhost->do_enquiry)
> +			ibmvfc_channel_enquiry(vhost);
>  	} else {
>  		vhost->do_enquiry = 0;
>  		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);

[Severity: High]
Does removing the else block here cause the host initialization state machine
to stall if vhost->do_enquiry is false?

If sub-CRQ channel allocation fails, do_enquiry is set to 0. When NPIV login
subsequently completes, this block skips ibmvfc_channel_enquiry().

Since there is no fallback to transition the state to IBMVFC_HOST_ACTION_QUERY
when do_enquiry is false, does this cause the state machine to permanently
stall?

[Severity: High]
One additional question about target discovery behavior in
ibmvfc_discover_targets():

When both SCSI and NVMe target discovery are active, both discovery MADs
are sent concurrently:

	if (!ibmvfc_send_event(evt, vhost, default_timeout))
		ibmvfc_dbg(vhost, "Sent discover SCSI targets\n");
    ...
	if (!ibmvfc_send_event(evt, vhost, default_timeout))
		ibmvfc_dbg(vhost, "Sent discover NVMe targets\n");

However, when each completes, they both call ibmvfc_discover_targets_done(),
which attempts to advance the shared state machine:

	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS);

Will the second completion be ignored because the host action is no longer
IBMVFC_HOST_ACTION_INIT_WAIT, causing one protocol's discovered targets to be
silently dropped and never allocated?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260723000149.969416-1-tyreld@linux.ibm.com?part=10

  reply	other threads:[~2026-07-23  0:28 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-23  0:01 [PATCH v2 00/33] ibmvfc: NVMe/FC support over IBM Virtual FC Tyrel Datwyler
2026-07-23  0:01 ` [PATCH v2 01/33] ibmvfc: don't call locked done variant for MADs on send failure Tyrel Datwyler
2026-07-23  0:42   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 02/33] ibmvfc: flush rport_add_work_q during driver teardown Tyrel Datwyler
2026-07-23  0:35   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 03/33] ibmvfc: check for NULL evt in implicit LOGO and target delete path Tyrel Datwyler
2026-07-23  0:30   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 04/33] ibmvfc: free ibmvfc_target allocations with mempool_free Tyrel Datwyler
2026-07-23  0:01 ` [PATCH v2 05/33] ibmvfc: move target list from host to protocol specific channel groups Tyrel Datwyler
2026-07-23  0:34   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 06/33] ibmvfc: add NVMe/FC protocol interface definitions Tyrel Datwyler
2026-07-23  0:28   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 07/33] ibmvfc: split NVMe support into separate source file and add transport stubs Tyrel Datwyler
2026-07-23  0:22   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 08/33] ibmvfc: initialize NVMe channel configuration during driver probe Tyrel Datwyler
2026-07-23  0:21   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 09/33] ibmvfc: alloc/dealloc sub-queues for nvme channels Tyrel Datwyler
2026-07-23  0:33   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 10/33] ibmvfc: add logic for protocol specific fabric logins Tyrel Datwyler
2026-07-23  0:28   ` sashiko-bot [this message]
2026-07-23  0:01 ` [PATCH v2 11/33] ibmvfc: add wrapper to get vhost associated with a channel struct Tyrel Datwyler
2026-07-23  0:01 ` [PATCH v2 12/33] ibmvfc: add helper for creating protocol specific discovery event Tyrel Datwyler
2026-07-23  0:01 ` [PATCH v2 13/33] ibmvfc: add helper to check NVMe/FC support with active channels Tyrel Datwyler
2026-07-23  0:17   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 14/33] ibmvfc: allocate and free NVMe channel group discover buffer Tyrel Datwyler
2026-07-23  0:01 ` [PATCH v2 15/33] ibmvfc: send NVMe target discovery MAD Tyrel Datwyler
2026-07-23  0:31   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 16/33] ibmvfc: add NVMe/FC Implicit Logout and Move Login support Tyrel Datwyler
2026-07-23  0:36   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 17/33] ibmvfc: add NVMe/FC Port " Tyrel Datwyler
2026-07-23  0:38   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 18/33] ibmvfc: add NVMe/FC Process " Tyrel Datwyler
2026-07-23  0:39   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 19/33] ibmvfc: add NVMe/FC Query Target support Tyrel Datwyler
2026-07-23  0:50   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 20/33] ibmvfc: allocate targets based on protocol Tyrel Datwyler
2026-07-23  0:43   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 21/33] ibmvfc: delete NVMe/FC targets as well as SCSI Tyrel Datwyler
2026-07-23  0:52   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 22/33] ibmvfc: update state machine to process NVMe/FC targets Tyrel Datwyler
2026-07-23  0:53   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 23/33] ibmvfc: implement NVMe/FC stubs for local/remote port registration Tyrel Datwyler
2026-07-23  0:54   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 24/33] ibmvfc: register local nvme fc port after fabric login Tyrel Datwyler
2026-07-23  0:53   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 25/33] ibmvfc: process NVMe/FC rports in work thread Tyrel Datwyler
2026-07-23  0:50   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 26/33] ibmvfc: extend ibmvfc_debug visibility to ibmvfc-nvme.h Tyrel Datwyler
2026-07-23  0:42   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 27/33] ibmvfc: declare global function definitions Tyrel Datwyler
2026-07-23  0:01 ` [PATCH v2 28/33] ibmvfc: implement LLDD callbacks for mapping nvme-fc queues Tyrel Datwyler
2026-07-23  0:58   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 29/33] ibmvfc: implement nvme-fc LS submission transport callback Tyrel Datwyler
2026-07-23  1:00   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 30/33] ibmvfc: implement nvme-fc IO command submission callback Tyrel Datwyler
2026-07-23  1:08   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 31/33] ibmvfc: implement nvme-fc LS abort handling callback Tyrel Datwyler
2026-07-23  1:05   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 32/33] ibmvfc: implement nvme-fc FCP abort callback Tyrel Datwyler
2026-07-23  1:05   ` sashiko-bot
2026-07-23  0:01 ` [PATCH v2 33/33] ibmvfc: fail nvme-fc fcp-io and ls requests during transport reset Tyrel Datwyler
2026-07-23  0:58   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260723002857.BB7FA1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=tyreld@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox