-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Description
I am part of the group that develops the Pelion Device Management Client. We use mbed-os with KVSTORE and in our testing we do a lot of seeding of a DRBG, which calls the mbedtls mbedtls_entropy_func
function, which calls the mbedtls_hardware_poll
function to generate random entropy from the K64F hardware.
In addition, the Pelion device management client runs a thread that every number of seconds tries to generate random data from the mbedtls_hardware_poll API. The problem is that the mbedtls_hardware_poll
API is not thread safe and we occationally get the following hard fault:
++ MbedOS Fault Handler ++
FaultType: HardFault
Context:
R0 : 20008CF5
R1 : 00000005
R2 : 40029004
R3 : 00010000
R4 : 00000030
R5 : 0000001B
R6 : 20008CF5
R7 : 40029000
R8 : 20008CDC
R9 : 00000000
R10 : 00000000
R11 : 00000000
R12 : 00000010
SP : 20008CA8
LR : 0001CC0B
PC : 0001CBDC
xPSR : 41000000
PSP : 20008C88
MSP : 2002FFB8
CPUID: 410FC241
HFSR : 40000000
MMFSR: 00000000
BFSR : 00000082
UFSR : 00000000
DFSR : 00000008
AFSR : 00000000
BFAR : 40029004
Mode : Thread
Priv : Privileged
Stack: PSP
-- MbedOS Fault Handler --
++ MbedOS Error Info ++
Error Status: 0x80FF013D Code: 317 Module: 255
Error Message: Fault exception
Location: 0x16441
Error Value: 0x1CBDC
Current Thread: 20008d60 Id: 0x20008D88 Entry: 0x83CD StackSize: 0x11B8 StackMem: 0x20007B80 SP: 0x2002FF10
For more info, visit: https://armmbed.github.io/mbedos-error/?error=0x80FF013D
-- MbedOS Error Info --
After disassembling the code, program counter points to the following instruction (the disasse:
0001cbb4 <trng_get_byte>:
1cbb4: 2100 movs r1, #0
1cbb6: 7001 strb r1, [r0, #0]
1cbb8: f249 0204 movw r2, #36868 ; 0x9004
1cbbc: f2c4 0202 movt r2, #16386 ; 0x4002
1cbc0: e00c b.n 1cbdc <trng_get_byte+0x28>
1cbc2: 6893 ldr r3, [r2, #8]
1cbc4: f003 0301 and.w r3, r3, #1
1cbc8: fa03 fc01 lsl.w ip, r3, r1
1cbcc: 7803 ldrb r3, [r0, #0]
1cbce: ea43 030c orr.w r3, r3, ip
1cbd2: 7003 strb r3, [r0, #0]
1cbd4: 3101 adds r1, #1
1cbd6: 2908 cmp r1, #8
1cbd8: bf08 it eq
1cbda: 4770 bxeq lr
*PC POINTS HERE* -> 1cbdc: 6813 ldr r3, [r2, #0]
1cbde: f413 4f7f tst.w r3, #65280 ; 0xff00
1cbe2: d0fb beq.n 1cbdc <trng_get_byte+0x28>
1cbe4: e7ed b.n 1cbc2 <trng_get_byte+0xe>
from looking at the following file:
targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/trng_api.c
I see that the trng_get_byte()
API polls the TRNG status register and when it is set, the function reads from the output register. Now, it is possible for 2 threads to read that the status register has been set and then one thread will read the output register, while the next thread will try to read from the output register while the status register has been set back to 0 (after the first thread read), which according to the K64F reference manual, will raise a hardware exception.
Not sure that that is in fact what is happening but is possible.
Shouldn't the trng_get_byte
function protect from that situation?
- Another question, mbedtls does provide multi-thread protection (MBEDTLS_THREADING_C flag) but I don't see that mbed-os provides a port for that. Shouldn't it?
Reproducing
Our issue can easily be reproduced by creating two threads that simply call mbedtls_hardware_poll()
. The dump I added was from the ARMC compiler but the same happens with GCC ARM.
Issue request type
[ ] Question
[ ] Enhancement
[x ] Bug