From fdb0d2ab35085bd97d5cae420df0a2c9c6f99c0a Mon Sep 17 00:00:00 2001
From: renoseven <dev@renoseven.net>
Date: Fri, 22 Dec 2023 13:40:29 +0800
Subject: [PATCH 06/15] daemon: check patch before patch restoration

Signed-off-by: renoseven <dev@renoseven.net>
---
 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<PatchStatus> {
         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

