mirror of
https://github.com/eclipse-threadx/threadx.git
synced 2026-10-06 06:59:08 +08:00
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>