[PATCH RFC v4 16/18] ACPI: RISC-V: Parse RISC-V Quality of Service Controller (RQSC) table
Drew Fustini
fustini at kernel.org
Sat May 16 22:01:11 PDT 2026
On Tue, May 12, 2026 at 09:46:28PM +0000, sashiko-bot at kernel.org wrote:
> > + for (node = ACPI_ADD_PTR(struct acpi_rqsc_node, rqsc,
> > + sizeof(struct acpi_table_rqsc));
> > + node < end;
> > + node = ACPI_ADD_PTR(struct acpi_rqsc_node, node, node->length)
> > + ) {
> > + const struct acpi_rqsc_resource *res0;
> > + struct cbqri_controller_info info = {};
> > + int ret;
> > +
> > + if ((void *)node + sizeof(*node) > (void *)end) {
> > + pr_err("truncated entry at end of table, aborting\n");
> > + riscv_cbqri_unregister_last(num_controllers);
> > + return -EINVAL;
> > + }
>
> Does this code also need to verify that the entire declared length of the node
> fits within the table boundary?
>
> If a malformed node declares a length extending beyond the end of the ACPI
> table, the node pointer could advance past end during the loop increment:
>
> node = ACPI_ADD_PTR(struct acpi_rqsc_node, node, node->length)
>
> Could this cleanly fail the loop condition on the next iteration and silently
> return success instead of rejecting the corrupted table?
I will add an explicit check so that an overrun is flagged as corruption
rather than silently truncating the controller list.
> > + if (node->length < sizeof(*node)) {
> > + pr_err("malformed RQSC entry: length %u < %zu, aborting\n",
> > + node->length, sizeof(*node));
> > + riscv_cbqri_unregister_last(num_controllers);
> > + return -EINVAL;
> > + }
>
> Could this loop be bounded by rqsc->num instead of just node < end?
>
> If the firmware pads the table at the end for alignment, the parser might
> attempt to process the zeroed padding as a node.
>
> Would encountering this padding trigger this length check, unregister all
> successfully parsed controllers, and completely abort initialization for an
> otherwise valid table?
The behavior is intentional. RQSC does not document a padding allowance,
so a zero length entry inside the declared table length is treated as
corruption.
> > + /* GAS must describe system memory. ioremap() consumes it later. */
> > + if (node->reg.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
> > + pr_warn("controller has unsupported address space_id=%u, skipping\n",
> > + node->reg.space_id);
> > + continue;
> > + }
>
> Should this code check node->flags before proceeding? Standard ACPI practice
> typically uses Bit 0 to indicate whether a hardware block is present and
> enabled.
>
> If flags are ignored, could the driver risk mapping and accessing
> memory-mapped registers of explicitly disabled hardware?
Ignoring node->flags is correct here as RQSC defines bit 0 as: "When
set, indicates the controller supports allocating zero capacity blocks
or zero bandwidth blocks to an RCID."
> > + /*
> > + * Resources follow the node header in-line. Only res[0] is
> > + * consumed. Bound it against end before reading its prefix so
> > + * a table that ends partway through a resource subtable is
> > + * rejected rather than read past the mapping.
> > + */
> > + res0 = (const struct acpi_rqsc_resource *)
> > + ((const u8 *)node + sizeof(*node));
>
> Is it safe to hardcode the start of the resource subtables using
> sizeof(*node)?
>
> If a future revision of the RQSC table extends the acpi_rqsc_node structure
> with additional fields, sizeof(*node) would be smaller than the actual
> node header size.
>
> Could this missing rqsc->header.revision check cause the parser to point into
> the middle of the new header fields and incorrectly interpret them as the
> first resource descriptor?
I will add a revision check at the top of acpi_parse_rqsc()
> > + if (res0->id1 > U32_MAX) {
> > + pr_warn("controller at %pa: id1 0x%llx exceeds u32, skipping\n",
> > + &info.addr, res0->id1);
> > + continue;
> > + }
> > +
> > + switch (info.type) {
> > + case CBQRI_CONTROLLER_TYPE_CAPACITY:
> > + info.cache_id = (u32)res0->id1;
> > + break;
> > + case CBQRI_CONTROLLER_TYPE_BANDWIDTH:
> > + info.prox_dom = (u32)res0->id1;
> > + break;
>
> Does this code need to validate the type and id_type fields of the resource
> descriptor before extracting res0->id1?
>
> If a controller specifies multiple resources (node->nres > 1) and the first
> descriptor is not the expected cache ID or proximity domain, could the
> parser blindly misinterpret its contents?
I will add a check for res0->type and res0->id_type before using id1.
-Drew
More information about the linux-riscv
mailing list