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: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ patina_ffs_extractors = { version = "22.1.0", path = "sdk/patina_ffs_extractors"
patina_internal_collections = { version = "22.1.0", path = "core/patina_internal_collections", default-features = false }
patina_internal_cpu = { version = "22.1.0", path = "core/patina_internal_cpu" }
patina_internal_depex = { version = "22.1.0", path = "core/patina_internal_depex" }
patina_lzma_rs = { version = "0.3.2", default-features = false }
lzma-rust2 = { version = "0.16", default-features = false }
patina_macro = { version = "22.1.0", path = "sdk/patina_macro" }
patina_mm = { version = "22.1.0", path = "components/patina_mm" }
patina_mtrr = { version = "1.1.6" }
Expand Down Expand Up @@ -73,7 +73,6 @@ winapi = { version = "0.3" }
serde = { version = "1.0", default-features = false, features = ["derive"] }
serde_yaml = { version = "0.9" }
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
lzma-rs = { version = "0.3" }

[workspace.lints.clippy]
indexing_slicing = "deny"
Expand Down
2 changes: 1 addition & 1 deletion sdk/patina_ffs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ log = {workspace = true}
serde = {workspace = true}
uuid = {workspace = true}
serde_yaml = {workspace = true}
lzma-rs = {workspace = true}
lzma-rust2 = { workspace = true, features = ["encoder"] }

[features]
# All non-std features to test in CI
Expand Down
43 changes: 29 additions & 14 deletions sdk/patina_ffs/src/volume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ impl TryFrom<(&VolumeRef<'_>, &dyn SectionExtractor)> for Volume {
mod test {
use core::{mem, sync::atomic::AtomicBool};
use log::{self, Level, LevelFilter, Metadata, Record};
use lzma_rs::lzma_decompress;
use lzma_rust2::{LzmaOptions, LzmaReader, LzmaWriter, Read, Write};
use patina::pi::fw_fs::{self, ffs, fv};
use r_efi::efi;
use serde::Deserialize;
Expand All @@ -783,7 +783,6 @@ mod test {
env,
error::Error,
fs::{self, File},
io::Cursor,
path::Path,
};
use uuid::Uuid;
Expand Down Expand Up @@ -1289,9 +1288,17 @@ mod test {
&& guid_header.section_definition_guid == fw_fs::guid::LZMA_SECTION
{
let data = section.try_content_as_slice()?;
let mut decompressed: Vec<u8> = Vec::new();
lzma_decompress(&mut Cursor::new(data), &mut decompressed)
let mut reader = LzmaReader::new_mem_limit(data, patina::base::SIZE_512MB as u32, None)
.map_err(|_| FirmwareFileSystemError::DataCorrupt)?;
let mut decompressed: Vec<u8> = Vec::new();
let mut chunk = [0u8; 4096];
loop {
let n = reader.read(&mut chunk).map_err(|_| FirmwareFileSystemError::DataCorrupt)?;
if n == 0 {
break;
}
decompressed.extend_from_slice(chunk.get(..n).ok_or(FirmwareFileSystemError::DataCorrupt)?);
}
return Ok(decompressed);
}
Err(FirmwareFileSystemError::Unsupported)
Expand Down Expand Up @@ -1348,9 +1355,17 @@ mod test {
&& guid_header.section_definition_guid == fw_fs::guid::LZMA_SECTION
{
let data = section.try_content_as_slice()?;
let mut decompressed: Vec<u8> = Vec::new();
lzma_decompress(&mut Cursor::new(data), &mut decompressed)
let mut reader = LzmaReader::new_mem_limit(data, patina::base::SIZE_512MB as u32, None)
.map_err(|_| FirmwareFileSystemError::DataCorrupt)?;
let mut decompressed: Vec<u8> = Vec::new();
let mut chunk = [0u8; 4096];
loop {
Comment thread
Javagedes marked this conversation as resolved.
let n = reader.read(&mut chunk).map_err(|_| FirmwareFileSystemError::DataCorrupt)?;
if n == 0 {
break;
}
decompressed.extend_from_slice(chunk.get(..n).ok_or(FirmwareFileSystemError::DataCorrupt)?);
}
return Ok(decompressed);
}
Err(FirmwareFileSystemError::Unsupported)
Expand All @@ -1377,11 +1392,11 @@ mod test {
}
}
let mut compressed: Vec<u8> = Vec::new();
let options = lzma_rs::compress::Options {
unpacked_size: lzma_rs::compress::UnpackedSize::WriteToHeader(Some(content.len() as u64)),
};
lzma_rs::lzma_compress_with_options(&mut Cursor::new(content), &mut compressed, &options)
let options = LzmaOptions::with_preset(6);
let mut writer = LzmaWriter::new_use_header(&mut compressed, &options, Some(content.len() as u64))
.map_err(|_| FirmwareFileSystemError::ComposeFailed)?;
writer.write_all(&content).map_err(|_| FirmwareFileSystemError::ComposeFailed)?;
writer.finish().map_err(|_| FirmwareFileSystemError::ComposeFailed)?;

let mut header = section.header().clone();
header.set_content_size(compressed.len()).map_err(|_| FirmwareFileSystemError::InvalidHeader)?;
Expand Down Expand Up @@ -1453,8 +1468,8 @@ mod test {
//re-serialize the FV with the original logo file.
let serialized_fv_bytes = serialized_fv.serialize().map_err(stringify)?;

//unfortunately, the lzma-rs encoder isn't robust enough to encode with the expected lzma parameters,
//otherwise we could just just compare the original fv bytes to the serialized fv bytes directly.
//unfortunately, the lzma-rust2 encoder doesn't encode with the exact lzma parameters used to build the
//original FV, otherwise we could just just compare the original fv bytes to the serialized fv bytes directly.
//instead, we'll compare the contents.
let serialized_fv_ref = VolumeRef::new(&serialized_fv_bytes).map_err(stringify)?;

Expand All @@ -1478,8 +1493,8 @@ mod test {
for (org_section, round_trip_section) in Iterator::zip(org_sections.iter(), round_trip_sections.iter()) {
assert_eq!(org_section.section_type(), round_trip_section.section_type());
if org_section.section_type() == Some(ffs::section::Type::GuidDefined) {
// the GUID-defined section content is LZMA compressed, but lzma-rs encoder doesn't support the UEFI
// parameter set, so the content won't match because the compression parameters are different.
// the GUID-defined section content is LZMA compressed, but the lzma-rust2 encoder doesn't use the
// exact UEFI parameter set, so the content won't match because the compression parameters differ.
// however, the sub-sections will be produced as part of the section iterator, so those will be compared.
continue;
}
Expand Down
7 changes: 5 additions & 2 deletions sdk/patina_ffs_extractors/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ r-efi = {workspace = true}
brotli-decompressor = { workspace = true, optional = true }
alloc-no-stdlib = { workspace = true, optional = true }
crc32fast = { workspace = true, optional = true }
patina_lzma_rs = { workspace = true, optional = true, default-features = false }
lzma-rust2 = { workspace = true, optional = true, default-features = false }

[features]
default = ["brotli", "crc32", "lzma"]
std = []
brotli = ["dep:brotli-decompressor", "dep:alloc-no-stdlib"]
crc32 = ["dep:crc32fast"]
lzma = ["dep:patina_lzma_rs"]
lzma = ["dep:lzma-rust2"]
# All non-std features to test in CI
ci_features = ["brotli", "crc32", "lzma"]

[dev-dependencies]
lzma-rust2 = { workspace = true }
25 changes: 21 additions & 4 deletions sdk/patina_ffs_extractors/src/lzma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@
//!
use alloc::vec::Vec;
use core::result::Result;
use lzma_rust2::{LzmaReader, Read};
use patina::pi::fw_fs::guid::LZMA_SECTION;
use patina_ffs::{
FirmwareFileSystemError,
section::{Section, SectionExtractor, SectionHeader},
};

use patina_lzma_rs::io::Cursor;
/// Sentinel uncompressed-size value in the `.lzma` (FORMAT_ALONE) header that indicates
/// the uncompressed size is unknown.
const LZMA_UNKNOWN_UNPACKED_SIZE_MAGIC_VALUE: u64 = 0xFFFF_FFFF_FFFF_FFFF;

pub const LZMA_UNKNOWN_UNPACKED_SIZE_MAGIC_VALUE: u64 = 0xFFFF_FFFF_FFFF_FFFF;
/// Maximum memory limit for LZMA decompression. This is set to 512MB as a reasonable upper limit.
const LZMA_MAX_MEMORY_LIMIT: u32 = patina::base::SIZE_512MB as u32;

/// Provides decompression for LZMA GUIDed sections.
#[derive(Default, Clone, Copy)]
Expand All @@ -37,7 +41,7 @@ impl SectionExtractor for LzmaSectionExtractor {
{
let data = section.try_content_as_slice()?;

// Get unpacked size to pre-allocate vector, if available
// Get unpacked size to pre-allocate the output vector, if available.
// See https://github.com/tukaani-project/xz/blob/dd4a1b259936880e04669b43e778828b60619860/doc/lzma-file-format.txt#L131
let unpacked_size =
u64::from_le_bytes(data.get(5..13).ok_or(FirmwareFileSystemError::DataCorrupt)?.try_into().unwrap());
Expand All @@ -47,9 +51,22 @@ impl SectionExtractor for LzmaSectionExtractor {
Vec::<u8>::with_capacity(unpacked_size as usize)
};

patina_lzma_rs::lzma_decompress(&mut Cursor::new(data), &mut decompressed)
// The section payload is a `.lzma` (FORMAT_ALONE) stream: a 13-byte header
// (properties byte, dictionary size, uncompressed size) followed by the
// range-coded payload. `LzmaReader::new_mem_limit` parses that header.
let mut reader = LzmaReader::new_mem_limit(data, LZMA_MAX_MEMORY_LIMIT, None)
.map_err(|_| FirmwareFileSystemError::DataCorrupt)?;

let mut chunk = [0u8; 4096];
loop {
let read = reader.read(&mut chunk).map_err(|_| FirmwareFileSystemError::DataCorrupt)?;
if read == 0 {
break;
}
let decoded = chunk.get(..read).ok_or(FirmwareFileSystemError::DataCorrupt)?;
decompressed.extend_from_slice(decoded);
}

return Ok(decompressed);
}
Err(FirmwareFileSystemError::Unsupported)
Expand Down
10 changes: 3 additions & 7 deletions supply-chain/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -336,9 +336,9 @@ criteria = "safe-to-deploy"
version = "0.10.5"
criteria = "safe-to-deploy"

[[exemptions.lzma-rs]]
version = "0.3.0"
criteria = "safe-to-run"
[[exemptions.lzma-rust2]]
version = "0.16.4"
criteria = "safe-to-deploy"

[[exemptions.managed]]
version = "0.8.0"
Expand Down Expand Up @@ -380,10 +380,6 @@ criteria = "safe-to-run"
version = "0.9.12"
criteria = "safe-to-run"

[[exemptions.patina_lzma_rs]]
version = "0.3.2"
criteria = "safe-to-deploy"

[[exemptions.patina_mtrr]]
version = "1.1.4"
criteria = "safe-to-deploy"
Expand Down
Loading