updated to use new ImageHeader correctly

This commit is contained in:
Bruce Leidl 2019-04-02 15:16:12 -04:00
parent cf85d10055
commit 81e9e224fc
2 changed files with 54 additions and 56 deletions

View File

@ -1,6 +1,7 @@
use std::path::{Path,PathBuf};
use std::fs;
use crate::{Result,ImageHeader,MetaInfo,Mount,PublicKey,public_key_for_channel};
use crate::{Result,ImageHeader,MetaInfo,Mounts,PublicKey,public_key_for_channel};
use std::sync::Arc;
#[derive(Clone)]
pub struct Partition {
@ -11,8 +12,7 @@ pub struct Partition {
#[derive(Clone)]
struct HeaderInfo {
header: ImageHeader,
metainfo: MetaInfo,
header: Arc<ImageHeader>,
// None if no public key available for channel named in metainfo
pubkey: Option<PublicKey>,
}
@ -39,14 +39,8 @@ impl Partition {
if !header.is_magic_valid() {
return Ok(None);
}
let metainfo = match header.metainfo() {
Ok(metainfo) => metainfo,
Err(e) => {
warn!("Reading partition {}: {}", dev.display(), e);
return Ok(None);
},
};
let metainfo = header.metainfo();
let pubkey = match public_key_for_channel(metainfo.channel()) {
Ok(result) => result,
Err(err) => {
@ -55,8 +49,9 @@ impl Partition {
}
};
let header = Arc::new(header);
Ok(Some(HeaderInfo {
header, metainfo, pubkey,
header, pubkey,
}))
}
@ -84,14 +79,9 @@ impl Partition {
&self.hinfo.as_ref().unwrap().header
}
fn header_mut(&mut self) -> &mut ImageHeader {
pub fn metainfo(&self) -> Arc<MetaInfo> {
assert!(self.is_initialized());
&mut self.hinfo.as_mut().unwrap().header
}
pub fn metainfo(&self) -> &MetaInfo {
assert!(self.is_initialized());
&self.hinfo.as_ref().unwrap().metainfo
self.hinfo.as_ref().unwrap().header.metainfo()
}
pub fn is_new(&self) -> bool {
@ -116,7 +106,6 @@ impl Partition {
return pubkey.verify(
&self.header().metainfo_bytes(),
&self.header().signature())
}
}
false
@ -131,17 +120,17 @@ impl Partition {
}
pub fn write_status(&mut self, status: u8) -> Result<()> {
self.header_mut().set_status(status);
self.header().set_status(status);
self.header().write_partition(&self.path)
}
pub fn set_flag_and_write(&mut self, flag: u8) -> Result<()> {
self.header_mut().set_flag(flag);
self.header().set_flag(flag);
self.header().write_partition(&self.path)
}
pub fn clear_flag_and_write(&mut self, flag: u8) -> Result<()> {
self.header_mut().clear_flag(flag);
self.header().clear_flag(flag);
self.header().write_partition(&self.path)
}
@ -176,7 +165,7 @@ impl Partition {
}
fn is_in_use(path: &Path) -> Result<bool> {
if Mount::is_source_mounted(path)? {
if Mounts::is_source_mounted(path)? {
return Ok(true);
}
let holders = count_block_holders(path)?;

View File

@ -3,9 +3,12 @@ use std::ffi::OsStr;
use std::io::{self,Seek,SeekFrom};
use std::path::{Path, PathBuf};
use crate::{CommandLine,OsRelease,ImageHeader,MetaInfo,Result,Partition,Mount,verity,util};
use crate::{CommandLine, OsRelease, ImageHeader, MetaInfo, Result, Partition, Mounts, util, LoopDevice};
use failure::ResultExt;
use std::sync::Arc;
use crate::UtsName;
use crate::verity::Verity;
const STORAGE_BASEDIR: &str = "/sysroot/storage/resources";
const RUN_DIRECTORY: &str = "/run/citadel/images";
@ -30,7 +33,6 @@ const RUN_DIRECTORY: &str = "/run/citadel/images";
pub struct ResourceImage {
path: PathBuf,
header: ImageHeader,
metainfo: MetaInfo,
}
impl ResourceImage {
@ -77,8 +79,7 @@ impl ResourceImage {
if !header.is_magic_valid() {
bail!("Image file {} does not have a valid header", path.as_ref().display());
}
let metainfo = header.metainfo()?;
Ok(ResourceImage::new(path.as_ref(), header, metainfo))
Ok(ResourceImage::new(path.as_ref(), header ))
}
pub fn is_valid_image(&self) -> bool {
@ -90,20 +91,24 @@ impl ResourceImage {
&self.path
}
fn verity(&self) -> Verity {
Verity::new(self.path())
}
pub fn header(&self) -> &ImageHeader {
&self.header
}
pub fn metainfo(&self) -> &MetaInfo {
&self.metainfo
pub fn metainfo(&self) -> Arc<MetaInfo> {
self.header.metainfo()
}
fn new(path: &Path, header: ImageHeader, metainfo: MetaInfo) -> ResourceImage {
fn new(path: &Path, header: ImageHeader) -> ResourceImage {
assert_eq!(path.extension(), Some(OsStr::new("img")), "image filename must have .img extension");
ResourceImage {
path: path.to_owned(),
header, metainfo,
header,
}
}
@ -147,7 +152,7 @@ impl ResourceImage {
}
pub fn write_to_partition(&self, partition: &Partition) -> Result<()> {
if self.metainfo.image_type() != "rootfs" {
if self.metainfo().image_type() != "rootfs" {
bail!("Cannot write to partition, image type is not rootfs");
}
@ -156,9 +161,13 @@ impl ResourceImage {
}
info!("writing rootfs image to {}", partition.path().display());
cmd_with_output!("/bin/dd", "if={} of={} bs=4096 skip=1", self.path.display(), partition.path().display())?;
/*
let args = format!("if={} of={} bs=4096 skip=1",
self.path.display(), partition.path().display());
util::exec_cmdline_quiet("/bin/dd", args)?;
*/
self.header.set_status(ImageHeader::STATUS_NEW);
self.header.write_partition(partition.path())?;
@ -184,15 +193,18 @@ impl ResourceImage {
if !self.header.verify_signature(pubkey) {
bail!("Header signature verification failed");
}
info!("Image header signature is valid");
}
None => bail!("Cannot verify header signature because no public key for channel {} is available", self.metainfo.channel())
None => bail!("Cannot verify header signature because no public key for channel {} is available", self.metainfo().channel())
}
}
info!("Setting up dm-verity device for image");
if !self.has_verity_hashtree() {
self.generate_verity_hashtree()?;
}
verity::setup_image_device(self.path(), self.metainfo())
let devname = self.verity().setup(&self.metainfo())?;
Ok(Path::new("/dev/mapper").join(devname))
// verity::setup_image_device(self.path(), &self.metainfo())
}
pub fn generate_verity_hashtree(&self) -> Result<()> {
@ -203,7 +215,8 @@ impl ResourceImage {
self.decompress()?;
}
info!("Generating dm-verity hash tree for image {}", self.path.display());
verity::generate_image_hashtree(self.path(), self.metainfo())?;
// verity::generate_image_hashtree(self.path(), self.metainfo().nblocks(), self.metainfo().verity_salt())?;
self.verity().generate_image_hashtree(&self.metainfo())?;
self.header.set_flag(ImageHeader::FLAG_HASH_TREE);
self.header.write_header_to(self.path())?;
Ok(())
@ -214,7 +227,8 @@ impl ResourceImage {
self.generate_verity_hashtree()?;
}
info!("Verifying dm-verity hash tree");
verity::verify_image(self.path(), self.metainfo())
self.verity().verify(&self.metainfo())
// verity::verify_image(self.path(), &self.metainfo())
}
pub fn generate_shasum(&self) -> Result<String> {
@ -222,7 +236,7 @@ impl ResourceImage {
self.decompress()?;
}
info!("Calculating sha256 of image");
let output = util::exec_cmdline_pipe_input("sha256sum", "-", self.path(), util::FileRange::Range{offset: 4096, len: self.metainfo.nblocks() * 4096})
let output = util::exec_cmdline_pipe_input("sha256sum", "-", self.path(), util::FileRange::Range{offset: 4096, len: self.metainfo().nblocks() * 4096})
.context(format!("failed to calculate sha256 on {}", self.path().display()))?;
let v: Vec<&str> = output.split_whitespace().collect();
let shasum = v[0].trim().to_owned();
@ -240,28 +254,23 @@ impl ResourceImage {
}
let mount_path = self.mount_path();
let loopdev = self.create_loopdev()?;
let loopdev = LoopDevice::create(self.path(), Some(4096), true)?;
info!("Loop device created: {}", loopdev.display());
info!("Loop device created: {}", loopdev);
info!("Mounting to: {}", mount_path.display());
fs::create_dir_all(&mount_path)?;
util::mount(&loopdev.to_string_lossy(), mount_path, Some("-oro"))
}
pub fn create_loopdev(&self) -> Result<PathBuf> {
let args = format!("--offset 4096 -f --read-only --show {}", self.path.display());
let output = util::exec_cmdline_with_output("/sbin/losetup", args)?;
Ok(PathBuf::from(output))
util::mount(&loopdev.device_str(), mount_path, Some("-oro"))
}
// Return the path at which to mount this resource image.
fn mount_path(&self) -> PathBuf {
if self.metainfo.image_type() == "realmfs" {
PathBuf::from(format!("{}/{}-realmfs.mountpoint", RUN_DIRECTORY, self.metainfo.realmfs_name().expect("realmfs image has no name")))
let metainfo = self.metainfo();
if metainfo.image_type() == "realmfs" {
PathBuf::from(format!("{}/{}-realmfs.mountpoint", RUN_DIRECTORY, metainfo.realmfs_name().expect("realmfs image has no name")))
} else {
PathBuf::from(format!("{}/{}.mountpoint", RUN_DIRECTORY, self.metainfo.image_type()))
PathBuf::from(format!("{}/{}.mountpoint", RUN_DIRECTORY, metainfo.image_type()))
}
}
@ -309,8 +318,8 @@ impl ResourceImage {
// If the /storage directory is not mounted, attempt to mount it.
// Return true if already mounted or if the attempt to mount it succeeds.
fn ensure_storage_mounted() -> Result<bool> {
if Mount::is_source_mounted("/dev/mapper/citadel-storage")? {
pub fn ensure_storage_mounted() -> Result<bool> {
if Mounts::is_source_mounted("/dev/mapper/citadel-storage")? {
return Ok(true);
}
let path = Path::new("/dev/mapper/citadel-storage");
@ -351,7 +360,7 @@ fn search_directory<P: AsRef<Path>>(dir: P, image_type: &str, channel: Option<&s
let mut best = None;
let mut matches = all_matching_images(dir.as_ref(), image_type, channel)?;
info!("Found {} matching images", matches.len());
debug!("Found {} matching images", matches.len());
if channel.is_none() {
if matches.is_empty() {
@ -408,7 +417,7 @@ fn parse_timestamp(img: &ResourceImage) -> Result<usize> {
}
fn current_kernel_version() -> String {
let utsname = util::uname();
let utsname = UtsName::uname();
let v = utsname.release().split("-").collect::<Vec<_>>();
v[0].to_string()
}
@ -461,9 +470,9 @@ fn maybe_add_dir_entry(entry: DirEntry,
return Ok(())
}
let metainfo = header.metainfo()?;
let metainfo = header.metainfo();
info!("Found an image type={} channel={} kernel={:?}", metainfo.image_type(), metainfo.channel(), metainfo.kernel_version());
debug!("Found an image type={} channel={} kernel={:?}", metainfo.image_type(), metainfo.channel(), metainfo.kernel_version());
if let Some(channel) = channel {
if metainfo.channel() != channel {
@ -481,7 +490,7 @@ fn maybe_add_dir_entry(entry: DirEntry,
}
}
images.push(ResourceImage::new(&path, header, metainfo));
images.push(ResourceImage::new(&path, header));
Ok(())
}