Skip to content
This repository was archived by the owner on Jan 10, 2025. It is now read-only.

Commit b961d88

Browse files
committed
Adds explicit sign extension of results in SBPF-v2.
1 parent 4dc039f commit b961d88

File tree

5 files changed

+218
-40
lines changed

5 files changed

+218
-40
lines changed

src/interpreter.rs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {
152152
true
153153
}
154154

155+
fn sign_extension(&self, value: i32) -> u64 {
156+
if self
157+
.executable
158+
.get_sbpf_version()
159+
.implicit_sign_extension_of_results()
160+
{
161+
value as i64 as u64
162+
} else {
163+
value as u32 as u64
164+
}
165+
}
166+
155167
/// Advances the interpreter state by one instruction
156168
///
157169
/// Returns false if the program terminated or threw an error.
@@ -245,14 +257,14 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {
245257
},
246258

247259
// BPF_ALU class
248-
ebpf::ADD32_IMM => self.reg[dst] = (self.reg[dst] as i32).wrapping_add(insn.imm as i32) as u64,
249-
ebpf::ADD32_REG => self.reg[dst] = (self.reg[dst] as i32).wrapping_add(self.reg[src] as i32) as u64,
260+
ebpf::ADD32_IMM => self.reg[dst] = self.sign_extension((self.reg[dst] as i32).wrapping_add(insn.imm as i32)),
261+
ebpf::ADD32_REG => self.reg[dst] = self.sign_extension((self.reg[dst] as i32).wrapping_add(self.reg[src] as i32)),
250262
ebpf::SUB32_IMM => if self.executable.get_sbpf_version().swap_sub_reg_imm_operands() {
251-
self.reg[dst] = (insn.imm as i32).wrapping_sub(self.reg[dst] as i32) as u64
263+
self.reg[dst] = self.sign_extension((insn.imm as i32).wrapping_sub(self.reg[dst] as i32))
252264
} else {
253-
self.reg[dst] = (self.reg[dst] as i32).wrapping_sub(insn.imm as i32) as u64
265+
self.reg[dst] = self.sign_extension((self.reg[dst] as i32).wrapping_sub(insn.imm as i32))
254266
},
255-
ebpf::SUB32_REG => self.reg[dst] = (self.reg[dst] as i32).wrapping_sub(self.reg[src] as i32) as u64,
267+
ebpf::SUB32_REG => self.reg[dst] = self.sign_extension((self.reg[dst] as i32).wrapping_sub(self.reg[src] as i32)),
256268
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,
257269
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,
258270
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,
@@ -277,9 +289,13 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {
277289
ebpf::XOR32_IMM => self.reg[dst] = (self.reg[dst] as u32 ^ insn.imm as u32) as u64,
278290
ebpf::XOR32_REG => self.reg[dst] = (self.reg[dst] as u32 ^ self.reg[src] as u32) as u64,
279291
ebpf::MOV32_IMM => self.reg[dst] = insn.imm as u32 as u64,
280-
ebpf::MOV32_REG => self.reg[dst] = (self.reg[src] as u32) as u64,
281-
ebpf::ARSH32_IMM => self.reg[dst] = (self.reg[dst] as i32).wrapping_shr(insn.imm as u32) as u64 & (u32::MAX as u64),
282-
ebpf::ARSH32_REG => self.reg[dst] = (self.reg[dst] as i32).wrapping_shr(self.reg[src] as u32) as u64 & (u32::MAX as u64),
292+
ebpf::MOV32_REG => self.reg[dst] = if self.executable.get_sbpf_version().implicit_sign_extension_of_results() {
293+
self.reg[src] as u32 as u64
294+
} else {
295+
self.reg[src] as i32 as i64 as u64
296+
},
297+
ebpf::ARSH32_IMM => self.reg[dst] = (self.reg[dst] as i32).wrapping_shr(insn.imm as u32) as u32 as u64,
298+
ebpf::ARSH32_REG => self.reg[dst] = (self.reg[dst] as i32).wrapping_shr(self.reg[src] as u32) as u32 as u64,
283299
ebpf::LE if self.executable.get_sbpf_version().enable_le() => {
284300
self.reg[dst] = match insn.imm {
285301
16 => (self.reg[dst] as u16).to_le() as u64,
@@ -342,8 +358,8 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {
342358
}
343359

344360
// BPF_PQR class
345-
ebpf::LMUL32_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,
346-
ebpf::LMUL32_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,
361+
ebpf::LMUL32_IMM if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u32).wrapping_mul(insn.imm as u32) as u64,
362+
ebpf::LMUL32_REG if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u32).wrapping_mul(self.reg[src] as u32) as u64,
347363
ebpf::LMUL64_IMM if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = self.reg[dst].wrapping_mul(insn.imm as u64),
348364
ebpf::LMUL64_REG if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = self.reg[dst].wrapping_mul(self.reg[src]),
349365
ebpf::UHMUL64_IMM if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u128).wrapping_mul(insn.imm as u64 as u128).wrapping_shr(64) as u64,
@@ -380,12 +396,12 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {
380396
},
381397
ebpf::SDIV32_IMM if self.executable.get_sbpf_version().enable_pqr() => {
382398
throw_error!(DivideOverflow; self, insn.imm, self.reg[dst], i32);
383-
self.reg[dst] = (self.reg[dst] as i32 / insn.imm as i32) as u64;
399+
self.reg[dst] = (self.reg[dst] as i32 / insn.imm as i32) as u32 as u64;
384400
}
385401
ebpf::SDIV32_REG if self.executable.get_sbpf_version().enable_pqr() => {
386402
throw_error!(DivideByZero; self, self.reg[src], i32);
387403
throw_error!(DivideOverflow; self, self.reg[src], self.reg[dst], i32);
388-
self.reg[dst] = (self.reg[dst] as i32 / self.reg[src] as i32) as u64;
404+
self.reg[dst] = (self.reg[dst] as i32 / self.reg[src] as i32) as u32 as u64;
389405
},
390406
ebpf::SDIV64_IMM if self.executable.get_sbpf_version().enable_pqr() => {
391407
throw_error!(DivideOverflow; self, insn.imm, self.reg[dst], i64);
@@ -398,12 +414,12 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {
398414
},
399415
ebpf::SREM32_IMM if self.executable.get_sbpf_version().enable_pqr() => {
400416
throw_error!(DivideOverflow; self, insn.imm, self.reg[dst], i32);
401-
self.reg[dst] = (self.reg[dst] as i32 % insn.imm as i32) as u64;
417+
self.reg[dst] = (self.reg[dst] as i32 % insn.imm as i32) as u32 as u64;
402418
}
403419
ebpf::SREM32_REG if self.executable.get_sbpf_version().enable_pqr() => {
404420
throw_error!(DivideByZero; self, self.reg[src], i32);
405421
throw_error!(DivideOverflow; self, self.reg[src], self.reg[dst], i32);
406-
self.reg[dst] = (self.reg[dst] as i32 % self.reg[src] as i32) as u64;
422+
self.reg[dst] = (self.reg[dst] as i32 % self.reg[src] as i32) as u32 as u64;
407423
},
408424
ebpf::SREM64_IMM if self.executable.get_sbpf_version().enable_pqr() => {
409425
throw_error!(DivideOverflow; self, insn.imm, self.reg[dst], i64);

src/jit.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -471,11 +471,15 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
471471
// BPF_ALU class
472472
ebpf::ADD32_IMM => {
473473
self.emit_sanitized_alu(OperandSize::S32, 0x01, 0, dst, insn.imm);
474-
self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, 0, None)); // sign extend i32 to i64
474+
if self.executable.get_sbpf_version().implicit_sign_extension_of_results() {
475+
self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, 0, None)); // sign extend i32 to i64
476+
}
475477
},
476478
ebpf::ADD32_REG => {
477479
self.emit_ins(X86Instruction::alu(OperandSize::S32, 0x01, src, dst, 0, None));
478-
self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, 0, None)); // sign extend i32 to i64
480+
if self.executable.get_sbpf_version().implicit_sign_extension_of_results() {
481+
self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, 0, None)); // sign extend i32 to i64
482+
}
479483
},
480484
ebpf::SUB32_IMM => {
481485
if self.executable.get_sbpf_version().swap_sub_reg_imm_operands() {
@@ -486,11 +490,15 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
486490
} else {
487491
self.emit_sanitized_alu(OperandSize::S32, 0x29, 5, dst, insn.imm);
488492
}
489-
self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, 0, None)); // sign extend i32 to i64
493+
if self.executable.get_sbpf_version().implicit_sign_extension_of_results() {
494+
self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, 0, None)); // sign extend i32 to i64
495+
}
490496
},
491497
ebpf::SUB32_REG => {
492498
self.emit_ins(X86Instruction::alu(OperandSize::S32, 0x29, src, dst, 0, None));
493-
self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, 0, None)); // sign extend i32 to i64
499+
if self.executable.get_sbpf_version().implicit_sign_extension_of_results() {
500+
self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, 0, None)); // sign extend i32 to i64
501+
}
494502
},
495503
ebpf::MUL32_IMM | ebpf::DIV32_IMM | ebpf::MOD32_IMM if !self.executable.get_sbpf_version().enable_pqr() =>
496504
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)),
@@ -514,7 +522,13 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
514522
self.emit_ins(X86Instruction::load_immediate(OperandSize::S32, dst, insn.imm));
515523
}
516524
}
517-
ebpf::MOV32_REG => self.emit_ins(X86Instruction::mov(OperandSize::S32, src, dst)),
525+
ebpf::MOV32_REG => {
526+
if self.executable.get_sbpf_version().implicit_sign_extension_of_results() {
527+
self.emit_ins(X86Instruction::mov(OperandSize::S32, src, dst));
528+
} else {
529+
self.emit_ins(X86Instruction::mov_with_sign_extension(OperandSize::S64, src, dst));
530+
}
531+
}
518532
ebpf::ARSH32_IMM => self.emit_shift(OperandSize::S32, 7, REGISTER_SCRATCH, dst, Some(insn.imm)),
519533
ebpf::ARSH32_REG => self.emit_shift(OperandSize::S32, 7, src, dst, None),
520534
ebpf::LE if self.executable.get_sbpf_version().enable_le() => {
@@ -1277,7 +1291,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
12771291
self.emit_ins(X86Instruction::pop(RAX));
12781292
}
12791293
if let OperandSize::S32 = size {
1280-
if signed {
1294+
if signed && self.executable.get_sbpf_version().implicit_sign_extension_of_results() {
12811295
self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, 0, None)); // sign extend i32 to i64
12821296
}
12831297
}

src/program.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ pub enum SBPFVersion {
2020
}
2121

2222
impl SBPFVersion {
23+
/// Implicitly perform sign extension of results
24+
pub fn implicit_sign_extension_of_results(&self) -> bool {
25+
self == &SBPFVersion::V1
26+
}
27+
2328
/// Enable the little-endian byte swap instructions
2429
pub fn enable_le(&self) -> bool {
2530
self == &SBPFVersion::V1

src/x86.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,19 @@ impl X86Instruction {
218218
}
219219
}
220220

221+
/// Move source to destination
222+
#[inline]
223+
pub const fn mov_with_sign_extension(size: OperandSize, source: u8, destination: u8) -> Self {
224+
exclude_operand_sizes!(size, OperandSize::S0 | OperandSize::S8 | OperandSize::S16);
225+
Self {
226+
size,
227+
opcode: 0x63,
228+
first_operand: destination,
229+
second_operand: source,
230+
..Self::DEFAULT
231+
}
232+
}
233+
221234
/// Conditionally move source to destination
222235
#[inline]
223236
pub const fn cmov(size: OperandSize, condition: u8, source: u8, destination: u8) -> Self {

0 commit comments

Comments
 (0)