From fdb0d2ab35085bd97d5cae420df0a2c9c6f99c0a Mon Sep 17 00:00:00 2001 From: renoseven Date: Fri, 22 Dec 2023 13:40:29 +0800 Subject: [PATCH 06/15] daemon: check patch before patch restoration Signed-off-by: renoseven --- daemon/src/patch/manager/driver/kpatch/mod.rs | 37 +++++++++--- daemon/src/patch/manager/driver/mod.rs | 2 +- daemon/src/patch/manager/driver/upatch/mod.rs | 58 +++++++++++++------ daemon/src/patch/manager/mod.rs | 3 +- daemon/src/patch/transaction.rs | 2 +- daemon/src/rpc/skeleton_impl/patch.rs | 2 +- 6 files changed, 73 insertions(+), 31 deletions(-) diff --git a/daemon/src/patch/manager/driver/kpatch/mod.rs b/daemon/src/patch/manager/driver/kpatch/mod.rs index 57aa127..efe80e5 100644 --- a/daemon/src/patch/manager/driver/kpatch/mod.rs +++ b/daemon/src/patch/manager/driver/kpatch/mod.rs @@ -2,7 +2,7 @@ use std::{ffi::OsString, os::unix::prelude::OsStrExt, path::Path}; use anyhow::{anyhow, bail, ensure, Context, Result}; use lazy_static::lazy_static; -use log::{debug, warn}; +use log::debug; use syscare_abi::PatchStatus; use syscare_common::{ @@ -87,15 +87,10 @@ impl KernelPatchDriver { } } -impl PatchDriver for KernelPatchDriver { - fn check(&self, patch: &Patch, flag: PatchOpFlag) -> Result<()> { +impl KernelPatchDriver { + fn check_compatiblity(&self, patch: &Patch) -> Result<()> { const KERNEL_NAME_PREFIX: &str = "kernel-"; - if flag == PatchOpFlag::SkipCheck { - warn!("Skipped patch \"{}\" check", patch); - return Ok(()); - } - let kernel_version = os::kernel::version(); let current_kernel = OsString::from(KERNEL_NAME_PREFIX).concat(kernel_version); @@ -113,18 +108,42 @@ impl PatchDriver for KernelPatchDriver { ); } + Ok(()) + } + + fn check_consistency(&self, patch: &Patch) -> Result<()> { let patch_ext: &KernelPatchExt = (&patch.info_ext).into(); let patch_file = patch_ext.patch_file.as_path(); let real_checksum = digest::file(patch_file)?; + debug!("Target checksum: {}", patch.checksum); + debug!("Expected checksum: {}", real_checksum); + ensure!( patch.checksum.eq(&real_checksum), - "Kpatch: Patch file \"{}\" checksum failed", + "Kpatch: Patch \"{}\" consistency check failed", patch_file.display() ); Ok(()) } + fn check_confliction(&self, _patch: &Patch) -> Result<()> { + Ok(()) + } +} + +impl PatchDriver for KernelPatchDriver { + fn check(&self, patch: &Patch, flag: PatchOpFlag) -> Result<()> { + self.check_compatiblity(patch)?; + self.check_consistency(patch)?; + + if flag != PatchOpFlag::Force { + self.check_confliction(patch)?; + } + + Ok(()) + } + fn status(&self, patch: &Patch, _flag: PatchOpFlag) -> Result { Self::get_patch_status(patch) } diff --git a/daemon/src/patch/manager/driver/mod.rs b/daemon/src/patch/manager/driver/mod.rs index 9beb999..c3a4ca4 100644 --- a/daemon/src/patch/manager/driver/mod.rs +++ b/daemon/src/patch/manager/driver/mod.rs @@ -13,7 +13,7 @@ use super::entity::*; #[derive(PartialEq, Clone, Copy)] pub enum PatchOpFlag { Normal, - SkipCheck, + Force, } /// Basic abstraction of patch operation diff --git a/daemon/src/patch/manager/driver/upatch/mod.rs b/daemon/src/patch/manager/driver/upatch/mod.rs index 993c116..e4a914b 100644 --- a/daemon/src/patch/manager/driver/upatch/mod.rs +++ b/daemon/src/patch/manager/driver/upatch/mod.rs @@ -1,6 +1,5 @@ use std::{ - ffi::OsString, - os::unix::prelude::OsStringExt, + ffi::CStr, path::{Path, PathBuf}, }; @@ -9,7 +8,7 @@ use anyhow::{anyhow, bail, ensure, Result}; use indexmap::IndexMap; use lazy_static::lazy_static; use libc::{c_char, EEXIST, EFAULT, ENOENT, EPERM}; -use log::{info, warn}; +use log::{debug, info}; use parking_lot::Mutex; use syscare_abi::PatchStatus; use syscare_common::util::digest; @@ -92,25 +91,33 @@ impl UserPatchDriver { } } -impl PatchDriver for UserPatchDriver { - fn check(&self, patch: &Patch, flag: PatchOpFlag) -> Result<()> { - const ERR_MSG_LEN: usize = 512; - - if flag == PatchOpFlag::SkipCheck { - warn!("Skipped patch \"{}\" check", patch); - return Ok(()); - } +impl UserPatchDriver { + fn check_compatiblity(&self, _patch: &Patch) -> Result<()> { + Ok(()) + } + fn check_consistency(&self, patch: &Patch) -> Result<()> { let patch_ext: &UserPatchExt = (&patch.info_ext).into(); let patch_file = &patch_ext.patch_file; let real_checksum = digest::file(patch_file).map_err(|e| anyhow!("Upatch: {}", e))?; + debug!("Target checksum: {}", patch.checksum); + debug!("Expected checksum: {}", real_checksum); + ensure!( patch.checksum.eq(&real_checksum), - "Upatch: Patch file \"{}\" checksum failed", + "Upatch: Patch \"{}\" consistency check failed", patch_file.display() ); + Ok(()) + } + + fn check_confliction(&self, patch: &Patch) -> Result<()> { + const ERR_MSG_LEN: usize = 512; + + let patch_ext: &UserPatchExt = (&patch.info_ext).into(); + let target_elf = patch_ext.target_elf.to_cstring()?; let patch_file = patch_ext.patch_file.to_cstring()?; let mut msg_buf = vec![0; ERR_MSG_LEN]; @@ -123,11 +130,28 @@ impl PatchDriver for UserPatchDriver { msg_buf.capacity(), ) }; + if ret_val != 0 { + match CStr::from_bytes_until_nul(&msg_buf) { + Ok(err_msg) => bail!(format!("Upatch: {}", err_msg.to_string_lossy())), + Err(_) => bail!(format!( + "Upatch: {}", + std::io::Error::from_raw_os_error(ret_val) + )), + } + } - ensure!( - ret_val == 0, - OsString::from_vec(msg_buf).to_string_lossy().to_string() - ); + Ok(()) + } +} + +impl PatchDriver for UserPatchDriver { + fn check(&self, patch: &Patch, flag: PatchOpFlag) -> Result<()> { + self.check_compatiblity(patch)?; + self.check_consistency(patch)?; + + if flag != PatchOpFlag::Force { + self.check_confliction(patch)?; + } Ok(()) } @@ -151,7 +175,7 @@ impl PatchDriver for UserPatchDriver { patch_uuid.as_ptr(), target_elf.as_ptr(), patch_file.as_ptr(), - matches!(flag, PatchOpFlag::SkipCheck), + matches!(flag, PatchOpFlag::Force), ) }; diff --git a/daemon/src/patch/manager/mod.rs b/daemon/src/patch/manager/mod.rs index 3b1aa8c..fdb218d 100644 --- a/daemon/src/patch/manager/mod.rs +++ b/daemon/src/patch/manager/mod.rs @@ -267,8 +267,7 @@ impl PatchManager { "Restore patch \"{}\" status to \"{}\"", patch, target_status ); - if let Err(e) = self.do_status_transition(&patch, target_status, PatchOpFlag::SkipCheck) - { + if let Err(e) = self.do_status_transition(&patch, target_status, PatchOpFlag::Force) { error!("{}", e); } } diff --git a/daemon/src/patch/transaction.rs b/daemon/src/patch/transaction.rs index 16bab46..079b024 100644 --- a/daemon/src/patch/transaction.rs +++ b/daemon/src/patch/transaction.rs @@ -70,7 +70,7 @@ where fn rollback(&mut self) -> Result<()> { let mut patch_manager = self.patch_manager.write(); while let Some((patch, status)) = self.finish_list.pop() { - patch_manager.do_status_transition(&patch, status, PatchOpFlag::SkipCheck)?; + patch_manager.do_status_transition(&patch, status, PatchOpFlag::Force)?; } Ok(()) } diff --git a/daemon/src/rpc/skeleton_impl/patch.rs b/daemon/src/rpc/skeleton_impl/patch.rs index 4517a03..8d4f57b 100644 --- a/daemon/src/rpc/skeleton_impl/patch.rs +++ b/daemon/src/rpc/skeleton_impl/patch.rs @@ -82,7 +82,7 @@ impl PatchSkeleton for PatchSkeletonImpl { PatchManager::apply_patch, match force { false => PatchOpFlag::Normal, - true => PatchOpFlag::SkipCheck, + true => PatchOpFlag::Force, }, identifier, )? -- 2.33.0