Netdev List
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: shshitrit@nvidia.com
Cc: netdev@vger.kernel.org, mst@redhat.com, jasowang@redhat.com,
	pabeni@redhat.com, virtualization@lists.linux.dev,
	parav@nvidia.com, yohadt@nvidia.com, xuanzhuo@linux.alibaba.com,
	eperezma@redhat.com, jgg@ziepe.ca, kevin.tian@intel.com,
	kuba@kernel.org, andrew+netdev@lunn.ch, edumazet@google.com,
	danielj@nvidia.com
Subject: Re: [net-next,v23,03/14] virtio: Add config_op for admin commands
Date: Wed, 02 Sep 2026 13:12:18 +0000	[thread overview]
Message-ID: <178835473869.3394541.13020013369139989380@kernel.org> (raw)
In-Reply-To: <20260831161109.2999926-4-shshitrit@nvidia.com>

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

Critical: 0 · High: 0 (3) · Medium: 1 · Low: 1

- [Medium] The newly published `->admin_cmd_exec` transport op has no
  lifecycle precondition check or documentation:…
- [Low] The kernel-doc added for `@admin_cmd_exec` in
  include/linux/virtio_config.h states no calling-context constraint,…

Pre-existing issues:
- [High] Free-while-in-flight / use-after-free on the admin-command kick-
  failure path.
- [High] The admin-command path accesses `admin_vq->info` with no
  synchronization against admin-queue teardown, and the newly published…
- [High] `struct virtio_admin_cmd::result_sg_size`, now part of the
  generic `->admin_cmd_exec` contract, is filled in…

--

virtio: Add config_op for admin commands

This adds a new optional admin_cmd_exec callback to struct
virtio_config_ops and points it at vp_modern_admin_cmd_exec() in both
modern virtio-pci config op tables, so that virtio device drivers can
issue admin commands through the transport.

No Link: tags in the commit header.

A few questions about the newly published op below.

> diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
> index dab63b044a312..3b2515e29728a 100644
> --- a/drivers/virtio/virtio_pci_modern.c
> +++ b/drivers/virtio/virtio_pci_modern.c
> @@ -1248,6 +1248,7 @@ static const struct virtio_config_ops virtio_pci_config_nodev_ops = {
>  	.get_shm_region  = vp_get_shm_region,
>  	.disable_vq_and_reset = vp_modern_disable_vq_and_reset,
>  	.enable_vq_after_reset = vp_modern_enable_vq_after_reset,
> +	.admin_cmd_exec = vp_modern_admin_cmd_exec,
>  };

[Severity: Medium]
Now that any bound driver can reach this path, is there anything that keeps
admin_vq.info valid at the entry point?  virtqueue_exec_admin_cmd() starts
with:

	vq = admin_vq->info->vq;
	if (!vq)
		return -EIO;

The guard tests the inner vq pointer, so it does not catch info == NULL.
The only precondition tested by vp_modern_admin_cmd_exec() is:

	if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
		return -EOPNOTSUPP;

That feature bit is set by vp_finalize_features() before the driver's probe
runs and it stays set across del_vqs(), while vp_del_vq() in
virtio_pci_common.c does:

	if (vp_is_avq(vq->vdev, vq->index)) {
		cancel_work_sync(&vp_dev->admin_vq.work);
		vp_dev->admin_vq.info = NULL;
	}

	vp_dev->del_vq(info);
	kfree(info);

So admin_vq.info is NULL before find_vqs() creates the admin queue, on the
find_vqs() error path, and after del_vqs().  Can a call made outside the
find_vqs()..del_vqs() window dereference NULL here?

The virtio_net consumers added later in this series do appear to stay inside
that window, so this may not be reachable in-tree today.  Would it still be
worth checking admin_vq->info and spelling out the required device/VQ state
in the new kernel-doc?

[Severity: High]
This isn't a bug introduced by this patch, but the kick-failure path in
virtqueue_exec_admin_cmd() looks like it leaves a descriptor in flight:

	mutex_lock(&admin_vq->lock);
	ret = virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_KERNEL);
	...
	if (!virtqueue_kick(vq))
		goto unlock_err;
	...
unlock_err:
	mutex_unlock(&admin_vq->lock);
	return -EIO;

virtqueue_kick() returns false when the vring is broken, and
virtio_break_device() can be called asynchronously, for example from
virtio_pci_remove():

	if (!pci_device_is_present(pci_dev))
		virtio_break_device(&vp_dev->vdev);

so the state can change between the virtqueue_is_broken() pre-check and the
kick.  The descriptor added by virtqueue_add_sgs() is not reclaimed on that
path, and vp_modern_admin_cmd_exec() then frees the buffers it published:

err_cmd_exec:
	kfree(va_hdr);
err_alloc:
	kfree(va_status);
	return ret;

