All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "João Peixoto" <jpeixoto@osyx.tech>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v5 2/3] virt: bao: add I/O dispatcher driver
Date: Sat, 07 Nov 2026 08:29:17 +0000	[thread overview]
Message-ID: <sashiko-outbox-202742@kernel.org> (raw)
In-Reply-To: <c900781e2f68a7dc4e262cbb856dd3eee354974f.1794038390.git.jpeixoto@osyx.tech>

Thank you for your contribution! Sashiko AI review found 7 potential
issues to consider:
- [Medium] virt: bao: race between attach error path and complete in
  bao_dm_ioctl()
- [Medium] virt: bao: missing 32-bit size_t truncation check in
  bao_dm_info_valid()
- [Medium] virt: bao: 32-bit unsigned long truncation on RV32 in
  bao_remio_hypercall()
- [Medium] virt: bao: broken client teardown order in
  bao_io_client_destroy()
- [Medium] virt: bao: missing eventfd read and -ENOENT in
  bao_irqfd_wakeup()/deassign()
- [Medium] virt: bao: broken conflict and datamatch handling in
  bao_ioeventfd_handler()
- [Low] virt: bao: range overflow and width truncation in
  bao_ioeventfd_match()
--

commit c7f53fde4f821f921b87ccd26ae05833f79dbbe0
Author: João Peixoto <jpeixoto@osyx.tech>

virt: bao: add I/O dispatcher driver

This commit adds the Bao hypervisor I/O dispatcher driver, exposing a
/dev/bao control device and per-device-model file descriptors to bridge
Bao Remote I/O requests, ioeventfds, and irqfds to userspace VirtIO
backends.

[Severity: Medium]
In drivers/virt/bao/io-dispatcher/Kconfig (line 4), BAO_IO_DISPATCHER
depends on ARM64 || RISCV_SBI, which allows building the driver on 32-bit
RISC-V (CONFIG_32BIT=y && CONFIG_RISCV_SBI=y). Can bao_remio_hypercall()
in drivers/virt/bao/bao_hypercall.h (line 174) and the dm->inflight XArray
operations in drivers/virt/bao/io-dispatcher/dm.c (lines 53, 144, and 166)
silently truncate 64-bit values on RV32?

In bao_remio_hypercall(), the u64 fields of struct bao_remio_hypercall_ctx
(dm_id, addr, op, value, request_id) are loaded into unsigned long
registers a0-a4, truncating 64-bit MMIO addresses, 8-byte I/O values, and
request IDs to 32 bits. Similarly, xa_insert() and xa_erase() on
dm->inflight take an unsigned long index, truncating the upper 32 bits of
req->request_id. Should BAO_IO_DISPATCHER depend on ARM64 || (RISCV_SBI &&
64BIT)?

[Severity: Medium]
In drivers/virt/bao/io-dispatcher/dm.c, within bao_dm_ioctl() at lines
132-184, can the BAO_IOCTL_IO_CLIENT_ATTACH error path race with a
concurrent BAO_IOCTL_IO_REQUEST_COMPLETE on the same file descriptor and
complete the same request twice?

CPU0                                  CPU1
bao_dm_ioctl(IO_CLIENT_ATTACH)
  bao_dm_inflight_add(dm, &req)
                                      bao_dm_ioctl(IO_REQUEST_COMPLETE)
                                        xa_erase(&dm->inflight, id)
                                        bao_remio_hypercall(&ctx)
  copy_to_user(...) -> -EFAULT
  kfree(xa_erase(&dm->inflight, id))
  bao_io_request_complete_error(...)  <-- duplicate completion

bao_dm_inflight_add() publishes req.request_id into dm->inflight before
copy_to_user(). If another thread completes that request_id while
copy_to_user() faults, xa_erase() on the error path returns NULL (or
erases a newly attached request if the hypervisor reused request_id), and
bao_io_request_complete_error() issues a second completion hypercall to
the hypervisor. Copy req to userspace before inserting it into
dm->inflight, or only call bao_io_request_complete_error() when xa_erase()
returns the entry.

[Severity: Medium]
In drivers/virt/bao/io-dispatcher/dm.c, within bao_dm_info_valid() at
line 348, can a 64-bit info->shmem_size with zero lower 32 bits bypass
validation on 32-bit builds by truncating to 0 in size_t and unsigned
long?

When sizeof(size_t) < sizeof(u64), passing info->shmem_addr = 0 and
info->shmem_size = 0x100000000ULL passes !info->shmem_size,
PAGE_ALIGNED(info->shmem_size), and upper_32_bits(end) == 0, but truncates
to size 0 in region_intersects() and request_mem_region() while leaving
dm->info.shmem_size set to 4 GiB. Adding a check for sizeof(size_t) <
sizeof(u64) && upper_32_bits(info->shmem_size) (matching
bao_ipcshmem_region_valid()) would prevent this.

[Severity: Medium]
In drivers/virt/bao/io-dispatcher/io_client.c, within
bao_io_client_destroy() at lines 140-161, does the teardown sequence
destroy dm->ioeventfds before stopping the kernel thread and then
prematurely resume the I/O dispatcher during DM teardown?

