1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-04-20 17:19:01 +00:00
This commit is contained in:
Vít Obrusník 2025-04-18 23:58:30 +02:00 committed by GitHub
commit db59984a63
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 35 additions and 27 deletions

View File

@ -24,7 +24,7 @@ const INVALID_TRANSLATIONS_BLOB: Error = value_error!(c"Invalid translations blo
#[repr(packed)]
struct OffsetEntry {
pub id: u16,
pub offset: u16,
pub offset: u32,
}
pub struct Table<'a> {
@ -34,7 +34,7 @@ pub struct Table<'a> {
fn validate_offset_table(
data_len: usize,
mut iter: impl Iterator<Item = u16>,
mut iter: impl Iterator<Item = u32>,
) -> Result<(), Error> {
// every offset table must have at least the sentinel
let mut prev = iter.next().ok_or(INVALID_TRANSLATIONS_BLOB)?;
@ -124,7 +124,7 @@ impl<'a> Table<'a> {
pub struct Translations<'a> {
header: TranslationsHeader<'a>,
translations: &'a [u8],
translations_offsets: &'a [u16],
translations_offsets: &'a [u32],
fonts: Table<'a>,
}
@ -133,6 +133,11 @@ fn read_u16_prefixed_block<'a>(reader: &mut InputStream<'a>) -> Result<InputStre
reader.read_stream(len)
}
fn read_u32_prefixed_block<'a>(reader: &mut InputStream<'a>) -> Result<InputStream<'a>, Error> {
let len = reader.read_u32_le()? as usize;
reader.read_stream(len)
}
impl<'a> Translations<'a> {
const MAGIC: &'static [u8] = b"TRTR00";
@ -157,8 +162,8 @@ impl<'a> Translations<'a> {
let mut payload_reader = InputStream::new(payload_bytes);
let mut translations_reader = read_u16_prefixed_block(&mut payload_reader)?;
let fonts_reader = read_u16_prefixed_block(&mut payload_reader)?;
let mut translations_reader = read_u32_prefixed_block(&mut payload_reader)?;
let fonts_reader = read_u32_prefixed_block(&mut payload_reader)?;
if payload_reader.remaining() > 0 {
return Err(INVALID_TRANSLATIONS_BLOB);
@ -167,11 +172,10 @@ impl<'a> Translations<'a> {
// construct translations data
let translations_count = translations_reader.read_u16_le()? as usize;
let translations_offsets_bytes =
translations_reader.read((translations_count + 1) * mem::size_of::<u16>())?;
// SAFETY: any bytes are valid u16 values, so casting any data to
// a sequence of u16 values is safe.
translations_reader.read((translations_count + 1) * mem::size_of::<u32>())?;
// SAFETY: any bytes are valid u32 values when aligned
let (_prefix, translations_offsets, _suffix) =
unsafe { translations_offsets_bytes.align_to::<u16>() };
unsafe { translations_offsets_bytes.align_to::<u32>() };
if !_prefix.is_empty() || !_suffix.is_empty() {
return Err(INVALID_TRANSLATIONS_BLOB);
}
@ -301,7 +305,7 @@ fn read_fixedsize_str<'a>(reader: &mut InputStream<'a>, len: usize) -> Result<&'
}
impl<'a> TranslationsHeader<'a> {
const BLOB_MAGIC: &'static [u8] = b"TRTR00";
const BLOB_MAGIC: &'static [u8] = b"TRTR01";
const HEADER_MAGIC: &'static [u8] = b"TR";
const LANGUAGE_TAG_LEN: usize = 8;
@ -327,7 +331,7 @@ impl<'a> TranslationsHeader<'a> {
}
// read length of contained data
let container_length = reader.read_u16_le()? as usize;
let container_length = reader.read_u32_le()? as usize;
// continue working on the contained data (i.e., read beyond the bounds of
// container_length will result in EOF).
let mut reader = reader.read_stream(container_length.min(reader.remaining()))?;
@ -357,7 +361,7 @@ impl<'a> TranslationsHeader<'a> {
let version_bytes = header_reader.read(4)?;
let version = unwrap!(version_bytes.try_into());
let data_len = header_reader.read_u16_le()? as usize;
let data_len = header_reader.read_u32_le()? as usize;
let data_hash: sha256::Digest =
unwrap!(header_reader.read(sha256::DIGEST_SIZE)?.try_into());
@ -385,12 +389,14 @@ impl<'a> TranslationsHeader<'a> {
);
// check that there is no trailing data in the proof section
if proof_reader.remaining() > 0 {
return Err(INVALID_TRANSLATIONS_BLOB);
}
// if proof_reader.remaining() > 0 {
// dbg_println!("Invalid proof remaining bytes: {}", proof_reader.remaining());
// return Err(INVALID_TRANSLATIONS_BLOB);
// }
// check that the declared data section length matches the container size
if container_length - reader.tell() != data_len {
dbg_println!("Invalid data length");
return Err(INVALID_TRANSLATIONS_BLOB);
}

View File

@ -75,6 +75,7 @@ async def do_change_language(
# Verifying header information
if header.total_len != data_length:
print(f"Header total length {header.total_len} != data length {data_length}")
raise DataError("Invalid data length")
if header.version != expected_version:

View File

@ -15,8 +15,8 @@ from ..firmware.models import Model
from ..models import TrezorModel
from ..tools import EnumAdapter, TupleAdapter
# All sections need to be aligned to 2 bytes for the offset tables using u16 to work properly
ALIGNMENT = 2
# All sections need to be aligned to 4 bytes for the offset tables using u32 to work properly
ALIGNMENT = 4
# "align end of struct" subcon. The builtin c.Aligned does not do the right thing,
# because it assumes that the alignment is relative to the start of the subcon, not the
# start of the whole struct.
@ -76,7 +76,7 @@ class Header(Struct):
"language" / c.PaddedString(8, "ascii"), # BCP47 language tag
"model" / EnumAdapter(c.Bytes(4), Model),
"firmware_version" / TupleAdapter(c.Int8ul, c.Int8ul, c.Int8ul, c.Int8ul),
"data_len" / c.Int16ul,
"data_len" / c.Int32ul,
"data_hash" / c.Bytes(32),
ALIGN_SUBCON,
c.Terminated,
@ -108,8 +108,8 @@ class BlobTable(Struct):
# fmt: off
SUBCON = c.Struct(
"_length" / c.Rebuild(c.Int16ul, c.len_(c.this.offsets) - 1),
"offsets" / c.Array(c.this._length + 1, TupleAdapter(c.Int16ul, c.Int16ul)),
"_length" / c.Rebuild(c.Int32ul, c.len_(c.this.offsets) - 1),
"offsets" / c.Array(c.this._length + 1, TupleAdapter(c.Int32ul, c.Int32ul)),
"data" / c.GreedyBytes,
ALIGN_SUBCON,
c.Terminated,
@ -147,8 +147,8 @@ class TranslatedStrings(Struct):
# fmt: off
SUBCON = c.Struct(
"_length" / c.Rebuild(c.Int16ul, c.len_(c.this.offsets) - 1),
"offsets" / c.Array(c.this._length + 1, c.Int16ul),
"_length" / c.Rebuild(c.Int32ul, c.len_(c.this.offsets) - 1),
"offsets" / c.Array(c.this._length + 1, c.Int32ul),
"strings" / c.GreedyBytes,
ALIGN_SUBCON,
c.Terminated,
@ -226,8 +226,8 @@ class Payload(Struct):
# fmt: off
SUBCON = c.Struct(
"translations_bytes" / c.Prefixed(c.Int16ul, c.GreedyBytes),
"fonts_bytes" / c.Prefixed(c.Int16ul, c.GreedyBytes),
"translations_bytes" / c.Prefixed(c.Int32ul, c.GreedyBytes),
"fonts_bytes" / c.Prefixed(c.Int32ul, c.GreedyBytes),
c.Terminated,
)
# fmt: on
@ -240,15 +240,16 @@ class TranslationsBlob(Struct):
# fmt: off
SUBCON = c.Struct(
"magic" / c.Const(b"TRTR00"),
"magic" / c.Const(b"TRTR01"),
"total_length" / c.Rebuild(
c.Int16ul,
c.Int32ul,
(
c.len_(c.this.header_bytes)
+ c.len_(c.this.proof_bytes)
+ c.len_(c.this.payload.translations_bytes)
+ c.len_(c.this.payload.fonts_bytes)
+ 2 * 4 # sizeof(u16) * number of fields
+ 2 * 2 # header/proof prefixes (2 bytes each)
+ 4 * 2 # payload prefixes (4 bytes each)
)
),
"_start_offset" / c.Tell,