From 136b9e6f2613193233494d920cea458a9bc8e772 Mon Sep 17 00:00:00 2001 From: yhql Date: Thu, 28 Sep 2023 12:12:07 +0200 Subject: [PATCH 1/7] fix: do not parse fonts if symbol not present --- speculos/main.py | 2 ++ src/launcher.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/speculos/main.py b/speculos/main.py index 43fc8831..3eb88541 100644 --- a/speculos/main.py +++ b/speculos/main.py @@ -115,6 +115,8 @@ def get_elf_infos(app_path): fonts_addr = bagl_fonts_symbol[0]['st_value'] fonts_size = bagl_fonts_symbol[0]['st_size'] logger.info(f"Found C_bagl_fonts at 0x{fonts_addr:X} ({fonts_size} bytes)\n") + else: + logger.info("Disabling OCR.") supp_ram = elf.get_section_by_name('.rfbss') ram_addr, ram_size = (supp_ram['sh_addr'], supp_ram['sh_size']) if supp_ram is not None else (0, 0) diff --git a/src/launcher.c b/src/launcher.c index 5a328ea4..d68c7f4e 100644 --- a/src/launcher.c +++ b/src/launcher.c @@ -541,8 +541,10 @@ static int run_app(char *name, unsigned long *parameters) app = get_current_app(); // Parse fonts and build bitmap -> character table - parse_fonts(memory.code, app->elf.text_load_addr, app->elf.fonts_addr, - app->elf.fonts_size); + if ((app->elf.fonts_addr != 0) || (hw_model == MODEL_STAX)) { + parse_fonts(memory.code, app->elf.text_load_addr, app->elf.fonts_addr, + app->elf.fonts_size); + } /* thumb mode */ f = (void *)((unsigned long)p | 1); From 6f42e28490591c97c72daf33a8cde4c5f31701d4 Mon Sep 17 00:00:00 2001 From: yhql Date: Thu, 28 Sep 2023 12:12:19 +0200 Subject: [PATCH 2/7] Changelog: Update for 0.3.1 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1747775c..4cce73ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.1] - 2023-09-28 + +### Fixed +- OCR: Prevent null dereference when expected font is not in ELF file + ## [0.3.0] - 2023-09-11 ### Added From 429b7dd7287adc311f64998ade6d9e906d3c6535 Mon Sep 17 00:00:00 2001 From: Daniel Morais Date: Wed, 4 Oct 2023 10:54:04 +0200 Subject: [PATCH 3/7] Make sure nb_bitmap_char is initialized --- src/bolos/fonts_info.c | 5 +++++ src/launcher.c | 6 ++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/bolos/fonts_info.c b/src/bolos/fonts_info.c index b8900863..84f94757 100644 --- a/src/bolos/fonts_info.c +++ b/src/bolos/fonts_info.c @@ -197,6 +197,11 @@ void parse_fonts(void *code, unsigned long text_load_addr, nb_fonts = fonts_size / 4; } + // There is no font or we don't know its format + if (!nb_fonts) { + return; + } + // Checks that fonts & nb_fonts are coherent if (fonts[nb_fonts] != nb_fonts) { fprintf(stdout, "ERROR: Expecting nb_fonts=%u and found %u instead!\n", diff --git a/src/launcher.c b/src/launcher.c index d68c7f4e..5a328ea4 100644 --- a/src/launcher.c +++ b/src/launcher.c @@ -541,10 +541,8 @@ static int run_app(char *name, unsigned long *parameters) app = get_current_app(); // Parse fonts and build bitmap -> character table - if ((app->elf.fonts_addr != 0) || (hw_model == MODEL_STAX)) { - parse_fonts(memory.code, app->elf.text_load_addr, app->elf.fonts_addr, - app->elf.fonts_size); - } + parse_fonts(memory.code, app->elf.text_load_addr, app->elf.fonts_addr, + app->elf.fonts_size); /* thumb mode */ f = (void *)((unsigned long)p | 1); From 7586afdf7d00cc99c5046ce7ec2f1fb64258be1f Mon Sep 17 00:00:00 2001 From: Daniel Morais Date: Wed, 4 Oct 2023 11:06:24 +0200 Subject: [PATCH 4/7] Fix spelling issue --- src/bolos/cx_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bolos/cx_utils.h b/src/bolos/cx_utils.h index 05e43e05..c8e3b629 100644 --- a/src/bolos/cx_utils.h +++ b/src/bolos/cx_utils.h @@ -10,7 +10,7 @@ #ifndef NATIVE_64BITS // NO 64BITS /** 64bits types, native or by-hands, depending on target and/or compiler * support. - * This type is defined here only because sha-3 struct used it INTENALLY. + * This type is defined here only because sha-3 struct used it INTERNALLY. * It should never be directly used by other modules. */ struct uint64_s { From 3ef54827c17104834b3ce65611e4ed1c22210a62 Mon Sep 17 00:00:00 2001 From: Lucas PASCAL Date: Thu, 12 Oct 2023 10:41:54 +0200 Subject: [PATCH 5/7] [fix] Notify the API thread when Speculos exits --- CHANGELOG.md | 4 ++++ speculos/api/api.py | 8 ++++++-- speculos/main.py | 3 +++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cce73ed..3e475741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.2] - 2023-09-28 + +### Fixed +- API: the API thread is asked to stop when Speculos exits ## [0.3.1] - 2023-09-28 diff --git a/speculos/api/api.py b/speculos/api/api.py index 5e455ae0..7192d148 100644 --- a/speculos/api/api.py +++ b/speculos/api/api.py @@ -30,6 +30,7 @@ def __init__(self, api_port: int) -> None: self._notify_exit: socket.socket self.sock, self._notify_exit = socket.socketpair() self.api_port: int = api_port + self._api_thread: threading.Thread @property def file(self): @@ -55,8 +56,11 @@ def start_server_thread(self, automation_server: BroadcastInterface) -> None: wrapper = ApiWrapper(screen_, seph_, automation_server) self._app = wrapper.app - api_thread = threading.Thread(target=self._run, name="API-server", daemon=True) - api_thread.start() + self._api_thread = threading.Thread(target=self._run, name="API-server", daemon=True) + self._api_thread.start() + + def stop(self): + self._api_thread.join(10) class ApiWrapper: diff --git a/speculos/main.py b/speculos/main.py index 3eb88541..0b80b42c 100644 --- a/speculos/main.py +++ b/speculos/main.py @@ -520,6 +520,9 @@ def main(prog=None) -> int: screen_notifier.run() + if apirun is not None: + apirun.stop() + s2.close() _, status = os.waitpid(qemu_pid, 0) qemu_exit_status = os.WEXITSTATUS(status) From ccf17cc09f9e749043c0f790d9e103593fb1a5bf Mon Sep 17 00:00:00 2001 From: Xavier Chapron Date: Wed, 25 Oct 2023 17:29:28 +0200 Subject: [PATCH 6/7] Launcher: Fix missing RAM relocation emulation on NanoX, NanoSP and Stax --- CHANGELOG.md | 5 +++++ src/launcher.c | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e475741..aad359a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.3] - 2023-10-26 + +### Fixed +- Launcher: Fix missing RAM relocation emulation on NanoX, NanoSP and Stax + ## [0.3.2] - 2023-09-28 ### Fixed diff --git a/src/launcher.c b/src/launcher.c index 5a328ea4..8e114d7b 100644 --- a/src/launcher.c +++ b/src/launcher.c @@ -17,6 +17,8 @@ #include "svc.h" #define LOAD_ADDR ((void *)0x40000000) +#define LINK_RAM_ADDR (0xda7a0000) +#define LOAD_RAM_ADDR (0x50000000) #define MAX_APP 16 #define MAIN_APP_NAME "main" @@ -299,6 +301,11 @@ static void *load_app(char *name) data_addr = get_lower_page_aligned_addr(app->elf.stack_addr); data_size = get_upper_page_aligned_size( app->elf.stack_size + app->elf.stack_addr - (unsigned long)data_addr); + if (app->elf.stack_addr == LINK_RAM_ADDR) { + // Emulate RAM relocation + data_addr = (void *)LOAD_RAM_ADDR; + data_size = get_upper_page_aligned_size(app->elf.stack_size); + } /* load code * map an extra page in case the _install_params are mapped in the beginning @@ -547,7 +554,11 @@ static int run_app(char *name, unsigned long *parameters) /* thumb mode */ f = (void *)((unsigned long)p | 1); stack_end = app->elf.stack_addr; - stack_start = app->elf.stack_addr + app->elf.stack_size; + if (app->elf.stack_addr == LINK_RAM_ADDR) { + // Emulate RAM relocation + stack_end = LOAD_RAM_ADDR; + } + stack_start = stack_end + app->elf.stack_size; asm volatile("mov r0, %2\n" "mov r9, %1\n" From 8620b360c735d28b28d3ecb4b3de8d75616e046d Mon Sep 17 00:00:00 2001 From: Xavier Chapron Date: Thu, 26 Oct 2023 15:18:54 +0200 Subject: [PATCH 7/7] README: Update Limitations section --- README.md | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b4a3e812..e2fe2bd5 100644 --- a/README.md +++ b/README.md @@ -33,17 +33,49 @@ being merged to `master`: ## Limitations -The emulator handles only a few syscalls made by common apps; for instance, +There is absolutely no guarantee that apps will have the same behavior on +hardware devices and Speculos, though the differences are limited. + +### Syscalls + +The emulator handles only a few syscalls made by common apps. For instance, syscalls related to app install, firmware update or OS info can't be implemented. -There is absolutely no guarantee that apps will have the same behavior on -hardware devices and Speculos: +Invalid syscall parameters might throw an exception on a real device while +being ignored on Speculos. +Notably, this is the case for application allowed derivation path and curve and +application settings flags which are enforced by the device OS, but ignored by +Speculos. + +### Memory alignment + +Attempts to perform unaligned accesses when not allowed (eg. dereferencing a +misaligned pointer) will cause an alignment fault on a Ledger Nano S device but +not on Speculos. Note that such unaligned accesses are supported by other +Ledger devices. + +Following code crashes on LNS device, but not on Speculos nor on other devices. +``` +uint8_t buffer[20]; +for (int i = 0; i < 20; i++) { + buffer[i] = i; +} +uint32_t display_value = *((uint32_t*) (buffer + 1)); +PRINTF("display_value: %d\n", display_value); +``` + +### Watchdog + +NanoX and Stax devices use an internal watchdog enforcing usage of regular +calls to `io_seproxyhal_io_heartbeat();`. This watchdog is not emulated on +Speculos. + +### Pending review screen -- Invalid syscall parameters might throw an exception on a real device while - being ignored on Speculos. -- Attempts to perform unaligned accesses when not allowed (eg. dereferencing a - misaligned pointer) will cause an alignment fault on a hardware device. +The C SDK offers a feature to display a warning screen upon app launch +indicating that the app has not been reviewed. +As the `_install_parameters` are not handled by Speculos, the screen won't be displayed. ## Security