From d17b1b6cacda06b6ff047a633046a1596b4319b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 3 Oct 2024 17:22:35 +0200 Subject: [PATCH 01/10] Removes unused items of InstructionType in assembler. --- src/assembler.rs | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/assembler.rs b/src/assembler.rs index 08c852f3..9d1f40e2 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -8,8 +8,8 @@ //! This module translates eBPF assembly language to binary. use self::InstructionType::{ - AluBinary, AluUnary, CallImm, CallReg, Endian, JumpConditional, JumpUnconditional, LoadAbs, - LoadDwImm, LoadInd, LoadReg, NoOperand, StoreImm, StoreReg, Syscall, + AluBinary, AluUnary, CallImm, CallReg, Endian, JumpConditional, JumpUnconditional, LoadDwImm, + LoadReg, NoOperand, StoreImm, StoreReg, Syscall, }; use crate::{ asm_parser::{ @@ -35,8 +35,6 @@ enum InstructionType { AluBinary, AluUnary, LoadDwImm, - LoadAbs, - LoadInd, LoadReg, StoreImm, StoreReg, @@ -193,18 +191,8 @@ fn make_instruction_map() -> HashMap { ); entry("srem32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_SREM); - // LoadAbs, LoadInd, LoadReg, StoreImm, and StoreReg. + // LoadReg, StoreImm, and StoreReg. for &(suffix, size) in &mem_sizes { - entry( - &format!("ldabs{suffix}"), - LoadAbs, - ebpf::BPF_ABS | ebpf::BPF_LD | size, - ); - entry( - &format!("ldind{suffix}"), - LoadInd, - ebpf::BPF_IND | ebpf::BPF_LD | size, - ); entry( &format!("ldx{suffix}"), LoadReg, @@ -381,8 +369,6 @@ pub fn assemble( insn(opc | ebpf::BPF_K, *dst, 0, 0, *imm) } (AluUnary, [Register(dst)]) => insn(opc, *dst, 0, 0, 0), - (LoadAbs, [Integer(imm)]) => insn(opc, 0, 0, 0, *imm), - (LoadInd, [Register(src), Integer(imm)]) => insn(opc, 0, *src, 0, *imm), (LoadReg, [Register(dst), Memory(src, off)]) | (StoreReg, [Memory(dst, off), Register(src)]) => { insn(opc, *dst, *src, *off, 0) From 4ed8106d6dc5129f261407065054d7038131bd00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 3 Oct 2024 18:02:08 +0200 Subject: [PATCH 02/10] Adds missing differentiation for PQR instructions in disassembler. --- src/assembler.rs | 2 -- src/disassembler.rs | 76 +++++++++++++++++++++---------------------- tests/disassembler.rs | 53 ++++++++++++++++-------------- 3 files changed, 67 insertions(+), 64 deletions(-) diff --git a/src/assembler.rs b/src/assembler.rs index 9d1f40e2..c1311dd3 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -134,7 +134,6 @@ fn make_instruction_map() -> HashMap { AluBinary, ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_UHMUL, ); - entry("uhmul32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_UHMUL); entry( "shmul", AluBinary, @@ -145,7 +144,6 @@ fn make_instruction_map() -> HashMap { AluBinary, ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_SHMUL, ); - entry("shmul32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_SHMUL); entry( "udiv", AluBinary, diff --git a/src/disassembler.rs b/src/disassembler.rs index 5adfbbe3..d9315204 100644 --- a/src/disassembler.rs +++ b/src/disassembler.rs @@ -146,10 +146,10 @@ pub fn disassemble_instruction( ebpf::ADD32_REG => { name = "add32"; desc = alu_reg_str(name, insn); }, ebpf::SUB32_IMM => { name = "sub32"; desc = alu_imm_str(name, insn); }, ebpf::SUB32_REG => { name = "sub32"; desc = alu_reg_str(name, insn); }, - ebpf::MUL32_IMM => { name = "mul32"; desc = alu_imm_str(name, insn); }, - ebpf::MUL32_REG => { name = "mul32"; desc = alu_reg_str(name, insn); }, - ebpf::DIV32_IMM => { name = "div32"; desc = alu_imm_str(name, insn); }, - ebpf::DIV32_REG => { name = "div32"; desc = alu_reg_str(name, insn); }, + ebpf::MUL32_IMM if !sbpf_version.enable_pqr() => { name = "mul32"; desc = alu_imm_str(name, insn); }, + ebpf::MUL32_REG if !sbpf_version.enable_pqr() => { name = "mul32"; desc = alu_reg_str(name, insn); }, + ebpf::DIV32_IMM if !sbpf_version.enable_pqr() => { name = "div32"; desc = alu_imm_str(name, insn); }, + ebpf::DIV32_REG if !sbpf_version.enable_pqr() => { name = "div32"; desc = alu_reg_str(name, insn); }, ebpf::OR32_IMM => { name = "or32"; desc = alu_imm_str(name, insn); }, ebpf::OR32_REG => { name = "or32"; desc = alu_reg_str(name, insn); }, ebpf::AND32_IMM => { name = "and32"; desc = alu_imm_str(name, insn); }, @@ -158,9 +158,9 @@ pub fn disassemble_instruction( ebpf::LSH32_REG => { name = "lsh32"; desc = alu_reg_str(name, insn); }, ebpf::RSH32_IMM => { name = "rsh32"; desc = alu_imm_str(name, insn); }, ebpf::RSH32_REG => { name = "rsh32"; desc = alu_reg_str(name, insn); }, - ebpf::NEG32 => { name = "neg32"; desc = format!("{} r{}", name, insn.dst); }, - ebpf::MOD32_IMM => { name = "mod32"; desc = alu_imm_str(name, insn); }, - ebpf::MOD32_REG => { name = "mod32"; desc = alu_reg_str(name, insn); }, + ebpf::NEG32 if sbpf_version.enable_neg() => { name = "neg32"; desc = format!("{} r{}", name, insn.dst); }, + ebpf::MOD32_IMM if !sbpf_version.enable_pqr() => { name = "mod32"; desc = alu_imm_str(name, insn); }, + ebpf::MOD32_REG if !sbpf_version.enable_pqr() => { name = "mod32"; desc = alu_reg_str(name, insn); }, ebpf::XOR32_IMM => { name = "xor32"; desc = alu_imm_str(name, insn); }, ebpf::XOR32_REG => { name = "xor32"; desc = alu_reg_str(name, insn); }, ebpf::MOV32_IMM => { name = "mov32"; desc = alu_imm_str(name, insn); }, @@ -175,10 +175,10 @@ pub fn disassemble_instruction( ebpf::ADD64_REG => { name = "add64"; desc = alu_reg_str(name, insn); }, ebpf::SUB64_IMM => { name = "sub64"; desc = alu_imm_str(name, insn); }, ebpf::SUB64_REG => { name = "sub64"; desc = alu_reg_str(name, insn); }, - ebpf::MUL64_IMM => { name = "mul64"; desc = alu_imm_str(name, insn); }, - ebpf::MUL64_REG => { name = "mul64"; desc = alu_reg_str(name, insn); }, - ebpf::DIV64_IMM => { name = "div64"; desc = alu_imm_str(name, insn); }, - ebpf::DIV64_REG => { name = "div64"; desc = alu_reg_str(name, insn); }, + ebpf::MUL64_IMM if !sbpf_version.enable_pqr() => { name = "mul64"; desc = alu_imm_str(name, insn); }, + ebpf::MUL64_REG if !sbpf_version.enable_pqr() => { name = "mul64"; desc = alu_reg_str(name, insn); }, + ebpf::DIV64_IMM if !sbpf_version.enable_pqr() => { name = "div64"; desc = alu_imm_str(name, insn); }, + ebpf::DIV64_REG if !sbpf_version.enable_pqr() => { name = "div64"; desc = alu_reg_str(name, insn); }, ebpf::OR64_IMM => { name = "or64"; desc = alu_imm_str(name, insn); }, ebpf::OR64_REG => { name = "or64"; desc = alu_reg_str(name, insn); }, ebpf::AND64_IMM => { name = "and64"; desc = alu_imm_str(name, insn); }, @@ -187,9 +187,9 @@ pub fn disassemble_instruction( ebpf::LSH64_REG => { name = "lsh64"; desc = alu_reg_str(name, insn); }, ebpf::RSH64_IMM => { name = "rsh64"; desc = alu_imm_str(name, insn); }, ebpf::RSH64_REG => { name = "rsh64"; desc = alu_reg_str(name, insn); }, - ebpf::NEG64 => { name = "neg64"; desc = format!("{} r{}", name, insn.dst); }, - ebpf::MOD64_IMM => { name = "mod64"; desc = alu_imm_str(name, insn); }, - ebpf::MOD64_REG => { name = "mod64"; desc = alu_reg_str(name, insn); }, + ebpf::NEG64 if sbpf_version.enable_neg() => { name = "neg64"; desc = format!("{} r{}", name, insn.dst); }, + ebpf::MOD64_IMM if !sbpf_version.enable_pqr() => { name = "mod64"; desc = alu_imm_str(name, insn); }, + ebpf::MOD64_REG if !sbpf_version.enable_pqr() => { name = "mod64"; desc = alu_reg_str(name, insn); }, ebpf::XOR64_IMM => { name = "xor64"; desc = alu_imm_str(name, insn); }, ebpf::XOR64_REG => { name = "xor64"; desc = alu_reg_str(name, insn); }, ebpf::MOV64_IMM => { name = "mov64"; desc = alu_imm_str(name, insn); }, @@ -199,30 +199,30 @@ pub fn disassemble_instruction( ebpf::HOR64_IMM => { name = "hor64"; desc = alu_imm_str(name, insn); }, // BPF_PQR class - ebpf::LMUL32_IMM => { name = "lmul32"; desc = alu_imm_str(name, insn); }, - ebpf::LMUL32_REG => { name = "lmul32"; desc = alu_reg_str(name, insn); }, - ebpf::LMUL64_IMM => { name = "lmul64"; desc = alu_imm_str(name, insn); }, - ebpf::LMUL64_REG => { name = "lmul64"; desc = alu_reg_str(name, insn); }, - ebpf::UHMUL64_IMM => { name = "uhmul64"; desc = alu_imm_str(name, insn); }, - ebpf::UHMUL64_REG => { name = "uhmul64"; desc = alu_reg_str(name, insn); }, - ebpf::SHMUL64_IMM => { name = "shmul64"; desc = alu_imm_str(name, insn); }, - ebpf::SHMUL64_REG => { name = "shmul64"; desc = alu_reg_str(name, insn); }, - ebpf::UDIV32_IMM => { name = "udiv32"; desc = alu_imm_str(name, insn); }, - ebpf::UDIV32_REG => { name = "udiv32"; desc = alu_reg_str(name, insn); }, - ebpf::UDIV64_IMM => { name = "udiv64"; desc = alu_imm_str(name, insn); }, - ebpf::UDIV64_REG => { name = "udiv64"; desc = alu_reg_str(name, insn); }, - ebpf::UREM32_IMM => { name = "urem32"; desc = alu_imm_str(name, insn); }, - ebpf::UREM32_REG => { name = "urem32"; desc = alu_reg_str(name, insn); }, - ebpf::UREM64_IMM => { name = "urem64"; desc = alu_imm_str(name, insn); }, - ebpf::UREM64_REG => { name = "urem64"; desc = alu_reg_str(name, insn); }, - ebpf::SDIV32_IMM => { name = "sdiv32"; desc = alu_imm_str(name, insn); }, - ebpf::SDIV32_REG => { name = "sdiv32"; desc = alu_reg_str(name, insn); }, - ebpf::SDIV64_IMM => { name = "sdiv64"; desc = alu_imm_str(name, insn); }, - ebpf::SDIV64_REG => { name = "sdiv64"; desc = alu_reg_str(name, insn); }, - ebpf::SREM32_IMM => { name = "srem32"; desc = alu_imm_str(name, insn); }, - ebpf::SREM32_REG => { name = "srem32"; desc = alu_reg_str(name, insn); }, - ebpf::SREM64_IMM => { name = "srem64"; desc = alu_imm_str(name, insn); }, - ebpf::SREM64_REG => { name = "srem64"; desc = alu_reg_str(name, insn); }, + ebpf::LMUL32_IMM if sbpf_version.enable_pqr() => { name = "lmul32"; desc = alu_imm_str(name, insn); }, + ebpf::LMUL32_REG if sbpf_version.enable_pqr() => { name = "lmul32"; desc = alu_reg_str(name, insn); }, + ebpf::LMUL64_IMM if sbpf_version.enable_pqr() => { name = "lmul64"; desc = alu_imm_str(name, insn); }, + ebpf::LMUL64_REG if sbpf_version.enable_pqr() => { name = "lmul64"; desc = alu_reg_str(name, insn); }, + ebpf::UHMUL64_IMM if sbpf_version.enable_pqr() => { name = "uhmul64"; desc = alu_imm_str(name, insn); }, + ebpf::UHMUL64_REG if sbpf_version.enable_pqr() => { name = "uhmul64"; desc = alu_reg_str(name, insn); }, + ebpf::SHMUL64_IMM if sbpf_version.enable_pqr() => { name = "shmul64"; desc = alu_imm_str(name, insn); }, + ebpf::SHMUL64_REG if sbpf_version.enable_pqr() => { name = "shmul64"; desc = alu_reg_str(name, insn); }, + ebpf::UDIV32_IMM if sbpf_version.enable_pqr() => { name = "udiv32"; desc = alu_imm_str(name, insn); }, + ebpf::UDIV32_REG if sbpf_version.enable_pqr() => { name = "udiv32"; desc = alu_reg_str(name, insn); }, + ebpf::UDIV64_IMM if sbpf_version.enable_pqr() => { name = "udiv64"; desc = alu_imm_str(name, insn); }, + ebpf::UDIV64_REG if sbpf_version.enable_pqr() => { name = "udiv64"; desc = alu_reg_str(name, insn); }, + ebpf::UREM32_IMM if sbpf_version.enable_pqr() => { name = "urem32"; desc = alu_imm_str(name, insn); }, + ebpf::UREM32_REG if sbpf_version.enable_pqr() => { name = "urem32"; desc = alu_reg_str(name, insn); }, + ebpf::UREM64_IMM if sbpf_version.enable_pqr() => { name = "urem64"; desc = alu_imm_str(name, insn); }, + ebpf::UREM64_REG if sbpf_version.enable_pqr() => { name = "urem64"; desc = alu_reg_str(name, insn); }, + ebpf::SDIV32_IMM if sbpf_version.enable_pqr() => { name = "sdiv32"; desc = alu_imm_str(name, insn); }, + ebpf::SDIV32_REG if sbpf_version.enable_pqr() => { name = "sdiv32"; desc = alu_reg_str(name, insn); }, + ebpf::SDIV64_IMM if sbpf_version.enable_pqr() => { name = "sdiv64"; desc = alu_imm_str(name, insn); }, + ebpf::SDIV64_REG if sbpf_version.enable_pqr() => { name = "sdiv64"; desc = alu_reg_str(name, insn); }, + ebpf::SREM32_IMM if sbpf_version.enable_pqr() => { name = "srem32"; desc = alu_imm_str(name, insn); }, + ebpf::SREM32_REG if sbpf_version.enable_pqr() => { name = "srem32"; desc = alu_reg_str(name, insn); }, + ebpf::SREM64_IMM if sbpf_version.enable_pqr() => { name = "srem64"; desc = alu_imm_str(name, insn); }, + ebpf::SREM64_REG if sbpf_version.enable_pqr() => { name = "srem64"; desc = alu_reg_str(name, insn); }, // BPF_JMP class ebpf::JA => { diff --git a/tests/disassembler.rs b/tests/disassembler.rs index 57856131..6b3b25c3 100644 --- a/tests/disassembler.rs +++ b/tests/disassembler.rs @@ -52,12 +52,6 @@ fn test_add64() { disasm!("entrypoint:\n add64 r1, 5\n"); } -// Example for InstructionType::AluUnary. -#[test] -fn test_neg64() { - disasm!("entrypoint:\n neg64 r1\n"); -} - // Example for InstructionType::LoadReg. #[test] fn test_ldxw() { @@ -164,13 +158,10 @@ fn test_alu_binary() { "entrypoint: add64 r1, r2 sub64 r1, r2 - mul64 r1, r2 - div64 r1, r2 or64 r1, r2 and64 r1, r2 lsh64 r1, r2 rsh64 r1, r2 - mod64 r1, r2 xor64 r1, r2 mov64 r1, r2 arsh64 r1, r2 @@ -181,13 +172,10 @@ fn test_alu_binary() { "entrypoint: add64 r1, 2 sub64 r1, 2 - mul64 r1, 2 - div64 r1, 2 or64 r1, 2 and64 r1, 2 lsh64 r1, 2 rsh64 r1, 2 - mod64 r1, 2 xor64 r1, 2 mov64 r1, 2 arsh64 r1, 2 @@ -198,13 +186,10 @@ fn test_alu_binary() { "entrypoint: add32 r1, r2 sub32 r1, r2 - mul32 r1, r2 - div32 r1, r2 or32 r1, r2 and32 r1, r2 lsh32 r1, r2 rsh32 r1, r2 - mod32 r1, r2 xor32 r1, r2 mov32 r1, r2 arsh32 r1, r2 @@ -215,27 +200,47 @@ fn test_alu_binary() { "entrypoint: add32 r1, 2 sub32 r1, 2 - mul32 r1, 2 - div32 r1, 2 or32 r1, 2 and32 r1, 2 lsh32 r1, 2 rsh32 r1, 2 - mod32 r1, 2 xor32 r1, 2 mov32 r1, 2 arsh32 r1, 2 " ); -} -// Test all supported AluUnary mnemonics. -#[test] -fn test_alu_unary() { disasm!( "entrypoint: - neg64 r1 - neg32 r1 + lmul64 r1, r2 + lmul32 r1, r2 + uhmul64 r1, r2 + shmul64 r1, r2 + udiv64 r1, r2 + udiv32 r1, r2 + urem64 r1, r2 + urem32 r1, r2 + sdiv64 r1, r2 + sdiv32 r1, r2 + srem64 r1, r2 + srem32 r1, r2 +" + ); + + disasm!( + "entrypoint: + lmul64 r1, 2 + lmul32 r1, 2 + uhmul64 r1, 2 + shmul64 r1, 2 + udiv64 r1, 2 + udiv32 r1, 2 + urem64 r1, 2 + urem32 r1, 2 + sdiv64 r1, 2 + sdiv32 r1, 2 + srem64 r1, 2 + srem32 r1, 2 " ); } From 5d94b37d76a280df927acd61e053c31b3dfa09d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 3 Oct 2024 16:18:01 +0200 Subject: [PATCH 03/10] Adds the new opcodes. --- src/ebpf.rs | 49 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/src/ebpf.rs b/src/ebpf.rs index bf12d05d..6b6cdd42 100644 --- a/src/ebpf.rs +++ b/src/ebpf.rs @@ -59,19 +59,19 @@ pub const MM_INPUT_START: u64 = 0x400000000; // Three least significant bits are operation class: /// BPF operation class: load from immediate. [DEPRECATED] pub const BPF_LD: u8 = 0x00; -/// BPF operation class: load from register. +/// BPF operation class: load from register. [DEPRECATED] pub const BPF_LDX: u8 = 0x01; -/// BPF operation class: store immediate. +/// BPF operation class: store immediate. [DEPRECATED] pub const BPF_ST: u8 = 0x02; -/// BPF operation class: store value from register. +/// BPF operation class: store value from register. [DEPRECATED] pub const BPF_STX: u8 = 0x03; -/// BPF operation class: 32 bits arithmetic operation. +/// BPF operation class: 32 bit arithmetic or load. pub const BPF_ALU: u8 = 0x04; -/// BPF operation class: jump. +/// BPF operation class: control flow. pub const BPF_JMP: u8 = 0x05; /// BPF operation class: product / quotient / remainder. pub const BPF_PQR: u8 = 0x06; -/// BPF operation class: 64 bits arithmetic operation. +/// BPF operation class: 64 bit arithmetic or store. pub const BPF_ALU64: u8 = 0x07; // For load and store instructions: @@ -90,15 +90,23 @@ pub const BPF_H: u8 = 0x08; pub const BPF_B: u8 = 0x10; /// BPF size modifier: double word (8 bytes). pub const BPF_DW: u8 = 0x18; +/// BPF size modifier: 1 byte. +pub const BPF_1B: u8 = 0x20; +/// BPF size modifier: 2 bytes. +pub const BPF_2B: u8 = 0x30; +/// BPF size modifier: 4 bytes. +pub const BPF_4B: u8 = 0x80; +/// BPF size modifier: 8 bytes. +pub const BPF_8B: u8 = 0x90; // Mode modifiers: /// BPF mode modifier: immediate value. pub const BPF_IMM: u8 = 0x00; /// BPF mode modifier: absolute load. pub const BPF_ABS: u8 = 0x20; -/// BPF mode modifier: indirect load. +/// BPF mode modifier: indirect load. [DEPRECATED] pub const BPF_IND: u8 = 0x40; -/// BPF mode modifier: load from / store to memory. +/// BPF mode modifier: load from / store to memory. [DEPRECATED] pub const BPF_MEM: u8 = 0x60; // [ 0x80 reserved ] // [ 0xa0 reserved ] @@ -229,6 +237,31 @@ pub const ST_W_REG: u8 = BPF_STX | BPF_MEM | BPF_W; /// BPF opcode: `stxdw [dst + off], src` /// `(dst + offset) as u64 = src`. pub const ST_DW_REG: u8 = BPF_STX | BPF_MEM | BPF_DW; +/// BPF opcode: `ldxb dst, [src + off]` /// `dst = (src + off) as u8`. +pub const LD_1B_REG: u8 = BPF_ALU | BPF_X | BPF_1B; +/// BPF opcode: `ldxh dst, [src + off]` /// `dst = (src + off) as u16`. +pub const LD_2B_REG: u8 = BPF_ALU | BPF_X | BPF_2B; +/// BPF opcode: `ldxw dst, [src + off]` /// `dst = (src + off) as u32`. +pub const LD_4B_REG: u8 = BPF_ALU | BPF_X | BPF_4B; +/// BPF opcode: `ldxdw dst, [src + off]` /// `dst = (src + off) as u64`. +pub const LD_8B_REG: u8 = BPF_ALU | BPF_X | BPF_8B; +/// BPF opcode: `stb [dst + off], imm` /// `(dst + offset) as u8 = imm`. +pub const ST_1B_IMM: u8 = BPF_ALU64 | BPF_K | BPF_1B; +/// BPF opcode: `sth [dst + off], imm` /// `(dst + offset) as u16 = imm`. +pub const ST_2B_IMM: u8 = BPF_ALU64 | BPF_K | BPF_2B; +/// BPF opcode: `stw [dst + off], imm` /// `(dst + offset) as u32 = imm`. +pub const ST_4B_IMM: u8 = BPF_ALU64 | BPF_K | BPF_4B; +/// BPF opcode: `stdw [dst + off], imm` /// `(dst + offset) as u64 = imm`. +pub const ST_8B_IMM: u8 = BPF_ALU64 | BPF_K | BPF_8B; +/// BPF opcode: `stxb [dst + off], src` /// `(dst + offset) as u8 = src`. +pub const ST_1B_REG: u8 = BPF_ALU64 | BPF_X | BPF_1B; +/// BPF opcode: `stxh [dst + off], src` /// `(dst + offset) as u16 = src`. +pub const ST_2B_REG: u8 = BPF_ALU64 | BPF_X | BPF_2B; +/// BPF opcode: `stxw [dst + off], src` /// `(dst + offset) as u32 = src`. +pub const ST_4B_REG: u8 = BPF_ALU64 | BPF_X | BPF_4B; +/// BPF opcode: `stxdw [dst + off], src` /// `(dst + offset) as u64 = src`. +pub const ST_8B_REG: u8 = BPF_ALU64 | BPF_X | BPF_8B; + /// BPF opcode: `add32 dst, imm` /// `dst += imm`. pub const ADD32_IMM: u8 = BPF_ALU | BPF_K | BPF_ADD; /// BPF opcode: `add32 dst, src` /// `dst += src`. From 4bbd429d8e0e89fb68341666f72324307393a6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 3 Oct 2024 16:18:14 +0200 Subject: [PATCH 04/10] Adds a feature flag for moving them. --- src/program.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/program.rs b/src/program.rs index 42b493b7..59c68a76 100644 --- a/src/program.rs +++ b/src/program.rs @@ -76,6 +76,11 @@ impl SBPFVersion { pub fn static_syscalls(&self) -> bool { self != &SBPFVersion::V1 } + + /// Move opcodes of memory instructions into ALU instruction classes + pub fn move_memory_instruction_classes(&self) -> bool { + self != &SBPFVersion::V1 + } } /// Holds the function symbols of an Executable From 3d1b97bd39c7116ec05b01d14e3dfcd9aac25929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 3 Oct 2024 16:38:35 +0200 Subject: [PATCH 05/10] Disables the old opcodes conditionally. --- src/disassembler.rs | 24 ++++++++++++------------ src/interpreter.rs | 24 ++++++++++++------------ src/jit.rs | 24 ++++++++++++------------ src/verifier.rs | 24 ++++++++++++------------ 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/disassembler.rs b/src/disassembler.rs index d9315204..da44c343 100644 --- a/src/disassembler.rs +++ b/src/disassembler.rs @@ -124,22 +124,22 @@ pub fn disassemble_instruction( ebpf::LD_DW_IMM => { name = "lddw"; desc = format!("{} r{:}, {:#x}", name, insn.dst, insn.imm); }, // BPF_LDX class - ebpf::LD_B_REG => { name = "ldxb"; desc = ld_reg_str(name, insn); }, - ebpf::LD_H_REG => { name = "ldxh"; desc = ld_reg_str(name, insn); }, - ebpf::LD_W_REG => { name = "ldxw"; desc = ld_reg_str(name, insn); }, - ebpf::LD_DW_REG => { name = "ldxdw"; desc = ld_reg_str(name, insn); }, + ebpf::LD_B_REG if !sbpf_version.move_memory_instruction_classes() => { name = "ldxb"; desc = ld_reg_str(name, insn); }, + ebpf::LD_H_REG if !sbpf_version.move_memory_instruction_classes() => { name = "ldxh"; desc = ld_reg_str(name, insn); }, + ebpf::LD_W_REG if !sbpf_version.move_memory_instruction_classes() => { name = "ldxw"; desc = ld_reg_str(name, insn); }, + ebpf::LD_DW_REG if !sbpf_version.move_memory_instruction_classes() => { name = "ldxdw"; desc = ld_reg_str(name, insn); }, // BPF_ST class - ebpf::ST_B_IMM => { name = "stb"; desc = ld_st_imm_str(name, insn); }, - ebpf::ST_H_IMM => { name = "sth"; desc = ld_st_imm_str(name, insn); }, - ebpf::ST_W_IMM => { name = "stw"; desc = ld_st_imm_str(name, insn); }, - ebpf::ST_DW_IMM => { name = "stdw"; desc = ld_st_imm_str(name, insn); }, + ebpf::ST_B_IMM if !sbpf_version.move_memory_instruction_classes() => { name = "stb"; desc = ld_st_imm_str(name, insn); }, + ebpf::ST_H_IMM if !sbpf_version.move_memory_instruction_classes() => { name = "sth"; desc = ld_st_imm_str(name, insn); }, + ebpf::ST_W_IMM if !sbpf_version.move_memory_instruction_classes() => { name = "stw"; desc = ld_st_imm_str(name, insn); }, + ebpf::ST_DW_IMM if !sbpf_version.move_memory_instruction_classes() => { name = "stdw"; desc = ld_st_imm_str(name, insn); }, // BPF_STX class - ebpf::ST_B_REG => { name = "stxb"; desc = st_reg_str(name, insn); }, - ebpf::ST_H_REG => { name = "stxh"; desc = st_reg_str(name, insn); }, - ebpf::ST_W_REG => { name = "stxw"; desc = st_reg_str(name, insn); }, - ebpf::ST_DW_REG => { name = "stxdw"; desc = st_reg_str(name, insn); }, + ebpf::ST_B_REG if !sbpf_version.move_memory_instruction_classes() => { name = "stxb"; desc = st_reg_str(name, insn); }, + ebpf::ST_H_REG if !sbpf_version.move_memory_instruction_classes() => { name = "stxh"; desc = st_reg_str(name, insn); }, + ebpf::ST_W_REG if !sbpf_version.move_memory_instruction_classes() => { name = "stxw"; desc = st_reg_str(name, insn); }, + ebpf::ST_DW_REG if !sbpf_version.move_memory_instruction_classes() => { name = "stxdw"; desc = st_reg_str(name, insn); }, // BPF_ALU class ebpf::ADD32_IMM => { name = "add32"; desc = alu_imm_str(name, insn); }, diff --git a/src/interpreter.rs b/src/interpreter.rs index 4cf3eae7..351e6e7a 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -206,55 +206,55 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { }, // BPF_LDX class - ebpf::LD_B_REG => { + ebpf::LD_B_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; self.reg[dst] = translate_memory_access!(self, load, vm_addr, u8); }, - ebpf::LD_H_REG => { + ebpf::LD_H_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; self.reg[dst] = translate_memory_access!(self, load, vm_addr, u16); }, - ebpf::LD_W_REG => { + ebpf::LD_W_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; self.reg[dst] = translate_memory_access!(self, load, vm_addr, u32); }, - ebpf::LD_DW_REG => { + ebpf::LD_DW_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; self.reg[dst] = translate_memory_access!(self, load, vm_addr, u64); }, // BPF_ST class - ebpf::ST_B_IMM => { + ebpf::ST_B_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[dst] as i64).wrapping_add( insn.off as i64) as u64; translate_memory_access!(self, store, insn.imm, vm_addr, u8); }, - ebpf::ST_H_IMM => { + ebpf::ST_H_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; translate_memory_access!(self, store, insn.imm, vm_addr, u16); }, - ebpf::ST_W_IMM => { + ebpf::ST_W_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; translate_memory_access!(self, store, insn.imm, vm_addr, u32); }, - ebpf::ST_DW_IMM => { + ebpf::ST_DW_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; translate_memory_access!(self, store, insn.imm, vm_addr, u64); }, // BPF_STX class - ebpf::ST_B_REG => { + ebpf::ST_B_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; translate_memory_access!(self, store, self.reg[src], vm_addr, u8); }, - ebpf::ST_H_REG => { + ebpf::ST_H_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; translate_memory_access!(self, store, self.reg[src], vm_addr, u16); }, - ebpf::ST_W_REG => { + ebpf::ST_W_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; translate_memory_access!(self, store, self.reg[src], vm_addr, u32); }, - ebpf::ST_DW_REG => { + ebpf::ST_DW_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; translate_memory_access!(self, store, self.reg[src], vm_addr, u64); }, diff --git a/src/jit.rs b/src/jit.rs index aa711eb7..8eef1294 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -439,44 +439,44 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { }, // BPF_LDX class - ebpf::LD_B_REG => { + ebpf::LD_B_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 1, None); }, - ebpf::LD_H_REG => { + ebpf::LD_H_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 2, None); }, - ebpf::LD_W_REG => { + ebpf::LD_W_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 4, None); }, - ebpf::LD_DW_REG => { + ebpf::LD_DW_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 8, None); }, // BPF_ST class - ebpf::ST_B_IMM => { + ebpf::ST_B_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 1, Some(Value::Constant64(insn.imm, true))); }, - ebpf::ST_H_IMM => { + ebpf::ST_H_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 2, Some(Value::Constant64(insn.imm, true))); }, - ebpf::ST_W_IMM => { + ebpf::ST_W_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 4, Some(Value::Constant64(insn.imm, true))); }, - ebpf::ST_DW_IMM => { + ebpf::ST_DW_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 8, Some(Value::Constant64(insn.imm, true))); }, // BPF_STX class - ebpf::ST_B_REG => { + ebpf::ST_B_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 1, Some(Value::Register(src))); }, - ebpf::ST_H_REG => { + ebpf::ST_H_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 2, Some(Value::Register(src))); }, - ebpf::ST_W_REG => { + ebpf::ST_W_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 4, Some(Value::Register(src))); }, - ebpf::ST_DW_REG => { + ebpf::ST_DW_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 8, Some(Value::Register(src))); }, diff --git a/src/verifier.rs b/src/verifier.rs index 0e7b3504..c82fad1d 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -250,22 +250,22 @@ impl Verifier for RequisiteVerifier { }, // BPF_LDX class - ebpf::LD_B_REG => {}, - ebpf::LD_H_REG => {}, - ebpf::LD_W_REG => {}, - ebpf::LD_DW_REG => {}, + ebpf::LD_B_REG if !sbpf_version.move_memory_instruction_classes() => {}, + ebpf::LD_H_REG if !sbpf_version.move_memory_instruction_classes() => {}, + ebpf::LD_W_REG if !sbpf_version.move_memory_instruction_classes() => {}, + ebpf::LD_DW_REG if !sbpf_version.move_memory_instruction_classes() => {}, // BPF_ST class - ebpf::ST_B_IMM => store = true, - ebpf::ST_H_IMM => store = true, - ebpf::ST_W_IMM => store = true, - ebpf::ST_DW_IMM => store = true, + ebpf::ST_B_IMM if !sbpf_version.move_memory_instruction_classes() => store = true, + ebpf::ST_H_IMM if !sbpf_version.move_memory_instruction_classes() => store = true, + ebpf::ST_W_IMM if !sbpf_version.move_memory_instruction_classes() => store = true, + ebpf::ST_DW_IMM if !sbpf_version.move_memory_instruction_classes() => store = true, // BPF_STX class - ebpf::ST_B_REG => store = true, - ebpf::ST_H_REG => store = true, - ebpf::ST_W_REG => store = true, - ebpf::ST_DW_REG => store = true, + ebpf::ST_B_REG if !sbpf_version.move_memory_instruction_classes() => store = true, + ebpf::ST_H_REG if !sbpf_version.move_memory_instruction_classes() => store = true, + ebpf::ST_W_REG if !sbpf_version.move_memory_instruction_classes() => store = true, + ebpf::ST_DW_REG if !sbpf_version.move_memory_instruction_classes() => store = true, // BPF_ALU class ebpf::ADD32_IMM => {}, From a28a0ee4ae339376725b46d6684a99798e288433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 3 Oct 2024 17:21:52 +0200 Subject: [PATCH 06/10] Enables the new opcodes conditionally in the verifier. --- src/verifier.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/verifier.rs b/src/verifier.rs index c82fad1d..39158d59 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -274,8 +274,10 @@ impl Verifier for RequisiteVerifier { ebpf::SUB32_REG => {}, ebpf::MUL32_IMM if !sbpf_version.enable_pqr() => {}, ebpf::MUL32_REG if !sbpf_version.enable_pqr() => {}, + ebpf::LD_1B_REG if sbpf_version.move_memory_instruction_classes() => {}, ebpf::DIV32_IMM if !sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; }, ebpf::DIV32_REG if !sbpf_version.enable_pqr() => {}, + ebpf::LD_2B_REG if sbpf_version.move_memory_instruction_classes() => {}, ebpf::OR32_IMM => {}, ebpf::OR32_REG => {}, ebpf::AND32_IMM => {}, @@ -285,8 +287,10 @@ impl Verifier for RequisiteVerifier { ebpf::RSH32_IMM => { check_imm_shift(&insn, insn_ptr, 32)?; }, ebpf::RSH32_REG => {}, ebpf::NEG32 if sbpf_version.enable_neg() => {}, + ebpf::LD_4B_REG if sbpf_version.move_memory_instruction_classes() => {}, ebpf::MOD32_IMM if !sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; }, ebpf::MOD32_REG if !sbpf_version.enable_pqr() => {}, + ebpf::LD_8B_REG if sbpf_version.move_memory_instruction_classes() => {}, ebpf::XOR32_IMM => {}, ebpf::XOR32_REG => {}, ebpf::MOV32_IMM => {}, @@ -302,9 +306,13 @@ impl Verifier for RequisiteVerifier { ebpf::SUB64_IMM => {}, ebpf::SUB64_REG => {}, ebpf::MUL64_IMM if !sbpf_version.enable_pqr() => {}, + ebpf::ST_1B_IMM if sbpf_version.move_memory_instruction_classes() => store = true, ebpf::MUL64_REG if !sbpf_version.enable_pqr() => {}, + ebpf::ST_1B_REG if sbpf_version.move_memory_instruction_classes() => store = true, ebpf::DIV64_IMM if !sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; }, + ebpf::ST_2B_IMM if sbpf_version.move_memory_instruction_classes() => store = true, ebpf::DIV64_REG if !sbpf_version.enable_pqr() => {}, + ebpf::ST_2B_REG if sbpf_version.move_memory_instruction_classes() => store = true, ebpf::OR64_IMM => {}, ebpf::OR64_REG => {}, ebpf::AND64_IMM => {}, @@ -313,9 +321,13 @@ impl Verifier for RequisiteVerifier { ebpf::LSH64_REG => {}, ebpf::RSH64_IMM => { check_imm_shift(&insn, insn_ptr, 64)?; }, ebpf::RSH64_REG => {}, + ebpf::ST_4B_IMM if sbpf_version.move_memory_instruction_classes() => store = true, ebpf::NEG64 if sbpf_version.enable_neg() => {}, + ebpf::ST_4B_REG if sbpf_version.move_memory_instruction_classes() => store = true, ebpf::MOD64_IMM if !sbpf_version.enable_pqr() => { check_imm_nonzero(&insn, insn_ptr)?; }, + ebpf::ST_8B_IMM if sbpf_version.move_memory_instruction_classes() => store = true, ebpf::MOD64_REG if !sbpf_version.enable_pqr() => {}, + ebpf::ST_8B_REG if sbpf_version.move_memory_instruction_classes() => store = true, ebpf::XOR64_IMM => {}, ebpf::XOR64_REG => {}, ebpf::MOV64_IMM => {}, From 727d464feefb75a46d016e3aa7e457559cee5bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 3 Oct 2024 18:10:37 +0200 Subject: [PATCH 07/10] Enables the new opcodes conditionally in the dis-/assembler. --- src/assembler.rs | 64 ++++++++++++++++++------------ src/disassembler.rs | 12 ++++++ test_utils/src/lib.rs | 14 +++---- tests/assembler.rs | 90 +++++++++---------------------------------- 4 files changed, 77 insertions(+), 103 deletions(-) diff --git a/src/assembler.rs b/src/assembler.rs index c1311dd3..ffdc451c 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -19,7 +19,7 @@ use crate::{ }, ebpf::{self, Insn}, elf::Executable, - program::{BuiltinProgram, FunctionRegistry}, + program::{BuiltinProgram, FunctionRegistry, SBPFVersion}, vm::ContextObject, }; use std::collections::HashMap; @@ -47,7 +47,7 @@ enum InstructionType { NoOperand, } -fn make_instruction_map() -> HashMap { +fn make_instruction_map(sbpf_version: &SBPFVersion) -> HashMap { let mut result = HashMap::new(); let alu_binary_ops = [ @@ -66,11 +66,31 @@ fn make_instruction_map() -> HashMap { ("hor", ebpf::BPF_HOR), ]; + let mem_classes = [ + ( + "ldx", + LoadReg, + ebpf::BPF_MEM | ebpf::BPF_LDX, + ebpf::BPF_ALU | ebpf::BPF_X, + ), + ( + "st", + StoreImm, + ebpf::BPF_MEM | ebpf::BPF_ST, + ebpf::BPF_ALU64 | ebpf::BPF_K, + ), + ( + "stx", + StoreReg, + ebpf::BPF_MEM | ebpf::BPF_STX, + ebpf::BPF_ALU64 | ebpf::BPF_X, + ), + ]; let mem_sizes = [ - ("w", ebpf::BPF_W), - ("h", ebpf::BPF_H), - ("b", ebpf::BPF_B), - ("dw", ebpf::BPF_DW), + ("b", ebpf::BPF_B, ebpf::BPF_1B), + ("h", ebpf::BPF_H, ebpf::BPF_2B), + ("w", ebpf::BPF_W, ebpf::BPF_4B), + ("dw", ebpf::BPF_DW, ebpf::BPF_8B), ]; let jump_conditions = [ @@ -189,23 +209,19 @@ fn make_instruction_map() -> HashMap { ); entry("srem32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_SREM); - // LoadReg, StoreImm, and StoreReg. - for &(suffix, size) in &mem_sizes { - entry( - &format!("ldx{suffix}"), - LoadReg, - ebpf::BPF_MEM | ebpf::BPF_LDX | size, - ); - entry( - &format!("st{suffix}"), - StoreImm, - ebpf::BPF_MEM | ebpf::BPF_ST | size, - ); - entry( - &format!("stx{suffix}"), - StoreReg, - ebpf::BPF_MEM | ebpf::BPF_STX | size, - ); + // Memory + if sbpf_version.move_memory_instruction_classes() { + for &(prefix, class, _, opcode) in &mem_classes { + for &(suffix, _, size) in &mem_sizes { + entry(&format!("{prefix}{suffix}"), class, opcode | size); + } + } + } else { + for &(prefix, class, opcode, _) in &mem_classes { + for &(suffix, size, _) in &mem_sizes { + entry(&format!("{prefix}{suffix}"), class, opcode | size); + } + } } // JumpConditional. @@ -300,7 +316,7 @@ pub fn assemble( let sbpf_version = loader.get_config().enabled_sbpf_versions.end().clone(); let statements = parse(src)?; - let instruction_map = make_instruction_map(); + let instruction_map = make_instruction_map(&sbpf_version); let mut insn_ptr = 0; let mut function_registry = FunctionRegistry::default(); let mut labels = HashMap::new(); diff --git a/src/disassembler.rs b/src/disassembler.rs index da44c343..17a6d2f6 100644 --- a/src/disassembler.rs +++ b/src/disassembler.rs @@ -148,8 +148,10 @@ pub fn disassemble_instruction( ebpf::SUB32_REG => { name = "sub32"; desc = alu_reg_str(name, insn); }, ebpf::MUL32_IMM if !sbpf_version.enable_pqr() => { name = "mul32"; desc = alu_imm_str(name, insn); }, ebpf::MUL32_REG if !sbpf_version.enable_pqr() => { name = "mul32"; desc = alu_reg_str(name, insn); }, + ebpf::LD_1B_REG if sbpf_version.move_memory_instruction_classes() => { name = "ldxb"; desc = ld_reg_str(name, insn); }, ebpf::DIV32_IMM if !sbpf_version.enable_pqr() => { name = "div32"; desc = alu_imm_str(name, insn); }, ebpf::DIV32_REG if !sbpf_version.enable_pqr() => { name = "div32"; desc = alu_reg_str(name, insn); }, + ebpf::LD_2B_REG if sbpf_version.move_memory_instruction_classes() => { name = "ldxh"; desc = ld_reg_str(name, insn); }, ebpf::OR32_IMM => { name = "or32"; desc = alu_imm_str(name, insn); }, ebpf::OR32_REG => { name = "or32"; desc = alu_reg_str(name, insn); }, ebpf::AND32_IMM => { name = "and32"; desc = alu_imm_str(name, insn); }, @@ -159,8 +161,10 @@ pub fn disassemble_instruction( ebpf::RSH32_IMM => { name = "rsh32"; desc = alu_imm_str(name, insn); }, ebpf::RSH32_REG => { name = "rsh32"; desc = alu_reg_str(name, insn); }, ebpf::NEG32 if sbpf_version.enable_neg() => { name = "neg32"; desc = format!("{} r{}", name, insn.dst); }, + ebpf::LD_4B_REG if sbpf_version.move_memory_instruction_classes() => { name = "ldxw"; desc = ld_reg_str(name, insn); }, ebpf::MOD32_IMM if !sbpf_version.enable_pqr() => { name = "mod32"; desc = alu_imm_str(name, insn); }, ebpf::MOD32_REG if !sbpf_version.enable_pqr() => { name = "mod32"; desc = alu_reg_str(name, insn); }, + ebpf::LD_8B_REG if sbpf_version.move_memory_instruction_classes() => { name = "ldxdw"; desc = ld_reg_str(name, insn); }, ebpf::XOR32_IMM => { name = "xor32"; desc = alu_imm_str(name, insn); }, ebpf::XOR32_REG => { name = "xor32"; desc = alu_reg_str(name, insn); }, ebpf::MOV32_IMM => { name = "mov32"; desc = alu_imm_str(name, insn); }, @@ -176,9 +180,13 @@ pub fn disassemble_instruction( ebpf::SUB64_IMM => { name = "sub64"; desc = alu_imm_str(name, insn); }, ebpf::SUB64_REG => { name = "sub64"; desc = alu_reg_str(name, insn); }, ebpf::MUL64_IMM if !sbpf_version.enable_pqr() => { name = "mul64"; desc = alu_imm_str(name, insn); }, + ebpf::ST_1B_IMM if sbpf_version.move_memory_instruction_classes() => { name = "stb"; desc = ld_st_imm_str(name, insn); }, ebpf::MUL64_REG if !sbpf_version.enable_pqr() => { name = "mul64"; desc = alu_reg_str(name, insn); }, + ebpf::ST_1B_REG if sbpf_version.move_memory_instruction_classes() => { name = "stxb"; desc = st_reg_str(name, insn); }, ebpf::DIV64_IMM if !sbpf_version.enable_pqr() => { name = "div64"; desc = alu_imm_str(name, insn); }, + ebpf::ST_2B_IMM if sbpf_version.move_memory_instruction_classes() => { name = "sth"; desc = ld_st_imm_str(name, insn); }, ebpf::DIV64_REG if !sbpf_version.enable_pqr() => { name = "div64"; desc = alu_reg_str(name, insn); }, + ebpf::ST_2B_REG if sbpf_version.move_memory_instruction_classes() => { name = "stxh"; desc = st_reg_str(name, insn); }, ebpf::OR64_IMM => { name = "or64"; desc = alu_imm_str(name, insn); }, ebpf::OR64_REG => { name = "or64"; desc = alu_reg_str(name, insn); }, ebpf::AND64_IMM => { name = "and64"; desc = alu_imm_str(name, insn); }, @@ -187,9 +195,13 @@ pub fn disassemble_instruction( ebpf::LSH64_REG => { name = "lsh64"; desc = alu_reg_str(name, insn); }, ebpf::RSH64_IMM => { name = "rsh64"; desc = alu_imm_str(name, insn); }, ebpf::RSH64_REG => { name = "rsh64"; desc = alu_reg_str(name, insn); }, + ebpf::ST_4B_IMM if sbpf_version.move_memory_instruction_classes() => { name = "stw"; desc = ld_st_imm_str(name, insn); }, ebpf::NEG64 if sbpf_version.enable_neg() => { name = "neg64"; desc = format!("{} r{}", name, insn.dst); }, + ebpf::ST_4B_REG if sbpf_version.move_memory_instruction_classes() => { name = "stxw"; desc = st_reg_str(name, insn); }, ebpf::MOD64_IMM if !sbpf_version.enable_pqr() => { name = "mod64"; desc = alu_imm_str(name, insn); }, + ebpf::ST_8B_IMM if sbpf_version.move_memory_instruction_classes() => { name = "stdw"; desc = ld_st_imm_str(name, insn); }, ebpf::MOD64_REG if !sbpf_version.enable_pqr() => { name = "mod64"; desc = alu_reg_str(name, insn); }, + ebpf::ST_8B_REG if sbpf_version.move_memory_instruction_classes() => { name = "stxdw"; desc = st_reg_str(name, insn); }, ebpf::XOR64_IMM => { name = "xor64"; desc = alu_imm_str(name, insn); }, ebpf::XOR64_REG => { name = "xor64"; desc = alu_reg_str(name, insn); }, ebpf::MOV64_IMM => { name = "mov64"; desc = alu_imm_str(name, insn); }, diff --git a/test_utils/src/lib.rs b/test_utils/src/lib.rs index 7c56eb57..360b7c7e 100644 --- a/test_utils/src/lib.rs +++ b/test_utils/src/lib.rs @@ -87,21 +87,21 @@ pub const TCP_SACK_ASM: &str = " exit"; pub const TCP_SACK_BIN: [u8; 352] = [ - 0x71, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, // - 0x71, 0x13, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x2c, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x2c, 0x13, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x67, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // 0x4f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x55, 0x03, 0x25, 0x00, 0x08, 0x00, 0x00, 0x00, // - 0x71, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x2c, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x55, 0x02, 0x23, 0x00, 0x06, 0x00, 0x00, 0x00, // - 0x71, 0x12, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x2c, 0x12, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, // 0x57, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, // 0x67, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // 0x0f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // - 0x69, 0x14, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x3c, 0x14, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x07, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, // 0x77, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // 0x57, 0x04, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, // @@ -115,7 +115,7 @@ pub const TCP_SACK_BIN: [u8; 352] = [ 0xc7, 0x05, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // 0xbf, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0f, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // - 0x71, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x2c, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x15, 0x05, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, // 0x15, 0x05, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xbf, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // @@ -123,7 +123,7 @@ pub const TCP_SACK_BIN: [u8; 352] = [ 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x07, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // 0xbf, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // - 0x71, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x2c, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0f, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x67, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // 0xc7, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // diff --git a/tests/assembler.rs b/tests/assembler.rs index 4020d6cd..2898f7da 100644 --- a/tests/assembler.rs +++ b/tests/assembler.rs @@ -72,33 +72,6 @@ fn test_neg64() { assert_eq!(asm("neg64 r1"), Ok(vec![insn(0, ebpf::NEG64, 1, 0, 0, 0)])); } -// Example for InstructionType::LoadReg. -#[test] -fn test_ldxw() { - assert_eq!( - asm("ldxw r1, [r2+5]"), - Ok(vec![insn(0, ebpf::LD_W_REG, 1, 2, 5, 0)]) - ); -} - -// Example for InstructionType::StoreImm. -#[test] -fn test_stw() { - assert_eq!( - asm("stw [r2+5], 7"), - Ok(vec![insn(0, ebpf::ST_W_IMM, 2, 0, 5, 7)]) - ); -} - -// Example for InstructionType::StoreReg. -#[test] -fn test_stxw() { - assert_eq!( - asm("stxw [r2+5], r8"), - Ok(vec![insn(0, ebpf::ST_W_REG, 2, 8, 5, 0)]) - ); -} - // Example for InstructionType::JumpUnconditional. #[test] fn test_ja() { @@ -161,33 +134,6 @@ fn test_lddw() { ); } -// Example for InstructionType::LoadReg. -#[test] -fn test_ldxdw() { - assert_eq!( - asm("ldxdw r1, [r2+3]"), - Ok(vec![insn(0, ebpf::LD_DW_REG, 1, 2, 3, 0)]) - ); -} - -// Example for InstructionType::StoreImm. -#[test] -fn test_sth() { - assert_eq!( - asm("sth [r1+2], 3"), - Ok(vec![insn(0, ebpf::ST_H_IMM, 1, 0, 2, 3)]) - ); -} - -// Example for InstructionType::StoreReg. -#[test] -fn test_stxh() { - assert_eq!( - asm("stxh [r1+2], r3"), - Ok(vec![insn(0, ebpf::ST_H_REG, 1, 3, 2, 0)]) - ); -} - // Test all supported AluBinary mnemonics. #[test] fn test_alu_binary() { @@ -385,15 +331,15 @@ fn test_alu_unary() { #[test] fn test_load_reg() { assert_eq!( - asm("ldxw r1, [r2+3] + asm("ldxb r1, [r2+3] ldxh r1, [r2+3] - ldxb r1, [r2+3] + ldxw r1, [r2+3] ldxdw r1, [r2+3]"), Ok(vec![ - insn(0, ebpf::LD_W_REG, 1, 2, 3, 0), - insn(1, ebpf::LD_H_REG, 1, 2, 3, 0), - insn(2, ebpf::LD_B_REG, 1, 2, 3, 0), - insn(3, ebpf::LD_DW_REG, 1, 2, 3, 0) + insn(0, ebpf::LD_1B_REG, 1, 2, 3, 0), + insn(1, ebpf::LD_2B_REG, 1, 2, 3, 0), + insn(2, ebpf::LD_4B_REG, 1, 2, 3, 0), + insn(3, ebpf::LD_8B_REG, 1, 2, 3, 0) ]) ); } @@ -402,15 +348,15 @@ fn test_load_reg() { #[test] fn test_store_imm() { assert_eq!( - asm("stw [r1+2], 3 + asm("stb [r1+2], 3 sth [r1+2], 3 - stb [r1+2], 3 + stw [r1+2], 3 stdw [r1+2], 3"), Ok(vec![ - insn(0, ebpf::ST_W_IMM, 1, 0, 2, 3), - insn(1, ebpf::ST_H_IMM, 1, 0, 2, 3), - insn(2, ebpf::ST_B_IMM, 1, 0, 2, 3), - insn(3, ebpf::ST_DW_IMM, 1, 0, 2, 3) + insn(0, ebpf::ST_1B_IMM, 1, 0, 2, 3), + insn(1, ebpf::ST_2B_IMM, 1, 0, 2, 3), + insn(2, ebpf::ST_4B_IMM, 1, 0, 2, 3), + insn(3, ebpf::ST_8B_IMM, 1, 0, 2, 3) ]) ); } @@ -419,15 +365,15 @@ fn test_store_imm() { #[test] fn test_store_reg() { assert_eq!( - asm("stxw [r1+2], r3 + asm("stxb [r1+2], r3 stxh [r1+2], r3 - stxb [r1+2], r3 + stxw [r1+2], r3 stxdw [r1+2], r3"), Ok(vec![ - insn(0, ebpf::ST_W_REG, 1, 3, 2, 0), - insn(1, ebpf::ST_H_REG, 1, 3, 2, 0), - insn(2, ebpf::ST_B_REG, 1, 3, 2, 0), - insn(3, ebpf::ST_DW_REG, 1, 3, 2, 0) + insn(0, ebpf::ST_1B_REG, 1, 3, 2, 0), + insn(1, ebpf::ST_2B_REG, 1, 3, 2, 0), + insn(2, ebpf::ST_4B_REG, 1, 3, 2, 0), + insn(3, ebpf::ST_8B_REG, 1, 3, 2, 0) ]) ); } From eda979d8c6b0e845ace5f4b7488fc97c23d5dd7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Mon, 7 Oct 2024 21:00:47 +0200 Subject: [PATCH 08/10] Enables the new opcodes conditionally in the interpreter and JIT. --- src/interpreter.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++- src/jit.rs | 36 +++++++++++++++++++++++++++++++++ tests/execution.rs | 2 +- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index 351e6e7a..66fd9b70 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -225,7 +225,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { // BPF_ST class ebpf::ST_B_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { - let vm_addr = (self.reg[dst] as i64).wrapping_add( insn.off as i64) as u64; + let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; translate_memory_access!(self, store, insn.imm, vm_addr, u8); }, ebpf::ST_H_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => { @@ -270,11 +270,19 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { ebpf::SUB32_REG => self.reg[dst] = self.sign_extension((self.reg[dst] as i32).wrapping_sub(self.reg[src] as i32)), ebpf::MUL32_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as i32).wrapping_mul(insn.imm as i32) as u64, ebpf::MUL32_REG if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as i32).wrapping_mul(self.reg[src] as i32) as u64, + ebpf::LD_1B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; + self.reg[dst] = translate_memory_access!(self, load, vm_addr, u8); + }, ebpf::DIV32_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u32 / insn.imm as u32) as u64, ebpf::DIV32_REG if !self.executable.get_sbpf_version().enable_pqr() => { throw_error!(DivideByZero; self, self.reg[src], u32); self.reg[dst] = (self.reg[dst] as u32 / self.reg[src] as u32) as u64; }, + ebpf::LD_2B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; + self.reg[dst] = translate_memory_access!(self, load, vm_addr, u16); + }, ebpf::OR32_IMM => self.reg[dst] = (self.reg[dst] as u32 | insn.imm as u32) as u64, ebpf::OR32_REG => self.reg[dst] = (self.reg[dst] as u32 | self.reg[src] as u32) as u64, ebpf::AND32_IMM => self.reg[dst] = (self.reg[dst] as u32 & insn.imm as u32) as u64, @@ -284,11 +292,19 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { ebpf::RSH32_IMM => self.reg[dst] = (self.reg[dst] as u32).wrapping_shr(insn.imm as u32) as u64, ebpf::RSH32_REG => self.reg[dst] = (self.reg[dst] as u32).wrapping_shr(self.reg[src] as u32) as u64, ebpf::NEG32 if self.executable.get_sbpf_version().enable_neg() => self.reg[dst] = (self.reg[dst] as i32).wrapping_neg() as u64 & (u32::MAX as u64), + ebpf::LD_4B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; + self.reg[dst] = translate_memory_access!(self, load, vm_addr, u32); + }, ebpf::MOD32_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u32 % insn.imm as u32) as u64, ebpf::MOD32_REG if !self.executable.get_sbpf_version().enable_pqr() => { throw_error!(DivideByZero; self, self.reg[src], u32); self.reg[dst] = (self.reg[dst] as u32 % self.reg[src] as u32) as u64; }, + ebpf::LD_8B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; + self.reg[dst] = translate_memory_access!(self, load, vm_addr, u64); + }, ebpf::XOR32_IMM => self.reg[dst] = (self.reg[dst] as u32 ^ insn.imm as u32) as u64, ebpf::XOR32_REG => self.reg[dst] = (self.reg[dst] as u32 ^ self.reg[src] as u32) as u64, ebpf::MOV32_IMM => self.reg[dst] = insn.imm as u32 as u64, @@ -330,12 +346,28 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { }, ebpf::SUB64_REG => self.reg[dst] = self.reg[dst].wrapping_sub(self.reg[src]), ebpf::MUL64_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = self.reg[dst].wrapping_mul(insn.imm as u64), + ebpf::ST_1B_IMM if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; + translate_memory_access!(self, store, insn.imm, vm_addr, u8); + }, ebpf::MUL64_REG if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = self.reg[dst].wrapping_mul(self.reg[src]), + ebpf::ST_1B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; + translate_memory_access!(self, store, self.reg[src], vm_addr, u8); + }, ebpf::DIV64_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] /= insn.imm as u64, + ebpf::ST_2B_IMM if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; + translate_memory_access!(self, store, insn.imm, vm_addr, u16); + }, ebpf::DIV64_REG if !self.executable.get_sbpf_version().enable_pqr() => { throw_error!(DivideByZero; self, self.reg[src], u64); self.reg[dst] /= self.reg[src]; }, + ebpf::ST_2B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; + translate_memory_access!(self, store, self.reg[src], vm_addr, u16); + }, ebpf::OR64_IMM => self.reg[dst] |= insn.imm as u64, ebpf::OR64_REG => self.reg[dst] |= self.reg[src], ebpf::AND64_IMM => self.reg[dst] &= insn.imm as u64, @@ -344,12 +376,28 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { ebpf::LSH64_REG => self.reg[dst] = self.reg[dst].wrapping_shl(self.reg[src] as u32), ebpf::RSH64_IMM => self.reg[dst] = self.reg[dst].wrapping_shr(insn.imm as u32), ebpf::RSH64_REG => self.reg[dst] = self.reg[dst].wrapping_shr(self.reg[src] as u32), + ebpf::ST_4B_IMM if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; + translate_memory_access!(self, store, insn.imm, vm_addr, u32); + }, ebpf::NEG64 if self.executable.get_sbpf_version().enable_neg() => self.reg[dst] = (self.reg[dst] as i64).wrapping_neg() as u64, + ebpf::ST_4B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; + translate_memory_access!(self, store, self.reg[src], vm_addr, u32); + }, ebpf::MOD64_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] %= insn.imm as u64, + ebpf::ST_8B_IMM if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; + translate_memory_access!(self, store, insn.imm, vm_addr, u64); + }, ebpf::MOD64_REG if !self.executable.get_sbpf_version().enable_pqr() => { throw_error!(DivideByZero; self, self.reg[src], u64); self.reg[dst] %= self.reg[src]; }, + ebpf::ST_8B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; + translate_memory_access!(self, store, self.reg[src], vm_addr, u64); + }, ebpf::XOR64_IMM => self.reg[dst] ^= insn.imm as u64, ebpf::XOR64_REG => self.reg[dst] ^= self.reg[src], ebpf::MOV64_IMM => self.reg[dst] = insn.imm as u64, diff --git a/src/jit.rs b/src/jit.rs index 8eef1294..e53da412 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -514,8 +514,14 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { }, ebpf::MUL32_IMM | ebpf::DIV32_IMM | ebpf::MOD32_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.emit_product_quotient_remainder(OperandSize::S32, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD, (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL, dst, dst, Some(insn.imm)), + ebpf::LD_1B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 1, None); + }, ebpf::MUL32_REG | ebpf::DIV32_REG | ebpf::MOD32_REG if !self.executable.get_sbpf_version().enable_pqr() => self.emit_product_quotient_remainder(OperandSize::S32, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD, (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL, src, dst, None), + ebpf::LD_2B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 2, None); + }, ebpf::OR32_IMM => self.emit_sanitized_alu(OperandSize::S32, 0x09, 1, dst, insn.imm), ebpf::OR32_REG => self.emit_ins(X86Instruction::alu(OperandSize::S32, 0x09, src, dst, 0, None)), ebpf::AND32_IMM => self.emit_sanitized_alu(OperandSize::S32, 0x21, 4, dst, insn.imm), @@ -525,6 +531,12 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { ebpf::RSH32_IMM => self.emit_shift(OperandSize::S32, 5, REGISTER_SCRATCH, dst, Some(insn.imm)), ebpf::RSH32_REG => self.emit_shift(OperandSize::S32, 5, src, dst, None), ebpf::NEG32 if self.executable.get_sbpf_version().enable_neg() => self.emit_ins(X86Instruction::alu(OperandSize::S32, 0xf7, 3, dst, 0, None)), + ebpf::LD_4B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 4, None); + }, + ebpf::LD_8B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 8, None); + }, ebpf::XOR32_IMM => self.emit_sanitized_alu(OperandSize::S32, 0x31, 6, dst, insn.imm), ebpf::XOR32_REG => self.emit_ins(X86Instruction::alu(OperandSize::S32, 0x31, src, dst, 0, None)), ebpf::MOV32_IMM => { @@ -587,8 +599,20 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { ebpf::SUB64_REG => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x29, src, dst, 0, None)), ebpf::MUL64_IMM | ebpf::DIV64_IMM | ebpf::MOD64_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.emit_product_quotient_remainder(OperandSize::S64, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD, (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL, dst, dst, Some(insn.imm)), + ebpf::ST_1B_IMM if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 1, Some(Value::Constant64(insn.imm, true))); + }, + ebpf::ST_2B_IMM if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 2, Some(Value::Constant64(insn.imm, true))); + }, ebpf::MUL64_REG | ebpf::DIV64_REG | ebpf::MOD64_REG if !self.executable.get_sbpf_version().enable_pqr() => self.emit_product_quotient_remainder(OperandSize::S64, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD, (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL, src, dst, None), + ebpf::ST_1B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 1, Some(Value::Register(src))); + }, + ebpf::ST_2B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 2, Some(Value::Register(src))); + }, ebpf::OR64_IMM => self.emit_sanitized_alu(OperandSize::S64, 0x09, 1, dst, insn.imm), ebpf::OR64_REG => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x09, src, dst, 0, None)), ebpf::AND64_IMM => self.emit_sanitized_alu(OperandSize::S64, 0x21, 4, dst, insn.imm), @@ -597,7 +621,19 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { ebpf::LSH64_REG => self.emit_shift(OperandSize::S64, 4, src, dst, None), ebpf::RSH64_IMM => self.emit_shift(OperandSize::S64, 5, REGISTER_SCRATCH, dst, Some(insn.imm)), ebpf::RSH64_REG => self.emit_shift(OperandSize::S64, 5, src, dst, None), + ebpf::ST_4B_IMM if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 4, Some(Value::Constant64(insn.imm, true))); + }, ebpf::NEG64 if self.executable.get_sbpf_version().enable_neg() => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0xf7, 3, dst, 0, None)), + ebpf::ST_4B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 4, Some(Value::Register(src))); + }, + ebpf::ST_8B_IMM if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 8, Some(Value::Constant64(insn.imm, true))); + }, + ebpf::ST_8B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => { + self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 8, Some(Value::Register(src))); + }, ebpf::XOR64_IMM => self.emit_sanitized_alu(OperandSize::S64, 0x31, 6, dst, insn.imm), ebpf::XOR64_REG => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x31, src, dst, 0, None)), ebpf::MOV64_IMM => { diff --git a/tests/execution.rs b/tests/execution.rs index 3eea021a..8f7363ce 100644 --- a/tests/execution.rs +++ b/tests/execution.rs @@ -2283,7 +2283,7 @@ fn test_err_mem_access_out_of_bound() { let mut prog = [0; 32]; prog[0] = ebpf::MOV32_IMM; prog[8] = ebpf::HOR64_IMM; - prog[16] = ebpf::ST_B_IMM; + prog[16] = ebpf::ST_1B_IMM; prog[24] = ebpf::EXIT; let loader = Arc::new(BuiltinProgram::new_mock()); for address in [0x2u64, 0x8002u64, 0x80000002u64, 0x8000000000000002u64] { From f603d3439c97ceaca1b9249adc7f0bfa50d07862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Fri, 4 Oct 2024 19:20:23 +0200 Subject: [PATCH 09/10] Renames BPF_ALU => BPF_ALU32_LOAD. Renames BPF_ALU64 => BPF_ALU64_STORE. --- src/assembler.rs | 12 +-- src/disassembler.rs | 4 +- src/ebpf.rs | 138 ++++++++++++++++----------------- src/insn_builder.rs | 4 +- src/interpreter.rs | 4 +- src/jit.rs | 4 +- src/verifier.rs | 4 +- tests/execution.rs | 2 +- tests/exercise_instructions.rs | 2 +- 9 files changed, 87 insertions(+), 87 deletions(-) diff --git a/src/assembler.rs b/src/assembler.rs index ffdc451c..d3966ffb 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -71,19 +71,19 @@ fn make_instruction_map(sbpf_version: &SBPFVersion) -> HashMap HashMap( ebpf::ST_W_REG if !sbpf_version.move_memory_instruction_classes() => { name = "stxw"; desc = st_reg_str(name, insn); }, ebpf::ST_DW_REG if !sbpf_version.move_memory_instruction_classes() => { name = "stxdw"; desc = st_reg_str(name, insn); }, - // BPF_ALU class + // BPF_ALU32_LOAD class ebpf::ADD32_IMM => { name = "add32"; desc = alu_imm_str(name, insn); }, ebpf::ADD32_REG => { name = "add32"; desc = alu_reg_str(name, insn); }, ebpf::SUB32_IMM => { name = "sub32"; desc = alu_imm_str(name, insn); }, @@ -174,7 +174,7 @@ pub fn disassemble_instruction( ebpf::LE => { name = "le"; desc = byteswap_str(name, insn); }, ebpf::BE => { name = "be"; desc = byteswap_str(name, insn); }, - // BPF_ALU64 class + // BPF_ALU64_STORE class ebpf::ADD64_IMM => { name = "add64"; desc = alu_imm_str(name, insn); }, ebpf::ADD64_REG => { name = "add64"; desc = alu_reg_str(name, insn); }, ebpf::SUB64_IMM => { name = "sub64"; desc = alu_imm_str(name, insn); }, diff --git a/src/ebpf.rs b/src/ebpf.rs index 6b6cdd42..b15a2b7f 100644 --- a/src/ebpf.rs +++ b/src/ebpf.rs @@ -66,13 +66,13 @@ pub const BPF_ST: u8 = 0x02; /// BPF operation class: store value from register. [DEPRECATED] pub const BPF_STX: u8 = 0x03; /// BPF operation class: 32 bit arithmetic or load. -pub const BPF_ALU: u8 = 0x04; +pub const BPF_ALU32_LOAD: u8 = 0x04; /// BPF operation class: control flow. pub const BPF_JMP: u8 = 0x05; /// BPF operation class: product / quotient / remainder. pub const BPF_PQR: u8 = 0x06; /// BPF operation class: 64 bit arithmetic or store. -pub const BPF_ALU64: u8 = 0x07; +pub const BPF_ALU64_STORE: u8 = 0x07; // For load and store instructions: // +------------+--------+------------+ @@ -112,7 +112,7 @@ pub const BPF_MEM: u8 = 0x60; // [ 0xa0 reserved ] // [ 0xc0 reserved ] -// For arithmetic (BPF_ALU/BPF_ALU64) and jump (BPF_JMP) instructions: +// For arithmetic (BPF_ALU/BPF_ALU64_STORE) and jump (BPF_JMP) instructions: // +----------------+--------+--------+ // | 4 bits |1 b.| 3 bits | // | operation code | src| insn class | @@ -125,7 +125,7 @@ pub const BPF_K: u8 = 0x00; /// BPF source operand modifier: `src` register. pub const BPF_X: u8 = 0x08; -// Operation codes -- BPF_ALU or BPF_ALU64 classes: +// Operation codes -- BPF_ALU32_LOAD or BPF_ALU64_STORE classes: /// BPF ALU/ALU64 operation code: addition. pub const BPF_ADD: u8 = 0x00; /// BPF ALU/ALU64 operation code: subtraction. @@ -238,80 +238,80 @@ pub const ST_W_REG: u8 = BPF_STX | BPF_MEM | BPF_W; pub const ST_DW_REG: u8 = BPF_STX | BPF_MEM | BPF_DW; /// BPF opcode: `ldxb dst, [src + off]` /// `dst = (src + off) as u8`. -pub const LD_1B_REG: u8 = BPF_ALU | BPF_X | BPF_1B; +pub const LD_1B_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_1B; /// BPF opcode: `ldxh dst, [src + off]` /// `dst = (src + off) as u16`. -pub const LD_2B_REG: u8 = BPF_ALU | BPF_X | BPF_2B; +pub const LD_2B_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_2B; /// BPF opcode: `ldxw dst, [src + off]` /// `dst = (src + off) as u32`. -pub const LD_4B_REG: u8 = BPF_ALU | BPF_X | BPF_4B; +pub const LD_4B_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_4B; /// BPF opcode: `ldxdw dst, [src + off]` /// `dst = (src + off) as u64`. -pub const LD_8B_REG: u8 = BPF_ALU | BPF_X | BPF_8B; +pub const LD_8B_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_8B; /// BPF opcode: `stb [dst + off], imm` /// `(dst + offset) as u8 = imm`. -pub const ST_1B_IMM: u8 = BPF_ALU64 | BPF_K | BPF_1B; +pub const ST_1B_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_1B; /// BPF opcode: `sth [dst + off], imm` /// `(dst + offset) as u16 = imm`. -pub const ST_2B_IMM: u8 = BPF_ALU64 | BPF_K | BPF_2B; +pub const ST_2B_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_2B; /// BPF opcode: `stw [dst + off], imm` /// `(dst + offset) as u32 = imm`. -pub const ST_4B_IMM: u8 = BPF_ALU64 | BPF_K | BPF_4B; +pub const ST_4B_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_4B; /// BPF opcode: `stdw [dst + off], imm` /// `(dst + offset) as u64 = imm`. -pub const ST_8B_IMM: u8 = BPF_ALU64 | BPF_K | BPF_8B; +pub const ST_8B_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_8B; /// BPF opcode: `stxb [dst + off], src` /// `(dst + offset) as u8 = src`. -pub const ST_1B_REG: u8 = BPF_ALU64 | BPF_X | BPF_1B; +pub const ST_1B_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_1B; /// BPF opcode: `stxh [dst + off], src` /// `(dst + offset) as u16 = src`. -pub const ST_2B_REG: u8 = BPF_ALU64 | BPF_X | BPF_2B; +pub const ST_2B_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_2B; /// BPF opcode: `stxw [dst + off], src` /// `(dst + offset) as u32 = src`. -pub const ST_4B_REG: u8 = BPF_ALU64 | BPF_X | BPF_4B; +pub const ST_4B_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_4B; /// BPF opcode: `stxdw [dst + off], src` /// `(dst + offset) as u64 = src`. -pub const ST_8B_REG: u8 = BPF_ALU64 | BPF_X | BPF_8B; +pub const ST_8B_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_8B; /// BPF opcode: `add32 dst, imm` /// `dst += imm`. -pub const ADD32_IMM: u8 = BPF_ALU | BPF_K | BPF_ADD; +pub const ADD32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_ADD; /// BPF opcode: `add32 dst, src` /// `dst += src`. -pub const ADD32_REG: u8 = BPF_ALU | BPF_X | BPF_ADD; +pub const ADD32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_ADD; /// BPF opcode: `sub32 dst, imm` /// `dst = imm - dst`. -pub const SUB32_IMM: u8 = BPF_ALU | BPF_K | BPF_SUB; +pub const SUB32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_SUB; /// BPF opcode: `sub32 dst, src` /// `dst -= src`. -pub const SUB32_REG: u8 = BPF_ALU | BPF_X | BPF_SUB; +pub const SUB32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_SUB; /// BPF opcode: `mul32 dst, imm` /// `dst *= imm`. -pub const MUL32_IMM: u8 = BPF_ALU | BPF_K | BPF_MUL; +pub const MUL32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_MUL; /// BPF opcode: `mul32 dst, src` /// `dst *= src`. -pub const MUL32_REG: u8 = BPF_ALU | BPF_X | BPF_MUL; +pub const MUL32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_MUL; /// BPF opcode: `div32 dst, imm` /// `dst /= imm`. -pub const DIV32_IMM: u8 = BPF_ALU | BPF_K | BPF_DIV; +pub const DIV32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_DIV; /// BPF opcode: `div32 dst, src` /// `dst /= src`. -pub const DIV32_REG: u8 = BPF_ALU | BPF_X | BPF_DIV; +pub const DIV32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_DIV; /// BPF opcode: `or32 dst, imm` /// `dst |= imm`. -pub const OR32_IMM: u8 = BPF_ALU | BPF_K | BPF_OR; +pub const OR32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_OR; /// BPF opcode: `or32 dst, src` /// `dst |= src`. -pub const OR32_REG: u8 = BPF_ALU | BPF_X | BPF_OR; +pub const OR32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_OR; /// BPF opcode: `and32 dst, imm` /// `dst &= imm`. -pub const AND32_IMM: u8 = BPF_ALU | BPF_K | BPF_AND; +pub const AND32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_AND; /// BPF opcode: `and32 dst, src` /// `dst &= src`. -pub const AND32_REG: u8 = BPF_ALU | BPF_X | BPF_AND; +pub const AND32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_AND; /// BPF opcode: `lsh32 dst, imm` /// `dst <<= imm`. -pub const LSH32_IMM: u8 = BPF_ALU | BPF_K | BPF_LSH; +pub const LSH32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_LSH; /// BPF opcode: `lsh32 dst, src` /// `dst <<= src`. -pub const LSH32_REG: u8 = BPF_ALU | BPF_X | BPF_LSH; +pub const LSH32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_LSH; /// BPF opcode: `rsh32 dst, imm` /// `dst >>= imm`. -pub const RSH32_IMM: u8 = BPF_ALU | BPF_K | BPF_RSH; +pub const RSH32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_RSH; /// BPF opcode: `rsh32 dst, src` /// `dst >>= src`. -pub const RSH32_REG: u8 = BPF_ALU | BPF_X | BPF_RSH; +pub const RSH32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_RSH; /// BPF opcode: `neg32 dst` /// `dst = -dst`. -pub const NEG32: u8 = BPF_ALU | BPF_NEG; +pub const NEG32: u8 = BPF_ALU32_LOAD | BPF_NEG; /// BPF opcode: `mod32 dst, imm` /// `dst %= imm`. -pub const MOD32_IMM: u8 = BPF_ALU | BPF_K | BPF_MOD; +pub const MOD32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_MOD; /// BPF opcode: `mod32 dst, src` /// `dst %= src`. -pub const MOD32_REG: u8 = BPF_ALU | BPF_X | BPF_MOD; +pub const MOD32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_MOD; /// BPF opcode: `xor32 dst, imm` /// `dst ^= imm`. -pub const XOR32_IMM: u8 = BPF_ALU | BPF_K | BPF_XOR; +pub const XOR32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_XOR; /// BPF opcode: `xor32 dst, src` /// `dst ^= src`. -pub const XOR32_REG: u8 = BPF_ALU | BPF_X | BPF_XOR; +pub const XOR32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_XOR; /// BPF opcode: `mov32 dst, imm` /// `dst = imm`. -pub const MOV32_IMM: u8 = BPF_ALU | BPF_K | BPF_MOV; +pub const MOV32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_MOV; /// BPF opcode: `mov32 dst, src` /// `dst = src`. -pub const MOV32_REG: u8 = BPF_ALU | BPF_X | BPF_MOV; +pub const MOV32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_MOV; /// BPF opcode: `arsh32 dst, imm` /// `dst >>= imm (arithmetic)`. -pub const ARSH32_IMM: u8 = BPF_ALU | BPF_K | BPF_ARSH; +pub const ARSH32_IMM: u8 = BPF_ALU32_LOAD | BPF_K | BPF_ARSH; /// BPF opcode: `arsh32 dst, src` /// `dst >>= src (arithmetic)`. -pub const ARSH32_REG: u8 = BPF_ALU | BPF_X | BPF_ARSH; +pub const ARSH32_REG: u8 = BPF_ALU32_LOAD | BPF_X | BPF_ARSH; /// BPF opcode: `lmul32 dst, imm` /// `dst *= (dst * imm) as u32`. pub const LMUL32_IMM: u8 = BPF_PQR | BPF_K | BPF_LMUL; @@ -343,62 +343,62 @@ pub const SREM32_IMM: u8 = BPF_PQR | BPF_K | BPF_SREM; pub const SREM32_REG: u8 = BPF_PQR | BPF_X | BPF_SREM; /// BPF opcode: `le dst` /// `dst = htole(dst), with imm in {16, 32, 64}`. -pub const LE: u8 = BPF_ALU | BPF_K | BPF_END; +pub const LE: u8 = BPF_ALU32_LOAD | BPF_K | BPF_END; /// BPF opcode: `be dst` /// `dst = htobe(dst), with imm in {16, 32, 64}`. -pub const BE: u8 = BPF_ALU | BPF_X | BPF_END; +pub const BE: u8 = BPF_ALU32_LOAD | BPF_X | BPF_END; /// BPF opcode: `add64 dst, imm` /// `dst += imm`. -pub const ADD64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_ADD; +pub const ADD64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_ADD; /// BPF opcode: `add64 dst, src` /// `dst += src`. -pub const ADD64_REG: u8 = BPF_ALU64 | BPF_X | BPF_ADD; +pub const ADD64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_ADD; /// BPF opcode: `sub64 dst, imm` /// `dst -= imm`. -pub const SUB64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_SUB; +pub const SUB64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_SUB; /// BPF opcode: `sub64 dst, src` /// `dst -= src`. -pub const SUB64_REG: u8 = BPF_ALU64 | BPF_X | BPF_SUB; +pub const SUB64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_SUB; /// BPF opcode: `mul64 dst, imm` /// `dst *= imm`. -pub const MUL64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_MUL; +pub const MUL64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_MUL; /// BPF opcode: `mul64 dst, src` /// `dst *= src`. -pub const MUL64_REG: u8 = BPF_ALU64 | BPF_X | BPF_MUL; +pub const MUL64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_MUL; /// BPF opcode: `div64 dst, imm` /// `dst /= imm`. -pub const DIV64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_DIV; +pub const DIV64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_DIV; /// BPF opcode: `div64 dst, src` /// `dst /= src`. -pub const DIV64_REG: u8 = BPF_ALU64 | BPF_X | BPF_DIV; +pub const DIV64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_DIV; /// BPF opcode: `or64 dst, imm` /// `dst |= imm`. -pub const OR64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_OR; +pub const OR64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_OR; /// BPF opcode: `or64 dst, src` /// `dst |= src`. -pub const OR64_REG: u8 = BPF_ALU64 | BPF_X | BPF_OR; +pub const OR64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_OR; /// BPF opcode: `and64 dst, imm` /// `dst &= imm`. -pub const AND64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_AND; +pub const AND64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_AND; /// BPF opcode: `and64 dst, src` /// `dst &= src`. -pub const AND64_REG: u8 = BPF_ALU64 | BPF_X | BPF_AND; +pub const AND64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_AND; /// BPF opcode: `lsh64 dst, imm` /// `dst <<= imm`. -pub const LSH64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_LSH; +pub const LSH64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_LSH; /// BPF opcode: `lsh64 dst, src` /// `dst <<= src`. -pub const LSH64_REG: u8 = BPF_ALU64 | BPF_X | BPF_LSH; +pub const LSH64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_LSH; /// BPF opcode: `rsh64 dst, imm` /// `dst >>= imm`. -pub const RSH64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_RSH; +pub const RSH64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_RSH; /// BPF opcode: `rsh64 dst, src` /// `dst >>= src`. -pub const RSH64_REG: u8 = BPF_ALU64 | BPF_X | BPF_RSH; +pub const RSH64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_RSH; /// BPF opcode: `neg64 dst` /// `dst = -dst`. -pub const NEG64: u8 = BPF_ALU64 | BPF_NEG; +pub const NEG64: u8 = BPF_ALU64_STORE | BPF_NEG; /// BPF opcode: `mod64 dst, imm` /// `dst %= imm`. -pub const MOD64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_MOD; +pub const MOD64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_MOD; /// BPF opcode: `mod64 dst, src` /// `dst %= src`. -pub const MOD64_REG: u8 = BPF_ALU64 | BPF_X | BPF_MOD; +pub const MOD64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_MOD; /// BPF opcode: `xor64 dst, imm` /// `dst ^= imm`. -pub const XOR64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_XOR; +pub const XOR64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_XOR; /// BPF opcode: `xor64 dst, src` /// `dst ^= src`. -pub const XOR64_REG: u8 = BPF_ALU64 | BPF_X | BPF_XOR; +pub const XOR64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_XOR; /// BPF opcode: `mov64 dst, imm` /// `dst = imm`. -pub const MOV64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_MOV; +pub const MOV64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_MOV; /// BPF opcode: `mov64 dst, src` /// `dst = src`. -pub const MOV64_REG: u8 = BPF_ALU64 | BPF_X | BPF_MOV; +pub const MOV64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_MOV; /// BPF opcode: `arsh64 dst, imm` /// `dst >>= imm (arithmetic)`. -pub const ARSH64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_ARSH; +pub const ARSH64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_ARSH; /// BPF opcode: `arsh64 dst, src` /// `dst >>= src (arithmetic)`. -pub const ARSH64_REG: u8 = BPF_ALU64 | BPF_X | BPF_ARSH; +pub const ARSH64_REG: u8 = BPF_ALU64_STORE | BPF_X | BPF_ARSH; /// BPF opcode: `hor64 dst, imm` /// `dst |= imm << 32`. -pub const HOR64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_HOR; +pub const HOR64_IMM: u8 = BPF_ALU64_STORE | BPF_K | BPF_HOR; /// BPF opcode: `lmul64 dst, imm` /// `dst = (dst * imm) as u64`. pub const LMUL64_IMM: u8 = BPF_PQR | BPF_B | BPF_K | BPF_LMUL; diff --git a/src/insn_builder.rs b/src/insn_builder.rs index 411e9b88..638cc275 100644 --- a/src/insn_builder.rs +++ b/src/insn_builder.rs @@ -365,9 +365,9 @@ enum OpBits { /// Architecture of instructions pub enum Arch { /// 64-bit instructions - X64 = BPF_ALU64 as isize, + X64 = BPF_ALU64_STORE as isize, /// 32-bit instructions - X32 = BPF_ALU as isize, + X32 = BPF_ALU32_LOAD as isize, } /// struct representation of byte swap operation diff --git a/src/interpreter.rs b/src/interpreter.rs index 66fd9b70..1ed54209 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -259,7 +259,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { translate_memory_access!(self, store, self.reg[src], vm_addr, u64); }, - // BPF_ALU class + // BPF_ALU32_LOAD class ebpf::ADD32_IMM => self.reg[dst] = self.sign_extension((self.reg[dst] as i32).wrapping_add(insn.imm as i32)), ebpf::ADD32_REG => self.reg[dst] = self.sign_extension((self.reg[dst] as i32).wrapping_add(self.reg[src] as i32)), ebpf::SUB32_IMM => if self.executable.get_sbpf_version().swap_sub_reg_imm_operands() { @@ -336,7 +336,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { }; }, - // BPF_ALU64 class + // BPF_ALU64_STORE class ebpf::ADD64_IMM => self.reg[dst] = self.reg[dst].wrapping_add(insn.imm as u64), ebpf::ADD64_REG => self.reg[dst] = self.reg[dst].wrapping_add(self.reg[src]), ebpf::SUB64_IMM => if self.executable.get_sbpf_version().swap_sub_reg_imm_operands() { diff --git a/src/jit.rs b/src/jit.rs index e53da412..fbcbb556 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -480,7 +480,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 8, Some(Value::Register(src))); }, - // BPF_ALU class + // BPF_ALU32_LOAD class ebpf::ADD32_IMM => { self.emit_sanitized_alu(OperandSize::S32, 0x01, 0, dst, insn.imm); if self.executable.get_sbpf_version().implicit_sign_extension_of_results() { @@ -583,7 +583,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { } }, - // BPF_ALU64 class + // BPF_ALU64_STORE class ebpf::ADD64_IMM => self.emit_sanitized_alu(OperandSize::S64, 0x01, 0, dst, insn.imm), ebpf::ADD64_REG => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x01, src, dst, 0, None)), ebpf::SUB64_IMM => { diff --git a/src/verifier.rs b/src/verifier.rs index 39158d59..779a7498 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -267,7 +267,7 @@ impl Verifier for RequisiteVerifier { ebpf::ST_W_REG if !sbpf_version.move_memory_instruction_classes() => store = true, ebpf::ST_DW_REG if !sbpf_version.move_memory_instruction_classes() => store = true, - // BPF_ALU class + // BPF_ALU32_LOAD class ebpf::ADD32_IMM => {}, ebpf::ADD32_REG => {}, ebpf::SUB32_IMM => {}, @@ -300,7 +300,7 @@ impl Verifier for RequisiteVerifier { ebpf::LE if sbpf_version.enable_le() => { check_imm_endian(&insn, insn_ptr)?; }, ebpf::BE => { check_imm_endian(&insn, insn_ptr)?; }, - // BPF_ALU64 class + // BPF_ALU64_STORE class ebpf::ADD64_IMM => {}, ebpf::ADD64_REG => {}, ebpf::SUB64_IMM => {}, diff --git a/tests/execution.rs b/tests/execution.rs index 8f7363ce..14ca544d 100644 --- a/tests/execution.rs +++ b/tests/execution.rs @@ -189,7 +189,7 @@ macro_rules! test_interpreter_and_jit_elf { }; } -// BPF_ALU : Arithmetic and Logic +// BPF_ALU32_LOAD : Arithmetic and Logic #[test] fn test_mov32_imm() { diff --git a/tests/exercise_instructions.rs b/tests/exercise_instructions.rs index e2fc04b8..659c5770 100644 --- a/tests/exercise_instructions.rs +++ b/tests/exercise_instructions.rs @@ -131,7 +131,7 @@ macro_rules! test_interpreter_and_jit_asm { }; } -// BPF_ALU : Arithmetic and Logic +// BPF_ALU32_LOAD : Arithmetic and Logic #[test] fn fuzz_alu() { let seed = 0xC2DB2F8F282284A0; From f1c6741ace17c436f48f8bf2dd6f66b8a6e0a7d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Fri, 4 Oct 2024 19:29:32 +0200 Subject: [PATCH 10/10] Adds test coverage for both before and after. --- tests/execution.rs | 361 +++++++++++++++++++++------------------------ 1 file changed, 169 insertions(+), 192 deletions(-) diff --git a/tests/execution.rs b/tests/execution.rs index 14ca544d..52a10116 100644 --- a/tests/execution.rs +++ b/tests/execution.rs @@ -913,7 +913,175 @@ fn test_err_divide_overflow() { } } -// BPF_LD : Loads +// Loads and stores + +#[test] +fn test_memory_instructions() { + for sbpf_version in [SBPFVersion::V1, SBPFVersion::V2] { + let config = Config { + enabled_sbpf_versions: sbpf_version.clone()..=sbpf_version, + ..Config::default() + }; + + test_interpreter_and_jit_asm!( + " + ldxb r0, [r1+2] + exit", + config.clone(), + [0xaa, 0xbb, 0x11, 0xcc, 0xdd], + (), + TestContextObject::new(2), + ProgramResult::Ok(0x11), + ); + test_interpreter_and_jit_asm!( + " + ldxh r0, [r1+2] + exit", + config.clone(), + [0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd], + (), + TestContextObject::new(2), + ProgramResult::Ok(0x2211), + ); + test_interpreter_and_jit_asm!( + " + ldxw r0, [r1+2] + exit", + config.clone(), + [ + 0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0xcc, 0xdd, // + ], + (), + TestContextObject::new(2), + ProgramResult::Ok(0x44332211), + ); + test_interpreter_and_jit_asm!( + " + ldxdw r0, [r1+2] + exit", + config.clone(), + [ + 0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // + 0x77, 0x88, 0xcc, 0xdd, // + ], + (), + TestContextObject::new(2), + ProgramResult::Ok(0x8877665544332211), + ); + + test_interpreter_and_jit_asm!( + " + stb [r1+2], 0x11 + ldxb r0, [r1+2] + exit", + config.clone(), + [0xaa, 0xbb, 0xff, 0xcc, 0xdd], + (), + TestContextObject::new(3), + ProgramResult::Ok(0x11), + ); + test_interpreter_and_jit_asm!( + " + sth [r1+2], 0x2211 + ldxh r0, [r1+2] + exit", + config.clone(), + [ + 0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd, // + ], + (), + TestContextObject::new(3), + ProgramResult::Ok(0x2211), + ); + test_interpreter_and_jit_asm!( + " + stw [r1+2], 0x44332211 + ldxw r0, [r1+2] + exit", + config.clone(), + [ + 0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd, // + ], + (), + TestContextObject::new(3), + ProgramResult::Ok(0x44332211), + ); + test_interpreter_and_jit_asm!( + " + stdw [r1+2], 0x44332211 + ldxdw r0, [r1+2] + exit", + config.clone(), + [ + 0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // + 0xff, 0xff, 0xcc, 0xdd, // + ], + (), + TestContextObject::new(3), + ProgramResult::Ok(0x44332211), + ); + + test_interpreter_and_jit_asm!( + " + mov32 r2, 0x11 + stxb [r1+2], r2 + ldxb r0, [r1+2] + exit", + config.clone(), + [ + 0xaa, 0xbb, 0xff, 0xcc, 0xdd, // + ], + (), + TestContextObject::new(4), + ProgramResult::Ok(0x11), + ); + test_interpreter_and_jit_asm!( + " + mov32 r2, 0x2211 + stxh [r1+2], r2 + ldxh r0, [r1+2] + exit", + config.clone(), + [ + 0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd, // + ], + (), + TestContextObject::new(4), + ProgramResult::Ok(0x2211), + ); + test_interpreter_and_jit_asm!( + " + mov32 r2, 0x44332211 + stxw [r1+2], r2 + ldxw r0, [r1+2] + exit", + config.clone(), + [ + 0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd, // + ], + (), + TestContextObject::new(4), + ProgramResult::Ok(0x44332211), + ); + test_interpreter_and_jit_asm!( + " + mov r2, -2005440939 + lsh r2, 32 + or r2, 0x44332211 + stxdw [r1+2], r2 + ldxdw r0, [r1+2] + exit", + config.clone(), + [ + 0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // + 0xff, 0xff, 0xcc, 0xdd, // + ], + (), + TestContextObject::new(6), + ProgramResult::Ok(0x8877665544332211), + ); + } +} #[test] fn test_hor64() { @@ -929,47 +1097,6 @@ fn test_hor64() { ); } -#[test] -fn test_ldxb() { - test_interpreter_and_jit_asm!( - " - ldxb r0, [r1+2] - exit", - [0xaa, 0xbb, 0x11, 0xcc, 0xdd], - (), - TestContextObject::new(2), - ProgramResult::Ok(0x11), - ); -} - -#[test] -fn test_ldxh() { - test_interpreter_and_jit_asm!( - " - ldxh r0, [r1+2] - exit", - [0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd], - (), - TestContextObject::new(2), - ProgramResult::Ok(0x2211), - ); -} - -#[test] -fn test_ldxw() { - test_interpreter_and_jit_asm!( - " - ldxw r0, [r1+2] - exit", - [ - 0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0xcc, 0xdd, // - ], - (), - TestContextObject::new(2), - ProgramResult::Ok(0x44332211), - ); -} - #[test] fn test_ldxh_same_reg() { test_interpreter_and_jit_asm!( @@ -985,22 +1112,6 @@ fn test_ldxh_same_reg() { ); } -#[test] -fn test_lldxdw() { - test_interpreter_and_jit_asm!( - " - ldxdw r0, [r1+2] - exit", - [ - 0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // - 0x77, 0x88, 0xcc, 0xdd, // - ], - (), - TestContextObject::new(2), - ProgramResult::Ok(0x8877665544332211), - ); -} - #[test] fn test_err_ldxdw_oob() { test_interpreter_and_jit_asm!( @@ -1235,140 +1346,6 @@ fn test_ldxw_all() { ); } -#[test] -fn test_stb() { - test_interpreter_and_jit_asm!( - " - stb [r1+2], 0x11 - ldxb r0, [r1+2] - exit", - [0xaa, 0xbb, 0xff, 0xcc, 0xdd], - (), - TestContextObject::new(3), - ProgramResult::Ok(0x11), - ); -} - -#[test] -fn test_sth() { - test_interpreter_and_jit_asm!( - " - sth [r1+2], 0x2211 - ldxh r0, [r1+2] - exit", - [ - 0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd, // - ], - (), - TestContextObject::new(3), - ProgramResult::Ok(0x2211), - ); -} - -#[test] -fn test_stw() { - test_interpreter_and_jit_asm!( - " - stw [r1+2], 0x44332211 - ldxw r0, [r1+2] - exit", - [ - 0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd, // - ], - (), - TestContextObject::new(3), - ProgramResult::Ok(0x44332211), - ); -} - -#[test] -fn test_stdw() { - test_interpreter_and_jit_asm!( - " - stdw [r1+2], 0x44332211 - ldxdw r0, [r1+2] - exit", - [ - 0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // - 0xff, 0xff, 0xcc, 0xdd, // - ], - (), - TestContextObject::new(3), - ProgramResult::Ok(0x44332211), - ); -} - -#[test] -fn test_stxb() { - test_interpreter_and_jit_asm!( - " - mov32 r2, 0x11 - stxb [r1+2], r2 - ldxb r0, [r1+2] - exit", - [ - 0xaa, 0xbb, 0xff, 0xcc, 0xdd, // - ], - (), - TestContextObject::new(4), - ProgramResult::Ok(0x11), - ); -} - -#[test] -fn test_stxh() { - test_interpreter_and_jit_asm!( - " - mov32 r2, 0x2211 - stxh [r1+2], r2 - ldxh r0, [r1+2] - exit", - [ - 0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd, // - ], - (), - TestContextObject::new(4), - ProgramResult::Ok(0x2211), - ); -} - -#[test] -fn test_stxw() { - test_interpreter_and_jit_asm!( - " - mov32 r2, 0x44332211 - stxw [r1+2], r2 - ldxw r0, [r1+2] - exit", - [ - 0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd, // - ], - (), - TestContextObject::new(4), - ProgramResult::Ok(0x44332211), - ); -} - -#[test] -fn test_stxdw() { - test_interpreter_and_jit_asm!( - " - mov r2, -2005440939 - lsh r2, 32 - or r2, 0x44332211 - stxdw [r1+2], r2 - ldxdw r0, [r1+2] - exit", - [ - 0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // - 0xff, 0xff, 0xcc, 0xdd, // - ], - (), - TestContextObject::new(6), - ProgramResult::Ok(0x8877665544332211), - ); -} - #[test] fn test_stxb_all() { test_interpreter_and_jit_asm!(