This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Security State transitions - Processor Mode

Edit: CONTROL.nPRIV is actually banked so I modified my question

Hi,

I have a question regarding S/NS state transitions and PE modes.

From what I read in the ARMv8-M ARM there is no restriction in terms of PE mode for state transitions.

The PE mode is preserved during the State transition (IPSR is not banked, and not modified by transition mechanims) but the privileged flag is (CONTROL.nPRIV is banked), right?

Is the following correct:

  • I am for example running in NS unprivileged Thread Mode, say I am calling an NSC veneer and thus switching to Secure State. I would then execute the target function in S state in Thread Mode but I can't be sure of the privilege level, it would be the last privilege level used in S (because CONTROL.nPRIV is banked). The only predictable case is when I transition from Handler Mode which is always privileged.
  • When running in S state, if I BLXNS into an NS function the current PE Mode is preserved but the privilege level can't be predicted (as in previous bullet).

?

Am I correct? If so is it not an issue?

Thanks

Parents
  • Have a follow on question: Since the mode is carried over on transition to and from secure world, the secure firmware/secure Api developer essentially needs to specify the mode AND privilege level in which any given API can be called ? if I'm in non secure thread mode and the secure API/secure firmware is designed so that only the API;s can only execute in privileged mode, the non secure world HAS to call the secure API's through an SVC and in handler mode, since that is the only way to guarantee privileged mode ?
Reply
  • Have a follow on question: Since the mode is carried over on transition to and from secure world, the secure firmware/secure Api developer essentially needs to specify the mode AND privilege level in which any given API can be called ? if I'm in non secure thread mode and the secure API/secure firmware is designed so that only the API;s can only execute in privileged mode, the non secure world HAS to call the secure API's through an SVC and in handler mode, since that is the only way to guarantee privileged mode ?
