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

View File

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