The token handed to virtqueue_add_sgs() is the caller's struct
virtio_admin_cmd, which goes out of scope when the caller returns.  When the
following reset runs vp_modern_avq_cleanup():

	while ((cmd = virtqueue_detach_unused_buf(vq))) {
		cmd->ret = -EIO;
		complete(&cmd->completion);
	}

does this write through a stale token belonging to another task's stack
frame, and can the device still DMA into the freed, device-writable
va_status?  Should the error path detach the descriptor (or defer the frees)
before this op is exposed to more drivers?

[Severity: High]
This is a pre-existing issue, but the admin queue accesses do not share a
lock with admin queue teardown, and this patch widens the set of contexts
that can submit commands without adding a serialization rule.

Reader side, with no lock held:

virtio_pci_modern.c:virtqueue_exec_admin_cmd() {
	vq = admin_vq->info->vq;
	if (!vq)
		return -EIO;
}

virtio_pci_modern.c:vp_modern_avq_cleanup() {
	vq = vp_dev->admin_vq.info->vq;
	if (!vq)
		return;

	while ((cmd = virtqueue_detach_unused_buf(vq))) {
}

vp_modern_avq_work() also reads admin_vq->info->vq before taking the mutex.

Writer side, holding only vp_dev->lock for the list removal:

virtio_pci_common.c:vp_del_vq() {
	if (vp_is_avq(vq->vdev, vq->index)) {
		cancel_work_sync(&vp_dev->admin_vq.work);
		vp_dev->admin_vq.info = NULL;
	}

	vp_dev->del_vq(info);
	kfree(info);
}

Since admin_vq->lock is not held by the cleanup or the teardown, can a
command submitted from an unrelated driver context concurrently with
del_vqs() or reset dereference NULL or the freed struct
virtio_pci_vq_info, and then operate on a destroyed vring?

The concrete unsynchronized submitter today is the existing
virtio_pci_admin_* path used by virtio-vfio-pci, which reaches a PF admin
queue while the PF's virtio driver can be unbound independently.  Should the
new kernel-doc carry an analogue of the @reset rule about not running in
parallel with virtqueues being added or removed?

> 
>  static const struct virtio_config_ops virtio_pci_config_ops = {
> @@ -1268,6 +1269,7 @@ static const struct virtio_config_ops virtio_pci_config_ops = {
>  	.get_shm_region  = vp_get_shm_region,
>  	.disable_vq_and_reset = vp_modern_disable_vq_and_reset,
>  	.enable_vq_after_reset = vp_modern_enable_vq_after_reset,
> +	.admin_cmd_exec = vp_modern_admin_cmd_exec,
>  };
>  
>  /* the PCI probing function */
> diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
> index 69f84ea85d71a..e36a32e0a20c8 100644
> --- a/include/linux/virtio_config.h
> +++ b/include/linux/virtio_config.h
> @@ -108,6 +108,10 @@ struct virtqueue_info {
>   *	Returns 0 on success or error status
>   *	If disable_vq_and_reset is set, then enable_vq_after_reset must also be
>   *	set.
> + * @admin_cmd_exec: Execute an admin VQ command (optional).
> + *	vdev: the virtio_device
> + *	cmd: the command to execute
> + *	Returns 0 on success or error status

[Severity: Low]
Could this kernel-doc also state the calling context?  The implementation
sleeps in several places: two kzalloc_obj() GFP_KERNEL allocations in
vp_modern_admin_cmd_exec(), and in virtqueue_exec_admin_cmd():

	mutex_lock(&admin_vq->lock);
	ret = virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_KERNEL);
	...
	wait_for_completion(&cmd->completion);

The wait has no timeout and is only woken by vp_modern_avq_work() or by
vp_modern_avq_cleanup() on reset.

The header of this struct is otherwise explicit about context, for example
that @get/@set, @get_status/@set_status and @get_features/@finalize_features
are not safe from atomic context, and that a device must not be reset from
its vq or config callbacks.

No in-tree caller violates this today.  Would it help to note that
admin_cmd_exec may sleep, must be called from process context, and can block
until the device completes the command or the device is reset?

[Severity: High]
This is a pre-existing issue, but the cmd->result_sg_size field that this
contract now exposes to arbitrary drivers is filled straight from the
device-written used ring length.  In vp_modern_avq_work():

		while ((cmd = virtqueue_get_buf(vq, &len))) {
			if (len < status_size)
				cmd->result_sg_size = 0;
			else
				cmd->result_sg_size = len - status_size;

virtio_ring does not clamp that length against the posted buffer; in
virtqueue_get_buf_ctx_split() and virtqueue_get_buf_ctx_packed() only the
descriptor id is range-checked while the length is taken verbatim:

	*len = vring_read_split_used_len(vq, last_used);

Is result_sg_size therefore fully device-controlled and able to exceed the
caller's result scatterlist?  The existing consumer already trusts it:
virtio_pci_admin_dev_parts_get() does *res_size = cmd.result_sg_size; and
drivers/vfio/pci/virtio/migrate.c does buf->length = res_size; for a buffer
whose real size is ctx_size, which the migration file then reads from.

Should the transport clamp result_sg_size to the total length of the
caller's result_sg before completing the command, and should the new
kernel-doc say that this field is untrusted device input?

>   */
>  struct virtio_config_ops {
>  	void (*get)(struct virtio_device *vdev, unsigned offset,
> @@ -137,6 +141,8 @@ struct virtio_config_ops {
>  			       struct virtio_shm_region *region, u8 id);
>  	int (*disable_vq_and_reset)(struct virtqueue *vq);
>  	int (*enable_vq_after_reset)(struct virtqueue *vq);
> +	int (*admin_cmd_exec)(struct virtio_device *vdev,
> +			      struct virtio_admin_cmd *cmd);
>  };

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831161109.2999926-1-shshitrit%40nvidia.com

  reply	other threads:[~2026-09-02 13:12 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 16:10 [PATCH net-next v23 00/14] virtio_net: Add ethtool flow rules support Shahar Shitrit
2026-08-31 16:10 ` [PATCH net-next v23 01/14] virtio_pci: Remove supported_caps cache and build assert Shahar Shitrit
2026-08-31 16:10 ` [PATCH net-next v23 02/14] virtio_pci: Fix sleeping under spinlock in admin command path Shahar Shitrit
2026-09-02 13:12   ` [net-next,v23,02/14] " netdev-bot+sashiko
2026-09-03  9:25     ` Paolo Abeni
2026-08-31 16:10 ` [PATCH net-next v23 03/14] virtio: Add config_op for admin commands Shahar Shitrit
2026-09-02 13:12   ` netdev-bot+sashiko [this message]
2026-08-31 16:10 ` [PATCH net-next v23 04/14] virtio: Expose generic device capability operations Shahar Shitrit
2026-09-02 13:12   ` [net-next,v23,04/14] " netdev-bot+sashiko
2026-08-31 16:11 ` [PATCH net-next v23 05/14] virtio: Expose object create and destroy API Shahar Shitrit
2026-09-02 13:12   ` [net-next,v23,05/14] " netdev-bot+sashiko
2026-08-31 16:11 ` [PATCH net-next v23 06/14] virtio_net: Query and set flow filter caps Shahar Shitrit
2026-09-02 13:12   ` [net-next,v23,06/14] " netdev-bot+sashiko
2026-08-31 16:11 ` [PATCH net-next v23 07/14] virtio_net: Create a FF group for ethtool steering Shahar Shitrit
2026-09-02 13:12   ` [net-next,v23,07/14] " netdev-bot+sashiko
2026-08-31 16:11 ` [PATCH net-next v23 08/14] ethtool: Introduce ethtool_flow_type_mask() Shahar Shitrit
2026-08-31 16:11 ` [PATCH net-next v23 09/14] virtio_net: Implement layer 2 ethtool flow rules Shahar Shitrit
2026-09-02 13:12   ` [net-next,v23,09/14] " netdev-bot+sashiko
2026-08-31 16:11 ` [PATCH net-next v23 10/14] virtio_net: Use existing classifier if possible Shahar Shitrit
2026-09-02 13:12   ` [net-next,v23,10/14] " netdev-bot+sashiko
2026-08-31 16:11 ` [PATCH net-next v23 11/14] virtio_net: Implement IPv4 ethtool flow rules Shahar Shitrit
2026-09-02 13:12   ` [net-next,v23,11/14] " netdev-bot+sashiko
2026-08-31 16:11 ` [PATCH net-next v23 12/14] virtio_net: Add support for IPv6 ethtool steering Shahar Shitrit
2026-09-02 13:12   ` [net-next,v23,12/14] " netdev-bot+sashiko
2026-08-31 16:11 ` [PATCH net-next v23 13/14] virtio_net: Add support for TCP and UDP ethtool rules Shahar Shitrit
2026-08-31 16:11 ` [PATCH net-next v23 14/14] virtio_net: Add get ethtool flow rules ops Shahar Shitrit
2026-09-02 13:12   ` [net-next,v23,14/14] " netdev-bot+sashiko
2026-08-31 16:37 ` [PATCH net-next v23 00/14] virtio_net: Add ethtool flow rules support Michael S. Tsirkin
2026-08-31 19:45 ` Michael S. Tsirkin

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=178835473869.3394541.13020013369139989380@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=danielj@nvidia.com \
    --cc=edumazet@google.com \
    --cc=eperezma@redhat.com \
    --cc=jasowang@redhat.com \
    --cc=jgg@ziepe.ca \
    --cc=kevin.tian@intel.com \
    --cc=kuba@kernel.org \
    --cc=mst@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=parav@nvidia.com \
    --cc=shshitrit@nvidia.com \
    --cc=virtualization@lists.linux.dev \
    --cc=xuanzhuo@linux.alibaba.com \
    --cc=yohadt@nvidia.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