From: sashiko-bot@kernel.org
To: "Long Li" <longli@microsoft.com>
Cc: linux-hyperv@vger.kernel.org
Subject: Re: [PATCH net v4 7/7] net: mana: keep max_num_cqs immutable once cq_table is allocated
Date: Sun, 09 Aug 2026 02:35:01 +0000 [thread overview]
Message-ID: <20260809023503.10E581F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260808023417.1746886-8-longli@microsoft.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing reader-side acquire barrier and missing reset of `gc->max_num_cqs` on teardown allows a malicious host to bypass the `cq_table` bounds check on resume, leading to an out-of-bounds read and potential control flow hijack.
- [High] A spoofed `GDMA_EQE_HWC_INIT_EQ_ID_DB` event overwrites the hardware channel doorbell ID without bounds checking, leading to a guest kernel panic.
--
--- Patch [7]: [PATCH net v4 7/7] net: mana: keep max_num_cqs immutable once cq_table is allocated ---
commit cb30244d24849d9dc1bb09cc690c55b40f642e06
Author: Long Li <longli@microsoft.com>
net: mana: keep max_num_cqs immutable once cq_table is allocated
This commit prevents post-init HWC events from inflating the CQ count
bound past the cq_table allocation size. It stores the reported max_num_cqs
in the channel context and commits it once during channel establishment.
This ensures the allocation size and the bounds check remain consistent.
> diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
> index 2f0dae3539552..03b5e2f02e352 100644
> --- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
> +++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
> @@ -246,7 +246,15 @@ static void mana_hwc_init_event_handler(void *ctx, struct gdma_queue *q_self,
> break;
>
> case HWC_INIT_DATA_MAX_NUM_CQS:
[Severity: High]
This is a pre-existing issue, but can a spoofed GDMA_EQE_HWC_INIT_EQ_ID_DB
event cause an out-of-bounds MMIO write?
Looking at mana_hwc_init_event_handler(), it blindly trusts the doorbell ID
provided by the host:
case GDMA_EQE_HWC_INIT_EQ_ID_DB:
eq_db.as_uint32 = event->details[0];
hwc->cq->gdma_eq->id = eq_db.eq_id;
gd->doorbell = eq_db.doorbell;
break;
The next time the driver rings the doorbell in mana_gd_ring_doorbell(), it
uses this unvalidated spoofed ID to calculate the MMIO address:
void __iomem *addr = gc->db_page_base + gc->db_page_size * db_index;
...
writeq(e.as_uint64, addr);
Could this result in writing outside the mapped bar0_va region and cause a
guest kernel panic?
> - gd->gdma_context->max_num_cqs = val;
> + /* Store, don't apply: mana_hwc_establish_channel()
> + * commits this to gc->max_num_cqs once, together
> + * with sizing cq_table, so a spoofed post-init event
> + * cannot inflate the bound past the allocation.
> + * WRITE_ONCE() pairs with the READ_ONCE() there:
> + * this store runs in EQ interrupt context,
> + * concurrently with that process-context read.
> + */
> + WRITE_ONCE(hwc->hwc_init_max_num_cqs, val);
> break;
[ ... ]
> @@ -881,15 +891,29 @@ static int mana_hwc_establish_channel(struct gdma_context *gc, u16 *q_depth,
> *max_req_msg_size = hwc->hwc_init_max_req_msg_size;
> *max_resp_msg_size = hwc->hwc_init_max_resp_msg_size;
>
> - /* Both were set in mana_hwc_init_event_handler(). */
> - if (WARN_ON(cq->id >= gc->max_num_cqs))
> + /* Snapshot the device-reported CQ count and CQ id into locals and
> + * use only the locals below, so the same value that sizes cq_table
> + * also bounds and indexes it -- even across the sleeping vcalloc().
> + * Both fields are written by mana_hwc_init_event_handler() from EQ
> + * interrupt context: hwc_init_max_num_cqs under WRITE_ONCE() (paired
> + * here), and cq->id as an ordinary store. READ_ONCE() keeps each
> + * read tear-free and, crucially, non-reloadable, so a spoofed
> + * post-init event cannot make the WARN_ON() pass against one value
> + * while the allocation or the index uses another.
> + */
> + num_cqs = READ_ONCE(hwc->hwc_init_max_num_cqs);
> + cq_id = READ_ONCE(cq->id);
> +
> + if (WARN_ON(cq_id >= num_cqs))
> return -EPROTO;
>
> - cq_table = vcalloc(gc->max_num_cqs, sizeof(*cq_table));
> + cq_table = vcalloc(num_cqs, sizeof(*cq_table));
> if (!cq_table)
> return -ENOMEM;
>
> - rcu_assign_pointer(cq_table[cq->id], cq);
> + gc->max_num_cqs = num_cqs;
> +
[Severity: High]
This is a pre-existing issue, but does teardown leave gc->max_num_cqs at a
stale value?
Looking at mana_hwc_destroy_channel() in
drivers/net/ethernet/microsoft/mana/hw_channel.c, it replaces the
cq_table pointer but doesn't reset gc->max_num_cqs:
old_cq_table = rcu_replace_pointer(gc->cq_table, NULL, true);
synchronize_rcu();
During a device resume, mana_hwc_establish_channel() will publish a new,
potentially smaller cq_table and update gc->max_num_cqs.
If a malicious host sends a GDMA_EQE_COMPLETION event concurrently, the
reader in mana_gd_process_eqe() in
drivers/net/ethernet/microsoft/mana/gdma_main.c checks the bounds:
cq_table = rcu_dereference(gc->cq_table);
if (WARN_ON_ONCE(cq_id >= gc->max_num_cqs || !cq_table))
break;
Since there is no acquire barrier between reading gc->cq_table and
gc->max_num_cqs, could weakly ordered CPUs read the stale, large
max_num_cqs bound and the new, smaller cq_table pointer?
This seems like it could allow a crafted cq_id to pass the bounds
check and cause an out-of-bounds memory read.
> + rcu_assign_pointer(cq_table[cq_id], cq);
> /* Publish the fully-initialised table last; pairs with the
> * rcu_dereference(gc->cq_table) in mana_gd_process_eqe().
> */
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260803234355.636038-1-longli@microsoft.com?part=7
prev parent reply other threads:[~2026-08-09 2:35 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-03 23:43 [PATCH net v3 0/6] net: mana: HW channel reliability and hardening fixes Long Li
2026-08-03 23:43 ` [PATCH net v3 1/6] net: mana: RCU-protect gc->cq_table lookups against concurrent CQ destroy Long Li
2026-08-04 23:44 ` sashiko-bot
2026-08-06 17:23 ` Jakub Kicinski
2026-08-03 23:43 ` [PATCH net v3 2/6] net: mana: fix HWC RQ/SQ buffer size swap Long Li
2026-08-04 23:44 ` sashiko-bot
2026-08-06 17:23 ` Jakub Kicinski
2026-08-03 23:43 ` [PATCH net v3 3/6] net: mana: free HWC comp_buf after destroying the EQ Long Li
2026-08-04 23:44 ` sashiko-bot
2026-08-06 17:23 ` Jakub Kicinski
2026-08-03 23:43 ` [PATCH net v3 4/6] net: mana: validate hardware-supplied values in the HWC RX path Long Li
2026-08-04 23:44 ` sashiko-bot
2026-08-06 17:24 ` Jakub Kicinski
2026-08-03 23:43 ` [PATCH net v3 5/6] net: mana: fix HWC teardown safety with setup_active flag and destroy ordering Long Li
2026-08-04 23:44 ` sashiko-bot
2026-08-06 17:24 ` Jakub Kicinski
2026-08-03 23:43 ` [PATCH net v3 6/6] net: mana: fix stale HWC response after command timeout Long Li
2026-08-04 23:44 ` sashiko-bot
2026-08-06 17:24 ` Jakub Kicinski
2026-08-08 2:10 ` [EXTERNAL] " Long Li
2026-08-08 2:34 ` [PATCH net v4 0/7] net: mana: HW channel reliability and hardening fixes Long Li
2026-08-08 2:34 ` [PATCH net v4 1/7] net: mana: RCU-protect gc->cq_table lookups against concurrent CQ destroy Long Li
2026-08-09 2:34 ` sashiko-bot
2026-08-08 2:34 ` [PATCH net v4 2/7] net: mana: fix HWC RQ/SQ buffer size swap Long Li
2026-08-09 2:35 ` sashiko-bot
2026-08-08 2:34 ` [PATCH net v4 3/7] net: mana: free HWC comp_buf after destroying the EQ Long Li
2026-08-09 2:35 ` sashiko-bot
2026-08-08 2:34 ` [PATCH net v4 4/7] net: mana: validate hardware-supplied values in the HWC RX path Long Li
2026-08-09 2:34 ` sashiko-bot
2026-08-08 2:34 ` [PATCH net v4 5/7] net: mana: fix HWC teardown safety with setup_active flag and destroy ordering Long Li
2026-08-08 2:34 ` [PATCH net v4 6/7] net: mana: fix stale HWC response after command timeout Long Li
2026-08-09 2:34 ` sashiko-bot
2026-08-08 2:34 ` [PATCH net v4 7/7] net: mana: keep max_num_cqs immutable once cq_table is allocated Long Li
2026-08-09 2:35 ` sashiko-bot [this message]
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=20260809023503.10E581F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-hyperv@vger.kernel.org \
--cc=longli@microsoft.com \
--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.