From 6cef0b8f8d7904379dd965335951397035dda548 Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Tue, 6 Aug 2024 20:23:06 +0800 Subject: [PATCH 01/13] add riscv64 support --- rust-toolchain.toml | 2 - src/arch/mod.rs | 6 +++ src/arch/riscv64.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 +- 4 files changed, 99 insertions(+), 4 deletions(-) delete mode 100644 rust-toolchain.toml create mode 100644 src/arch/riscv64.rs diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 5d56faf..0000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly" diff --git a/src/arch/mod.rs b/src/arch/mod.rs index c056393..af11916 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -14,3 +14,9 @@ pub use x86::*; mod aarch64; #[cfg(target_arch = "aarch64")] pub use aarch64::*; + +#[cfg(target_arch = "riscv64")] +mod riscv64; + +#[cfg(target_arch = "riscv64")] +pub use riscv64::*; \ No newline at end of file diff --git a/src/arch/riscv64.rs b/src/arch/riscv64.rs new file mode 100644 index 0000000..5f3d06d --- /dev/null +++ b/src/arch/riscv64.rs @@ -0,0 +1,91 @@ +//! riscv64 arch-sepcific implementations + +use crate::{JumpEntry, JumpLabelType}; + + +/// Length of jump instruction to be replaced +pub const ARCH_JUMP_INS_LENGTH: usize = 4; + +const RISCV_INSN_JAL: u32 = 0x0000006f; + + +/// New instruction generated according to jump label type and jump entry +#[inline(always)] +pub fn arch_jump_entry_instruction( + jump_label_type: JumpLabelType, + jump_entry: &JumpEntry, +) -> [u8; ARCH_JUMP_INS_LENGTH] { + match jump_label_type { + // [offset ] [rd] [opcode ] + // [20|10:1|11|19:12] [rd] [1101111] + JumpLabelType::Jmp => { + // Note that riscv64 only supports relative address within +/-512k. + // In current implementation, this assumption is always hold. + let relative_addr = (jump_entry.target_addr() - jump_entry.code_addr()) as u32; + let mut jal = RISCV_INSN_JAL; + // MASK 19:12 = 0b_0000_0000_0000_1111_1111_0000_0000_0000 = 0x000FF000 + // MASK 11 = 0b_0000_0000_0000_0000_0000_1000_0000_0000 = 0x00000800 + // MASK 10:1 = 0b_0000_0000_0000_0000_0000_0111_1111_1110 = 0x000007FE + // MASK 20 = 0b_0000_0000_0001_0000_0000_0000_0000_0000 = 0x00100000 + jal |= + ((relative_addr & 0x000FF000) << 0) | + ((relative_addr & 0x00000800) << 9) | + ((relative_addr & 0x000007FE) << 20) | + ((relative_addr & 0x00100000) << 11); + jal.to_ne_bytes() + } + // RISCV_INSN_NOP 0x00000013 + JumpLabelType::Nop => [0x00, 0x00, 0x00, 0x13], + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! arch_static_key_init_nop_asm_template { + () => { + ::core::concat!( + r#" + .option push + .option norelax + .option norvc + 2: + nop + .option pop + .pushsection "#, + $crate::os_static_key_sec_name_attr!(), + r#" + .balign 8 + .quad 2b - . + .quad {0} - . + .quad {1} + {2} - . + .popsection + "# + ) + }; +} + + +#[doc(hidden)] +#[macro_export] +macro_rules! arch_static_key_init_jmp_asm_template { + () => { + ::core::concat!( + r#" + .option push + .option norelax + .option norvc + 2: + jal zero, {0} + .option pop + .pushsection "#, + $crate::os_static_key_sec_name_attr!(), + r#" + .balign 8 + .quad 2b - . + .quad {0} - . + .quad {1} + {2} - . + .popsection + "# + ) + }; +} diff --git a/src/lib.rs b/src/lib.rs index f3086af..ca1a54e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -188,10 +188,10 @@ impl GenericStaticKey { /// Count of jump entries in __static_keys section. Note that /// there will be several dummy jump entries inside this section. -pub fn jump_entries_count() { +pub fn jump_entries_count()-> usize { let jump_entry_start_addr = core::ptr::addr_of_mut!(os::JUMP_ENTRY_START); let jump_entry_stop_addr = core::ptr::addr_of_mut!(os::JUMP_ENTRY_STOP); - unsafe { jump_entry_stop_addr.offset_from(jump_entry_start_addr) as usize }; + unsafe { jump_entry_stop_addr.offset_from(jump_entry_start_addr) as usize } } // ---------------------------- Create ---------------------------- From f5e39b5dbad4a76ee4198f2859febe33ffad7e1b Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Tue, 6 Aug 2024 20:37:49 +0800 Subject: [PATCH 02/13] fmt code and restore toolchain file --- rust-toolchain.toml | 2 + src/arch/mod.rs | 2 +- src/arch/riscv64.rs | 178 ++++++++++++++++++++++---------------------- src/lib.rs | 2 +- 4 files changed, 91 insertions(+), 93 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..b33505e --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/src/arch/mod.rs b/src/arch/mod.rs index af11916..03ea04a 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -19,4 +19,4 @@ pub use aarch64::*; mod riscv64; #[cfg(target_arch = "riscv64")] -pub use riscv64::*; \ No newline at end of file +pub use riscv64::*; diff --git a/src/arch/riscv64.rs b/src/arch/riscv64.rs index 5f3d06d..5e42a03 100644 --- a/src/arch/riscv64.rs +++ b/src/arch/riscv64.rs @@ -1,91 +1,87 @@ -//! riscv64 arch-sepcific implementations - -use crate::{JumpEntry, JumpLabelType}; - - -/// Length of jump instruction to be replaced -pub const ARCH_JUMP_INS_LENGTH: usize = 4; - -const RISCV_INSN_JAL: u32 = 0x0000006f; - - -/// New instruction generated according to jump label type and jump entry -#[inline(always)] -pub fn arch_jump_entry_instruction( - jump_label_type: JumpLabelType, - jump_entry: &JumpEntry, -) -> [u8; ARCH_JUMP_INS_LENGTH] { - match jump_label_type { - // [offset ] [rd] [opcode ] - // [20|10:1|11|19:12] [rd] [1101111] - JumpLabelType::Jmp => { - // Note that riscv64 only supports relative address within +/-512k. - // In current implementation, this assumption is always hold. - let relative_addr = (jump_entry.target_addr() - jump_entry.code_addr()) as u32; - let mut jal = RISCV_INSN_JAL; - // MASK 19:12 = 0b_0000_0000_0000_1111_1111_0000_0000_0000 = 0x000FF000 - // MASK 11 = 0b_0000_0000_0000_0000_0000_1000_0000_0000 = 0x00000800 - // MASK 10:1 = 0b_0000_0000_0000_0000_0000_0111_1111_1110 = 0x000007FE - // MASK 20 = 0b_0000_0000_0001_0000_0000_0000_0000_0000 = 0x00100000 - jal |= - ((relative_addr & 0x000FF000) << 0) | - ((relative_addr & 0x00000800) << 9) | - ((relative_addr & 0x000007FE) << 20) | - ((relative_addr & 0x00100000) << 11); - jal.to_ne_bytes() - } - // RISCV_INSN_NOP 0x00000013 - JumpLabelType::Nop => [0x00, 0x00, 0x00, 0x13], - } -} - -#[doc(hidden)] -#[macro_export] -macro_rules! arch_static_key_init_nop_asm_template { - () => { - ::core::concat!( - r#" - .option push - .option norelax - .option norvc - 2: - nop - .option pop - .pushsection "#, - $crate::os_static_key_sec_name_attr!(), - r#" - .balign 8 - .quad 2b - . - .quad {0} - . - .quad {1} + {2} - . - .popsection - "# - ) - }; -} - - -#[doc(hidden)] -#[macro_export] -macro_rules! arch_static_key_init_jmp_asm_template { - () => { - ::core::concat!( - r#" - .option push - .option norelax - .option norvc - 2: - jal zero, {0} - .option pop - .pushsection "#, - $crate::os_static_key_sec_name_attr!(), - r#" - .balign 8 - .quad 2b - . - .quad {0} - . - .quad {1} + {2} - . - .popsection - "# - ) - }; -} +//! riscv64 arch-sepcific implementations + +use crate::{JumpEntry, JumpLabelType}; + +/// Length of jump instruction to be replaced +pub const ARCH_JUMP_INS_LENGTH: usize = 4; + +const RISCV_INSN_JAL: u32 = 0x0000006f; + +/// New instruction generated according to jump label type and jump entry +#[inline(always)] +pub fn arch_jump_entry_instruction( + jump_label_type: JumpLabelType, + jump_entry: &JumpEntry, +) -> [u8; ARCH_JUMP_INS_LENGTH] { + match jump_label_type { + // [offset ] [rd] [opcode ] + // [20|10:1|11|19:12] [rd] [1101111] + JumpLabelType::Jmp => { + // Note that riscv64 only supports relative address within +/-512k. + // In current implementation, this assumption is always hold. + let relative_addr = (jump_entry.target_addr() - jump_entry.code_addr()) as u32; + let mut jal = RISCV_INSN_JAL; + // MASK 19:12 = 0b_0000_0000_0000_1111_1111_0000_0000_0000 = 0x000FF000 + // MASK 11 = 0b_0000_0000_0000_0000_0000_1000_0000_0000 = 0x00000800 + // MASK 10:1 = 0b_0000_0000_0000_0000_0000_0111_1111_1110 = 0x000007FE + // MASK 20 = 0b_0000_0000_0001_0000_0000_0000_0000_0000 = 0x00100000 + jal |= ((relative_addr & 0x000FF000) << 0) + | ((relative_addr & 0x00000800) << 9) + | ((relative_addr & 0x000007FE) << 20) + | ((relative_addr & 0x00100000) << 11); + jal.to_ne_bytes() + } + // RISCV_INSN_NOP 0x00000013 + JumpLabelType::Nop => [0x00, 0x00, 0x00, 0x13], + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! arch_static_key_init_nop_asm_template { + () => { + ::core::concat!( + r#" + .option push + .option norelax + .option norvc + 2: + nop + .option pop + .pushsection "#, + $crate::os_static_key_sec_name_attr!(), + r#" + .balign 8 + .quad 2b - . + .quad {0} - . + .quad {1} + {2} - . + .popsection + "# + ) + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! arch_static_key_init_jmp_asm_template { + () => { + ::core::concat!( + r#" + .option push + .option norelax + .option norvc + 2: + jal zero, {0} + .option pop + .pushsection "#, + $crate::os_static_key_sec_name_attr!(), + r#" + .balign 8 + .quad 2b - . + .quad {0} - . + .quad {1} + {2} - . + .popsection + "# + ) + }; +} diff --git a/src/lib.rs b/src/lib.rs index ca1a54e..847b696 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -188,7 +188,7 @@ impl GenericStaticKey { /// Count of jump entries in __static_keys section. Note that /// there will be several dummy jump entries inside this section. -pub fn jump_entries_count()-> usize { +pub fn jump_entries_count() -> usize { let jump_entry_start_addr = core::ptr::addr_of_mut!(os::JUMP_ENTRY_START); let jump_entry_stop_addr = core::ptr::addr_of_mut!(os::JUMP_ENTRY_STOP); unsafe { jump_entry_stop_addr.offset_from(jump_entry_start_addr) as usize } From d973b5b9d65eb5e7e362bbb35c06e671caf78ec3 Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Tue, 6 Aug 2024 22:04:55 +0800 Subject: [PATCH 03/13] fix the error about riscv nop instruction --- .github/workflows/ci.yml | 1 + src/arch/riscv64.rs | 2 +- src/lib.rs | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d33e674..81e0ca3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,6 +50,7 @@ jobs: target: [ i686-unknown-linux-gnu, aarch64-unknown-linux-gnu, + riscv64gc-unknown-linux-gnu, ] steps: - name: checkout diff --git a/src/arch/riscv64.rs b/src/arch/riscv64.rs index 5e42a03..3510d7a 100644 --- a/src/arch/riscv64.rs +++ b/src/arch/riscv64.rs @@ -32,7 +32,7 @@ pub fn arch_jump_entry_instruction( jal.to_ne_bytes() } // RISCV_INSN_NOP 0x00000013 - JumpLabelType::Nop => [0x00, 0x00, 0x00, 0x13], + JumpLabelType::Nop => [0x13, 0x00, 0x00, 0x00], } } diff --git a/src/lib.rs b/src/lib.rs index 847b696..9dda30a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ use code_manipulate::CodeManipulator; /// /// The relative addresses will be updated to absolute address after calling [`global_init`]. This /// is because we want to sort the jump entries in place. +#[derive(Debug)] struct JumpEntry { /// Address of the JMP/NOP instruction to be modified. code: usize, @@ -375,6 +376,7 @@ unsafe fn static_key_update( } /// Type of the instructions to be modified +#[derive(Debug)] enum JumpLabelType { /// 5 byte NOP Nop = 0, From ec729f5cc602809ae7abd45ce7158b6f0a4765fe Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Wed, 7 Aug 2024 13:25:20 +0800 Subject: [PATCH 04/13] add loongarch64 arch support --- .github/workflows/ci.yml | 1 + src/arch/loongarch64.rs | 74 ++++++++++++++++++++++++++++++++++++++++ src/arch/mod.rs | 6 +++- src/lib.rs | 9 +++-- 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 src/arch/loongarch64.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81e0ca3..f8f636c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,6 +51,7 @@ jobs: i686-unknown-linux-gnu, aarch64-unknown-linux-gnu, riscv64gc-unknown-linux-gnu, + loongarch64-unknown-linux-gnu, ] steps: - name: checkout diff --git a/src/arch/loongarch64.rs b/src/arch/loongarch64.rs new file mode 100644 index 0000000..d452f07 --- /dev/null +++ b/src/arch/loongarch64.rs @@ -0,0 +1,74 @@ +//! loongarch64 arch-sepcific implementations + +use crate::{JumpEntry, JumpLabelType}; + +/// Length of jump instruction to be replaced +pub const ARCH_JUMP_INS_LENGTH: usize = 4; + +const LOONGARCH64_INSN_NOP: u32 = 0x03400000; +const LOONGARCH64_INSN_B: u32 = 0x50000000; +/// New instruction generated according to jump label type and jump entry +#[inline(always)] +pub fn arch_jump_entry_instruction( + jump_label_type: JumpLabelType, + jump_entry: &JumpEntry, +) -> [u8; ARCH_JUMP_INS_LENGTH] { + match jump_label_type { + // 010100 [IMM] + // opcode I26[15:0] I26[25:16] + JumpLabelType::Jmp => { + // Note that loongarch64 only supports relative address within +/-128MB. + // In current implementation, this assumption is always hold. + let relative_addr = (jump_entry.target_addr() - jump_entry.code_addr()) as u32; + // MASK 25:16 = 0b_0000_0011_1111_1111_0000_0000_0000_0000 = 0x03FF0000 + // MASK 15:0 = 0b_0000_0000_0000_0000_1111_1111_1111_1111 = 0x0000FFFF + let mut b = LOONGARCH64_INSN_B; + let relative_addr = relative_addr >> 2; + b |= ((relative_addr & 0x03FF0000) >> 16) | ((relative_addr & 0x0000FFFF) << 10); + b.to_ne_bytes() + } + JumpLabelType::Nop => LOONGARCH64_INSN_NOP.to_ne_bytes(), + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! arch_static_key_init_nop_asm_template { + () => { + ::core::concat!( + r#" + 2: + nop + .pushsection "#, + $crate::os_static_key_sec_name_attr!(), + r#" + .balign 8 + .quad 2b - 0 + .quad {0} - 0 + .quad {1} + {2} - 0 + .popsection + "# + ) + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! arch_static_key_init_jmp_asm_template { + () => { + ::core::concat!( + r#" + 2: + b {0} + .pushsection "#, + $crate::os_static_key_sec_name_attr!(), + r#" + .balign 8 + .quad 2b - 0 + .quad {0} - 0 + .quad {1} + {2} - 0 + .popsection + "# + ) + }; +} diff --git a/src/arch/mod.rs b/src/arch/mod.rs index 03ea04a..cce03c3 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -17,6 +17,10 @@ pub use aarch64::*; #[cfg(target_arch = "riscv64")] mod riscv64; - #[cfg(target_arch = "riscv64")] pub use riscv64::*; + +#[cfg(target_arch = "loongarch64")] +mod loongarch64; +#[cfg(target_arch = "loongarch64")] +pub use loongarch64::*; diff --git a/src/lib.rs b/src/lib.rs index 9dda30a..7f09b76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,9 +35,12 @@ impl JumpEntry { /// Update fields to be absolute address #[cfg(not(all(target_os = "windows", target_arch = "x86_64")))] fn make_relative_address_absolute(&mut self) { - self.code = (core::ptr::addr_of!(self.code) as usize).wrapping_add(self.code); - self.target = (core::ptr::addr_of!(self.target) as usize).wrapping_add(self.target); - self.key = (core::ptr::addr_of!(self.key) as usize).wrapping_add(self.key); + #[cfg(not(target_arch = "loongarch64"))] + { + self.code = (core::ptr::addr_of!(self.code) as usize).wrapping_add(self.code); + self.target = (core::ptr::addr_of!(self.target) as usize).wrapping_add(self.target); + self.key = (core::ptr::addr_of!(self.key) as usize).wrapping_add(self.key); + } } // For Win64, the relative address is truncated into 32bit. From 9755973ae662006fa057330fc0654ac4e01429c3 Mon Sep 17 00:00:00 2001 From: linfeng Date: Wed, 7 Aug 2024 13:30:03 +0800 Subject: [PATCH 05/13] Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8f636c..34d3d00 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: - name: checkout uses: actions/checkout@v4 - name: Set up cross - run: cargo install cross + run: cargo install cross --git https://github.com/cross-rs/cross - name: Build all features run: cross build --verbose --all-features --target ${{ matrix.target }} - name: Run tests From e9689fa37186dcbe5d528f12740e8c510cef964b Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Fri, 9 Aug 2024 17:12:57 +0800 Subject: [PATCH 06/13] use relative addresses for jump entry --- src/arch/loongarch64.rs | 12 ++++++------ src/lib.rs | 9 +++------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/arch/loongarch64.rs b/src/arch/loongarch64.rs index d452f07..92527f2 100644 --- a/src/arch/loongarch64.rs +++ b/src/arch/loongarch64.rs @@ -43,9 +43,9 @@ macro_rules! arch_static_key_init_nop_asm_template { $crate::os_static_key_sec_name_attr!(), r#" .balign 8 - .quad 2b - 0 - .quad {0} - 0 - .quad {1} + {2} - 0 + .quad 2b - . + .quad {0} - . + .quad {1} + {2} - . .popsection "# ) @@ -64,9 +64,9 @@ macro_rules! arch_static_key_init_jmp_asm_template { $crate::os_static_key_sec_name_attr!(), r#" .balign 8 - .quad 2b - 0 - .quad {0} - 0 - .quad {1} + {2} - 0 + .quad 2b - . + .quad {0} - . + .quad {1} + {2} - . .popsection "# ) diff --git a/src/lib.rs b/src/lib.rs index 7f09b76..9dda30a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,12 +35,9 @@ impl JumpEntry { /// Update fields to be absolute address #[cfg(not(all(target_os = "windows", target_arch = "x86_64")))] fn make_relative_address_absolute(&mut self) { - #[cfg(not(target_arch = "loongarch64"))] - { - self.code = (core::ptr::addr_of!(self.code) as usize).wrapping_add(self.code); - self.target = (core::ptr::addr_of!(self.target) as usize).wrapping_add(self.target); - self.key = (core::ptr::addr_of!(self.key) as usize).wrapping_add(self.key); - } + self.code = (core::ptr::addr_of!(self.code) as usize).wrapping_add(self.code); + self.target = (core::ptr::addr_of!(self.target) as usize).wrapping_add(self.target); + self.key = (core::ptr::addr_of!(self.key) as usize).wrapping_add(self.key); } // For Win64, the relative address is truncated into 32bit. From 63537ab644e6549e014c04e1af99c99364fe1c1a Mon Sep 17 00:00:00 2001 From: linfeng Date: Wed, 7 Aug 2024 13:30:03 +0800 Subject: [PATCH 07/13] Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8f636c..34d3d00 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: - name: checkout uses: actions/checkout@v4 - name: Set up cross - run: cargo install cross + run: cargo install cross --git https://github.com/cross-rs/cross - name: Build all features run: cross build --verbose --all-features --target ${{ matrix.target }} - name: Run tests From 74a89ac8a89647b7780f6bc30d046c64db00045c Mon Sep 17 00:00:00 2001 From: Evian-Zhang Date: Thu, 8 Aug 2024 16:12:52 +0800 Subject: [PATCH 08/13] Add windows cache flush --- Cargo.toml | 2 +- src/os/windows.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bf80bb0..c9c9e97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ libc = { version = "0.2", default-features = false } mach2 = "0.4" [target.'cfg(target_os = "windows")'.dependencies] -windows = { version = "0.58", features = ["Win32_System_SystemInformation", "Win32_System_Memory"] } +windows = { version = "0.58", features = ["Win32_System_SystemInformation", "Win32_System_Memory", "Win32_System_Threading", "Win32_System_Diagnostics_Debug"] } [dev-dependencies] trybuild = "1" diff --git a/src/os/windows.rs b/src/os/windows.rs index e4dd1fd..e82c6d2 100644 --- a/src/os/windows.rs +++ b/src/os/windows.rs @@ -1,8 +1,10 @@ //! Windows-specific implementations use windows::Win32::System::{ + Diagnostics::Debug::FlushInstructionCache, Memory::{VirtualProtect, PAGE_EXECUTE_READWRITE, PAGE_PROTECTION_FLAGS}, SystemInformation::{GetSystemInfo, SYSTEM_INFO}, + Threading::GetCurrentProcess, }; use crate::{code_manipulate::CodeManipulator, JumpEntry}; @@ -69,5 +71,9 @@ impl CodeManipulator for ArchCodeManipulator { if res.is_err() { panic!("Unable to restore code region to non-writable"); } + let res = unsafe { FlushInstructionCache(GetCurrentProcess(), Some(addr), L) }; + if res.is_err() { + panic!("Failed to flush instruction cache"); + } } } From 778a3a905056543c63c62948ffd3f4ebfb2aa4b1 Mon Sep 17 00:00:00 2001 From: Evian-Zhang Date: Fri, 9 Aug 2024 15:57:04 +0800 Subject: [PATCH 09/13] Force 5-byte JMP in x86 and x86-64 --- src/arch/x86_64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arch/x86_64.rs b/src/arch/x86_64.rs index 5f9f47e..47e6966 100644 --- a/src/arch/x86_64.rs +++ b/src/arch/x86_64.rs @@ -51,8 +51,8 @@ macro_rules! arch_static_key_init_jmp_asm_template { ::core::concat!( r#" 2: - jmp {0} - .byte 0x90,0x90,0x90 + .byte 0xe9 + .long ({0} - 4) - . .pushsection "#, $crate::os_static_key_sec_name_attr!(), r#" From 7ebda6b5ad37109b35ee33077c8f25a0c1f23daf Mon Sep 17 00:00:00 2001 From: Evian-Zhang Date: Fri, 9 Aug 2024 15:58:50 +0800 Subject: [PATCH 10/13] Force 5-byte JMP in x86 and x86-64 --- src/arch/x86.rs | 7 ++++--- src/arch/x86_64.rs | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/arch/x86.rs b/src/arch/x86.rs index 16bc9ae..e1c4bb1 100644 --- a/src/arch/x86.rs +++ b/src/arch/x86.rs @@ -43,7 +43,8 @@ macro_rules! arch_static_key_init_nop_asm_template { }; } -// The `0x90,0x90,0x90` are three NOPs, which is to make sure the `jmp {0}` is at least 5 bytes long. +// Here we do not use `jmp {0}` because it may be compiled into a 3-byte jmp instead of 5 byte. +// See https://stackoverflow.com/q/74771372/10005095 #[doc(hidden)] #[macro_export] macro_rules! arch_static_key_init_jmp_asm_template { @@ -51,8 +52,8 @@ macro_rules! arch_static_key_init_jmp_asm_template { ::core::concat!( r#" 2: - jmp {0} - .byte 0x90,0x90,0x90 + .byte 0xe9 + .long ({0} - 4) - . .pushsection "#, $crate::os_static_key_sec_name_attr!(), r#" diff --git a/src/arch/x86_64.rs b/src/arch/x86_64.rs index 47e6966..c4ea629 100644 --- a/src/arch/x86_64.rs +++ b/src/arch/x86_64.rs @@ -43,7 +43,8 @@ macro_rules! arch_static_key_init_nop_asm_template { }; } -// The `0x90,0x90,0x90` are three NOPs, which is to make sure the `jmp {0}` is at least 5 bytes long. +// Here we do not use `jmp {0}` because it may be compiled into a 3-byte jmp instead of 5 byte. +// See https://stackoverflow.com/q/74771372/10005095 #[doc(hidden)] #[macro_export] macro_rules! arch_static_key_init_jmp_asm_template { From 9b7243a1fb3362ef8851c0c6d6eaa5a16131e940 Mon Sep 17 00:00:00 2001 From: Evian-Zhang Date: Fri, 9 Aug 2024 16:29:45 +0800 Subject: [PATCH 11/13] Use mmap and mremap to allow multi-thread static key modifying. Add clear cache for linux OS --- Cargo.toml | 1 + src/os/linux.rs | 48 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c9c9e97..e41e888 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ maintenance = { status = "actively-developed" } [target.'cfg(target_os = "linux")'.dependencies] libc = { version = "0.2", default-features = false } +clear-cache = "0.1" [target.'cfg(target_os = "macos")'.dependencies] mach2 = "0.4" diff --git a/src/os/linux.rs b/src/os/linux.rs index 3dbe59c..a00cab9 100644 --- a/src/os/linux.rs +++ b/src/os/linux.rs @@ -40,26 +40,56 @@ impl CodeManipulator for ArchCodeManipulator { } else { page_size }; - let res = unsafe { - libc::mprotect( - aligned_addr, + + // Create a temp mmap, which will store updated content of corresponding pages + let mmaped_addr = unsafe { + libc::mmap( + core::ptr::null_mut(), aligned_length, - libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, + -1, + 0, ) }; - if res != 0 { - panic!("Unable to make code region writable"); + if mmaped_addr == libc::MAP_FAILED { + panic!("Failed to create temp mappings"); + } + unsafe { + let addr_in_mmap = mmaped_addr.offset(addr.offset_from(aligned_addr)); + core::ptr::copy_nonoverlapping(aligned_addr, mmaped_addr, aligned_length); + core::ptr::copy_nonoverlapping(data.as_ptr(), addr_in_mmap.cast(), L); } - core::ptr::copy_nonoverlapping(data.as_ptr(), addr.cast(), L); let res = unsafe { libc::mprotect( - aligned_addr, + mmaped_addr, aligned_length, libc::PROT_READ | libc::PROT_EXEC, ) }; if res != 0 { - panic!("Unable to restore code region to non-writable"); + panic!("Unable to make mmaped mapping executable."); + } + // Remap the created temp mmaping to replace old mapping + let res = unsafe { + libc::mremap( + mmaped_addr, + aligned_length, + aligned_length, + libc::MREMAP_MAYMOVE | libc::MREMAP_FIXED, + // Any previous mapping at the address range specified by new_address and new_size is unmapped. + // So, no memory leak + aligned_addr, + ) + }; + if res == libc::MAP_FAILED { + panic!("Failed to mremap."); + } + let res = unsafe { + clear_cache::clear_cache(addr, addr.add(L)); + }; + if !res { + panic!("Failed to clear cache."); } } } From 07ef7391f6ed5feec2beacc1f5d848233d952e72 Mon Sep 17 00:00:00 2001 From: Evian-Zhang Date: Fri, 9 Aug 2024 16:30:48 +0800 Subject: [PATCH 12/13] Fix typo --- src/os/linux.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/os/linux.rs b/src/os/linux.rs index a00cab9..ac385b7 100644 --- a/src/os/linux.rs +++ b/src/os/linux.rs @@ -85,9 +85,7 @@ impl CodeManipulator for ArchCodeManipulator { if res == libc::MAP_FAILED { panic!("Failed to mremap."); } - let res = unsafe { - clear_cache::clear_cache(addr, addr.add(L)); - }; + let res = unsafe { clear_cache::clear_cache(addr, addr.add(L)) }; if !res { panic!("Failed to clear cache."); } From b70916d8fe3f08bfd183700629d4f0ebf9a28715 Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Fri, 9 Aug 2024 17:15:38 +0800 Subject: [PATCH 13/13] s --- Cargo.lock | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 46694dc..e0471c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "clear-cache" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20d9da0bc09582e0aa48f88476160bfe0f5f82cf97fc47eef1f701b7f59e27d2" +dependencies = [ + "libc", + "windows", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -125,6 +135,7 @@ dependencies = [ name = "static-keys" version = "0.4.0" dependencies = [ + "clear-cache", "libc", "mach2", "trybuild",