Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"emulate.h": "c",
"os.h": "c",
"os_types.h": "c",
"errors.h": "c"
"errors.h": "c",
"launcher.h": "c"
}
}
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ 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.25.10] 2025-11-20
## [0.25.10] 2025-12-04

### Added
- Support throwing exceptions from OS (mainly Cx syscalls) like on real devices
- Support retrieving appflags from elf and use it for derivation
- Support retrieving derivation_path from elf and use it for derivation

## [0.25.9] 2025-11-19

Expand Down
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mnemonic = ">=0.19,<1.0"
pillow = ">=8.0.0,<11.0.0"
pyelftools = ">=0.27,<1.0"
requests = ">=2.25.1,<3.0.0"
ledgered = ">=0.6.2"
ledgered = ">=0.14.0"
flask-cors = "*"
pygame = "*"

Expand Down
1,033 changes: 616 additions & 417 deletions Pipfile.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ dependencies = [
"pyelftools>=0.27,<1.0",
"pyqt6>=6.4.0,<7.0.0",
"requests>=2.25.1,<3.0.0",
"ledgered>=0.6.2",
"ledgered>=0.14.0",
"pygame>=2.6.1",
]
dynamic = ["version"]
Expand Down
49 changes: 49 additions & 0 deletions speculos/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@ class ElfInfo:
shared_ram_addr: int = 0
shared_ram_size: int = 0
pic_init_addr: int = 0
derivation_path: bytes = b''


BOLOS_TAG_DERIVEPATH = 0x04

DEFAULT_SEED = ('glory promote mansion idle axis finger extra february uncover one trip resource lawn turtle enact '
'monster seven myth punch hobby comfort wild raise skin')

Expand Down Expand Up @@ -138,6 +141,38 @@ def get_elf_infos(app_path, use_bagl, args):
supp_ram_section = elf.get_section_by_name('.rfbss')
ei.ram_addr, ei.ram_size = \
(supp_ram_section['sh_addr'], supp_ram_section['sh_size']) if supp_ram_section is not None else (0, 0)

# look at install_parameters
install_parameters = symtab_section.get_symbol_by_name('install_parameters')
if install_parameters is not None:
sym_addr = install_parameters[0]['st_value']
sym_size = install_parameters[0]['st_size']
# 2. Get section containing the symbol
sec_offset_in_file = text_section['sh_offset']
sec_addr_in_memory = text_section['sh_addr']

# 3. Compute offset of symbol in ELF
file_offset = sec_offset_in_file + (sym_addr - sec_addr_in_memory)
# 4. Read bytes
fp.seek(file_offset)
data = fp.read(sym_size)
# 5. Parse TLVs to find APP_FLAGS one
offset = 0
while offset < sym_size:
tag = data[offset]
offset += 1
len = data[offset]
offset += 1
if len == 0x81:
len = data[offset]
offset += 1
elif len == 0x82:
len = int.from_bytes(data[offset: offset + 2], 'big')
offset += 2
if tag == BOLOS_TAG_DERIVEPATH:
ei.derivation_path = data[offset: offset + len]
offset += len

ei.stack_size = estack - ei.stack_addr
return ei

Expand Down Expand Up @@ -272,6 +307,11 @@ def run_qemu(s1: socket.socket, s2: socket.socket, args: argparse.Namespace) ->
lib_arg += f':{1 if args.load_nvram else 0}'
lib_arg += f':{1 if args.save_nvram else 0}'
lib_arg += f':{1 if not use_bagl else 0}'
if len(ei.derivation_path) > 0:
lib_arg += f':{ei.derivation_path.hex()}'
else:
# if no derivationèpath found in binary, use 0 to indicate to launcher that it's not valid
lib_arg += ':0'
argv.append(lib_arg)

# for NBGL apps, fonts binary file is mandatory before API Level 23
Expand All @@ -283,6 +323,15 @@ def run_qemu(s1: socket.socket, s2: socket.socket, args: argparse.Namespace) ->
else:
logger.error(f"Fonts {fonts_filepath} not found")
sys.exit(1)
# retrieve app_flags from a dedicated section in app.elf
binary = LedgerBinaryApp(app_path)
app_flags = binary.sections.app_flags
if app_flags is None:
# if not found in app.elf, everything is allowed (old binaries)
app_flags = 0xFFFFFFFFFF
else:
app_flags = int(app_flags, 16)
argv += ['-l', str(app_flags)]

pid = os.fork()
if pid != 0:
Expand Down
111 changes: 111 additions & 0 deletions src/bolos/io/sdk/include/appflags.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#pragma once

