]> 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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 19 Oct 2025 14:21:48 +0000 (16:21 +0200)
commit 32278c677947ae2f042c9535674a7fff9a245dd3 upstream.

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
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kernel/umip.c

index 576b47e7523db01290660a5b7c99f37dfb110a83..9e31d77dbec595f914ac136406e5c3dbccb1cc2a 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) {