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
2 changes: 0 additions & 2 deletions lib/src/edit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,5 @@ pub use key::*;
pub use root::*;
pub use sign::*;

const KIB: u64 = 1024;
const MIB: u64 = 1024 * KIB;
#[expect(clippy::unreadable_literal)]
const OXIDE_BOOT_MAGIC: [u8; 4] = 0x1DEB0075_u32.to_le_bytes();
42 changes: 27 additions & 15 deletions lib/src/edit/os_images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use camino::Utf8Path;
use camino::Utf8PathBuf;
use flate2::read::GzDecoder;
use futures_util::TryStreamExt;
use sha2::Digest;
use sha2::Sha256;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
use tufaceous_artifact::ArtifactVersion;
Expand All @@ -19,8 +21,6 @@ use tufaceous_artifact::OsVariant;
use crate::COSMO_PHASE_1_PATH;
use crate::GIMLET_PHASE_1_PATH;
use crate::PHASE_2_PATH;
use crate::edit::KIB;
use crate::edit::MIB;
use crate::edit::OXIDE_BOOT_MAGIC;
use crate::edit::input::Input;
use crate::edit::source::BytesSource;
Expand All @@ -30,6 +30,9 @@ use crate::error::Error;
use crate::error::ErrorKind;
use crate::error::try_path;

const KIB: u64 = 1024;
const MIB: u64 = 1024 * KIB;

impl Input<TargetSource<'static>> {
pub(crate) async fn os_images(
os_variant: OsVariant,
Expand Down Expand Up @@ -210,16 +213,28 @@ impl Input<BytesSource> {
format!(
"cosmo {os_variant} OS phase 1 image version {interior_version}\n"
),
MIB,
32 * KIB,
);
let gimlet_phase_1 = BytesSource::fake_padded(
format!(
"gimlet {os_variant} OS phase 1 image version {interior_version}\n"
),
MIB,
16 * KIB,
);

let mut phase_2_bytes = BytesMut::with_capacity(4096);
let phase_2_size = 64 * KIB;
let phase_2_data =
format!("OS phase 2 image version {interior_version}\n");
let mut hasher = Sha256::new();
hasher.update(&phase_2_data);
hasher.update(vec![
0;
usize::try_from(phase_2_size).unwrap()
- phase_2_data.len()
]);

let mut phase_2_bytes =
BytesMut::with_capacity(4096 + phase_2_data.len());
phase_2_bytes.put(OXIDE_BOOT_MAGIC.as_slice()); // uint32_t odh_magic;
phase_2_bytes.put_u32_le(2); // uint32_t odh_version;
// The only defined ODH_FLAG is:
Expand All @@ -233,12 +248,7 @@ impl Input<BytesSource> {
phase_2_bytes.put_u64_le(1 << 32); // uint64_t odh_target_size;
// #define OXBOOT_CSUMLEN_SHA256 32
// uint8_t odh_sha256[OXBOOT_CSUMLEN_SHA256];
phase_2_bytes.put(
// head -c $((4 * 1024 * 1024)) </dev/zero | sha256sum
b"\xbb\x9f\x8d\xf6\x14\x74\xd2\x5e\x71\xfa\x00\x72\x23\x18\xcd\x38\
\x73\x96\xca\x17\x36\x60\x5e\x12\x48\x82\x1c\xc0\xde\x3d\x3a\xf8"
.as_slice(),
);
phase_2_bytes.put(hasher.finalize().as_slice());
// #define OXBOOT_DISK_DATASET_SIZE 128
// char odh_dataset[OXBOOT_DISK_DATASET_SIZE];
let end = phase_2_bytes.len() + 128;
Expand All @@ -251,22 +261,24 @@ impl Input<BytesSource> {
OsVariant::Recovery => "recovery".as_bytes(),
});
phase_2_bytes.put(" fake123/789fake 1986-12-28 01:23".as_bytes());
// rest of header is zeroes, which will be written out by `fake_padded`
let phase_2 = BytesSource::fake_padded(phase_2_bytes, 4096 + 4 * MIB);
phase_2_bytes.resize(4096, 0); // rest of header is zeroes
phase_2_bytes.put(phase_2_data.as_bytes());
let phase_2 =
BytesSource::fake_padded(phase_2_bytes, 4096 + phase_2_size);

let mut extra_targets = BTreeMap::new();
extra_targets.insert(
String::from("unix.z"),
BytesSource::fake_padded(
format!("{os_variant} OS unix.z version {interior_version}\n"),
64 * KIB,
32 * KIB,
),
);
extra_targets.insert(
String::from("cpio.z"),
BytesSource::fake_padded(
format!("{os_variant} OS cpio.z version {interior_version}\n"),
256 * KIB,
32 * KIB,
),
);

Expand Down
63 changes: 63 additions & 0 deletions lib/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::convert::Infallible;
use std::io::Write;
use std::sync::Arc;
Expand All @@ -15,6 +17,8 @@ use semver::Version;
use tufaceous::RepositoryLoader;
use tufaceous::edit::RepositoryEditor;
use tufaceous::error::Error;
use tufaceous_artifact::Artifact;
use tufaceous_artifact::ArtifactHash;
use tufaceous_artifact::KnownArtifactTags;

const V1: Version = Version::new(1, 0, 0);
Expand Down Expand Up @@ -98,6 +102,65 @@ async fn no_artifacts() -> Result<(), Error> {
Ok(())
}

#[tokio::test]
async fn fake_artifacts_are_distinct() -> Result<(), Error> {
let log = slog::Logger::root(slog::Discard, slog::o!());

let signed = RepositoryEditor::fake(V1)?
.finish()
.await?
.generate_root()
.sign()
.await?;
let zip = signed.write_zip(Vec::new(), Utc::now()).await?;
let repo1 = RepositoryLoader::new()
.trust_root(signed.root())
.load_zip_buffer(zip, &log)
.await?;

let signed = RepositoryEditor::fake(V2)?
.finish()
.await?
.generate_root()
.sign()
.await?;
let zip = signed.write_zip(Vec::new(), Utc::now()).await?;
let repo2 = RepositoryLoader::new()
.trust_root(signed.root())
.load_zip_buffer(zip, &log)
.await?;

let hashes1 = repo1
.artifacts()
.iter()
.map(|artifact| artifact.hash)
.collect::<BTreeSet<_>>();
let hashes2 = repo2
.artifacts()
.iter()
.map(|artifact| artifact.hash)
.collect::<BTreeSet<_>>();
if !hashes1.is_disjoint(&hashes2) {
let intersection =
hashes1.intersection(&hashes2).collect::<BTreeSet<_>>();
let mut artifacts = BTreeMap::<ArtifactHash, Vec<&Artifact>>::new();
for repo in [&repo1, &repo2] {
for artifact in repo.artifacts() {
if intersection.contains(&artifact.hash) {
artifacts.entry(artifact.hash).or_default().push(artifact);
}
}
}
panic!(
"artifacts from fake repos of different versions \
have the same hash: {:?}",
artifacts.values()
);
}

Ok(())
}

#[tokio::test]
async fn inconsistent_fake() -> Result<(), Error> {
let log = slog::Logger::root(slog::Discard, slog::o!());
Expand Down
Loading