]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
x86/umip: Check that the instruction opcode is at least two bytes
authorSean Christopherson <seanjc@google.com>
Fri, 8 Aug 2025 17:23:56 +0000 (10:23 -0700)
committerBorislav Petkov (AMD) <bp@alien8.de>
Fri, 19 Sep 2025 18:21:12 +0000 (20:21 +0200)
When checking for a potential UMIP violation on #GP, verify the decoder found
at least two opcode bytes to avoid false positives when the kernel encounters
an unknown instruction that starts with 0f.  Because the array of opcode.bytes
is zero-initialized by insn_init(), peeking at bytes[1] will misinterpret
garbage as a potential SLDT or STR instruction, and can incorrectly trigger
emulation.

E.g. if a VPALIGNR instruction

   62 83 c5 05 0f 08 ff     vpalignr xmm17{k5},xmm23,XMMWORD PTR [r8],0xff

hits a #GP, the kernel emulates it as STR and squashes the #GP (and corrupts
the userspace code stream).

Arguably the check should look for exactly two bytes, but no three byte
opcodes use '0f 00 xx' or '0f 01 xx' as an escape, i.e. it should be
impossible to get a false positive if the first two opcode bytes match '0f 00'
or '0f 01'.  Go with a more conservative check with respect to the existing
code to minimize the chances of breaking userspace, e.g. due to decoder
weirdness.

Analyzed by Nick Bray <ncbray@google.com>.

Fixes: 1e5db223696a ("x86/umip: Add emulation code for UMIP instructions")
Reported-by: Dan Snyder <dansnyder@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: stable@vger.kernel.org
arch/x86/kernel/umip.c

index 5a4b21389b1d98b4e4fd65149ec1fd0b8fd485a7..406ac01ce16dc08dcc13ed2d70d1e33ebeaa4440 100644 (file)
@@ -156,8 +156,8 @@ static int identify_insn(struct insn *insn)
        if (!insn->modrm.nbytes)
                return -EINVAL;
 
-       /* All the instructions of interest start with 0x0f. */
-       if (insn->opcode.bytes[0] != 0xf)
+       /* The instructions of interest have 2-byte opcodes: 0F 00 or 0F 01. */
+       if (insn->opcode.nbytes < 2 || insn->opcode.bytes[0] != 0xf)
                return -EINVAL;
 
        if (insn->opcode.bytes[1] == 0x1) {