Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use explicit offsets for reading and writing #46

Merged
merged 2 commits into from
Jan 3, 2024
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
12 changes: 4 additions & 8 deletions src/bin/download_sysext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use std::ffi::OsStr;
use std::fs::File;
use std::fs;
use std::io;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::Duration;
Expand Down Expand Up @@ -136,16 +135,13 @@ impl<'a> Package<'a> {
fn verify_signature_on_disk(&mut self, from_path: &Path, pubkey_path: &str) -> Result<PathBuf> {
let upfile = File::open(from_path).context(format!("failed to open path ({:?})", from_path.display()))?;

// create a BufReader to pass down to parsing functions.
let upfreader = &mut BufReader::new(upfile);

// Read update payload from file, read delta update header from the payload.
let header = delta_update::read_delta_update_header(upfreader).context(format!("failed to read_delta_update_header path ({:?})", from_path.display()))?;
let header = delta_update::read_delta_update_header(&upfile).context(format!("failed to read_delta_update_header path ({:?})", from_path.display()))?;

let mut delta_archive_manifest = delta_update::get_manifest_bytes(upfreader, &header).context(format!("failed to get_manifest_bytes path ({:?})", from_path.display()))?;
let mut delta_archive_manifest = delta_update::get_manifest_bytes(&upfile, &header).context(format!("failed to get_manifest_bytes path ({:?})", from_path.display()))?;

// Extract signature from header.
let sigbytes = delta_update::get_signatures_bytes(upfreader, &header, &mut delta_archive_manifest).context(format!("failed to get_signatures_bytes path ({:?})", from_path.display()))?;
let sigbytes = delta_update::get_signatures_bytes(&upfile, &header, &mut delta_archive_manifest).context(format!("failed to get_signatures_bytes path ({:?})", from_path.display()))?;

// tmp dir == "/var/tmp/outdir/.tmp"
let tmpdirpathbuf = from_path.parent().ok_or(anyhow!("unable to get parent dir"))?.parent().ok_or(anyhow!("unable to get parent dir"))?.join(".tmp");
Expand All @@ -158,7 +154,7 @@ impl<'a> Package<'a> {
let hdhashvec: Vec<u8> = hdhash.clone().into();

// Extract data blobs into a file, datablobspath.
delta_update::get_data_blobs(upfreader, &header, &delta_archive_manifest, datablobspath.as_path()).context(format!("failed to get_data_blobs path ({:?})", datablobspath.display()))?;
delta_update::get_data_blobs(&upfile, &header, &delta_archive_manifest, datablobspath.as_path()).context(format!("failed to get_data_blobs path ({:?})", datablobspath.display()))?;

// Check for hash of data blobs with new_partition_info hash.
let pinfo_hash = match &delta_archive_manifest.new_partition_info.hash {
Expand Down
3 changes: 1 addition & 2 deletions src/download.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::{Context, Result, bail};
use std::io::{BufReader, Read, Seek, SeekFrom};
use std::io::{BufReader, Read};
use std::fs::File;
use std::path::Path;
use log::info;
Expand Down Expand Up @@ -39,7 +39,6 @@ pub fn hash_on_disk_sha256(path: &Path, maxlen: Option<usize>) -> Result<omaha::
let mut freader = BufReader::new(file);
let mut chunklen: usize;

freader.seek(SeekFrom::Start(0)).context("failed to seek(0)".to_string())?;
while maxlen_to_read > 0 {
if maxlen_to_read < CHUNKLEN {
chunklen = maxlen_to_read;
Expand Down
11 changes: 5 additions & 6 deletions test/crau_verify.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::io::{BufReader, Write};
use std::io::Write;
use std::error::Error;
use std::fs;

Expand Down Expand Up @@ -30,14 +30,13 @@ fn main() -> Result<(), Box<dyn Error>> {
// Read update payload from srcpath, read delta update header from the payload.
let upfile = fs::File::open(srcpath.clone())?;

let freader = &mut BufReader::new(upfile);
let header = delta_update::read_delta_update_header(freader)?;
let header = delta_update::read_delta_update_header(&upfile)?;

// Parse signature data from the signature containing data, version, special fields.
let mut delta_archive_manifest = delta_update::get_manifest_bytes(freader, &header)?;
let mut delta_archive_manifest = delta_update::get_manifest_bytes(&upfile, &header)?;

// Extract signature from header.
let sigbytes = delta_update::get_signatures_bytes(freader, &header, &mut delta_archive_manifest)?;
let sigbytes = delta_update::get_signatures_bytes(&upfile, &header, &mut delta_archive_manifest)?;

let tmpdir = tempfile::tempdir()?.into_path();
fs::create_dir_all(tmpdir.clone())?;
Expand All @@ -52,7 +51,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let datablobspath = tmpdir.join("ue_data_blobs");

// Extract data blobs into file path.
delta_update::get_data_blobs(freader, &header, &delta_archive_manifest, datablobspath.as_path())?;
delta_update::get_data_blobs(&upfile, &header, &delta_archive_manifest, datablobspath.as_path())?;

// Parse signature data from the signature containing data, version, special fields.
let sigdata = match delta_update::parse_signature_data(&sigbytes, hdhashvec.as_slice(), PUBKEY_FILE) {
Expand Down
48 changes: 31 additions & 17 deletions update-format-crau/src/delta_update.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::io::{BufReader, Read, Seek, SeekFrom, Write};
use std::io::{Read, Write};
use std::fs;
use std::fs::File;
use std::path::Path;
use std::mem;
use std::os::unix::prelude::FileExt;
use log::{debug, info};
use bzip2::read::BzDecoder;
use anyhow::{Context, Result, anyhow, bail};
Expand Down Expand Up @@ -32,37 +34,41 @@ impl DeltaUpdateFileHeader {
}

// Read delta update header from the given file, return DeltaUpdateFileHeader.
pub fn read_delta_update_header(f: &mut BufReader<File>) -> Result<DeltaUpdateFileHeader> {
pub fn read_delta_update_header(f: &File) -> Result<DeltaUpdateFileHeader> {
let mut header = DeltaUpdateFileHeader {
magic: [0; 4],
file_format_version: 0,
manifest_size: 0,
};

f.read_exact(&mut header.magic).context("failed to read header magic")?;
f.read_exact_at(&mut header.magic, 0).context("failed to read header magic")?;
if header.magic != DELTA_UPDATE_FILE_MAGIC {
bail!("bad file magic");
}

let mut buf = [0u8; 8];
f.read_exact(&mut buf).context("failed to read file format version")?;
f.read_exact_at(&mut buf, header.magic.len() as u64).context("failed to read file format version")?;
header.file_format_version = u64::from_be_bytes(buf);
if header.file_format_version != 1 {
bail!("unsupported file format version");
}

f.read_exact(&mut buf).context("failed to read manifest size")?;
f.read_exact_at(&mut buf, (header.magic.len() + mem::size_of::<u64>()) as u64).context("failed to read manifest size")?;
header.manifest_size = u64::from_be_bytes(buf);

Ok(header)
}

// Take a buffer stream and DeltaUpdateFileHeader,
// return DeltaArchiveManifest that contains manifest.
pub fn get_manifest_bytes(f: &mut BufReader<File>, header: &DeltaUpdateFileHeader) -> Result<proto::DeltaArchiveManifest> {
pub fn get_manifest_bytes(f: &File, header: &DeltaUpdateFileHeader) -> Result<proto::DeltaArchiveManifest> {
let manifest_bytes = {
let mut buf = vec![0u8; header.manifest_size as usize];
f.read_exact(&mut buf).context("failed to read manifest bytes")?;
f.read_exact_at(
&mut buf,
(header.magic.len() + mem::size_of::<u64>() + mem::size_of::<u64>()) as u64,
)
.context("failed to read manifest bytes")?;
buf.into_boxed_slice()
};

Expand All @@ -73,7 +79,7 @@ pub fn get_manifest_bytes(f: &mut BufReader<File>, header: &DeltaUpdateFileHeade

// Take a buffer stream and DeltaUpdateFileHeader,
// return a bytes slice of the actual signature data as well as its length.
pub fn get_signatures_bytes<'a>(f: &'a mut BufReader<File>, header: &'a DeltaUpdateFileHeader, manifest: &mut proto::DeltaArchiveManifest) -> Result<Box<[u8]>> {
pub fn get_signatures_bytes<'a>(f: &'a File, header: &'a DeltaUpdateFileHeader, manifest: &mut proto::DeltaArchiveManifest) -> Result<Box<[u8]>> {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!! signature offsets are from the END of the manifest !!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Expand All @@ -82,10 +88,8 @@ pub fn get_signatures_bytes<'a>(f: &'a mut BufReader<File>, header: &'a DeltaUpd

let signatures_bytes = match (manifest.signatures_offset, manifest.signatures_size) {
(Some(sig_offset), Some(sig_size)) => {
f.seek(SeekFrom::Start(header.translate_offset(sig_offset))).context("failed to seek to start of signature")?;

let mut buf = vec![0u8; sig_size as usize];
f.read_exact(&mut buf).context("failed to read signature")?;
f.read_exact_at(&mut buf, header.translate_offset(sig_offset)).context("failed to read signature")?;
Some(buf.into_boxed_slice())
}
_ => None,
Expand All @@ -108,7 +112,7 @@ pub fn get_header_data_length(header: &DeltaUpdateFileHeader, manifest: &proto::

// Take a buffer reader, delta file header, manifest as input.
// Return path to data blobs, without header, manifest, or signatures.
pub fn get_data_blobs<'a>(f: &'a mut BufReader<File>, header: &'a DeltaUpdateFileHeader, manifest: &proto::DeltaArchiveManifest, tmpfile: &Path) -> Result<File> {
pub fn get_data_blobs<'a>(f: &'a File, header: &'a DeltaUpdateFileHeader, manifest: &proto::DeltaArchiveManifest, tmpfile: &Path) -> Result<()> {
let tmpdir = tmpfile.parent().ok_or(anyhow!("unable to get parent directory"))?;
fs::create_dir_all(tmpdir).context(format!("failed to create directory {:?}", tmpdir))?;
let mut outfile = File::create(tmpfile).context(format!("failed to create file {:?}", tmpfile))?;
Expand All @@ -120,27 +124,37 @@ pub fn get_data_blobs<'a>(f: &'a mut BufReader<File>, header: &'a DeltaUpdateFil
for pop in &manifest.partition_operations {
let data_offset = pop.data_offset.ok_or(anyhow!("unable to get data offset"))?;
let data_length = pop.data_length.ok_or(anyhow!("unable to get data length"))?;
let block_size = manifest.block_size() as u64;
if pop.dst_extents.len() != 1 {
bail!(
"unexpected number of extents, only one can be handled: {}",
pop.dst_extents.len()
);
}
let start_block = block_size * pop.dst_extents[0].start_block.ok_or(anyhow!("unable to get start_block"))?;

let mut partdata = vec![0u8; data_length as usize];

let translated_offset = header.translate_offset(data_offset.into());
f.seek(SeekFrom::Start(translated_offset)).context(format!("failed to seek at offset {:?}", translated_offset))?;
f.read_exact(&mut partdata).context(format!("failed to read data with length {:?}", data_length))?;
f.read_exact_at(&mut partdata, translated_offset).context(format!(
"failed to read data with length {:?} at {:?}",
data_length, translated_offset
))?;

// In case of bzip2-compressed chunks, extract.
if pop.type_.ok_or(anyhow!("unable to get type_ from partition operations"))? == proto::install_operation::Type::REPLACE_BZ.into() {
let mut bzdecoder = BzDecoder::new(&partdata[..]);
let mut partdata_unpacked = Vec::new();
bzdecoder.read_to_end(&mut partdata_unpacked).context(format!("failed to unpack bzip2ed data at offset {:?}", translated_offset))?;

outfile.write_all(&partdata_unpacked).context(format!("failed to copy unpacked data at offset {:?}", translated_offset))?;
outfile.write_all_at(&partdata_unpacked, start_block).context(format!("failed to copy unpacked data at offset {:?}", translated_offset))?;
} else {
outfile.write_all(&partdata).context(format!("failed to copy plain data at offset {:?}", translated_offset))?;
outfile.write_all_at(&partdata, start_block).context(format!("failed to copy plain data at offset {:?}", translated_offset))?;
}
outfile.flush().context(format!("failed to flush at offset {:?}", translated_offset))?;
}

Ok(outfile)
Ok(())
}

#[rustfmt::skip]
Expand Down
Loading