Flaw in vMPU access check can cause HardFault when processing a malicious IPC request
- Dominant language
- C
- Stars
- 135
- Forks
- 72
- PR merge metrics
- No merged PRs in 30d
Description
Architecture affected: Armv7m
Target tested: EFM32
Code used to trigger the fault:
```
uvisor_ipc_desc_t send;
send.box_id = uvisor_box_id_self();
send.port = 1234;
send.len = sizeof(int);
int num_to_send = 0xdeadbeef;
int send_ret = ipc_send(&send, &num_to_send);
uvisor_ipc_desc_t recv;
recv.box_id = UVISOR_BOX_ID_ANY;
recv.port = 1234;
recv.len = sizeof(int);
int recv_ret = ipc_recv(&recv, 0);
```
Sequence to error:
(0) Flash memory initialised to be non-writable at vMPU initialisation. https://github.com/ARMmbed/uvisor/blob/a2b8ff5022c614afc928b7723a2934cdda4d36f0/core/vmpu/src/mpu_armv7m/vmpu_armv7m.c#L415
(1) Send/recv requests get queued up in the correspondent IPC queue
(2) uVisor drains IPC queue to find two matching requests
(3) uVisor validates receiving IPC IO request at https://github.com/ARMmbed/uvisor/blob/a2b8ff5022c614afc928b7723a2934cdda4d36f0/core/system/src/ipc.c#L313
(4) uVisor validates whether the data pointer is allowed for access for given length at https://github.com/ARMmbed/uvisor/blob/a2b8ff5022c614afc928b7723a2934cdda4d36f0/core/system/src/ipc.c#L188
(5) vMPU checks whether public box can access the memory at https://github.com/ARMmbed/uvisor/blob/a2b8ff5022c614afc928b7723a2934cdda4d36f0/core/vmpu/src/mpu_armv7m/vmpu_armv7m_mpu.c#L394
(6) vMPU checks whether the memory is in static region at https://github.com/ARMmbed/uvisor/blob/a2b8ff5022c614afc928b7723a2934cdda4d36f0/core/vmpu/src/mpu_armv7m/vmpu_armv7m_mpu.c#L399
(7) Check passes, because `0` is within the range of flash (static region 0) and end address is also in range.
(8) uVisor delivers message, triggers memory access violation due to `memcpy` https://github.com/ARMmbed/uvisor/blob/a2b8ff5022c614afc928b7723a2934cdda4d36f0/core/system/src/ipc.c#L145
Debug prints:
```
uVisor mode: 2
uvisor_ram : @0x20000000 (8192 bytes) [config]
@0x20000000 (8192 bytes) [linker]
bss_boxes : @0x20002000 (57344 bytes) [config]
box stack segment start=0x20002000 end=0x20010000 (length=57344)
MPU.REGIONS=8
MPU.ALIGNMENT=0x0000001F
MPU.ALIGNMENT_BITS=5
* MPU CONFIGURATION
Background region enabled
MPU bypassed @NMI, @HardFault
MPU enabled
Region Start Size XN AP TEX S C B SRD Valid
0 0x00000000 256KB 0 110 000 0 0 0 00000000 1
1 0x20000000 128KB 0 011 000 0 0 0 00011111 1
2 0x00000000 000B 0 000 000 0 0 0 00000000 0
3 0x00000000 000B 0 000 000 0 0 0 00000000 0
4 0x00000000 000B 0 000 000 0 0 0 00000000 0
5 0x00000000 000B 0 000 000 0 0 0 00000000 0
6 0x00000000 000B 0 000 000 0 0 0 00000000 0
7 0x00000000 000B 0 000 000 0 0 0 00000000 0
Box 0 ACLs:
- Peripheral: 0x400C8000 - 0x400C8088 (permissions: 0x0AB6)
- Peripheral: 0x400C0000 - 0x400C0058 (permissions: 0x0AB6)
- Peripheral: 0x40006000 - 0x40006140 (permissions: 0x0AB6)
- Peripheral: 0x40010000 - 0x4001008C (permissions: 0x0AB6)
- Peripheral: 0x4000E000 - 0x4000E060 (permissions: 0x0AB6)
- Peripheral: 0x0FE08000 - 0x0FE09000 (permissions: 0x0AB6)
- Peripheral: 0x42000000 - 0x44000000 (permissions: 0x0AB6)
Box 1 ACLs:
- SRAM: 0x20004000 - 0x20008000 (permissions: 0x0076, subregions: 0x10)
- BSS: 0x20004000 - 0x20005D3C (original size: 7484B, rounded size: 8192B)
- Stack: 0x20006800 - 0x20008000 (original size: 1024B, rounded size: 6144B)
Box 2 ACLs:
- SRAM: 0x20008000 - 0x2000C000 (permissions: 0x0076, subregions: 0x10)
- BSS: 0x20008000 - 0x2000993C (original size: 6460B, rounded size: 8192B)
- Stack: 0x2000A800 - 0x2000C000 (original size: 1024B, rounded size: 6144B)
Box 3 ACLs:
- SRAM: 0x2000C000 - 0x20010000 (permissions: 0x0076, subregions: 0x10)
- BSS: 0x2000C000 - 0x2000D948 (original size: 6472B, rounded size: 8192B)
- Stack: 0x2000E800 - 0x20010000 (original size: 1024B, rounded size: 6144B)
vmpu_enumerate_boxes [DONE]
page heap: [0x20010000, 0x20014000] 16kB -> 16 1kB pages
uvisor initialized
IRQ 20 registered to box 0
IRQ 21 registered to box 0
IRQ 21 priority set to 3 (NVIC), 1 (virtual)
***********************************************************
HARD FAULT
***********************************************************
* Active Box ID: 1
* FAULT SYNDROME REGISTERS
HFSR: 0x40000000
--> FORCED: another priority escalated to hard fault.
--> Escalated from SysTick IRQ.
* EXCEPTION STACK FRAME
lr: 0xFFFFFFF1
--> FP stack frame not saved.
--> Exception from P mode.
--> Return to MSP.
sp: 0x20001EF0
sp[07]: 0x6100000B | xPSR
sp[06]: 0x00007E0C | pc
sp[05]: 0x00001773 | lr
sp[04]: 0x00000000 | r12
sp[03]: 0xDEADBEEF | r3
sp[02]: 0x00000000 | r2
sp[01]: 0x20005014 | r1
sp[00]: 0x00000000 | r0
* MPU CONFIGURATION
Background region enabled
MPU bypassed @NMI, @HardFault
MPU enabled
Region Start Size XN AP TEX S C B SRD Valid
0 0x00000000 256KB 0 110 000 0 0 0 00000000 1
1 0x20000000 128KB 0 011 000 0 0 0 00011111 1
2 0x00000000 000B 0 000 000 0 0 0 00000000 0
3 0x20004000 016KB 1 011 000 0 0 0 00010000 1
4 0x00000000 000B 0 000 000 0 0 0 00000000 0
5 0x00000000 000B 0 000 000 0 0 0 00000000 0
6 0x00000000 000B 0 000 000 0 0 0 00000000 0
7 0x00000000 000B 0 000 000 0 0 0 00000000 0
***********************************************************
HALT_ERROR(./core/vmpu/src/mpu_armv7m/vmpu_armv7m.c#141): Cannot recover from a hard fault.
```
Suggested Fix:
If the flash is public (as in Armv8m), fix the ACL for public flash memory
Otherwise, fix access check to take parameter indicating the permission needed and check whether the operation is permitted against the ACL.
Contributor guide
Research direction
Read the cited access-check paths in core/system/src/ipc.c, core/vmpu/src/mpu_armv7m/vmpu_armv7m_mpu.c, and the flash setup in core/vmpu/src/mpu_armv7m/vmpu_armv7m.c. Reproduce the malicious IPC sequence on Armv7m, then verify that an invalid receive pointer is rejected according to the required ACL permission without reaching memcpy or causing a HardFault.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- embedded-iot, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 38/100