1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
/***************************************************************************
* Copyright (c) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5.5).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Test */
/** */
/** Module execution harness: protected module memory fault */
/** */
/**************************************************************************/
/**************************************************************************/
/* A user-mode, memory-protected module that reads a word of kernel memory must
take a MemManage fault on that read. The Module Manager must terminate the
faulting thread, report it to the application's fault notification with the
right module, thread and address, and still let the module be stopped and
unloaded.
This image is also the harness's proof that the emulated MPU is enforcing at
all: if QEMU let the unprivileged read through, the module would record the
value and finish, and every check below would fail. */
#include "harness_checks.h"
#define MODULE_WAIT_TICKS ((ULONG) 500UL)
#define PROTECTED_PROPERTIES ((ULONG) 0x02000007UL) /* GNU; user mode, memory protection, shared memory */
#define KERNEL_WORD_VALUE ((ULONG) 0x6B65726EUL)
/* CFSR: MemManage data access violation, with MMFAR valid. */
#define CFSR_DACCVIOL ((ULONG) 0x02UL)
#define CFSR_MMARVALID ((ULONG) 0x80UL)
extern UCHAR module_services_protected[];
static TXM_MODULE_INSTANCE test_module;
static volatile ULONG kernel_word = KERNEL_WORD_VALUE;
VOID harness_test(VOID)
{
ULONG available_before;
ULONG start;
harness_print("Module fault: protected module reads kernel memory\n");
available_before = harness_module_pool_available();
harness_shared_clear();
MODULE_SHARED[MODULE_IN_CYCLE] = 1UL;
MODULE_SHARED[MODULE_IN_KERNEL_WORD] = (ULONG) &kernel_word;
harness_expect("memory load", (ULONG) txm_module_manager_memory_load(&test_module, "services protected",
(VOID *) module_services_protected),
(ULONG) TX_SUCCESS);
harness_expect("module properties", test_module.txm_module_instance_property_flags, PROTECTED_PROPERTIES);
harness_expect("shared area grant", (ULONG) harness_shared_grant(&test_module), (ULONG) TX_SUCCESS);
harness_expect("module start", (ULONG) txm_module_manager_start(&test_module), (ULONG) TX_SUCCESS);
start = tx_time_get();
while ((harness_fault_count == 0UL) && ((tx_time_get() - start) < MODULE_WAIT_TICKS))
{
tx_thread_sleep(1);
}
/* The kernel services before the read still worked. */
harness_check_services(1UL);
harness_expect("module ran unprivileged", MODULE_SHARED[MODULE_OUT_CONTROL] & CONTROL_NPRIV, CONTROL_NPRIV);
/* The read was attempted and faulted. */
harness_expect("kernel read attempted", MODULE_SHARED[MODULE_OUT_KERNEL_READ_TRY], 1UL);
harness_expect("kernel read did not complete", MODULE_SHARED[MODULE_OUT_KERNEL_READ_DONE], 0UL);
harness_expect("kernel value not disclosed", MODULE_SHARED[MODULE_OUT_KERNEL_VALUE], 0UL);
harness_expect("module did not finish", MODULE_SHARED[MODULE_DONE], 0UL);
harness_expect("one memory fault reported", harness_fault_count, 1UL);
harness_expect("fault names the module", (ULONG) harness_fault_module, (ULONG) &test_module);
harness_expect("fault names the start thread", (ULONG) harness_fault_thread,
(ULONG) &test_module.txm_module_instance_start_stop_thread);
harness_expect("fault address is the kernel word", harness_fault_address, (ULONG) &kernel_word);
harness_expect("fault is a data access violation",
harness_fault_status & (CFSR_DACCVIOL | CFSR_MMARVALID), CFSR_DACCVIOL | CFSR_MMARVALID);
harness_expect("faulting thread terminated",
(ULONG) test_module.txm_module_instance_start_stop_thread.tx_thread_state, (ULONG) TX_TERMINATED);
harness_expect("kernel word unchanged", kernel_word, KERNEL_WORD_VALUE);
harness_expect("module stop", (ULONG) txm_module_manager_stop(&test_module), (ULONG) TX_SUCCESS);
harness_expect("module unload", (ULONG) txm_module_manager_unload(&test_module), (ULONG) TX_SUCCESS);
harness_expect("module memory returned", harness_module_pool_available(), available_before);
}
|