updated to use new ImageHeader correctly
This commit is contained in:
parent
cf85d10055
commit
81e9e224fc
@ -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)?;
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user