From 3edd35eabbaec9d791f6c86f708f207f96d12f63 Mon Sep 17 00:00:00 2001 From: Lucas <lucas.tnagel@gmail.com> Date: Thu, 10 Oct 2024 12:08:42 -0300 Subject: [PATCH 1/3] Modify assembler and disassembler --- src/assembler.rs | 7 ++++++- src/disassembler.rs | 15 ++++----------- src/ebpf.rs | 10 ++++++---- src/insn_builder.rs | 2 +- src/interpreter.rs | 3 ++- src/jit.rs | 3 ++- tests/assembler.rs | 13 +++++++++++++ tests/disassembler.rs | 9 +++++++++ 8 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/assembler.rs b/src/assembler.rs index 46a88e65..cc4c721a 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -122,7 +122,11 @@ fn make_instruction_map(sbpf_version: SBPFVersion) -> HashMap<String, (Instructi // Miscellaneous. entry("ja", JumpUnconditional, ebpf::JA); - entry("syscall", Syscall, ebpf::CALL_IMM); + if sbpf_version == SBPFVersion::V1 { + entry("syscall", Syscall, ebpf::CALL_IMM); + } else { + entry("syscall", Syscall, ebpf::SYSCALL); + } entry("call", CallImm, ebpf::CALL_IMM); entry("callx", CallReg, ebpf::CALL_REG); entry("lddw", LoadDwImm, ebpf::LD_DW_IMM); @@ -450,6 +454,7 @@ pub fn assemble<C: ContextObject>( 0, ebpf::hash_symbol_name(label.as_bytes()) as i32 as i64, ), + (Syscall, [Integer(imm)]) => insn(opc, 0, 0, 0, *imm), (CallImm, [Label(label)]) => { let label: &str = label; let target_pc = *labels diff --git a/src/disassembler.rs b/src/disassembler.rs index 94a7695c..b500b0a5 100644 --- a/src/disassembler.rs +++ b/src/disassembler.rs @@ -265,14 +265,7 @@ pub fn disassemble_instruction<C: ContextObject>( ebpf::JSLE_IMM => { name = "jsle"; desc = jmp_imm_str(name, insn, cfg_nodes); }, ebpf::JSLE_REG => { name = "jsle"; desc = jmp_reg_str(name, insn, cfg_nodes); }, ebpf::CALL_IMM => { - let mut function_name = None; - if sbpf_version.static_syscalls() { - if insn.src != 0 { - function_name = Some(resolve_label(cfg_nodes, insn.imm as usize).to_string()); - } - } else { - function_name = function_registry.lookup_by_key(insn.imm as u32).map(|(function_name, _)| String::from_utf8_lossy(function_name).to_string()); - } + let function_name = function_registry.lookup_by_key(insn.imm as u32).map(|(function_name, _)| String::from_utf8_lossy(function_name).to_string()); let function_name = if let Some(function_name) = function_name { name = "call"; function_name @@ -284,9 +277,9 @@ pub fn disassemble_instruction<C: ContextObject>( }, ebpf::CALL_REG => { name = "callx"; desc = format!("{} r{}", name, if sbpf_version.callx_uses_src_reg() { insn.src } else { insn.imm as u8 }); }, ebpf::EXIT - | ebpf::RETURN if !sbpf_version.static_syscalls() => { name = "exit"; desc = name.to_string(); }, - ebpf::EXIT - | ebpf::RETURN if sbpf_version.static_syscalls() => { name = "return"; desc = name.to_string(); }, + | ebpf::RETURN if !sbpf_version.static_syscalls() => { name = "exit"; desc = name.to_string(); }, + ebpf::RETURN if sbpf_version.static_syscalls() => { name = "return"; desc = name.to_string(); }, + ebpf::SYSCALL if sbpf_version.static_syscalls() => { desc = format!("syscall {}", insn.imm); }, _ => { name = "unknown"; desc = format!("{} opcode={:#x}", name, insn.opc); }, }; diff --git a/src/ebpf.rs b/src/ebpf.rs index 6608452b..57d57290 100644 --- a/src/ebpf.rs +++ b/src/ebpf.rs @@ -195,8 +195,8 @@ pub const BPF_JSGT: u8 = 0x60; pub const BPF_JSGE: u8 = 0x70; /// BPF JMP operation code: syscall function call. pub const BPF_CALL: u8 = 0x80; -/// BPF JMP operation code: return from program. -pub const BPF_EXIT: u8 = 0x90; +/// BPF JMP operation code: return from program (V1) or syscall (V2). +pub const BPF_EXIT_SYSCALL: u8 = 0x90; /// BPF JMP operation code: jump if lower than. pub const BPF_JLT: u8 = 0xa0; /// BPF JMP operation code: jump if lower or equal. @@ -481,9 +481,11 @@ pub const CALL_IMM: u8 = BPF_JMP | BPF_CALL; /// BPF opcode: tail call. pub const CALL_REG: u8 = BPF_JMP | BPF_X | BPF_CALL; /// BPF opcode: `exit` /// `return r0`. /// Valid only for SBPFv1 -pub const EXIT: u8 = BPF_JMP | BPF_EXIT; +pub const EXIT: u8 = BPF_JMP | BPF_EXIT_SYSCALL; /// BPF opcode: `return` /// `return r0`. /// Valid only for SBPFv2 -pub const RETURN: u8 = BPF_JMP | BPF_X | BPF_EXIT; +pub const RETURN: u8 = BPF_JMP | BPF_X | BPF_EXIT_SYSCALL; +/// BPF opcode: `syscall` /// `syscall imm`. /// Valid only for SBPFv2 +pub const SYSCALL: u8 = BPF_JMP | BPF_EXIT_SYSCALL; // Used in JIT /// Mask to extract the operation class from an operation code. diff --git a/src/insn_builder.rs b/src/insn_builder.rs index 638cc275..f9400762 100644 --- a/src/insn_builder.rs +++ b/src/insn_builder.rs @@ -616,7 +616,7 @@ impl<'i> Exit<'i> { impl Instruction for Exit<'_> { fn opt_code_byte(&self) -> u8 { - BPF_EXIT | BPF_JMP + BPF_EXIT_SYSCALL | BPF_JMP } fn get_insn_mut(&mut self) -> &mut Insn { diff --git a/src/interpreter.rs b/src/interpreter.rs index adc2ab79..34ea6dd8 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -526,7 +526,8 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { // Do not delegate the check to the verifier, since self.registered functions can be // changed after the program has been verified. - ebpf::CALL_IMM => { + ebpf::CALL_IMM + | ebpf::SYSCALL if insn.opc == ebpf::CALL_IMM || self.executable.get_sbpf_version().static_syscalls() => { let mut resolved = false; let (external, internal) = if self.executable.get_sbpf_version().static_syscalls() { (insn.src == 0, insn.src != 0) diff --git a/src/jit.rs b/src/jit.rs index cf1fd63e..d17abd19 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -705,7 +705,8 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { ebpf::JSLT_REG => self.emit_conditional_branch_reg(0x8c, false, src, dst, target_pc), ebpf::JSLE_IMM => self.emit_conditional_branch_imm(0x8e, false, insn.imm, dst, target_pc), ebpf::JSLE_REG => self.emit_conditional_branch_reg(0x8e, false, src, dst, target_pc), - ebpf::CALL_IMM => { + ebpf::CALL_IMM | ebpf::SYSCALL + if insn.opc == ebpf::CALL_IMM || self.executable.get_sbpf_version().static_syscalls() => { // For JIT, external functions MUST be registered at compile time. let mut resolved = false; diff --git a/tests/assembler.rs b/tests/assembler.rs index d94c2155..66df864d 100644 --- a/tests/assembler.rs +++ b/tests/assembler.rs @@ -71,6 +71,19 @@ fn test_exit() { ); } +#[test] +fn test_static_syscall() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V2..=SBPFVersion::V2, + ..Config::default() + }; + + assert_eq!( + asm_with_config("syscall 3", config), + Ok(vec![insn(0, ebpf::SYSCALL, 0, 0, 0, 3)]) + ); +} + #[test] fn test_return() { let config = Config { diff --git a/tests/disassembler.rs b/tests/disassembler.rs index 0740787e..e77d274f 100644 --- a/tests/disassembler.rs +++ b/tests/disassembler.rs @@ -60,6 +60,15 @@ fn test_return() { disasm!("entrypoint:\n return\n", config); } +#[test] +fn test_static_syscall() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V2..=SBPFVersion::V2, + ..Config::default() + }; + disasm!("entrypoint:\n syscall 5\n", config); +} + // Example for InstructionType::AluBinary. #[test] fn test_add64() { From 9596526305aec899a5c85e24852715fa5487d59e Mon Sep 17 00:00:00 2001 From: Lucas <lucas.tnagel@gmail.com> Date: Fri, 11 Oct 2024 16:26:56 -0300 Subject: [PATCH 2/3] Rebase onto main --- src/verifier.rs | 1 + tests/verifier.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/verifier.rs b/src/verifier.rs index e9a28024..6f46a0a3 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -392,6 +392,7 @@ impl Verifier for RequisiteVerifier { ebpf::CALL_REG => { check_callx_register(&insn, insn_ptr, sbpf_version)?; }, ebpf::EXIT if !sbpf_version.static_syscalls() => {}, ebpf::RETURN if sbpf_version.static_syscalls() => {}, + ebpf::SYSCALL if sbpf_version.static_syscalls() => {}, _ => { return Err(VerifierError::UnknownOpCode(insn.opc, insn_ptr)); diff --git a/tests/verifier.rs b/tests/verifier.rs index a7cf9421..5fa54218 100644 --- a/tests/verifier.rs +++ b/tests/verifier.rs @@ -431,7 +431,7 @@ fn return_instr() { for sbpf_version in [SBPFVersion::V1, SBPFVersion::V2] { let prog = &[ 0xbf, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov64 r0, 2 - 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit + 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit (v1), syscall (v2) 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // return ]; @@ -444,7 +444,7 @@ fn return_instr() { .unwrap(); let result = executable.verify::<RequisiteVerifier>(); if sbpf_version == SBPFVersion::V2 { - assert_error!(result, "VerifierError(UnknownOpCode(149, 1))"); + assert!(result.is_ok()); } else { assert_error!(result, "VerifierError(UnknownOpCode(157, 2))"); } From 64c8ca5d8bd215bfd896f54977487916d8ff75e3 Mon Sep 17 00:00:00 2001 From: Lucas <lucas.tnagel@gmail.com> Date: Fri, 11 Oct 2024 15:49:18 -0300 Subject: [PATCH 3/3] Fix naming and assembler --- src/assembler.rs | 14 +++++++++----- src/ebpf.rs | 12 +++++++----- src/insn_builder.rs | 2 +- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/assembler.rs b/src/assembler.rs index cc4c721a..ffdb3508 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -122,11 +122,15 @@ fn make_instruction_map(sbpf_version: SBPFVersion) -> HashMap<String, (Instructi // Miscellaneous. entry("ja", JumpUnconditional, ebpf::JA); - if sbpf_version == SBPFVersion::V1 { - entry("syscall", Syscall, ebpf::CALL_IMM); - } else { - entry("syscall", Syscall, ebpf::SYSCALL); - } + entry( + "syscall", + Syscall, + if sbpf_version == SBPFVersion::V1 { + ebpf::CALL_IMM + } else { + ebpf::SYSCALL + }, + ); entry("call", CallImm, ebpf::CALL_IMM); entry("callx", CallReg, ebpf::CALL_REG); entry("lddw", LoadDwImm, ebpf::LD_DW_IMM); diff --git a/src/ebpf.rs b/src/ebpf.rs index 57d57290..9c443092 100644 --- a/src/ebpf.rs +++ b/src/ebpf.rs @@ -195,8 +195,10 @@ pub const BPF_JSGT: u8 = 0x60; pub const BPF_JSGE: u8 = 0x70; /// BPF JMP operation code: syscall function call. pub const BPF_CALL: u8 = 0x80; -/// BPF JMP operation code: return from program (V1) or syscall (V2). -pub const BPF_EXIT_SYSCALL: u8 = 0x90; +/// BPF JMP operation code: return from program (V1). +pub const BPF_EXIT: u8 = 0x90; +/// BPF JMP operation code: static syscall (V2). +pub const BPF_SYSCALL: u8 = 0x90; /// BPF JMP operation code: jump if lower than. pub const BPF_JLT: u8 = 0xa0; /// BPF JMP operation code: jump if lower or equal. @@ -481,11 +483,11 @@ pub const CALL_IMM: u8 = BPF_JMP | BPF_CALL; /// BPF opcode: tail call. pub const CALL_REG: u8 = BPF_JMP | BPF_X | BPF_CALL; /// BPF opcode: `exit` /// `return r0`. /// Valid only for SBPFv1 -pub const EXIT: u8 = BPF_JMP | BPF_EXIT_SYSCALL; +pub const EXIT: u8 = BPF_JMP | BPF_EXIT; /// BPF opcode: `return` /// `return r0`. /// Valid only for SBPFv2 -pub const RETURN: u8 = BPF_JMP | BPF_X | BPF_EXIT_SYSCALL; +pub const RETURN: u8 = BPF_JMP | BPF_X | BPF_EXIT; /// BPF opcode: `syscall` /// `syscall imm`. /// Valid only for SBPFv2 -pub const SYSCALL: u8 = BPF_JMP | BPF_EXIT_SYSCALL; +pub const SYSCALL: u8 = BPF_JMP | BPF_SYSCALL; // Used in JIT /// Mask to extract the operation class from an operation code. diff --git a/src/insn_builder.rs b/src/insn_builder.rs index f9400762..638cc275 100644 --- a/src/insn_builder.rs +++ b/src/insn_builder.rs @@ -616,7 +616,7 @@ impl<'i> Exit<'i> { impl Instruction for Exit<'_> { fn opt_code_byte(&self) -> u8 { - BPF_EXIT_SYSCALL | BPF_JMP + BPF_EXIT | BPF_JMP } fn get_insn_mut(&mut self) -> &mut Insn {