cancel
Showing results for 
Search instead for 
Did you mean: 

NUCLEO-L476RG 2 Images Configuration SBSFU firmware update failure

OAber
Associate II

The download & decryption & swapping of the firmware looks fine at first sight.

But then a critical failure occurs because additional code is detected beyond the FW image.

======================================================================
=              (C) COPYRIGHT 2017 STMicroelectronics                 =
=                                                                    =
=              Secure Boot and Secure Firmware Update                =
======================================================================
 
 
= [SBOOT] SECURE ENGINE INITIALIZATION SUCCESSFUL
= [SBOOT] STATE: CHECK STATUS ON RESET
	  INFO: A Reboot has been triggered by a Hardware reset!
	  INFO: Last execution status before Reboot was:Executing Fw Image.
	  INFO: Last execution detected error was: No error. Success.
= [SBOOT] STATE: CHECK NEW FIRMWARE TO DOWNLOAD
= [SBOOT] STATE: DOWNLOAD NEW USER FIRMWARE
	  File> Transfer> YMODEM> Send 
[Ready to receive].[EOT].
	  FwSize=-16843010 | PartialFwSize=-16843010 | PartialFwOffset=-16843010 | 33632 bytes received
= [SBOOT] STATE: REBOOT STATE MACHINE
========= End of Execution ==========
======================================================================
=              (C) COPYRIGHT 2017 STMicroelectronics                 =
=                                                                    =
=              Secure Boot and Secure Firmware Update                =
======================================================================
 
 
= [SBOOT] SECURE ENGINE INITIALIZATION SUCCESSFUL
= [SBOOT] STATE: CHECK STATUS ON RESET
	  INFO: A Reboot has been triggered by a Software reset!
	  INFO: Last execution status before Reboot was:Rebooting the State Machine
	  INFO: Last execution detected error was: No error. Success.
= [SBOOT] STATE: CHECK NEW FIRMWARE TO DOWNLOAD
= [SBOOT] STATE: CHECK USER FW STATUS
= [FWIMG] SLOT_ACTIVE_1 state = 1
	  New Fw to be installed from slot SLOT_DWL_1
= [SBOOT] STATE: INSTALL NEW USER FIRMWARE 
= [SBOOT] RuntimeProtections: 0
	  33120 bytes of ciphertext decrypted.
	  Image preparation done.
	  Swapping the firmware images.....................................................
=         Installation procedure completed.
= [FWIMG] FW installation succeeded.
========= End of Execution ==========
======================================================================
=              (C) COPYRIGHT 2017 STMicroelectronics                 =
=                                                                    =
=              Secure Boot and Secure Firmware Update                =
======================================================================
 
 
= [SBOOT] SECURE ENGINE INITIALIZATION SUCCESSFUL
= [SBOOT] STATE: CHECK STATUS ON RESET
	  INFO: A Reboot has been triggered by a Software reset!
	  INFO: Last execution status before Reboot was:Installing new Fw Image.
	  INFO: Last execution detected error was: No error. Success.
= [SBOOT] STATE: CHECK NEW FIRMWARE TO DOWNLOAD
= [SBOOT] STATE: CHECK USER FW STATUS
= [FWIMG] SLOT_ACTIVE_1 state = 4
	  New Fw to be installed from slot SLOT_DWL_1
= [SBOOT] STATE: INSTALL NEW USER FIRMWARE 
= [SBOOT] RuntimeProtections: 0
= [FWIMG] Additional code detected beyond FW image!
=         Installation procedure cannot be finalized!
= [FWIMG] FW installation failed!
= [SBOOT] STATE: HANDLE CRITICAL FAILURE
= [EXCPT] FLASH ERROR!
= [SBOOT] STATE: REBOOT STATE MACHINE
========= End of Execution ==========

The failure comes from the following function (in PrepareCandidateImageForInstall() in sfu_fwimg_swap.c):

e_ret_status = VerifySlot((uint8_t *) SlotStartAdd[DwlSlot], SLOT_SIZE(DwlSlot),
                            pFwImageHeader->PartialFwSize + (pFwImageHeader->PartialFwOffset %
                                                             SLOT_SIZE(SLOT_SWAP)));

Any idea why this could be happening?

8 REPLIES 8
Jocelyn RICARD
ST Employee

Hello,

In SBSFU you define a SLOT size where your application firmware will be located.

Usually actual firmware uses a portion of this slot size.

