diff options
| author | iximeow <me@iximeow.net> | 2020-08-09 19:47:08 -0700 | 
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2020-08-09 19:47:08 -0700 | 
| commit | f523478b3c6f5f29f600368afb1b84c9f5a41eba (patch) | |
| tree | e34a5234b32600f3bbf31aac908f66bea2e123a5 | |
| parent | 57ff56d8b5c3a3fa4f1d7f4881afbe2ce8e47cfd (diff) | |
reject instructions made invalid by lock prefixes
| -rw-r--r-- | src/long_mode/mod.rs | 28 | ||||
| -rw-r--r-- | src/protected_mode/mod.rs | 27 | ||||
| -rw-r--r-- | test/long_mode/mod.rs | 3 | ||||
| -rw-r--r-- | test/protected_mode/mod.rs | 3 | 
4 files changed, 61 insertions, 0 deletions
| diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 4d663d3..3d6dc2b 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -3828,6 +3828,28 @@ pub enum OperandCode {      Yv_AX = OperandCodeBuilder::new().special_case(101).bits(),  } +const LOCKABLE_INSTRUCTIONS: &[Opcode] = &[ +    Opcode::ADD, +    Opcode::ADC, +    Opcode::AND, +    Opcode::BTC, +    Opcode::BTR, +    Opcode::BTS, +    Opcode::CMPXCHG, +    Opcode::CMPXCHG8B, +    Opcode::CMPXCHG16B, +    Opcode::DEC, +    Opcode::INC, +    Opcode::NEG, +    Opcode::NOT, +    Opcode::OR, +    Opcode::SBB, +    Opcode::SUB, +    Opcode::XOR, +    Opcode::XADD, +    Opcode::XCHG, +]; +  fn base_opcode_map(v: u8) -> Opcode {      match v {          0 => Opcode::ADD, @@ -5650,6 +5672,12 @@ fn read_instr<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, in      }      instruction.length = length; +    if instruction.prefixes.lock() { +        if !LOCKABLE_INSTRUCTIONS.contains(&instruction.opcode) || !instruction.operands[0].is_memory() { +            return Err(DecodeError::InvalidPrefixes); +        } +    } +      if decoder != &InstDecoder::default() {          // we might have to fix up or reject this instruction under whatever cpu features we need to          // pretend to have. diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs index 42595a8..1517c7c 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -3777,6 +3777,27 @@ pub enum OperandCode {      DS = OperandCodeBuilder::new().special_case(106).bits(),  } +const LOCKABLE_INSTRUCTIONS: &[Opcode] = &[ +    Opcode::ADD, +    Opcode::ADC, +    Opcode::AND, +    Opcode::BTC, +    Opcode::BTR, +    Opcode::BTS, +    Opcode::CMPXCHG, +    Opcode::CMPXCHG8B, +    Opcode::DEC, +    Opcode::INC, +    Opcode::NEG, +    Opcode::NOT, +    Opcode::OR, +    Opcode::SBB, +    Opcode::SUB, +    Opcode::XOR, +    Opcode::XADD, +    Opcode::XCHG, +]; +  fn base_opcode_map(v: u8) -> Opcode {      match v {          0 => Opcode::ADD, @@ -5571,6 +5592,12 @@ fn read_instr<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, in      }      instruction.length = length; +    if instruction.prefixes.lock() { +        if !LOCKABLE_INSTRUCTIONS.contains(&instruction.opcode) || !instruction.operands[0].is_memory() { +            return Err(DecodeError::InvalidPrefixes); +        } +    } +      if decoder != &InstDecoder::default() {          // we might have to fix up or reject this instruction under whatever cpu features we need to          // pretend to have. diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index 25c8deb..a3ff318 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -1095,6 +1095,9 @@ fn test_prefixes() {      test_display(&[0x66, 0x41, 0x31, 0xc0], "xor r8w, ax");      test_display(&[0x66, 0x41, 0x32, 0xc0], "xor al, r8b");      test_display(&[0x40, 0x32, 0xc5], "xor al, bpl"); +    test_invalid(&[0xf0, 0x33, 0xc0]); +    test_display(&[0xf0, 0x31, 0x00], "lock xor [rax], eax"); +    test_invalid(&[0xf0, 0xc7, 0x00, 0x00, 0x00, 0x00]);  }  #[test] diff --git a/test/protected_mode/mod.rs b/test/protected_mode/mod.rs index 185e98d..bf9315c 100644 --- a/test/protected_mode/mod.rs +++ b/test/protected_mode/mod.rs @@ -970,6 +970,9 @@ fn test_prefixes() {      test_display(&[0x66, 0x31, 0xc0], "xor ax, ax");      test_display(&[0x66, 0x32, 0xc0], "xor al, al");      test_display(&[0x66, 0x32, 0xc5], "xor al, ch"); +    test_invalid(&[0xf0, 0x33, 0xc0]); +    test_display(&[0xf0, 0x31, 0x00], "lock xor [eax], eax"); +    test_invalid(&[0xf0, 0xc7, 0x00, 0x00, 0x00, 0x00]);  }  #[test] | 
