]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.16-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 31 Jan 2022 10:38:43 +0000 (11:38 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 31 Jan 2022 10:38:43 +0000 (11:38 +0100)
added patches:
block-fix-wrong-offset-in-bio_truncate.patch
kvm-nvmx-allow-vmread-when-enlightened-vmcs-is-in-use.patch
kvm-nvmx-implement-evmcs_field_offset-suitable-for-handle_vmread.patch
kvm-nvmx-rename-vmcs_to_field_offset-_table.patch

queue-5.16/block-fix-wrong-offset-in-bio_truncate.patch [new file with mode: 0644]
queue-5.16/kvm-nvmx-allow-vmread-when-enlightened-vmcs-is-in-use.patch [new file with mode: 0644]
queue-5.16/kvm-nvmx-implement-evmcs_field_offset-suitable-for-handle_vmread.patch [new file with mode: 0644]
queue-5.16/kvm-nvmx-rename-vmcs_to_field_offset-_table.patch [new file with mode: 0644]
queue-5.16/series

diff --git a/queue-5.16/block-fix-wrong-offset-in-bio_truncate.patch b/queue-5.16/block-fix-wrong-offset-in-bio_truncate.patch
new file mode 100644 (file)
index 0000000..a4e3aea
--- /dev/null
@@ -0,0 +1,38 @@
+From 3ee859e384d453d6ac68bfd5971f630d9fa46ad3 Mon Sep 17 00:00:00 2001
+From: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
+Date: Sun, 9 Jan 2022 18:36:43 +0900
+Subject: block: Fix wrong offset in bio_truncate()
+
+From: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
+
+commit 3ee859e384d453d6ac68bfd5971f630d9fa46ad3 upstream.
+
+bio_truncate() clears the buffer outside of last block of bdev, however
+current bio_truncate() is using the wrong offset of page. So it can
+return the uninitialized data.
+
+This happened when both of truncated/corrupted FS and userspace (via
+bdev) are trying to read the last of bdev.
+
+Reported-by: syzbot+ac94ae5f68b84197f41c@syzkaller.appspotmail.com
+Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
+Reviewed-by: Ming Lei <ming.lei@redhat.com>
+Link: https://lore.kernel.org/r/875yqt1c9g.fsf@mail.parknet.co.jp
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/bio.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/block/bio.c
++++ b/block/bio.c
+@@ -569,7 +569,8 @@ static void bio_truncate(struct bio *bio
+                               offset = new_size - done;
+                       else
+                               offset = 0;
+-                      zero_user(bv.bv_page, offset, bv.bv_len - offset);
++                      zero_user(bv.bv_page, bv.bv_offset + offset,
++                                bv.bv_len - offset);
+                       truncated = true;
+               }
+               done += bv.bv_len;
diff --git a/queue-5.16/kvm-nvmx-allow-vmread-when-enlightened-vmcs-is-in-use.patch b/queue-5.16/kvm-nvmx-allow-vmread-when-enlightened-vmcs-is-in-use.patch
new file mode 100644 (file)
index 0000000..2fe5a33
--- /dev/null
@@ -0,0 +1,134 @@
+From 6cbbaab60ff33f59355492c241318046befd9ffc Mon Sep 17 00:00:00 2001
+From: Vitaly Kuznetsov <vkuznets@redhat.com>
+Date: Wed, 12 Jan 2022 18:01:34 +0100
+Subject: KVM: nVMX: Allow VMREAD when Enlightened VMCS is in use
+
+From: Vitaly Kuznetsov <vkuznets@redhat.com>
+
+commit 6cbbaab60ff33f59355492c241318046befd9ffc upstream.
+
+Hyper-V TLFS explicitly forbids VMREAD and VMWRITE instructions when
+Enlightened VMCS interface is in use:
+
+"Any VMREAD or VMWRITE instructions while an enlightened VMCS is
+active is unsupported and can result in unexpected behavior.""
+
+Windows 11 + WSL2 seems to ignore this, attempts to VMREAD VMCS field
+0x4404 ("VM-exit interruption information") are observed. Failing
+these attempts with nested_vmx_failInvalid() makes such guests
+unbootable.
+
+Microsoft confirms this is a Hyper-V bug and claims that it'll get fixed
+eventually but for the time being we need a workaround. (Temporary) allow
+VMREAD to get data from the currently loaded Enlightened VMCS.
+
+Note: VMWRITE instructions remain forbidden, it is not clear how to
+handle them properly and hopefully won't ever be needed.
+
+Reviewed-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
+Message-Id: <20220112170134.1904308-6-vkuznets@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/evmcs.h  |   12 ++++++++++
+ arch/x86/kvm/vmx/nested.c |   55 ++++++++++++++++++++++++++++++++--------------
+ 2 files changed, 51 insertions(+), 16 deletions(-)
+
+--- a/arch/x86/kvm/vmx/evmcs.h
++++ b/arch/x86/kvm/vmx/evmcs.h
+@@ -96,6 +96,18 @@ static __always_inline int evmcs_field_o
+       return evmcs_field->offset;
+ }
++static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
++                               unsigned long field, u16 offset)
++{
++      /*
++       * vmcs12_read_any() doesn't care whether the supplied structure
++       * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
++       * the exact offset of the required field, use it for convenience
++       * here.
++       */
++      return vmcs12_read_any((void *)evmcs, field, offset);
++}
++
+ #if IS_ENABLED(CONFIG_HYPERV)
+ static __always_inline int get_evmcs_offset(unsigned long field,
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -7,6 +7,7 @@
+ #include <asm/mmu_context.h>
+ #include "cpuid.h"
++#include "evmcs.h"
+ #include "hyperv.h"
+ #include "mmu.h"
+ #include "nested.h"
+@@ -5074,27 +5075,49 @@ static int handle_vmread(struct kvm_vcpu
+       if (!nested_vmx_check_permission(vcpu))
+               return 1;
+-      /*
+-       * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
+-       * any VMREAD sets the ALU flags for VMfailInvalid.
+-       */
+-      if (vmx->nested.current_vmptr == INVALID_GPA ||
+-          (is_guest_mode(vcpu) &&
+-           get_vmcs12(vcpu)->vmcs_link_pointer == INVALID_GPA))
+-              return nested_vmx_failInvalid(vcpu);
+-
+       /* Decode instruction info and find the field to read */
+       field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
+-      offset = get_vmcs12_field_offset(field);
+-      if (offset < 0)
+-              return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
++      if (!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
++              /*
++               * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
++               * any VMREAD sets the ALU flags for VMfailInvalid.
++               */
++              if (vmx->nested.current_vmptr == INVALID_GPA ||
++                  (is_guest_mode(vcpu) &&
++                   get_vmcs12(vcpu)->vmcs_link_pointer == INVALID_GPA))
++                      return nested_vmx_failInvalid(vcpu);
++
++              offset = get_vmcs12_field_offset(field);
++              if (offset < 0)
++                      return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
++
++              if (!is_guest_mode(vcpu) && is_vmcs12_ext_field(field))
++                      copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
++
++              /* Read the field, zero-extended to a u64 value */
++              value = vmcs12_read_any(vmcs12, field, offset);
++      } else {
++              /*
++               * Hyper-V TLFS (as of 6.0b) explicitly states, that while an
++               * enlightened VMCS is active VMREAD/VMWRITE instructions are
++               * unsupported. Unfortunately, certain versions of Windows 11
++               * don't comply with this requirement which is not enforced in
++               * genuine Hyper-V. Allow VMREAD from an enlightened VMCS as a
++               * workaround, as misbehaving guests will panic on VM-Fail.
++               * Note, enlightened VMCS is incompatible with shadow VMCS so
++               * all VMREADs from L2 should go to L1.
++               */
++              if (WARN_ON_ONCE(is_guest_mode(vcpu)))
++                      return nested_vmx_failInvalid(vcpu);
+-      if (!is_guest_mode(vcpu) && is_vmcs12_ext_field(field))
+-              copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
++              offset = evmcs_field_offset(field, NULL);
++              if (offset < 0)
++                      return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+-      /* Read the field, zero-extended to a u64 value */
+-      value = vmcs12_read_any(vmcs12, field, offset);
++              /* Read the field, zero-extended to a u64 value */
++              value = evmcs_read_any(vmx->nested.hv_evmcs, field, offset);
++      }
+       /*
+        * Now copy part of this value to register or memory, as requested.
diff --git a/queue-5.16/kvm-nvmx-implement-evmcs_field_offset-suitable-for-handle_vmread.patch b/queue-5.16/kvm-nvmx-implement-evmcs_field_offset-suitable-for-handle_vmread.patch
new file mode 100644 (file)
index 0000000..8226ced
--- /dev/null
@@ -0,0 +1,113 @@
+From 892a42c10ddb945d3a4dcf07dccdf9cb98b21548 Mon Sep 17 00:00:00 2001
+From: Vitaly Kuznetsov <vkuznets@redhat.com>
+Date: Wed, 12 Jan 2022 18:01:33 +0100
+Subject: KVM: nVMX: Implement evmcs_field_offset() suitable for handle_vmread()
+
+From: Vitaly Kuznetsov <vkuznets@redhat.com>
+
+commit 892a42c10ddb945d3a4dcf07dccdf9cb98b21548 upstream.
+
+In preparation to allowing reads from Enlightened VMCS from
+handle_vmread(), implement evmcs_field_offset() to get the correct
+read offset. get_evmcs_offset(), which is being used by KVM-on-Hyper-V,
+is almost what's needed but a few things need to be adjusted. First,
+WARN_ON() is unacceptable for handle_vmread() as any field can (in
+theory) be supplied by the guest and not all fields are defined in
+eVMCS v1. Second, we need to handle 'holes' in eVMCS (missing fields).
+It also sounds like a good idea to WARN_ON() if such fields are ever
+accessed by KVM-on-Hyper-V.
+
+Implement dedicated evmcs_field_offset() helper.
+
+No functional change intended.
+
+Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
+Message-Id: <20220112170134.1904308-5-vkuznets@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/evmcs.c |    3 +--
+ arch/x86/kvm/vmx/evmcs.h |   32 ++++++++++++++++++++++++--------
+ 2 files changed, 25 insertions(+), 10 deletions(-)
+
+--- a/arch/x86/kvm/vmx/evmcs.c
++++ b/arch/x86/kvm/vmx/evmcs.c
+@@ -12,8 +12,6 @@
+ DEFINE_STATIC_KEY_FALSE(enable_evmcs);
+-#if IS_ENABLED(CONFIG_HYPERV)
+-
+ #define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
+ #define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
+               {EVMCS1_OFFSET(name), clean_field}
+@@ -296,6 +294,7 @@ const struct evmcs_field vmcs_field_to_e
+ };
+ const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
++#if IS_ENABLED(CONFIG_HYPERV)
+ __init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
+ {
+       vmcs_conf->pin_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_PINCTRL;
+--- a/arch/x86/kvm/vmx/evmcs.h
++++ b/arch/x86/kvm/vmx/evmcs.h
+@@ -63,8 +63,6 @@ DECLARE_STATIC_KEY_FALSE(enable_evmcs);
+ #define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
+ #define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING)
+-#if IS_ENABLED(CONFIG_HYPERV)
+-
+ struct evmcs_field {
+       u16 offset;
+       u16 clean_field;
+@@ -73,26 +71,44 @@ struct evmcs_field {
+ extern const struct evmcs_field vmcs_field_to_evmcs_1[];
+ extern const unsigned int nr_evmcs_1_fields;
+-static __always_inline int get_evmcs_offset(unsigned long field,
+-                                          u16 *clean_field)
++static __always_inline int evmcs_field_offset(unsigned long field,
++                                            u16 *clean_field)
+ {
+       unsigned int index = ROL16(field, 6);
+       const struct evmcs_field *evmcs_field;
+-      if (unlikely(index >= nr_evmcs_1_fields)) {
+-              WARN_ONCE(1, "KVM: accessing unsupported EVMCS field %lx\n",
+-                        field);
++      if (unlikely(index >= nr_evmcs_1_fields))
+               return -ENOENT;
+-      }
+       evmcs_field = &vmcs_field_to_evmcs_1[index];
++      /*
++       * Use offset=0 to detect holes in eVMCS. This offset belongs to
++       * 'revision_id' but this field has no encoding and is supposed to
++       * be accessed directly.
++       */
++      if (unlikely(!evmcs_field->offset))
++              return -ENOENT;
++
+       if (clean_field)
+               *clean_field = evmcs_field->clean_field;
+       return evmcs_field->offset;
+ }
++#if IS_ENABLED(CONFIG_HYPERV)
++
++static __always_inline int get_evmcs_offset(unsigned long field,
++                                          u16 *clean_field)
++{
++      int offset = evmcs_field_offset(field, clean_field);
++
++      WARN_ONCE(offset < 0, "KVM: accessing unsupported EVMCS field %lx\n",
++                field);
++
++      return offset;
++}
++
+ static __always_inline void evmcs_write64(unsigned long field, u64 value)
+ {
+       u16 clean_field;
diff --git a/queue-5.16/kvm-nvmx-rename-vmcs_to_field_offset-_table.patch b/queue-5.16/kvm-nvmx-rename-vmcs_to_field_offset-_table.patch
new file mode 100644 (file)
index 0000000..f4f134b
--- /dev/null
@@ -0,0 +1,98 @@
+From 2423a4c0d17418eca1ba1e3f48684cb2ab7523d5 Mon Sep 17 00:00:00 2001
+From: Vitaly Kuznetsov <vkuznets@redhat.com>
+Date: Wed, 12 Jan 2022 18:01:32 +0100
+Subject: KVM: nVMX: Rename vmcs_to_field_offset{,_table}
+
+From: Vitaly Kuznetsov <vkuznets@redhat.com>
+
+commit 2423a4c0d17418eca1ba1e3f48684cb2ab7523d5 upstream.
+
+vmcs_to_field_offset{,_table} may sound misleading as VMCS is an opaque
+blob which is not supposed to be accessed directly. In fact,
+vmcs_to_field_offset{,_table} are related to KVM defined VMCS12 structure.
+
+Rename vmcs_field_to_offset() to get_vmcs12_field_offset() for clarity.
+
+No functional change intended.
+
+Reviewed-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
+Message-Id: <20220112170134.1904308-4-vkuznets@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/nested.c |    6 +++---
+ arch/x86/kvm/vmx/vmcs12.c |    4 ++--
+ arch/x86/kvm/vmx/vmcs12.h |    6 +++---
+ 3 files changed, 8 insertions(+), 8 deletions(-)
+
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -5086,7 +5086,7 @@ static int handle_vmread(struct kvm_vcpu
+       /* Decode instruction info and find the field to read */
+       field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
+-      offset = vmcs_field_to_offset(field);
++      offset = get_vmcs12_field_offset(field);
+       if (offset < 0)
+               return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+@@ -5189,7 +5189,7 @@ static int handle_vmwrite(struct kvm_vcp
+       field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
+-      offset = vmcs_field_to_offset(field);
++      offset = get_vmcs12_field_offset(field);
+       if (offset < 0)
+               return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+@@ -6435,7 +6435,7 @@ static u64 nested_vmx_calc_vmcs_enum_msr
+       max_idx = 0;
+       for (i = 0; i < nr_vmcs12_fields; i++) {
+               /* The vmcs12 table is very, very sparsely populated. */
+-              if (!vmcs_field_to_offset_table[i])
++              if (!vmcs12_field_offsets[i])
+                       continue;
+               idx = vmcs_field_index(VMCS12_IDX_TO_ENC(i));
+--- a/arch/x86/kvm/vmx/vmcs12.c
++++ b/arch/x86/kvm/vmx/vmcs12.c
+@@ -8,7 +8,7 @@
+       FIELD(number, name),                                            \
+       [ROL16(number##_HIGH, 6)] = VMCS12_OFFSET(name) + sizeof(u32)
+-const unsigned short vmcs_field_to_offset_table[] = {
++const unsigned short vmcs12_field_offsets[] = {
+       FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id),
+       FIELD(POSTED_INTR_NV, posted_intr_nv),
+       FIELD(GUEST_ES_SELECTOR, guest_es_selector),
+@@ -151,4 +151,4 @@ const unsigned short vmcs_field_to_offse
+       FIELD(HOST_RSP, host_rsp),
+       FIELD(HOST_RIP, host_rip),
+ };
+-const unsigned int nr_vmcs12_fields = ARRAY_SIZE(vmcs_field_to_offset_table);
++const unsigned int nr_vmcs12_fields = ARRAY_SIZE(vmcs12_field_offsets);
+--- a/arch/x86/kvm/vmx/vmcs12.h
++++ b/arch/x86/kvm/vmx/vmcs12.h
+@@ -361,10 +361,10 @@ static inline void vmx_check_vmcs12_offs
+       CHECK_OFFSET(guest_pml_index, 996);
+ }
+-extern const unsigned short vmcs_field_to_offset_table[];
++extern const unsigned short vmcs12_field_offsets[];
+ extern const unsigned int nr_vmcs12_fields;
+-static inline short vmcs_field_to_offset(unsigned long field)
++static inline short get_vmcs12_field_offset(unsigned long field)
+ {
+       unsigned short offset;
+       unsigned int index;
+@@ -377,7 +377,7 @@ static inline short vmcs_field_to_offset
+               return -ENOENT;
+       index = array_index_nospec(index, nr_vmcs12_fields);
+-      offset = vmcs_field_to_offset_table[index];
++      offset = vmcs12_field_offsets[index];
+       if (offset == 0)
+               return -ENOENT;
+       return offset;
index 59530c47096cb619e8b0e965db0cdc6e5963bc2c..bb89cc606e4c9173b7cf3521adb6c47e3371d41c 100644 (file)
@@ -194,3 +194,7 @@ psi-fix-defined-but-not-used-warnings-when-config_proc_fs-n.patch
 usb-dwc3-xilinx-fix-uninitialized-return-value.patch
 usr-include-makefile-add-linux-nfc.h-to-the-compile-test-coverage.patch
 tools-testing-scatterlist-add-missing-defines.patch
+kvm-nvmx-rename-vmcs_to_field_offset-_table.patch
+kvm-nvmx-implement-evmcs_field_offset-suitable-for-handle_vmread.patch
+kvm-nvmx-allow-vmread-when-enlightened-vmcs-is-in-use.patch
+block-fix-wrong-offset-in-bio_truncate.patch