Skip to content

Commit dc0f126

Browse files
committed
CFI in asm
1 parent 744d628 commit dc0f126

File tree

18 files changed

+348
-60
lines changed

18 files changed

+348
-60
lines changed

definitions/src/asm.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{RISCV_GENERAL_REGISTER_NUMBER, instructions::Instruction};
1+
use crate::{DEFAULT_SHADOW_STACK_SIZE, RISCV_GENERAL_REGISTER_NUMBER, instructions::Instruction};
22
use std::alloc::{Layout, dealloc};
33

44
// The number of trace items to keep
@@ -15,6 +15,8 @@ pub const RET_OUT_OF_BOUND: u8 = 7;
1515
pub const RET_INVALID_PERMISSION: u8 = 8;
1616
pub const RET_SLOWPATH: u8 = 9;
1717
pub const RET_PAUSE: u8 = 10;
18+
pub const RET_SHADOW_STACK_SOFTWARE_CHECK_EXCEPTION: u8 = 11;
19+
pub const RET_SHADOW_STACK_STACK_OUT_OF_STACK: u8 = 12;
1820

1921
#[inline(always)]
2022
pub fn calculate_slot(addr: u64) -> usize {
@@ -100,6 +102,11 @@ pub struct AsmCoreMachine {
100102
pub memory_ptr: u64,
101103
pub flags_ptr: u64,
102104
pub frames_ptr: u64,
105+
106+
pub cfi: u8,
107+
pub elp: u32,
108+
pub shadow_stack: [u8; DEFAULT_SHADOW_STACK_SIZE],
109+
pub ssp: u64,
103110
}
104111

105112
impl Drop for AsmCoreMachine {

definitions/src/generate_asm_constants.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
use ckb_vm_definitions::{
2-
MEMORY_FRAME_PAGE_SHIFTS, MEMORY_FRAME_SHIFTS, MEMORY_FRAMESIZE, RISCV_PAGE_SHIFTS,
3-
RISCV_PAGESIZE,
2+
DEFAULT_SHADOW_STACK_SIZE, MEMORY_FRAME_PAGE_SHIFTS, MEMORY_FRAME_SHIFTS, MEMORY_FRAMESIZE,
3+
RISCV_PAGE_SHIFTS, RISCV_PAGESIZE,
44
asm::{
55
AsmCoreMachine, FixedTrace, InvokeData, RET_CYCLES_OVERFLOW, RET_DECODE_TRACE,
66
RET_DYNAMIC_JUMP, RET_EBREAK, RET_ECALL, RET_INVALID_PERMISSION, RET_MAX_CYCLES_EXCEEDED,
7-
RET_OUT_OF_BOUND, RET_PAUSE, RET_SLOWPATH, TRACE_ITEM_LENGTH,
7+
RET_OUT_OF_BOUND, RET_PAUSE, RET_SHADOW_STACK_SOFTWARE_CHECK_EXCEPTION,
8+
RET_SHADOW_STACK_STACK_OUT_OF_STACK, RET_SLOWPATH, TRACE_ITEM_LENGTH,
89
},
910
for_each_inst,
1011
instructions::{MAXIMUM_OPCODE, MINIMAL_OPCODE, instruction_opcode_name},
1112
memory::{FLAG_DIRTY, FLAG_EXECUTABLE, FLAG_FREEZED, FLAG_WRITABLE, FLAG_WXORX_BIT},
12-
registers::{RA, SP},
13+
registers::{RA, SP, T2},
1314
};
1415
use std::alloc::{Layout, alloc};
1516
use std::mem::{size_of, zeroed};
@@ -70,10 +71,19 @@ fn main() {
7071
);
7172
println!("#define CKB_VM_ASM_RET_SLOWPATH {}", RET_SLOWPATH);
7273
println!("#define CKB_VM_ASM_RET_PAUSE {}", RET_PAUSE);
74+
println!(
75+
"#define CKB_VM_ASM_RET_SHADOW_STACK_SOFTWARE_CHECK_EXCEPTION {}",
76+
RET_SHADOW_STACK_SOFTWARE_CHECK_EXCEPTION
77+
);
78+
println!(
79+
"#define CKB_VM_ASM_RET_SHADOW_STACK_STACK_OUT_OF_STACK {}",
80+
RET_SHADOW_STACK_STACK_OUT_OF_STACK
81+
);
7382
println!();
7483

7584
println!("#define CKB_VM_ASM_REGISTER_RA {}", RA);
7685
println!("#define CKB_VM_ASM_REGISTER_SP {}", SP);
86+
println!("#define CKB_VM_ASM_REGISTER_T2 {}", T2);
7787
println!();
7888

7989
println!("#define CKB_VM_ASM_MEMORY_FLAG_FREEZED {}", FLAG_FREEZED);
@@ -209,6 +219,22 @@ fn main() {
209219
"#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_FRAMES_PTR {}",
210220
(&m.frames_ptr as *const u64 as usize) - m_address
211221
);
222+
println!(
223+
"#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_CFI {}",
224+
(&m.cfi as *const u8 as usize) - m_address
225+
);
226+
println!(
227+
"#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_ELP {}",
228+
(&m.elp as *const u32 as usize) - m_address
229+
);
230+
println!(
231+
"#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_SHADOW_STACK {}",
232+
(&m.shadow_stack as *const [u8; DEFAULT_SHADOW_STACK_SIZE] as usize) - m_address
233+
);
234+
println!(
235+
"#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_SSP {}",
236+
(&m.ssp as *const u64 as usize) - m_address
237+
);
212238
println!();
213239

214240
for op in MINIMAL_OPCODE..MAXIMUM_OPCODE {

fuzz/fuzz_targets/isa_a.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ fuzz_target!(|data: [u8; 512]| {
8686
}
8787

8888
let inst = inst | ((rs1 as u32) << 15) | ((rs2 as u32) << 20) | ((rd as u32) << 7);
89-
let insn = ckb_vm::instructions::a::factory::<u64>(inst, ckb_vm_version).unwrap();
89+
let insn =
90+
ckb_vm::instructions::a::factory::<u64>(inst, ckb_vm_version, Default::default())
91+
.unwrap();
9092

9193
spike.execute(inst as u64).unwrap();
9294
ckb_vm::instructions::execute_instruction(insn, &mut ckb_vm_int).unwrap();

fuzz/fuzz_targets/isa_b.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ fuzz_target!(|data: [u8; 512]| {
112112
let mask = insts[choose].1;
113113

114114
let inst = inst | (mask & deque.u32());
115-
let insn = ckb_vm::instructions::b::factory::<u64>(inst, ckb_vm_version).unwrap();
115+
let insn =
116+
ckb_vm::instructions::b::factory::<u64>(inst, ckb_vm_version, Default::default())
117+
.unwrap();
116118

117119
spike.execute(inst as u64).unwrap();
118120
ckb_vm::instructions::execute_instruction(insn, &mut ckb_vm_int).unwrap();

fuzz/fuzz_targets/snapshot2.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ fuzz_target!(|data: [u8; 96]| {
112112
let metadata = ProgramMetadata {
113113
actions: loading_action_vec.clone(),
114114
entry: 0,
115+
cfi: Default::default(),
115116
};
116117

117118
let mut machine1 = build_machine();

src/elf.rs

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This module maps the data structure of different versions of goblin to the
22
// same internal structure.
3-
use crate::machine::{VERSION1, VERSION3};
3+
use crate::machine::{VERSION0, VERSION1, VERSION2, VERSION3};
44
use crate::memory::{FLAG_EXECUTABLE, FLAG_FREEZED, round_page_down, round_page_up};
55
use crate::{Error, Register};
66
use bytes::Bytes;
@@ -143,6 +143,24 @@ pub struct CFI {
143143
pub lp_func_sig: bool,
144144
}
145145

146+
impl From<u8> for CFI {
147+
fn from(byte: u8) -> Self {
148+
Self {
149+
lp_unlabeled: byte & 0b0000_0001 != 0,
150+
ss: byte & 0b0000_0010 != 0,
151+
lp_func_sig: byte & 0b0000_0100 != 0,
152+
}
153+
}
154+
}
155+
156+
impl From<CFI> for u8 {
157+
fn from(val: CFI) -> Self {
158+
(if val.lp_unlabeled { 0b0000_0001 } else { 0 })
159+
| (if val.ss { 0b0000_0010 } else { 0 })
160+
| (if val.lp_func_sig { 0b0000_0100 } else { 0 })
161+
}
162+
}
163+
146164
#[derive(Default)]
147165
pub struct ParseElfPortableData {
148166
pub entry: u64,
@@ -154,10 +172,7 @@ pub struct ParseElfPortableData {
154172
impl ParseElfPortableData {
155173
pub fn from_v0<R: Register>(program: &Bytes) -> Result<Self, Error> {
156174
use goblin_v023::container::Ctx;
157-
use goblin_v023::elf::{
158-
Header, program_header::ProgramHeader as GoblinProgramHeader,
159-
section_header::SectionHeader as GoblinSectionHeader,
160-
};
175+
use goblin_v023::elf::{Header, program_header::ProgramHeader as GoblinProgramHeader};
161176
let header = program.pread::<Header>(0)?;
162177
let container = header.container().map_err(|_e| Error::ElfBits)?;
163178
let endianness = header.endianness().map_err(|_e| Error::ElfBits)?;
@@ -174,15 +189,35 @@ impl ParseElfPortableData {
174189
.iter()
175190
.map(ProgramHeader::from_v0)
176191
.collect();
177-
let section_headers = GoblinSectionHeader::parse(
192+
let section_headers = vec![];
193+
Ok(Self {
194+
entry: header.e_entry,
195+
program_headers,
196+
section_headers,
197+
shstrtab_offset: header.e_shstrndx as usize,
198+
})
199+
}
200+
201+
pub fn from_v1<R: Register>(program: &Bytes) -> Result<Self, Error> {
202+
use goblin_v040::container::Ctx;
203+
use goblin_v040::elf::{Header, program_header::ProgramHeader as GoblinProgramHeader};
204+
let header = program.pread::<Header>(0)?;
205+
let container = header.container().map_err(|_e| Error::ElfBits)?;
206+
let endianness = header.endianness().map_err(|_e| Error::ElfBits)?;
207+
if R::BITS != if container.is_big() { 64 } else { 32 } {
208+
return Err(Error::ElfBits);
209+
}
210+
let ctx = Ctx::new(container, endianness);
211+
let program_headers = GoblinProgramHeader::parse(
178212
program,
179-
header.e_shoff as usize,
180-
header.e_shnum as usize,
213+
header.e_phoff as usize,
214+
header.e_phnum as usize,
181215
ctx,
182216
)?
183217
.iter()
184-
.map(SectionHeader::from_v0)
218+
.map(ProgramHeader::from_v1)
185219
.collect();
220+
let section_headers = vec![];
186221
Ok(Self {
187222
entry: header.e_entry,
188223
program_headers,
@@ -191,7 +226,7 @@ impl ParseElfPortableData {
191226
})
192227
}
193228

194-
pub fn from_v1<R: Register>(program: &Bytes) -> Result<Self, Error> {
229+
pub fn from_v3<R: Register>(program: &Bytes) -> Result<Self, Error> {
195230
use goblin_v040::container::Ctx;
196231
use goblin_v040::elf::{
197232
Header, program_header::ProgramHeader as GoblinProgramHeader,
@@ -256,15 +291,15 @@ fn parse_gnu_property_note(note_data: &[u8]) -> Result<CFI, Error> {
256291
));
257292
}
258293
offset += 8;
259-
if pr_type == GNU_PROPERTY_RISCV_FEATURE_1_AND && pr_datasz >= 4 {
260-
if offset + 4 <= note_data.len() {
261-
buf.copy_from_slice(&note_data[offset..offset + 4]);
262-
let feature_flags = u32::from_le_bytes(buf);
263-
cfi.lp_unlabeled =
264-
feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED != 0;
265-
cfi.ss = feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS != 0;
266-
cfi.lp_func_sig = feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG != 0;
267-
}
294+
if pr_type == GNU_PROPERTY_RISCV_FEATURE_1_AND
295+
&& pr_datasz >= 4
296+
&& offset + 4 <= note_data.len()
297+
{
298+
buf.copy_from_slice(&note_data[offset..offset + 4]);
299+
let feature_flags = u32::from_le_bytes(buf);
300+
cfi.lp_unlabeled = feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED != 0;
301+
cfi.ss = feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS != 0;
302+
cfi.lp_func_sig = feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG != 0;
268303
}
269304
// Align to 8 bytes for next property.
270305
let aligned_datasz = (pr_datasz + 7) & !7;
@@ -276,10 +311,11 @@ fn parse_gnu_property_note(note_data: &[u8]) -> Result<CFI, Error> {
276311
pub fn parse_elf<R: Register>(program: &Bytes, version: u32) -> Result<ProgramMetadata, Error> {
277312
// We did not use Elf::parse here to avoid triggering potential bugs in goblin.
278313
// * https://github.com/nervosnetwork/ckb-vm/issues/143
279-
let pepd = if version < VERSION1 {
280-
ParseElfPortableData::from_v0::<R>(program)?
281-
} else {
282-
ParseElfPortableData::from_v1::<R>(program)?
314+
let pepd = match version {
315+
VERSION0 => ParseElfPortableData::from_v0::<R>(program)?,
316+
VERSION1 | VERSION2 => ParseElfPortableData::from_v1::<R>(program)?,
317+
VERSION3 => ParseElfPortableData::from_v3::<R>(program)?,
318+
_ => ParseElfPortableData::from_v3::<R>(program)?,
283319
};
284320
let mut cfi = CFI::default();
285321
// CFI will only be parsed when using version 3. This avoids errors in older code from

src/instructions/execute.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{instructions::tagged::TaggedInstruction, memory::Memory};
88
use ckb_vm_definitions::{
99
for_each_inst_array1, for_each_inst_match2,
1010
instructions::{self as insts, paste},
11-
registers::{RA, T0, T2},
11+
registers::{RA, T2},
1212
};
1313

1414
pub fn handle_sub<Mac: Machine>(machine: &mut Mac, inst: Instruction) -> Result<(), Error> {
@@ -555,10 +555,8 @@ pub fn handle_jalr_version1<Mac: Machine>(
555555
next_pc = next_pc & (!Mac::REG::one());
556556
update_register(machine, i.rd(), link);
557557
machine.update_pc(next_pc);
558-
if machine.cfi().lp_unlabeled {
559-
if i.rs1() != RA && i.rs1() != T0 && i.rs1() != T2 {
560-
machine.set_elp(1);
561-
}
558+
if inst & (1 << 28) != 0 {
559+
machine.set_elp(1);
562560
}
563561
Ok(())
564562
}

src/instructions/i.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use ckb_vm_definitions::instructions as insts;
2+
use ckb_vm_definitions::registers::{RA, T0, T2};
23

34
use super::utils::{
45
btype_immediate, funct3, funct7, itype_immediate, jalr, jtype_immediate, lb, lbu, ld, lh, lhu,
@@ -32,7 +33,7 @@ impl FenceType {
3233
}
3334
}
3435

35-
pub fn factory<R: Register>(instruction_bits: u32, version: u32, _: CFI) -> Option<Instruction> {
36+
pub fn factory<R: Register>(instruction_bits: u32, version: u32, cfi: CFI) -> Option<Instruction> {
3637
let bit_length = R::BITS;
3738
if bit_length != 32 && bit_length != 64 {
3839
return None;
@@ -70,13 +71,14 @@ pub fn factory<R: Register>(instruction_bits: u32, version: u32, _: CFI) -> Opti
7071
_ => None,
7172
};
7273
inst_opt.map(|inst| {
73-
Itype::new_s(
74-
inst,
75-
rd(instruction_bits),
76-
rs1(instruction_bits),
77-
itype_immediate(instruction_bits),
78-
)
79-
.0
74+
let rd = rd(instruction_bits);
75+
let rs1 = rs1(instruction_bits);
76+
let n = Itype::new_s(inst, rd, rs1, itype_immediate(instruction_bits)).0;
77+
if cfi.lp_unlabeled && rs1 != RA && rs1 != T0 && rs1 != T2 {
78+
n | (1 << 28) // Mark as a cfi jump for CFI
79+
} else {
80+
n
81+
}
8082
})
8183
}
8284
0b_0000011 => {

src/machine/asm/cdefinitions_generated.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
#define CKB_VM_ASM_RET_INVALID_PERMISSION 8
1818
#define CKB_VM_ASM_RET_SLOWPATH 9
1919
#define CKB_VM_ASM_RET_PAUSE 10
20+
#define CKB_VM_ASM_RET_SHADOW_STACK_SOFTWARE_CHECK_EXCEPTION 11
21+
#define CKB_VM_ASM_RET_SHADOW_STACK_STACK_OUT_OF_STACK 12
2022

2123
#define CKB_VM_ASM_REGISTER_RA 1
2224
#define CKB_VM_ASM_REGISTER_SP 2
25+
#define CKB_VM_ASM_REGISTER_T2 7
2326

2427
#define CKB_VM_ASM_MEMORY_FLAG_FREEZED 1
2528
#define CKB_VM_ASM_MEMORY_FLAG_EXECUTABLE 2
@@ -54,6 +57,10 @@
5457
#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_MEMORY_PTR 368
5558
#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_FLAGS_PTR 376
5659
#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_FRAMES_PTR 384
60+
#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_CFI 392
61+
#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_ELP 396
62+
#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_SHADOW_STACK 400
63+
#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_SSP 65936
5764

5865
#define CKB_VM_ASM_OP_UNLOADED 16
5966
#define CKB_VM_ASM_OP_ADD 17
@@ -211,7 +218,13 @@
211218
#define CKB_VM_ASM_OP_JALR_VERSION1 169
212219
#define CKB_VM_ASM_OP_FAR_JUMP_REL 170
213220
#define CKB_VM_ASM_OP_FAR_JUMP_ABS 171
214-
#define CKB_VM_ASM_OP_CUSTOM_ASM_TRACE_JUMP 172
221+
#define CKB_VM_ASM_OP_LPAD 172
222+
#define CKB_VM_ASM_OP_SSPUSH 173
223+
#define CKB_VM_ASM_OP_SSPOPCHK 174
224+
#define CKB_VM_ASM_OP_SSRDP 175
225+
#define CKB_VM_ASM_OP_SSAMOSWAP_W 176
226+
#define CKB_VM_ASM_OP_SSAMOSWAP_D 177
227+
#define CKB_VM_ASM_OP_CUSTOM_ASM_TRACE_JUMP 178
215228

216229
#ifdef CKB_VM_ASM_GENERATE_LABEL_TABLES
217230
#ifdef __APPLE__
@@ -394,6 +407,12 @@
394407
.long .CKB_VM_ASM_LABEL_OP_JALR_VERSION1 - .CKB_VM_ASM_LABEL_TABLE
395408
.long .CKB_VM_ASM_LABEL_OP_FAR_JUMP_REL - .CKB_VM_ASM_LABEL_TABLE
396409
.long .CKB_VM_ASM_LABEL_OP_FAR_JUMP_ABS - .CKB_VM_ASM_LABEL_TABLE
410+
.long .CKB_VM_ASM_LABEL_OP_LPAD - .CKB_VM_ASM_LABEL_TABLE
411+
.long .CKB_VM_ASM_LABEL_OP_SSPUSH - .CKB_VM_ASM_LABEL_TABLE
412+
.long .CKB_VM_ASM_LABEL_OP_SSPOPCHK - .CKB_VM_ASM_LABEL_TABLE
413+
.long .CKB_VM_ASM_LABEL_OP_SSRDP - .CKB_VM_ASM_LABEL_TABLE
414+
.long .CKB_VM_ASM_LABEL_OP_SSAMOSWAP_W - .CKB_VM_ASM_LABEL_TABLE
415+
.long .CKB_VM_ASM_LABEL_OP_SSAMOSWAP_D - .CKB_VM_ASM_LABEL_TABLE
397416
.long .CKB_VM_ASM_LABEL_OP_CUSTOM_ASM_TRACE_JUMP - .CKB_VM_ASM_LABEL_TABLE
398417
.long .CKB_VM_ASM_LABEL_OP_CUSTOM_TRACE_END - .CKB_VM_ASM_LABEL_TABLE
399418
#endif /* CKB_VM_ASM_GENERATE_LABEL_TABLES */

0 commit comments

Comments
 (0)