CVE-2022-23066: Incorrect Calculation (CWE-682)
value: In Solana rBPF versions 0.2.26 and 0.2.27 are affected by Incorrect Calculation which is caused by improper implementation of sdiv instruction. This can lead to the wrong execution path, resulting in huge loss in specific cases. For example, the result of a sdiv instruction may decide whether to transfer tokens or not. The vulnerability affects both integrity and may cause serious availability problems.
CWE description: The product performs a calculation that generates incorrect or unintended results that are later used in security-critical decisions or resource management.
CVSS v3 base score: 9.1
Published: 2022-05-09T07:15Z
Repository: https://github.com/solana-labs/rbpf
Language: Rust
Files changed: src/jit.rs, tests/ubpf_execution.rs
Commit date: 2022-04-29 15:08:56 +0200
Commit message: jit: sign-extend the quotient register on sdiv32 (#310)


Diff: diff --git a/src/jit.rs b/src/jit.rs
index 03dddde..fa1aaac 100644
--- a/src/jit.rs
+++ b/src/jit.rs
@@ -911,11 +911,11 @@ fn emit_muldivmod<E: UserDefinedError>(jit: &mut JitCompiler, opc: u8, src: u8,
             X86Instruction::mov(OperandSize::S64, RAX, dst).emit(jit)?;
         }
         X86Instruction::pop(RAX).emit(jit)?;
     }
 
-    if size == OperandSize::S32 && opc & ebpf::BPF_ALU_OP_MASK == ebpf::BPF_MUL {
+    if size == OperandSize::S32 && (mul || sdiv)  {
         X86Instruction::sign_extend_i32_to_i64(dst, dst).emit(jit)?;
     }
     Ok(())
 }
 
diff --git a/tests/ubpf_execution.rs b/tests/ubpf_execution.rs
index c3ee967..55ee750 100644
--- a/tests/ubpf_execution.rs
+++ b/tests/ubpf_execution.rs
@@ -836,10 +836,25 @@ fn test_sdiv32_imm() {
         { |_vm, res: Result| { res.unwrap() == 0x3 } },
         3
     );
 }
 
+#[test]
+fn test_sdiv32_neg_imm() {
+    test_interpreter_and_jit_asm!(
+        "
+        lddw r0, 0x10000000c
+        sdiv32 r0, -4
+        exit",
+        [],
+        (),
+        0,
+        { |_vm, res: Result| { res.unwrap() as i64 == -3 } },
+        3
+    );
+}
+
 #[test]
 fn test_sdiv32_reg() {
     test_interpreter_and_jit_asm!(
         "
         lddw r0, 0x10000000c
@@ -852,10 +867,26 @@ fn test_sdiv32_reg() {
         { |_vm, res: Result| { res.unwrap() == 0x3 } },
         4
     );
 }
 
+#[test]
+fn test_sdiv32_neg_reg() {
+    test_interpreter_and_jit_asm!(
+        "
+        lddw r0, 0x10000000c
+        mov r1, -4
+        sdiv32 r0, r1
+        exit",
+        [],
+        (),
+        0,
+        { |_vm, res: Result| { res.unwrap() as i64 == -0x3 } },
+        4
+    );
+}
+
 #[test]
 fn test_div64_imm() {
     test_interpreter_and_jit_asm!(
         "
         mov r0, 0xc

Vulnerable code:     if size == OperandSize::S32 && opc & ebpf::BPF_ALU_OP_MASK == ebpf::BPF_MUL {
Fixed code:     if size == OperandSize::S32 && (mul || sdiv)  {
#[test]
fn test_sdiv32_neg_imm() {
    test_interpreter_and_jit_asm!(
        "
        lddw r0, 0x10000000c
        sdiv32 r0, -4
        exit",
        [],
        (),
        0,
        { |_vm, res: Result| { res.unwrap() as i64 == -3 } },
        3
    );
}

#[test]
fn test_sdiv32_neg_reg() {
    test_interpreter_and_jit_asm!(
        "
        lddw r0, 0x10000000c
        mov r1, -4
        sdiv32 r0, r1
        exit",
        [],
        (),
        0,
        { |_vm, res: Result| { res.unwrap() as i64 == -0x3 } },
        4
    );
}