From 237314ad0dfe1098201e50cc833d1a53c130ca71 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 18 Mar 2021 08:43:55 +0100 Subject: [PATCH] tape: improve catalog consistency checks Try to check if we read the correct catalog by verifying uuid, media_set_uuid and seq_nr. Note: this changes the catalog format again. --- src/api2/tape/media.rs | 2 +- src/tape/file_formats/mod.rs | 11 +++++++++ src/tape/media_catalog.rs | 47 +++++++++++++++++++++++++++++------- src/tape/pool_writer.rs | 5 ++-- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/api2/tape/media.rs b/src/api2/tape/media.rs index 45ea99ed..50e8a3cc 100644 --- a/src/api2/tape/media.rs +++ b/src/api2/tape/media.rs @@ -432,7 +432,7 @@ pub fn list_content( .generate_media_set_name(&set.uuid, template) .unwrap_or_else(|_| set.uuid.to_string()); - let catalog = MediaCatalog::open(status_path, &media_id.label.uuid, false, false)?; + let catalog = MediaCatalog::open(status_path, &media_id, false, false)?; for (store, content) in catalog.content() { for snapshot in content.snapshot_index.keys() { diff --git a/src/tape/file_formats/mod.rs b/src/tape/file_formats/mod.rs index a70224e8..b60fbe7b 100644 --- a/src/tape/file_formats/mod.rs +++ b/src/tape/file_formats/mod.rs @@ -213,6 +213,17 @@ pub struct SnapshotArchiveHeader { pub store: String, } +#[derive(Deserialize, Serialize)] +/// Header for Catalog archives +pub struct CatalogArchiveHeader { + /// The uuid of the media the catalog is for + pub uuid: Uuid, + /// The media set uuid the catalog is for + pub media_set_uuid: Uuid, + /// Media sequence number + pub seq_nr: u64, +} + #[derive(Serialize,Deserialize,Clone,Debug)] /// Media Label /// diff --git a/src/tape/media_catalog.rs b/src/tape/media_catalog.rs index de50cf32..766ee024 100644 --- a/src/tape/media_catalog.rs +++ b/src/tape/media_catalog.rs @@ -26,6 +26,7 @@ use crate::{ backup::BackupDir, tape::{ MediaId, + file_formats::MediaSetLabel, }, }; @@ -136,11 +137,13 @@ impl MediaCatalog { /// Open a catalog database, load into memory pub fn open( base_path: &Path, - uuid: &Uuid, + media_id: &MediaId, write: bool, create: bool, ) -> Result { + let uuid = &media_id.label.uuid; + let mut path = base_path.to_owned(); path.push(uuid.to_string()); path.set_extension("log"); @@ -169,7 +172,7 @@ impl MediaCatalog { pending: Vec::new(), }; - let found_magic_number = me.load_catalog(&mut file)?; + let found_magic_number = me.load_catalog(&mut file, media_id.media_set_label.as_ref())?; if !found_magic_number { me.pending.extend(&Self::PROXMOX_BACKUP_MEDIA_CATALOG_MAGIC_1_1); @@ -230,10 +233,10 @@ impl MediaCatalog { me.pending.extend(&Self::PROXMOX_BACKUP_MEDIA_CATALOG_MAGIC_1_1); - me.register_label(&media_id.label.uuid, 0)?; + me.register_label(&media_id.label.uuid, 0, 0)?; if let Some(ref set) = media_id.media_set_label { - me.register_label(&set.uuid, 1)?; + me.register_label(&set.uuid, set.seq_nr, 1)?; } me.commit()?; @@ -364,12 +367,16 @@ impl MediaCatalog { } } - fn check_register_label(&self, file_number: u64) -> Result<(), Error> { + fn check_register_label(&self, file_number: u64, uuid: &Uuid) -> Result<(), Error> { if file_number >= 2 { bail!("register label failed: got wrong file number ({} >= 2)", file_number); } + if file_number == 0 && uuid != &self.uuid { + bail!("register label failed: uuid does not match"); + } + if self.current_archive.is_some() { bail!("register label failed: inside chunk archive"); } @@ -389,15 +396,21 @@ impl MediaCatalog { /// Register media labels (file 0 and 1) pub fn register_label( &mut self, - uuid: &Uuid, // Uuid form MediaContentHeader + uuid: &Uuid, // Media/MediaSet Uuid + seq_nr: u64, // onyl used for media set labels file_number: u64, ) -> Result<(), Error> { - self.check_register_label(file_number)?; + self.check_register_label(file_number, uuid)?; + + if file_number == 0 && seq_nr != 0 { + bail!("register_label failed - seq_nr should be 0 - iternal error"); + } let entry = LabelEntry { file_number, uuid: *uuid.as_bytes(), + seq_nr, }; if self.log_to_stdout { @@ -608,7 +621,11 @@ impl MediaCatalog { Ok(()) } - fn load_catalog(&mut self, file: &mut File) -> Result { + fn load_catalog( + &mut self, + file: &mut File, + media_set_label: Option<&MediaSetLabel>, + ) -> Result { let mut file = BufReader::new(file); let mut found_magic_number = false; @@ -713,7 +730,18 @@ impl MediaCatalog { let file_number = entry.file_number; let uuid = Uuid::from(entry.uuid); - self.check_register_label(file_number)?; + self.check_register_label(file_number, &uuid)?; + + if file_number == 1 { + if let Some(set) = media_set_label { + if set.uuid != uuid { + bail!("got unexpected media set uuid"); + } + if set.seq_nr != entry.seq_nr { + bail!("got unexpected media set sequence number"); + } + } + } self.last_entry = Some((uuid, file_number)); } @@ -789,6 +817,7 @@ impl MediaSetCatalog { struct LabelEntry { file_number: u64, uuid: [u8;16], + seq_nr: u64, // only used for media set labels } #[derive(Endian)] diff --git a/src/tape/pool_writer.rs b/src/tape/pool_writer.rs index b0b09f68..9c683861 100644 --- a/src/tape/pool_writer.rs +++ b/src/tape/pool_writer.rs @@ -253,9 +253,10 @@ impl PoolWriter { // load all catalogs read-only at start for media_uuid in pool.current_media_list()? { + let media_info = pool.lookup_media(media_uuid).unwrap(); let media_catalog = MediaCatalog::open( Path::new(TAPE_STATUS_DIR), - &media_uuid, + media_info.id(), false, false, )?; @@ -655,7 +656,7 @@ fn update_media_set_label( if new_set.encryption_key_fingerprint != media_set_label.encryption_key_fingerprint { bail!("detected changed encryption fingerprint - internal error"); } - media_catalog = MediaCatalog::open(status_path, &media_id.label.uuid, true, false)?; + media_catalog = MediaCatalog::open(status_path, &media_id, true, false)?; } else { worker.log( format!("wrinting new media set label (overwrite '{}/{}')",