First, at line 140, bao_io_client_destroy() calls
bao_ioeventfd_client_destroy(dm) before kthread_stop(client->thread),
emptying and freeing dm->ioeventfds while bao_io_client_kernel_thread() is
still draining queued requests via bao_ioeventfd_handler(), which silently
drops those eventfd notifications.

Second, at line 161, bao_io_client_destroy() calls
bao_io_dispatcher_resume(dm), which re-installs dm->intc_handler and
queues dm->io_work on dm->io_wq. Because bao_io_client_destroy() is only
called from bao_io_clients_destroy() during full DM teardown (in
bao_dm_destroy() or the error unwind of bao_dm_create()), resuming the
dispatcher mid-teardown causes io_dispatcher() to run BAO_IO_ASK
hypercalls when a BAO_IOCTL_CREATE_DM call fails after creating
control_client (for example, when bao_intc_init() fails), and during
bao_dm_release() it re-queues dm->io_work between destroying
ioeventfd_client and control_client, misrouting or error-completing
requests before bao_io_dispatcher_destroy() finally drains the workqueue.
Pausing or destroying the dispatcher at the start of bao_dm_destroy()
(before completing inflight requests and destroying clients) and removing
bao_io_dispatcher_resume() from bao_io_client_destroy() would avoid this.

[Severity: Low]
In drivers/virt/bao/io-dispatcher/io_client.c, within
bao_io_request_in_range() at line 398, and
drivers/virt/bao/io-dispatcher/ioeventfd.c, within bao_ioeventfd_match()
at line 124 and bao_ioeventfd_handler() at line 294, can a malformed or
top-of-address-space request wrap around in the range check or truncate
req->access_width?

In bao_io_request_in_range(), evaluating (req->addr + req->access_width -
1) <= range->end without checking that req->access_width > 0 and does not
overflow u64 allows a zero access_width or an address near U64_MAX to wrap
around and falsely match the range. In addition, passing u64
req->access_width into the signed int len parameter of
bao_ioeventfd_match() and testing p->length >= len without requiring len >
0 allows a zero or negative-truncated length to match any registered
ioeventfd.

[Severity: Medium]
In drivers/virt/bao/io-dispatcher/ioeventfd.c, within
bao_ioeventfd_is_conflict() at line 103 and bao_ioeventfd_handler() at
line 292, are conflicting eventfds at the same address allowed, and are
non-matching writes to a datamatch range silently dropped?

First, bao_ioeventfd_is_conflict() checks p->eventfd ==
ioeventfd->eventfd, which allows registering two different eventfds for
the exact same address and data match even though bao_ioeventfd_match()
only ever signals the first matching entry on dm->ioeventfds.

Second, bao_ioeventfd_assign() adds [addr, addr + length - 1] to
dm->ioeventfd_client, and bao_io_client_find() in
drivers/virt/bao/io-dispatcher/io_client.c (line 415) routes every request
in that address range to dm->ioeventfd_client without checking whether any
ioeventfd matches the request's data value, exact address, or access
width. When a guest writes a virtqueue index with no registered ioeventfd
to a shared QueueNotify register that has a BAO_IOEVENTFD_FLAG_DATAMATCH
entry, bao_ioeventfd_handler() finds no match in bao_ioeventfd_match() and
returns 0, completing the hypercall and dropping the write instead of
forwarding it to dm->control_client.

[Severity: Medium]
In drivers/virt/bao/io-dispatcher/irqfd.c, within bao_irqfd_wakeup() at
line 86 and bao_irqfd_deassign() at line 237, does irqfd signaling leave
the eventfd counter unconsumed, and does deassigning an unknown irqfd
succeed?

In bao_irqfd_wakeup(), EPOLLIN triggers bao_irqfd_inject() without calling
eventfd_ctx_do_read() to consume the eventfd counter, leaving the eventfd
permanently readable (and eventually saturating its counter at ULLONG_MAX
- 1). Also, in bao_irqfd_deassign(), if no matching entry is found in
dm->irqfds, the function still flushes dm->irqfd_server and returns 0
instead of -ENOENT.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1794038390.git.jpeixoto@osyx.tech?part=2

  reply	other threads:[~2026-11-07  8:29 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-07  8:06 [PATCH v5 0/3] virt: bao: add Bao hypervisor IPC and I/O dispatcher drivers João Peixoto
2026-11-07  8:06 ` João Peixoto
2026-11-07  8:06 ` [PATCH v5 1/3] virt: bao: add IPC shared-memory driver João Peixoto
2026-11-07  8:06   ` João Peixoto
2026-11-07  8:06 ` [PATCH v5 2/3] virt: bao: add I/O dispatcher driver João Peixoto
2026-11-07  8:06   ` João Peixoto
2026-11-07  8:29   ` sashiko-bot [this message]
2026-11-07  8:06 ` [PATCH v5 3/3] MAINTAINERS: add Bao hypervisor entry João Peixoto
2026-11-07  8:06   ` João Peixoto

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=sashiko-outbox-202742@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=jpeixoto@osyx.tech \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.