#include <stdint.h>

/**
* Base flag added to loaded application, to allow them to call all syscalls by
* default (the one requiring no extra permission)
*/
#define APPLICATION_FLAG_MAIN 0x1

/**
* Flag which combined with ::APPLICATION_FLAG_ISSUER.
* The application is given full nvram access after the global seed has been
* destroyed.
*/
#define APPLICATION_FLAG_BOLOS_UPGRADE 0x2

// this flag is set when a valid signature of the loaded application is
// presented at the end of the bolos application load.
#define APPLICATION_FLAG_SIGNED 0x4

// must be set on one application in the registry which is used
#define APPLICATION_FLAG_BOLOS_UX 0x8

// application is allowed to use the raw master seed, if not set, at least a
// level of derivation is required.
#define APPLICATION_FLAG_DERIVE_MASTER 0x10

#define APPLICATION_FLAG_SHARED_NVRAM 0x20
#define APPLICATION_FLAG_GLOBAL_PIN 0x40

// This flag means the application is meant to be debugged and allows for dump
// or core ARM register in case of a fault detection
#define APPLICATION_FLAG_DEBUG 0x80

/**
* Mark this application as defaultly booting along with the bootloader (no
* application menu displayed) Only one application can have this at a time. It
* is managed by the bootloader interface.
*/
#define APPLICATION_FLAG_AUTOBOOT 0x100

/**
* Application is allowed to change the settings
*/
#define APPLICATION_FLAG_BOLOS_SETTINGS 0x200

#define APPLICATION_FLAG_CUSTOM_CA 0x400

/**
* The application main can be called in two ways:
* - with first arg (stored in r0) set to 0: The application is called from the
* dashboard
* - with first arg (stored in r0) set to != 0 (ram address likely): The
* application is used as a library from another app.
*/
#define APPLICATION_FLAG_LIBRARY 0x800

/**
* The application won't be shown on the dashboard (somewhat reasonable for pure
* library)
*/
#define APPLICATION_FLAG_NO_RUN 0x1000

#if defined(HAVE_LANGUAGE_PACK)
/**
* This application is in fact a Language pack!
*/
#define APPLICATION_FLAG_LANGUAGE_PACK 0x2000
#endif // defined(HAVE_LANGUAGE_PACK)

/**
* Application has been loaded using a secure channel opened using the
* bootloader's issuer public key. This application is ledger legit.
*/
#define APPLICATION_FLAG_ISSUER 0x4000

/**
* Application is enabled (when not being updated or removed)
*/
#define APPLICATION_FLAG_ENABLED 0x8000

/**
* Application is actually a Stax background image
*/
#define APPLICATION_FLAG_BACKGROUND_IMG 0x10000

/**
* Application was not yet audited by ledger
*/
#define APPLICATION_FLAG_NOT_REVIEWED 0x20000

/**
* Reserved for future use
*/
#define APPLICATION_FLAG_RESERVED_FUTURE 0x40000

#define APPLICATION_FLAGS_MASK (0x00000000FFFFFFFFULL)
#define APPLICATION_FLAG_NEG_MASK (0xFFFFFFFF00000000ULL)
#define APPLICATION_FLAGS_SHIFT (32)

#define GET_COMPLEMENTED_APPLICATION_FLAGS(flags) \
(((~((flags)&APPLICATION_FLAGS_MASK) << APPLICATION_FLAGS_SHIFT)) | \
((flags)&APPLICATION_FLAGS_MASK))

#define IS_APPLICATION_FLAGS_SECURE(complemented_flags) \
(((~(complemented_flags) << APPLICATION_FLAGS_SHIFT) & \
APPLICATION_FLAG_NEG_MASK) == \
((complemented_flags)&APPLICATION_FLAG_NEG_MASK))

extern uint64_t app_flags;
4 changes: 2 additions & 2 deletions src/bolos/io/sdk/include/errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#if !defined(ERRORS_H)
#define ERRORS_H

#include "os_errors.h"

/**
* Applications-reserved error codes ranges.
* The Operating System do not use any error code within these ranges.
Expand Down Expand Up @@ -124,8 +126,6 @@ enum sdk_generic_identifiers {
#define SWO_IOL_BLE_0C (ERR_IOL_BLE + ERR_GEN_ID_0C) // 0x150C
#endif // HAVE_BLE

#define SWO_SEC_PIN_15 0x5515

/**
* The process is successful.
*/
Expand Down
Loading