SBSFU checks that no malicious code was previously injected in the remaining part of the SLOT.

This check is basically looking for either 0x00 or OxFF

So, if your flash is not clean, this will happen.

Could you please tell how you ended up having this issue?

Thank you

Best regards

Jocelyn

OAber
Associate II

I made these changes in Projects/NUCLEO-L476RG/Applications/2_Images/Linker_Common/SW4STM32/mapping_sbsfu.ld:

/* SE Startup: call before enabling firewall*/
 
   __ICFEDIT_SE_Startup_region_ROM_start__   = __ICFEDIT_SE_Key_region_ROM_end__ + 0x1;
 
   __ICFEDIT_SE_Code_nokey_region_ROM_start__ = __ICFEDIT_SE_Startup_region_ROM_start__ + 0x100;
 
-  __ICFEDIT_SE_Code_region_ROM_end__        = __ICFEDIT_SE_Startup_region_ROM_start__ + 0x4FFF;
 
+  __ICFEDIT_SE_Code_region_ROM_end__        = __ICFEDIT_SE_Startup_region_ROM_start__ + 0x5201;
 
 
/* SE IF ROM: used to locate Secure Engine interface code out of firewall */
 
    __ICFEDIT_SE_IF_region_ROM_start__        = __ICFEDIT_SE_Code_region_ROM_end__ + 1;
 
-  __ICFEDIT_SE_IF_region_ROM_end__          = __ICFEDIT_SE_IF_region_ROM_start__ + 0x5FF;
 
+  __ICFEDIT_SE_IF_region_ROM_end__          = __ICFEDIT_SE_IF_region_ROM_start__ + 0x6FF;

I enabled the rollback by adding the ENABLE_IMAGE_STATE_HANDLING flag.

I use the SECBOOT_ECCDSA_WITH_AES128_CBC_SHA256 configuration:

echo "	.section .SE_Key_Data,\"a\",%progbits" > "${OUTPUT_FILE}"
echo "	.syntax unified" >> "${OUTPUT_FILE}"
echo "	.thumb " >> "${OUTPUT_FILE}"
 
prepareimage.py trans  -a GNU -k "${ENCRYPT}" -f "SE_ReadKey_1" -v V7M >>"${OUTPUT_FILE}"
 
prepareimage.py trans  -a GNU -k "${SIGN}" -f "SE_ReadKey_1_Pub" -v V7M >>"${OUTPUT_FILE}"
prepareimage.py enc -k "${ENCRYPT}" -i "${IV}" "${BIN}" "${SFU}"
 
prepareimage.py sha256 "${BIN}" "${HASH}"
 
prepareimage.py pack -m "SFU1" -k "${SIGN}" -r 28 -v 1 -i "${IV}" -f "${SFU}" -t "${HASH}" "${SFB}" -o 512
 
prepareimage.py header -m "SFU1" -k "${SIGN}" -r 28 -v 1 -i "${IV}" -f "${SFU}" -t "${HASH}" -o "${BINHDRSIZE}" "${BINHEADER}"
 
prepareimage.py merge -v 0 -e 1 -i "${BINHEADER}" -s "${BL}" -u "${ELF}" "${BINOUT}"

Jocelyn RICARD
ST Employee

OK, I could reproduce the issue.

From what I could see on first glance, it seems that SBSFU tries to install the old firmware instead of just executing new installed firmware.

I mean, you have a V1 installed

Update with a V2

Swap V1 and V2

V1 in slot dwl and V2 in slot active after the swap

Then reset and check what is in slot dwl: valid fw obviously : try to install ...

I can better see this problem if you change the version number of the firmware you download.

You will then get following trace:

= [FWIMG] SLOT_ACTIVE_1 state = 4

     New Fw to be installed from slot SLOT_DWL_1

= [SBOOT] STATE: INSTALL NEW USER FIRMWARE

= [SBOOT] RuntimeProtections: 0

     Anti-rollback: candidate version(1) rejected | current version(2) , min.version(1) !

= [FWIMG] FW installation failed!

so, the installation of V1 fails, and V2 is running.

If you validate V2 everything is ok

If you don't validate V2 and reset, SBSFU will not rollback properly to V1 ...

As there is no example provided by default with this image state handling setup, we may have missed something.

I'll have a look in detail to understand the root cause

I'll also warn development team about this issue.

Best regards

Jocelyn

