Files
threadx/test/tx
Frédéric Desbiens 5f9ebde847 Merge commit from fork
A memory-protected module's queue request reaches the Module Manager's dispatch
layer, which decides how much of the module's buffer the privileged queue copy
may touch and hands that extent to the module port's range check. A queue's
tx_queue_message_size is a count of ULONGs and the copy moves that many words, so
the extent is message_size * sizeof(ULONG) bytes. Front-send passed the word count
itself. Send and receive, either side of it in the same header, have always
multiplied.

So a source buffer ending message_size bytes into memory the module may reach was
accepted, and _txe_queue_front_send then read message_size * sizeof(ULONG) bytes
from it in privileged mode: 3 * message_size bytes past the end of what the module
is allowed to read, which is 48 bytes at ThreadX's default message size limit and
96 at the limit this test tree builds with. The words land in the queue, and a
module that can receive from that queue reads them back, so the over-read is
disclosed rather than merely performed. Where the memory past the region is not
mapped for the requesting module, the privileged read faults instead.

The buffer cannot be aimed: it has to pass the same check to be accepted at all,
so it is anchored to the end of a region the module can already read and the
overrun is the fixed window immediately after it. That bounds what this reaches;
it does not make it the module's business.

The fix is the multiplication the other two services do, in the units the port
check has always expected. It changes nothing for a module loaded without memory
protection, because the check it corrects is inside the dispatcher's memory
protection block, and the tests hold that.

The regression test drives the three queue dispatchers directly, which nothing in
the tree did before, and measures the extent each one validates rather than
sampling either side of it: for a given message size it walks the room left
between the buffer and the end of the module's region and finds the smallest
amount the dispatcher accepts. That number is the extent. It has to be
message_size * sizeof(ULONG) for all three services, in the module's data, in a
shared region registered to it, and -- for the two services that read the buffer
rather than write it -- in the module's read-only image, which is where a module
sending a constant message sends it from. A receive destination in the read-only
image is refused at every extent.

Two things had to be arranged for a dispatcher to be testable on the host at all.
The dispatch table is a header of static functions wrapped one per service in
#ifndef TXM_<SERVICE>_CALL_NOT_USED, and at -O0 a compiler emits them all, so
linking the whole table would mean standing up every kernel entry point it
reaches. Defining the 93 guards the test does not exercise compiles the header
down to the three queue services, which leaves four symbols to stub and exercises
that conditional compilation, which nothing else in the tree does. The extent also
has to reach a check that honours it, so the test takes its module port headers
from a Cortex-M port, whose inline data check is the shape the memory-protected
module ports share. The Cortex-A7 port's data check takes the pointer alone and
translates a single address, so on that port no extent reaches anything and a test
built on it would pass equally with and without this change.

That is also the affected-port claim: the defect is in the portable dispatch layer
and was live on every memory-protected module port that honours the size it is
given, which is all of them except Cortex-A7, where the port's own check discarded
the size before this one's error could matter.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
2026-09-28 11:07:09 -04:00
..
2026-09-28 11:07:09 -04:00
2026-09-28 11:07:09 -04:00