From d7d84b3be6c929ee9d1b425a82b7121936a7cd34 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 16 Dec 2023 15:05:08 -0800 Subject: fix incorrect register selection for `vpmov*2m` with `rex.r` set --- CHANGELOG | 6 ++++++ src/shared/evex.in | 3 +++ test/long_mode/mod.rs | 4 ++++ test/protected_mode/mod.rs | 5 +++++ test/real_mode/mod.rs | 5 +++++ 5 files changed, 23 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 4210e30..5d8ae65 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,12 @@ instructions are otherwise decoded correctly.) * fix incorrect register selection for `vpmovm2*` with `rex.b` set (would select registers "k8" through "k15", but should be masked down to "k0".."k7".) +* fix incorrect register selection for `vpmov*2m` with `rex.r` set. similar to + above, except 64-bit only: in 32- and 16-bit modes, this case was and continues + to be a `bound` instruction. in 64-bit mode, this would disassemble as a + `vpmov*2m` with nonsense `k8..k15` selected. to real hardware, this bit + sequence is an invalid instruction, and so it is now invalid to yaxpeax-x86 + as well. ## 1.2.0 * fix incorrect old yaxpeax-arch version selection for ffi crates diff --git a/src/shared/evex.in b/src/shared/evex.in index 837b867..58ec14a 100644 --- a/src/shared/evex.in +++ b/src/shared/evex.in @@ -2810,6 +2810,9 @@ pub(crate) fn read_evex_operands< if mem_oper == OperandSpec::RegMMM { instruction.mem_size = 0; instruction.regs[0].bank = RegisterBank::K; + if instruction.regs[0].num > 7 { + return Err(DecodeError::InvalidOperand); + } } else { return Err(DecodeError::InvalidOperand); } diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index c7a4788..b087d74 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -1470,6 +1470,10 @@ fn evex() { // modrm bits as a register selector. out-of-range `k` seem to just get masked down.. test_display(&[0x62, 0xd2, 0x7e, 0x08, 0x28, 0xc2], "vpmovm2b xmm0, k2"); test_display(&[0x62, 0xf2, 0x7e, 0x08, 0x28, 0xc1], "vpmovm2b xmm0, k1"); + // vpmovb2m (and larger forms). out-of-range `k` are invalid in 64-bit mode, are part of the + // `bound` instruction for 32- and 16-bit modes. + test_invalid(&[0x62, 0x72, 0x7e, 0x28, 0x29, 0xfd]); + test_display(&[0x62, 0xf2, 0x7e, 0x28, 0x29, 0xfd], "vpmovb2m k7, ymm5"); test_display(&[0x62, 0x12, 0x7d, 0x06, 0xa0, 0x04, 0x2f], "vpscatterdd dword [r15 + xmm29 * 1], k6, xmm8"); test_display(&[0x62, 0x12, 0x7d, 0x06, 0xa0, 0x14, 0x0f], "vpscatterdd dword [r15 + xmm25 * 1], k6, xmm10"); diff --git a/test/protected_mode/mod.rs b/test/protected_mode/mod.rs index e843c7a..88d6c49 100644 --- a/test/protected_mode/mod.rs +++ b/test/protected_mode/mod.rs @@ -1337,6 +1337,11 @@ fn evex() { test_display(&[0x62, 0xd2, 0x7e, 0x08, 0x28, 0xc2], "vpmovm2b xmm0, k2"); test_display(&[0x62, 0xf2, 0x7e, 0x08, 0x28, 0xc1], "vpmovm2b xmm0, k1"); + // vpmovb2m (and larger forms). out-of-range `k` are invalid in 64-bit mode, are part of the + // `bound` instruction for 32- and 16-bit modes. + test_display(&[0x62, 0x72, 0x7e /* , 0x28, 0x29, 0xfd */], "bound esi, qword [edx + 0x7e]"); + test_display(&[0x62, 0xf2, 0x7e, 0x28, 0x29, 0xfd], "vpmovb2m k7, ymm5"); + test_display(&[0x62, 0xf2, 0x7d, 0x48, 0x2a, 0x44, 0x40, 0x01], "vmovntdqa zmm0, zmmword [eax + eax * 2 + 0x40]"); test_display(&[0x62, 0xf2, 0x7d, 0x08, 0x2a, 0x44, 0x40, 0x01], "vmovntdqa xmm0, xmmword [eax + eax * 2 + 0x10]"); } diff --git a/test/real_mode/mod.rs b/test/real_mode/mod.rs index a321e64..b422887 100644 --- a/test/real_mode/mod.rs +++ b/test/real_mode/mod.rs @@ -18406,6 +18406,11 @@ fn test_invalid_sequences() { test_display(&[0x62, 0xd2, 0x7e, 0x08, 0x28, 0xc2], "vpmovm2b xmm0, k2"); test_display(&[0x62, 0xf2, 0x7e, 0x08, 0x28, 0xc1], "vpmovm2b xmm0, k1"); + // vpmovb2m (and larger forms). out-of-range `k` are invalid in 64-bit mode, are part of the + // `bound` instruction for 32- and 16-bit modes. + test_display(&[0x62, 0x72, 0x7e /* , 0x28, 0x29, 0xfd */], "bound si, dword [bp + si * 1 + 0x7e]"); + test_display(&[0x62, 0xf2, 0x7e, 0x28, 0x29, 0xfd], "vpmovb2m k7, ymm5"); + } #[test] -- cgit v1.1