OAber
Associate II

Hello,

Is there any update on this?

Best regards

Omar

Jocelyn RICARD
ST Employee

Hello Omar,

I'm sorry for this late answer.

Issue was related to inability for the SECoreBin to read the DWL Header.

So, could you please test with the following changes ?

in file Projects\NUCLEO-L476RG\Applications\2_Images\2_Images_SECoreBin\Src\se_low_level.c

replace SE_LL_FLASH_Read function with following content:

SE_ErrorStatus SE_LL_FLASH_Read(uint8_t *pDestination, const uint8_t *pSource, uint32_t Length)

{

 uint32_t source = (uint32_t)pSource;

 SE_ErrorStatus e_ret_status = SE_ERROR;

 uint32_t i;

 uint32_t verified = 0U;

 /* Area should be inside 1 of the firmware image headers

   or inside 1 of the download areas */

 for (i = 0U; i < SFU_NB_MAX_ACTIVE_IMAGE; i++)

 {

  if ((source >= SlotHeaderAdd[SLOT_ACTIVE_1 + i]) &&

    ((source + Length) <= (SlotHeaderAdd[SLOT_ACTIVE_1 + i] + SFU_IMG_IMAGE_OFFSET)))

  {

   verified = 1U;

  }

 }

 for (i = 0U; i < SFU_NB_MAX_DWL_AREA; i++)

 {

  if ((source >= SlotStartAdd[SLOT_DWL_1 + i]) &&

    ((source + Length) <= (SlotStartAdd[SLOT_DWL_1 + i] + SLOT_SIZE(SLOT_DWL_1))))

  {

   verified = 1U;

  }

 }

 if (verified == 0U)

 {

  return SE_ERROR;

 }

 SE_DoubleECC_Error_Counter = 0U;

 (void)memcpy(pDestination, pSource, Length);

 if (SE_DoubleECC_Error_Counter == 0U)

 {

  e_ret_status = SE_SUCCESS;

 }

 SE_DoubleECC_Error_Counter = 0U;

 return e_ret_status;

}

and second change:

in Projects\NUCLEO-L476RG\Applications\2_Images\2_Images_SBSFU\SBSFU\App\sfu_fwimg_swap.c

in function FirmwareToInstall (the one under flag #if defined(ENABLE_IMAGE_STATE_HANDLING))

Replace end of function by (Replace SUCCESS by ERROR)

  else

  {

   e_ret_status = SFU_ERROR;

  }

 }

 return e_ret_status;

}

Best regards

Jocelyn

By the way, code looks much better with proper formatting when posted in "Code snippet". It's a </> button in edit field. 🙂

Hello Piranha,

yes your are right. Here it is:

SE_ErrorStatus SE_LL_FLASH_Read(uint8_t *pDestination, const uint8_t *pSource, uint32_t Length)
{
  uint32_t source = (uint32_t)pSource;
  SE_ErrorStatus e_ret_status = SE_ERROR;
  uint32_t i;
  uint32_t verified = 0U;
 
  /* Area should be inside 1 of the firmware image headers
     or inside 1 of the download areas */
  for (i = 0U; i < SFU_NB_MAX_ACTIVE_IMAGE; i++)
  {
    if ((source >= SlotHeaderAdd[SLOT_ACTIVE_1 + i]) &&
        ((source + Length) <= (SlotHeaderAdd[SLOT_ACTIVE_1 + i] + SFU_IMG_IMAGE_OFFSET)))
    {
      verified = 1U;
    }
  }
 
  for (i = 0U; i < SFU_NB_MAX_DWL_AREA; i++)
  {
    if ((source >= SlotStartAdd[SLOT_DWL_1 + i]) &&
        ((source + Length) <= (SlotStartAdd[SLOT_DWL_1 + i] + SLOT_SIZE(SLOT_DWL_1))))
    {
      verified = 1U;
    }
  }
 
  if (verified == 0U)
  {
    return SE_ERROR;
  }
 
  SE_DoubleECC_Error_Counter = 0U;
  (void)memcpy(pDestination, pSource, Length);
  if (SE_DoubleECC_Error_Counter == 0U)
  {
    e_ret_status = SE_SUCCESS;
  }
  SE_DoubleECC_Error_Counter = 0U;
  return e_ret_status;
}

Best regards

Jocelyn

Hi Jocelyn,

I can confirm that the patch works.

Best regards

Omar