InfiniTimeOrg / InfiniTime

Firmware for Pinetime smartwatch written in C++ and based on FreeRTOS
GNU General Public License v3.0
2.68k stars 916 forks source link

Invalid external resources may cause a boot loop #1568

Open azymohliad opened 1 year ago

azymohliad commented 1 year ago

Verification

Introduce the issue

Hey, I'm moving a relevant part of discussion #1533 (Fail safety with invalid external resources) to an issue report, as suggested there.

By loading invalid resources content during WatchMate companion app development I managed to brick my PineTime (stuck in the boot loop). To bring it back to life I had to flash InfiniTime 1.10 over SWD, remove invalid resources, and then upgrade back to 1.11.

This was due to a bug in early WatchMate implementation (it appended every next file to a buffer containing all previous files, and then flashed the whole buffer to the PineTime, so that the first file would be correct, the second file would be a concatenation of the first and the second file, and so on, and the last file would be a concatenation of all files). But it could also happen with correct app but malicious or maybe corrupted resources files.

Here's a hand-crafted resource archive that should reproduce the issue.

Steps to reproduce:

  1. Flash corrupted resources
  2. Select Infineat watch face.

After that, the PineTime should keep rebooting.

Preferred solution

No response

Version

1.11.0

JF002 commented 1 year ago

Thanks for this bug report, @azymohliad ! I can reproduce this issue on my devkit using the hand-crafted resource package, and I think I understand what is happening.

As you said, each file contain the concatenation of the previous file + the current one :

image

Infineat uses teko.bin, bebas.bin and pine_small.bin.

When Infineat loads the font in teko.bin, it in fact loads 7segments_115.bin, which is the content of the beginning of the file. It uses ~ 4.8KB of RAM (instead of 764B if the correct font was loaded). Then, it loads font bebas.bin, which loas again 7segments_115.bin and uses ~4.8KB of RAM (instead of 4.3KB) Then, it loads a picture from pine_small.bin. This file is supposed to contain a picture, but instead the beginning of the file is a font. LVGL probably notice that the file is not a picture and does nothing.

Infineat initializes many other LVGL object and ends up here with less than 100B available in the LVGL memory. It crashes in lv_obj_set_style_local_text_color probably because of a "segmentation fault".

So... this kind of issue should not occur if the resource package is not corrupted and the companion app does not corrupt the data during the transfer and the data is not corrupted during the BLE transfer and no corruption occurs when writing/reading the data to/from the SPI memory.

That's a lot of assumptions, and I guess we should better implement an integrity check on the files so we avoid reading a corrupted file. I guess we should start by looking at LFS and see if it provides such functionality.