aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2020-08-09 19:47:08 -0700
committeriximeow <me@iximeow.net>2020-08-09 19:47:08 -0700
commitf523478b3c6f5f29f600368afb1b84c9f5a41eba (patch)
treee34a5234b32600f3bbf31aac908f66bea2e123a5
parent57ff56d8b5c3a3fa4f1d7f4881afbe2ce8e47cfd (diff)
reject instructions made invalid by lock prefixes
-rw-r--r--src/long_mode/mod.rs28
-rw-r--r--src/protected_mode/mod.rs27
-rw-r--r--test/long_mode/mod.rs3
-rw-r--r--test/protected_mode/mod.rs3
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]