]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Feb 2023 09:48:15 +0000 (10:48 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Feb 2023 09:48:15 +0000 (10:48 +0100)
added patches:
bluetooth-btusb-add-more-device-ids-for-wcn6855.patch
uaccess-add-speculation-barrier-to-copy_from_user.patch
x86-alternatives-introduce-int3_emulate_jcc.patch
x86-alternatives-teach-text_poke_bp-to-patch-jcc.d32-instructions.patch
x86-static_call-add-support-for-jcc-tail-calls.patch

queue-6.1/bluetooth-btusb-add-more-device-ids-for-wcn6855.patch [new file with mode: 0644]
queue-6.1/series
queue-6.1/uaccess-add-speculation-barrier-to-copy_from_user.patch [new file with mode: 0644]
queue-6.1/x86-alternatives-introduce-int3_emulate_jcc.patch [new file with mode: 0644]
queue-6.1/x86-alternatives-teach-text_poke_bp-to-patch-jcc.d32-instructions.patch [new file with mode: 0644]
queue-6.1/x86-static_call-add-support-for-jcc-tail-calls.patch [new file with mode: 0644]

diff --git a/queue-6.1/bluetooth-btusb-add-more-device-ids-for-wcn6855.patch b/queue-6.1/bluetooth-btusb-add-more-device-ids-for-wcn6855.patch
new file mode 100644 (file)
index 0000000..5da27a9
--- /dev/null
@@ -0,0 +1,118 @@
+From ca2a99447e17acd67258aa1d54d7ea3c404a779c Mon Sep 17 00:00:00 2001
+From: Shengyu Qu <wiagn233@outlook.com>
+Date: Sun, 30 Oct 2022 01:22:54 +0800
+Subject: Bluetooth: btusb: Add more device IDs for WCN6855
+
+From: Shengyu Qu <wiagn233@outlook.com>
+
+commit ca2a99447e17acd67258aa1d54d7ea3c404a779c upstream.
+
+Add IDs to usb_device_id table for WCN6855. IDs are extracted from Windows
+driver of Lenovo Thinkpad T14 Gen 2(Driver version 1.0.0.1205 Windows 10)
+
+Windows driver download address:
+https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/
+thinkpad-t-series-laptops/thinkpad-t14-gen-2-type-20xk-20xl/downloads
+/driver-list/
+
+Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Cc: "Limonciello, Mario" <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/bluetooth/btusb.c |   84 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 84 insertions(+)
+
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -316,6 +316,90 @@ static const struct usb_device_id blackl
+       { USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 |
+                                                    BTUSB_WIDEBAND_SPEECH |
+                                                    BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9108), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9109), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9208), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9209), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9308), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9408), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9508), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9509), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9608), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9609), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x04ca, 0x3022), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x0489, 0xe0c9), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x0489, 0xe0ca), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x0489, 0xe0cb), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x0489, 0xe0ce), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x0489, 0xe0de), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x0489, 0xe0df), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x0489, 0xe0e1), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x0489, 0xe0ea), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x0489, 0xe0ec), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x04ca, 0x3023), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x04ca, 0x3024), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x04ca, 0x3a22), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x04ca, 0x3a24), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x04ca, 0x3a26), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
++      { USB_DEVICE(0x04ca, 0x3a27), .driver_info = BTUSB_QCA_WCN6855 |
++                                                   BTUSB_WIDEBAND_SPEECH |
++                                                   BTUSB_VALID_LE_STATES },
+       /* QCA WCN785x chipset */
+       { USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 |
index da13787891db8afe59cad35acf5894914faabb50..416a9d0af59569fae15b8b5d0daea622622cfc53 100644 (file)
@@ -28,3 +28,8 @@ powerpc-64s-radix-fix-rwx-mapping-with-relocated-ker.patch
 revert-netfilter-conntrack-fix-bug-in-for_each_sctp_.patch
 nfp-ethtool-support-reporting-link-modes.patch
 nfp-ethtool-fix-the-bug-of-setting-unsupported-port-.patch
+uaccess-add-speculation-barrier-to-copy_from_user.patch
+x86-alternatives-introduce-int3_emulate_jcc.patch
+x86-alternatives-teach-text_poke_bp-to-patch-jcc.d32-instructions.patch
+x86-static_call-add-support-for-jcc-tail-calls.patch
+bluetooth-btusb-add-more-device-ids-for-wcn6855.patch
diff --git a/queue-6.1/uaccess-add-speculation-barrier-to-copy_from_user.patch b/queue-6.1/uaccess-add-speculation-barrier-to-copy_from_user.patch
new file mode 100644 (file)
index 0000000..2a16639
--- /dev/null
@@ -0,0 +1,106 @@
+From 74e19ef0ff8061ef55957c3abd71614ef0f42f47 Mon Sep 17 00:00:00 2001
+From: Dave Hansen <dave.hansen@linux.intel.com>
+Date: Tue, 21 Feb 2023 12:30:15 -0800
+Subject: uaccess: Add speculation barrier to copy_from_user()
+
+From: Dave Hansen <dave.hansen@linux.intel.com>
+
+commit 74e19ef0ff8061ef55957c3abd71614ef0f42f47 upstream.
+
+The results of "access_ok()" can be mis-speculated.  The result is that
+you can end speculatively:
+
+       if (access_ok(from, size))
+               // Right here
+
+even for bad from/size combinations.  On first glance, it would be ideal
+to just add a speculation barrier to "access_ok()" so that its results
+can never be mis-speculated.
+
+But there are lots of system calls just doing access_ok() via
+"copy_to_user()" and friends (example: fstat() and friends).  Those are
+generally not problematic because they do not _consume_ data from
+userspace other than the pointer.  They are also very quick and common
+system calls that should not be needlessly slowed down.
+
+"copy_from_user()" on the other hand uses a user-controller pointer and
+is frequently followed up with code that might affect caches.  Take
+something like this:
+
+       if (!copy_from_user(&kernelvar, uptr, size))
+               do_something_with(kernelvar);
+
+If userspace passes in an evil 'uptr' that *actually* points to a kernel
+addresses, and then do_something_with() has cache (or other)
+side-effects, it could allow userspace to infer kernel data values.
+
+Add a barrier to the common copy_from_user() code to prevent
+mis-speculated values which happen after the copy.
+
+Also add a stub for architectures that do not define barrier_nospec().
+This makes the macro usable in generic code.
+
+Since the barrier is now usable in generic code, the x86 #ifdef in the
+BPF code can also go away.
+
+Reported-by: Jordy Zomer <jordyzomer@google.com>
+Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org>
+Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>   # BPF bits
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/nospec.h |    4 ++++
+ kernel/bpf/core.c      |    2 --
+ lib/usercopy.c         |    7 +++++++
+ 3 files changed, 11 insertions(+), 2 deletions(-)
+
+--- a/include/linux/nospec.h
++++ b/include/linux/nospec.h
+@@ -11,6 +11,10 @@
+ struct task_struct;
++#ifndef barrier_nospec
++# define barrier_nospec() do { } while (0)
++#endif
++
+ /**
+  * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
+  * @index: array element index
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -1908,9 +1908,7 @@ out:
+                * reuse preexisting logic from Spectre v1 mitigation that
+                * happens to produce the required code on x86 for v4 as well.
+                */
+-#ifdef CONFIG_X86
+               barrier_nospec();
+-#endif
+               CONT;
+ #define LDST(SIZEOP, SIZE)                                            \
+       STX_MEM_##SIZEOP:                                               \
+--- a/lib/usercopy.c
++++ b/lib/usercopy.c
+@@ -3,6 +3,7 @@
+ #include <linux/fault-inject-usercopy.h>
+ #include <linux/instrumented.h>
+ #include <linux/uaccess.h>
++#include <linux/nospec.h>
+ /* out-of-line parts */
+@@ -12,6 +13,12 @@ unsigned long _copy_from_user(void *to,
+       unsigned long res = n;
+       might_fault();
+       if (!should_fail_usercopy() && likely(access_ok(from, n))) {
++              /*
++               * Ensure that bad access_ok() speculation will not
++               * lead to nasty side effects *after* the copy is
++               * finished:
++               */
++              barrier_nospec();
+               instrument_copy_from_user_before(to, from, n);
+               res = raw_copy_from_user(to, from, n);
+               instrument_copy_from_user_after(to, from, n, res);
diff --git a/queue-6.1/x86-alternatives-introduce-int3_emulate_jcc.patch b/queue-6.1/x86-alternatives-introduce-int3_emulate_jcc.patch
new file mode 100644 (file)
index 0000000..a1ac21e
--- /dev/null
@@ -0,0 +1,132 @@
+From a0539dc166faebf980f242ad619d51e1f241e971 Mon Sep 17 00:00:00 2001
+From: Peter Zijlstra <peterz@infradead.org>
+Date: Mon, 23 Jan 2023 21:59:16 +0100
+Subject: x86/alternatives: Introduce int3_emulate_jcc()
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+commit db7adcfd1cec4e95155e37bc066fddab302c6340 upstream.
+
+Move the kprobe Jcc emulation into int3_emulate_jcc() so it can be
+used by more code -- specifically static_call() will need this.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Link: https://lore.kernel.org/r/20230123210607.057678245@infradead.org
+Signed-off-by: Nathan Chancellor <nathan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/include/asm/text-patching.h |   31 ++++++++++++++++++++++++++++
+ arch/x86/kernel/kprobes/core.c       |   38 +++++++----------------------------
+ 2 files changed, 39 insertions(+), 30 deletions(-)
+
+--- a/arch/x86/include/asm/text-patching.h
++++ b/arch/x86/include/asm/text-patching.h
+@@ -183,6 +183,37 @@ void int3_emulate_ret(struct pt_regs *re
+       unsigned long ip = int3_emulate_pop(regs);
+       int3_emulate_jmp(regs, ip);
+ }
++
++static __always_inline
++void int3_emulate_jcc(struct pt_regs *regs, u8 cc, unsigned long ip, unsigned long disp)
++{
++      static const unsigned long jcc_mask[6] = {
++              [0] = X86_EFLAGS_OF,
++              [1] = X86_EFLAGS_CF,
++              [2] = X86_EFLAGS_ZF,
++              [3] = X86_EFLAGS_CF | X86_EFLAGS_ZF,
++              [4] = X86_EFLAGS_SF,
++              [5] = X86_EFLAGS_PF,
++      };
++
++      bool invert = cc & 1;
++      bool match;
++
++      if (cc < 0xc) {
++              match = regs->flags & jcc_mask[cc >> 1];
++      } else {
++              match = ((regs->flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^
++                      ((regs->flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT);
++              if (cc >= 0xe)
++                      match = match || (regs->flags & X86_EFLAGS_ZF);
++      }
++
++      if ((match && !invert) || (!match && invert))
++              ip += disp;
++
++      int3_emulate_jmp(regs, ip);
++}
++
+ #endif /* !CONFIG_UML_X86 */
+ #endif /* _ASM_X86_TEXT_PATCHING_H */
+--- a/arch/x86/kernel/kprobes/core.c
++++ b/arch/x86/kernel/kprobes/core.c
+@@ -471,50 +471,26 @@ static void kprobe_emulate_call(struct k
+ }
+ NOKPROBE_SYMBOL(kprobe_emulate_call);
+-static nokprobe_inline
+-void __kprobe_emulate_jmp(struct kprobe *p, struct pt_regs *regs, bool cond)
++static void kprobe_emulate_jmp(struct kprobe *p, struct pt_regs *regs)
+ {
+       unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size;
+-      if (cond)
+-              ip += p->ainsn.rel32;
++      ip += p->ainsn.rel32;
+       int3_emulate_jmp(regs, ip);
+ }
+-
+-static void kprobe_emulate_jmp(struct kprobe *p, struct pt_regs *regs)
+-{
+-      __kprobe_emulate_jmp(p, regs, true);
+-}
+ NOKPROBE_SYMBOL(kprobe_emulate_jmp);
+-static const unsigned long jcc_mask[6] = {
+-      [0] = X86_EFLAGS_OF,
+-      [1] = X86_EFLAGS_CF,
+-      [2] = X86_EFLAGS_ZF,
+-      [3] = X86_EFLAGS_CF | X86_EFLAGS_ZF,
+-      [4] = X86_EFLAGS_SF,
+-      [5] = X86_EFLAGS_PF,
+-};
+-
+ static void kprobe_emulate_jcc(struct kprobe *p, struct pt_regs *regs)
+ {
+-      bool invert = p->ainsn.jcc.type & 1;
+-      bool match;
++      unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size;
+-      if (p->ainsn.jcc.type < 0xc) {
+-              match = regs->flags & jcc_mask[p->ainsn.jcc.type >> 1];
+-      } else {
+-              match = ((regs->flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^
+-                      ((regs->flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT);
+-              if (p->ainsn.jcc.type >= 0xe)
+-                      match = match || (regs->flags & X86_EFLAGS_ZF);
+-      }
+-      __kprobe_emulate_jmp(p, regs, (match && !invert) || (!match && invert));
++      int3_emulate_jcc(regs, p->ainsn.jcc.type, ip, p->ainsn.rel32);
+ }
+ NOKPROBE_SYMBOL(kprobe_emulate_jcc);
+ static void kprobe_emulate_loop(struct kprobe *p, struct pt_regs *regs)
+ {
++      unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size;
+       bool match;
+       if (p->ainsn.loop.type != 3) {  /* LOOP* */
+@@ -542,7 +518,9 @@ static void kprobe_emulate_loop(struct k
+       else if (p->ainsn.loop.type == 1)       /* LOOPE */
+               match = match && (regs->flags & X86_EFLAGS_ZF);
+-      __kprobe_emulate_jmp(p, regs, match);
++      if (match)
++              ip += p->ainsn.rel32;
++      int3_emulate_jmp(regs, ip);
+ }
+ NOKPROBE_SYMBOL(kprobe_emulate_loop);
diff --git a/queue-6.1/x86-alternatives-teach-text_poke_bp-to-patch-jcc.d32-instructions.patch b/queue-6.1/x86-alternatives-teach-text_poke_bp-to-patch-jcc.d32-instructions.patch
new file mode 100644 (file)
index 0000000..d883af1
--- /dev/null
@@ -0,0 +1,185 @@
+From 00b6c51f30708c378ed357067596ee75f2784655 Mon Sep 17 00:00:00 2001
+From: Peter Zijlstra <peterz@infradead.org>
+Date: Mon, 23 Jan 2023 21:59:17 +0100
+Subject: x86/alternatives: Teach text_poke_bp() to patch Jcc.d32 instructions
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+commit ac0ee0a9560c97fa5fe1409e450c2425d4ebd17a upstream.
+
+In order to re-write Jcc.d32 instructions text_poke_bp() needs to be
+taught about them.
+
+The biggest hurdle is that the whole machinery is currently made for 5
+byte instructions and extending this would grow struct text_poke_loc
+which is currently a nice 16 bytes and used in an array.
+
+However, since text_poke_loc contains a full copy of the (s32)
+displacement, it is possible to map the Jcc.d32 2 byte opcodes to
+Jcc.d8 1 byte opcode for the int3 emulation.
+
+This then leaves the replacement bytes; fudge that by only storing the
+last 5 bytes and adding the rule that 'length == 6' instruction will
+be prefixed with a 0x0f byte.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Link: https://lore.kernel.org/r/20230123210607.115718513@infradead.org
+[nathan: Introduce is_jcc32() as part of this change; upstream
+         introduced it in 3b6c1747da48]
+Signed-off-by: Nathan Chancellor <nathan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kernel/alternative.c |   59 ++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 48 insertions(+), 11 deletions(-)
+
+--- a/arch/x86/kernel/alternative.c
++++ b/arch/x86/kernel/alternative.c
+@@ -339,6 +339,12 @@ next:
+       }
+ }
++static inline bool is_jcc32(struct insn *insn)
++{
++      /* Jcc.d32 second opcode byte is in the range: 0x80-0x8f */
++      return insn->opcode.bytes[0] == 0x0f && (insn->opcode.bytes[1] & 0xf0) == 0x80;
++}
++
+ #if defined(CONFIG_RETPOLINE) && defined(CONFIG_OBJTOOL)
+ /*
+@@ -427,8 +433,7 @@ static int patch_retpoline(void *addr, s
+        *   [ NOP ]
+        * 1:
+        */
+-      /* Jcc.d32 second opcode byte is in the range: 0x80-0x8f */
+-      if (op == 0x0f && (insn->opcode.bytes[1] & 0xf0) == 0x80) {
++      if (is_jcc32(insn)) {
+               cc = insn->opcode.bytes[1] & 0xf;
+               cc ^= 1; /* invert condition */
+@@ -1311,6 +1316,11 @@ void text_poke_sync(void)
+       on_each_cpu(do_sync_core, NULL, 1);
+ }
++/*
++ * NOTE: crazy scheme to allow patching Jcc.d32 but not increase the size of
++ * this thing. When len == 6 everything is prefixed with 0x0f and we map
++ * opcode to Jcc.d8, using len to distinguish.
++ */
+ struct text_poke_loc {
+       /* addr := _stext + rel_addr */
+       s32 rel_addr;
+@@ -1432,6 +1442,10 @@ noinstr int poke_int3_handler(struct pt_
+               int3_emulate_jmp(regs, (long)ip + tp->disp);
+               break;
++      case 0x70 ... 0x7f: /* Jcc */
++              int3_emulate_jcc(regs, tp->opcode & 0xf, (long)ip, tp->disp);
++              break;
++
+       default:
+               BUG();
+       }
+@@ -1505,16 +1519,26 @@ static void text_poke_bp_batch(struct te
+        * Second step: update all but the first byte of the patched range.
+        */
+       for (do_sync = 0, i = 0; i < nr_entries; i++) {
+-              u8 old[POKE_MAX_OPCODE_SIZE] = { tp[i].old, };
++              u8 old[POKE_MAX_OPCODE_SIZE+1] = { tp[i].old, };
++              u8 _new[POKE_MAX_OPCODE_SIZE+1];
++              const u8 *new = tp[i].text;
+               int len = tp[i].len;
+               if (len - INT3_INSN_SIZE > 0) {
+                       memcpy(old + INT3_INSN_SIZE,
+                              text_poke_addr(&tp[i]) + INT3_INSN_SIZE,
+                              len - INT3_INSN_SIZE);
++
++                      if (len == 6) {
++                              _new[0] = 0x0f;
++                              memcpy(_new + 1, new, 5);
++                              new = _new;
++                      }
++
+                       text_poke(text_poke_addr(&tp[i]) + INT3_INSN_SIZE,
+-                                (const char *)tp[i].text + INT3_INSN_SIZE,
++                                new + INT3_INSN_SIZE,
+                                 len - INT3_INSN_SIZE);
++
+                       do_sync++;
+               }
+@@ -1542,8 +1566,7 @@ static void text_poke_bp_batch(struct te
+                * The old instruction is recorded so that the event can be
+                * processed forwards or backwards.
+                */
+-              perf_event_text_poke(text_poke_addr(&tp[i]), old, len,
+-                                   tp[i].text, len);
++              perf_event_text_poke(text_poke_addr(&tp[i]), old, len, new, len);
+       }
+       if (do_sync) {
+@@ -1560,10 +1583,15 @@ static void text_poke_bp_batch(struct te
+        * replacing opcode.
+        */
+       for (do_sync = 0, i = 0; i < nr_entries; i++) {
+-              if (tp[i].text[0] == INT3_INSN_OPCODE)
++              u8 byte = tp[i].text[0];
++
++              if (tp[i].len == 6)
++                      byte = 0x0f;
++
++              if (byte == INT3_INSN_OPCODE)
+                       continue;
+-              text_poke(text_poke_addr(&tp[i]), tp[i].text, INT3_INSN_SIZE);
++              text_poke(text_poke_addr(&tp[i]), &byte, INT3_INSN_SIZE);
+               do_sync++;
+       }
+@@ -1581,9 +1609,11 @@ static void text_poke_loc_init(struct te
+                              const void *opcode, size_t len, const void *emulate)
+ {
+       struct insn insn;
+-      int ret, i;
++      int ret, i = 0;
+-      memcpy((void *)tp->text, opcode, len);
++      if (len == 6)
++              i = 1;
++      memcpy((void *)tp->text, opcode+i, len-i);
+       if (!emulate)
+               emulate = opcode;
+@@ -1594,6 +1624,13 @@ static void text_poke_loc_init(struct te
+       tp->len = len;
+       tp->opcode = insn.opcode.bytes[0];
++      if (is_jcc32(&insn)) {
++              /*
++               * Map Jcc.d32 onto Jcc.d8 and use len to distinguish.
++               */
++              tp->opcode = insn.opcode.bytes[1] - 0x10;
++      }
++
+       switch (tp->opcode) {
+       case RET_INSN_OPCODE:
+       case JMP32_INSN_OPCODE:
+@@ -1610,7 +1647,6 @@ static void text_poke_loc_init(struct te
+               BUG_ON(len != insn.length);
+       };
+-
+       switch (tp->opcode) {
+       case INT3_INSN_OPCODE:
+       case RET_INSN_OPCODE:
+@@ -1619,6 +1655,7 @@ static void text_poke_loc_init(struct te
+       case CALL_INSN_OPCODE:
+       case JMP32_INSN_OPCODE:
+       case JMP8_INSN_OPCODE:
++      case 0x70 ... 0x7f: /* Jcc */
+               tp->disp = insn.immediate.value;
+               break;
diff --git a/queue-6.1/x86-static_call-add-support-for-jcc-tail-calls.patch b/queue-6.1/x86-static_call-add-support-for-jcc-tail-calls.patch
new file mode 100644 (file)
index 0000000..39b43fa
--- /dev/null
@@ -0,0 +1,135 @@
+From db720e3226a717120221095b2ddbbac34da79ec0 Mon Sep 17 00:00:00 2001
+From: Peter Zijlstra <peterz@infradead.org>
+Date: Thu, 26 Jan 2023 16:34:27 +0100
+Subject: x86/static_call: Add support for Jcc tail-calls
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+commit 923510c88d2b7d947c4217835fd9ca6bd65cc56c upstream.
+
+Clang likes to create conditional tail calls like:
+
+  0000000000000350 <amd_pmu_add_event>:
+  350:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1) 351: R_X86_64_NONE      __fentry__-0x4
+  355:       48 83 bf 20 01 00 00 00         cmpq   $0x0,0x120(%rdi)
+  35d:       0f 85 00 00 00 00       jne    363 <amd_pmu_add_event+0x13>     35f: R_X86_64_PLT32     __SCT__amd_pmu_branch_add-0x4
+  363:       e9 00 00 00 00          jmp    368 <amd_pmu_add_event+0x18>     364: R_X86_64_PLT32     __x86_return_thunk-0x4
+
+Where 0x35d is a static call site that's turned into a conditional
+tail-call using the Jcc class of instructions.
+
+Teach the in-line static call text patching about this.
+
+Notably, since there is no conditional-ret, in that case patch the Jcc
+to point at an empty stub function that does the ret -- or the return
+thunk when needed.
+
+Reported-by: "Erhard F." <erhard_f@mailbox.org>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Link: https://lore.kernel.org/r/Y9Kdg9QjHkr9G5b5@hirez.programming.kicks-ass.net
+[nathan: Backport to 6.1:
+         - Use __x86_return_thunk instead of x86_return_thunk for func in
+           __static_call_transform()
+         - Remove ASM_FUNC_ALIGN in __static_call_return() asm, as call
+           depth tracking was merged in 6.2]
+Signed-off-by: Nathan Chancellor <nathan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kernel/static_call.c |   49 +++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 46 insertions(+), 3 deletions(-)
+
+--- a/arch/x86/kernel/static_call.c
++++ b/arch/x86/kernel/static_call.c
+@@ -9,6 +9,7 @@ enum insn_type {
+       NOP = 1,  /* site cond-call */
+       JMP = 2,  /* tramp / site tail-call */
+       RET = 3,  /* tramp / site cond-tail-call */
++      JCC = 4,
+ };
+ /*
+@@ -25,12 +26,39 @@ static const u8 xor5rax[] = { 0x2e, 0x2e
+ static const u8 retinsn[] = { RET_INSN_OPCODE, 0xcc, 0xcc, 0xcc, 0xcc };
++static u8 __is_Jcc(u8 *insn) /* Jcc.d32 */
++{
++      u8 ret = 0;
++
++      if (insn[0] == 0x0f) {
++              u8 tmp = insn[1];
++              if ((tmp & 0xf0) == 0x80)
++                      ret = tmp;
++      }
++
++      return ret;
++}
++
++extern void __static_call_return(void);
++
++asm (".global __static_call_return\n\t"
++     ".type __static_call_return, @function\n\t"
++     "__static_call_return:\n\t"
++     ANNOTATE_NOENDBR
++     ANNOTATE_RETPOLINE_SAFE
++     "ret; int3\n\t"
++     ".size __static_call_return, . - __static_call_return \n\t");
++
+ static void __ref __static_call_transform(void *insn, enum insn_type type,
+                                         void *func, bool modinit)
+ {
+       const void *emulate = NULL;
+       int size = CALL_INSN_SIZE;
+       const void *code;
++      u8 op, buf[6];
++
++      if ((type == JMP || type == RET) && (op = __is_Jcc(insn)))
++              type = JCC;
+       switch (type) {
+       case CALL:
+@@ -56,6 +84,20 @@ static void __ref __static_call_transfor
+               else
+                       code = &retinsn;
+               break;
++
++      case JCC:
++              if (!func) {
++                      func = __static_call_return;
++                      if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
++                              func = __x86_return_thunk;
++              }
++
++              buf[0] = 0x0f;
++              __text_gen_insn(buf+1, op, insn+1, func, 5);
++              code = buf;
++              size = 6;
++
++              break;
+       }
+       if (memcmp(insn, code, size) == 0)
+@@ -67,9 +109,9 @@ static void __ref __static_call_transfor
+       text_poke_bp(insn, code, size, emulate);
+ }
+-static void __static_call_validate(void *insn, bool tail, bool tramp)
++static void __static_call_validate(u8 *insn, bool tail, bool tramp)
+ {
+-      u8 opcode = *(u8 *)insn;
++      u8 opcode = insn[0];
+       if (tramp && memcmp(insn+5, tramp_ud, 3)) {
+               pr_err("trampoline signature fail");
+@@ -78,7 +120,8 @@ static void __static_call_validate(void
+       if (tail) {
+               if (opcode == JMP32_INSN_OPCODE ||
+-                  opcode == RET_INSN_OPCODE)
++                  opcode == RET_INSN_OPCODE ||
++                  __is_Jcc(insn))
+                       return;
+       } else {
+               if (opcode == CALL_INSN_OPCODE ||