From 963c27aea732f3a035c8a62956f3bd629630133c Mon Sep 17 00:00:00 2001 From: Sangho Lee Date: Fri, 10 Apr 2026 20:27:46 +0000 Subject: [PATCH 1/2] harden HEKI patch text --- litebox_platform_lvbs/src/mshv/mem_integrity.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/litebox_platform_lvbs/src/mshv/mem_integrity.rs b/litebox_platform_lvbs/src/mshv/mem_integrity.rs index ba0174036..42a70310f 100644 --- a/litebox_platform_lvbs/src/mshv/mem_integrity.rs +++ b/litebox_platform_lvbs/src/mshv/mem_integrity.rs @@ -626,7 +626,10 @@ const JMP32_INSN_SIZE: u8 = 5; /// Refer [Linux](https://elixir.bootlin.com/linux/v6.6.85/source/arch/x86/kernel/alternative.c#L2164) pub fn validate_text_poke_bp_batch(patch_data: &HekiPatch, precomputed_patch: &HekiPatch) -> bool { // step 1 - if patch_data.size == 1 && patch_data.code[0] == INT3_INSN_OPCODE { + if patch_data.size == 1 + && patch_data.code[0] == INT3_INSN_OPCODE + && patch_data.pa[0] == precomputed_patch.pa[0] + { return true; } @@ -637,7 +640,15 @@ pub fn validate_text_poke_bp_batch(patch_data: &HekiPatch, precomputed_patch: &H || (patch_data.pa[0] == precomputed_patch.pa[1] && (precomputed_patch.pa[0] + 1).is_multiple_of(Size4KiB::SIZE))) { - 1 // step 2 + // step 2. pa[1] is dereferenced by `apply_vtl0_text_patch` only when + // `precomputed_patch.pa[0] + 1` is not page-aligned. In that case, it must + // equal `precomputed_patch.pa[1]`. + if !(precomputed_patch.pa[0] + 1).is_multiple_of(Size4KiB::SIZE) + && patch_data.pa[1] != precomputed_patch.pa[1] + { + return false; + } + 1 } else { return false; }; From 387bf650588286c5c434753e39db9bd435d26491 Mon Sep 17 00:00:00 2001 From: Sangho Lee Date: Fri, 24 Apr 2026 20:24:47 +0000 Subject: [PATCH 2/2] dead code --- litebox_platform_lvbs/src/mshv/vsm.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/litebox_platform_lvbs/src/mshv/vsm.rs b/litebox_platform_lvbs/src/mshv/vsm.rs index f66989fa3..765ed4ac8 100644 --- a/litebox_platform_lvbs/src/mshv/vsm.rs +++ b/litebox_platform_lvbs/src/mshv/vsm.rs @@ -1061,9 +1061,15 @@ impl Vtl0KernelInfo { self.system_certs.get().map(|b| &**b) } - // This function finds the precomputed patch data corresponding to the input patch data. - // We need this because each step of `mshv_vsm_patch_data`/`text_poke_bp_batch` only - // provides a part of the patch data and addresses (`patch[0]` or `patch[1..patch_size-1]`). + /// This function finds the precomputed patch data corresponding to the input patch data. + /// + /// Each step of `text_poke_bp_batch` only exposes a portion of the target's address range, + /// so we look up in the precomputed map by two keys derived from `patch_data.pa[0]`: + /// - `pa[0]` matches step 1 or 3 (target's first byte) and, for a precomputed patch that + /// straddles at offset 1, step 2. + /// - `pa[0] - 1` matches step 2 where `patch.pa[0] == precomputed.pa[0] + 1`. + /// + /// No legitimate step requires looking up by `patch.pa[1]`. pub fn find_precomputed_patch(&self, patch_data: &HekiPatch) -> Option { self.precomputed_patches .get(PhysAddr::new(patch_data.pa[0])) @@ -1071,11 +1077,6 @@ impl Vtl0KernelInfo { self.precomputed_patches .get(PhysAddr::new(patch_data.pa[0].saturating_sub(1))) }) - .or_else(|| { - self.precomputed_patches - .get(PhysAddr::new(patch_data.pa[1])) - }) - .or(None) } }