Children
  • Sorry for the long question. If the modes transfer between the worlds, then it appears that non secure world gets to decide the mode in which a secure API runs ? If handler/privileged code in non secure world invokes a secure API, the secure API runs in handler mode ? How can I force a secure API to only run in thread mode ?
  • Hi,
    While the Thread/Handler mode is carried over in function calls, the privileged level does not carry over in the same way. The CONTROL[0] is banked between security state, so if Non-secure caller is in unprivileged thread (CONTROL_NS[0]==1), and if CONTROL_S[0]==0, the processor will switch to privileged state during the Secure API execution.
    In normal use cases, it is not expected that Secure APIs need to specify if the Non-secure caller must in privileged or not.

    For example, if you are an SoC designer, your SoC might have a crypto engine on Secure side and you provide an API for Non-secure world to use it, your customers creating the Non-secure applications might want to call the API call in privileged state, or in unprivileged state, or both. This is entirely up to them.

    If you want to, you could read CONTROL_NS and IPSR to determine if the Non-secure caller is privileged or unprivileged. For example, if an API is for dealing with power management, you might not want to allow an unprivileged application task to change the power management setup.

    Hope this helps.
    regards,
    Joseph
    (p.s. It is UK holiday from 14-Apri-2017 to 17-Apr-2017, so there will be delays in answering questions on ARM Community).
  • Joseph,

    Thanks for the detailed explanation. Based on the ARMv8M-ARM, CONTROL_*[0] does not control whether the processor is in privileged or unprivileged mode right ? It only specifies if the processor, when running in thread mode, has privileged access or not. I haven't been able to find a bit or mode in any control register, that determines if the processor is in thread or handler mode. The only place where this is possible to specify or even recorded seems to be in the definition for EXC_RETURN payload.
    What happens if CONTROL_NS[0]==1 and CONTROL_S[0]==1 ?
    When normal world is in privileged/handler mode, and calls a secure API, with the above CONTROL_* settings, it seems like the secure API will start executing in privileged/handler mode in the secure world. Now, you mentioned I could check CONTROL_NS and IPSR to determine NS caller state, but these registers can only be read in privileged mode and reading it in thread/unprivileged mode on the secure side during the beginning of the secure API will result in a fault.
    So it appears that there is no way to design a secure API, that can only be run in thread/unprivileged mode. what am I missing here ?
    My ultimate goal is this: I want to have a very thin layer of privileged secure code, which basically secure boots/loads the NS RTOS, sets up SAU, MPU, and want all my secure API's to only run in thread + unprivileged mode on the secure side. This is to enforce principle of least privilege. Whether the non secure world calls the secure Api from ANY mode and setting, I want my secure API to ONLY run in thread/unprivileged mode on the secure side. How would I achieve this ?

    Raghu
  • > Based on the ARMv8M-ARM, CONTROL_*[0] does not control
    > whether the processor is in privileged or unprivileged
    > mode right ? It only specifies if the processor, when
    > running in thread mode, has privileged access or not.

    Yes, that's correct.

    >I haven't been able to find a bit or mode in any
    > control register, that determines if the processor
    > is in thread or handler mode.

    Please use IPSR.

    >if CONTROL_NS[0]==1 and CONTROL_S[0]==1, and processor
    > is in handler mode.

    Yes, if the Secure API is called it will be Secure
    privileged as it is handler mode. But you can add checks
    at starting of API if you won't want it to be execute
    in privileged.

    > mentioned I could check CONTROL_NS and IPSR to determine
    > NS caller state, but these registers can only be read
    > in privileged mode and reading it in thread/unprivileged
    > mode on the secure side during the beginning of the
    > secure API will result in a fault.

    That's incorrect. If you are in Secure unprivileged you
    will read 0 for CONTROL_NS and IPSR, no fault exception.
    So you can add check to ensure Secure API is unprivileged.

    regards,
    Joseph

  • Thanks Joseph. Follow up question: In the aforementioned scenario, If my secure Api does NOT check control_NS and IPSR, then the secure Api would execute in privileged secure mode. Suppose I'm a secure RTOS vendor, and I provide an SDK to write unprivileged secure API's, which run on top of my secure RTOS, how would I enforce that the secure API actually checks those registers? How would the secure RTOS kernel/privileged code defend itself from secure thread/unprivileged code that does not check CONTROL_NS and IPSR ? If the unprivileged secure API has an exploit, it seems like all you would need to do to exploit the secure RTOS kernel resources is to use the vulnerable secure API from handler mode in the non secure world and exploit it. Now, you potentially have access to the entire memory space of privileged secure code/data/resources and have bypassed the possible MPU protections put in place to enforce partitioning of secure resources as privileged or unprivileged. Is my thinking correct ? I apologize for the long questions but these details are very important in making software design decisions.
  • In an application use case, if the Non-secure applications are running in NS unprivileged, it means the hacker need to be break into privileged level first, before they can call the Secure API in handler mode. So there need to be two levels of vulnerabilities.
    But of course, I agree that a hacker can also just buy a chip and try to hack the Secure API....

    > If my secure Api does NOT check control_NS and IPSR....
    >If the unprivileged secure API has an exploit....
    First thing is to rethink why those APIs need to be in Secure world? (If you can't trust them to do the checks properly, I don't think I would put them in the Secure memory :-) )

    ARMv8-M also support eXecute Only Memory (XOM) - note: it depends on chip's system level design. If you only want to provide firmware protection, and if the firmware is not trusted, it might be better off to leave it in Non-secure world.

    One thing you can do in your case is don't provide direct access to NSC space to your 3rd parties software developers. Being the "owner" of Secure world, you can define the NSC allocation and entry points so that you can ensure all APIs would have proper checks if needed.

    By the way, if you are an RTOS developer, you could have access to our support via our ecosystem program. Please drop me an email directly and I will ask our ecosystem partner manager to follow up.

    regards,
    Joseph

  • Thanks again Joseph! Questions are motivated by the following :-)
    1) I'm not an RTOS developer but provide code that could be included in RTOS's and middleware code. So the code is trusted by firmware but one can never say if they are trusted they are immune to exploitation. I am trying to assess the worst that could happen if my code is exploited.
    2) I've done a fair bit of work on the ARMv8-A and I'm trying to understand the subtle(and not so subtle)differences between the two architectures.
    3) My questions are motivated by exploits like this(and related exploits): bits-please.blogspot.com/.../extracting-qualcomms-keymaster-keys.html :-). If I run an isolated unprivileged thread/process/app in the secure world and I get exploited, I wouldn't want all of secure world to be exploited because of this. or if somebody else code is exploited, I wouldn't want my code to be rendered useless.
    4) I like the NSC access restriction solution. I think making the NSC region protected by the MPU as secure privileged access only, would give me a model like the ARMv8-A TrustZone. If I mark the NSC region as privileged only, then all secure API's must go through the non secure RTOS kernel, then to the secure RTOS kernel, which can verify the non secure state, then switch to unprivileged thread mode, thus ensuring secure API's always run in secure thread mode. of course this would make all the ARMv8-M optimizations to make switching worlds quick, much slower!

    My questions have been answered. Thanks! :)
  • Hi Radhu,

    Regarding the NSC method I am thinking of, is to ensure that no 3rd party Secure unprivileged code would be marked as NSC, and only Secure world owner can provide entry points (with correct NSC setup obviously). The actual calls to unprivileged Secure APIs can only be made after a security check. So effectively a software wrapper is need for the Secure unprivileged API.

    The security check is quite simple. If CONTROL_S[0] is set to 1 then you only need to check if current IPSR is 0 (thread). Then you are sure that the API will execute in Secure unprivileged state.

    If you make the NSC region privilege access only, then a NS thread calling the Secure API will have a Secure MemManage fault as the SG instruction is executed. You can resolve that in the fault handler but this increases overhead.
    regards,
    Joseph
  • Thanks Joseph! Makes things very clear. :)