Comment 1 for bug 1895867

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

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 Embedded Toolchain:
  New

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?

To manage notifications about this bug go to:
https://bugs.launchpad.net/gcc-arm-embedded/+bug/1895867/+subscriptions