From: Greg Kroah-Hartman Date: Mon, 31 Jan 2022 10:38:43 +0000 (+0100) Subject: 5.16-stable patches X-Git-Tag: v5.4.176~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9be1560d208b00b6d539bdab5349e3d9e0c7c0f9;p=thirdparty%2Fkernel%2Fstable-queue.git 5.16-stable patches 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 --- 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 index 00000000000..a4e3aea70eb --- /dev/null +++ b/queue-5.16/block-fix-wrong-offset-in-bio_truncate.patch @@ -0,0 +1,38 @@ +From 3ee859e384d453d6ac68bfd5971f630d9fa46ad3 Mon Sep 17 00:00:00 2001 +From: OGAWA Hirofumi +Date: Sun, 9 Jan 2022 18:36:43 +0900 +Subject: block: Fix wrong offset in bio_truncate() + +From: OGAWA Hirofumi + +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 +Reviewed-by: Ming Lei +Link: https://lore.kernel.org/r/875yqt1c9g.fsf@mail.parknet.co.jp +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..2fe5a338581 --- /dev/null +++ b/queue-5.16/kvm-nvmx-allow-vmread-when-enlightened-vmcs-is-in-use.patch @@ -0,0 +1,134 @@ +From 6cbbaab60ff33f59355492c241318046befd9ffc Mon Sep 17 00:00:00 2001 +From: Vitaly Kuznetsov +Date: Wed, 12 Jan 2022 18:01:34 +0100 +Subject: KVM: nVMX: Allow VMREAD when Enlightened VMCS is in use + +From: Vitaly Kuznetsov + +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 +Signed-off-by: Vitaly Kuznetsov +Message-Id: <20220112170134.1904308-6-vkuznets@redhat.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + 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 + + #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 index 00000000000..8226cedfed3 --- /dev/null +++ b/queue-5.16/kvm-nvmx-implement-evmcs_field_offset-suitable-for-handle_vmread.patch @@ -0,0 +1,113 @@ +From 892a42c10ddb945d3a4dcf07dccdf9cb98b21548 Mon Sep 17 00:00:00 2001 +From: Vitaly Kuznetsov +Date: Wed, 12 Jan 2022 18:01:33 +0100 +Subject: KVM: nVMX: Implement evmcs_field_offset() suitable for handle_vmread() + +From: Vitaly Kuznetsov + +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 +Message-Id: <20220112170134.1904308-5-vkuznets@redhat.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..f4f134be876 --- /dev/null +++ b/queue-5.16/kvm-nvmx-rename-vmcs_to_field_offset-_table.patch @@ -0,0 +1,98 @@ +From 2423a4c0d17418eca1ba1e3f48684cb2ab7523d5 Mon Sep 17 00:00:00 2001 +From: Vitaly Kuznetsov +Date: Wed, 12 Jan 2022 18:01:32 +0100 +Subject: KVM: nVMX: Rename vmcs_to_field_offset{,_table} + +From: Vitaly Kuznetsov + +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 +Signed-off-by: Vitaly Kuznetsov +Message-Id: <20220112170134.1904308-4-vkuznets@redhat.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + 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; diff --git a/queue-5.16/series b/queue-5.16/series index 59530c47096..bb89cc606e4 100644 --- a/queue-5.16/series +++ b/queue-5.16/series @@ -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