Strange optimization of TrustZone callback security determination

Bug #1895867 reported by Austin
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Arm Embedded Toolchain
New
Undecided
Unassigned

Bug Description

This was posted to the Answers section, but there have been no replies.

Pertinent bug report info:
 - Issue present on 10-2020-q2, 9-2020-q2 and 9-2019-q4 at least
 - Using Linux binaries

---------

Consider the following basic implementation of a callback system in a secure TrustZone environment:

```c
typedef __attribute__((cmse_nonsecure_call)) void (* ns_callback)(void);

void (* callback_ptr)(void);

void secure_callback(void)
{
    __BKPT(0);
}

void set_callback(void (p_callback)(void))
{
    bool callback_is_secure = (NULL == cmse_check_pointed_object((void *) p_callback, CMSE_AU_NONSECURE));

    callback_ptr = callback_is_secure ? p_callback : (void (*)(void))cmse_nsfptr_create(p_callback);
}

__attribute__((cmse_nonsecure_entry)) void set_callback_guard(void (p_callback)(void))
{
    set_callback(p_callback);
}

void call_callback(void)
{
    if(!cmse_is_nsfptr(callback_ptr))
    {
        callback_ptr();
    }
    else
    {
        ns_callback p_callback = (ns_callback) (callback_ptr);
        p_callback();
    }
}

void main(void) {

    set_callback(secure_callback);

    call_callback();

    while(1)
    {
        __BKPT(0);
    }
}
```

At O0 and O1, the program halts at the breakpoint in `call_callback`. However, at O2 `call_callback` is optimized to always call the `else` branch, causing a Secure Fault as `p_callback` points to a secure function.

If `volatile` is added to the `ns_callback` typedef as below:

```c
typedef __attribute__((cmse_nonsecure_call)) void (* volatile ns_callback)(void);
```

...then at O2 the compiler correctly picks the true branch in `call_callback` but still optimizes away the other branch, causing issues if `p_callback` is non-secure.

Is this behavior expected? If so, is there a recommended way to ensure both branches of `call_callback` are available without using pragmas or dropping the optimization level?

Revision history for this message
stewo (wolfer-y) wrote : [Autoreply] [Bug 1895867] [NEW] Strange optimization of TrustZone callback security determination
Download full text (5.2 KiB)

Ich bin bis 28.09. nicht im Haus und kann Ihre Nachricht daher leider nicht bearbeiten. In dringenden Fällen wenden Sie sich bitte an <email address hidden> bzw. für technische Fragen an <email address hidden>.

I am out of office until September 28th and won't be able to read your message. In urgent cases, please refer to <email address hidden> or for technical questions to <email address hidden>.

Mit freundlichen Grüßen / Best regards

Steffen Wolfer

--
Dipl.-Inform. Steffen Wolfer
Software Engineer Embedded Systems

WEISS ROBOTICS GmbH & Co. KG
Karl-Heinrich-Käferle-Str. 8
D-71640 Ludwigsburg, Germany

Phone: +49 7141 94702-22
Fax: +49 7141 94702-99
http://www.weiss-robotics.com

Sitz der Gesellschaft: Ludwigsburg
Registergericht Stuttgart, HRA725006

Pers. haftende Gesellschafterin:
Weiss Robotics Verwaltungs-GmbH, Sitz Ludwigsburg
Registergericht Stuttgart, HRB73310
Geschäftsführer: Dr. Karsten Weiß

Public bug reported:

This was posted to the Answers section, but there have been no replies.

Pertinent bug report info:
 - Issue present on 10-2020-q2, 9-2020-q2 and 9-2019-q4 at least
 - Using Linux binaries

---------

Consider the following basic implementation of a callback system in a
secure TrustZone environment:

```c
typedef __attribute__((cmse_nonsecure_call)) void (* ns_callback)(void);

void (* callback_ptr)(void);

void secure_callback(void)
{
    __BKPT(0);
}

void set_callback(void (p_callback)(void))
{
    bool callback_is_secure = (NULL == cmse_check_pointed_object((void *) p_callback, CMSE_AU_NONSECURE));

    callback_ptr = callback_is_secure ? p_callback : (void (*)(void))cmse_nsfptr_create(p_callback);
}

__attribute__((cmse_nonsecure_entry)) void set_callback_guard(void (p_callback)(void))
{
    set_callback(p_callback);
}

void call_callback(void)
{
    if(!cmse_is_nsfptr(callback_ptr))
    {
        callback_ptr();
    }
    else
    {
        ns_callback p_callback = (ns_callback) (callback_ptr);
        p_callback();
    }
}

void main(void) {

    set_callback(secure_callback);

    call_callback();

    while(1)
    {
        __BKPT(0);
    }
}
```

At O0 and O1, the program halts at the breakpoint in `call_callback`.
However, at O2 `call_callback` is optimized to always call the `else`
branch, causing a Secure Fault as `p_callback` points to a secure
function.

If `volatile` is added to the `ns_callback` typedef as below:

```c
typedef __attribute__((cmse_nonsecure_call)) void (* volatile ns_callback)(void);
```

...then at O2 the compiler correctly picks the true branch in
`call_callback` but still optimizes away the other branch, causing
issues if `p_callback` is non-secure.

Is this behavior expected? If so, is there a recommended way to ensure
both branches of `call_callback` are available without using pragmas or
dropping the optimization level?

** Affects: gcc-arm-embedded
     Importance: Undecided
         Status: New

--
You received this bug notification because you are subscribed to GNU Arm
Embedded Toolchain.
Matching subscriptions: Älles
https://bugs.launchpad.net/bugs/1895867

Title:
  Strange optimization of TrustZone callback security determination

Status in GNU Arm Embed...

Read more...

Revision history for this message
Austin (auric) wrote :

My apologies, I forgot to mention: The code was compiled for a CM33 part.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.