]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 13 Jan 2018 14:53:19 +0000 (15:53 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 13 Jan 2018 14:53:19 +0000 (15:53 +0100)
added patches:
bpf-add-bpf_patch_insn_single-helper.patch
crypto-algapi-fix-null-dereference-in-crypto_remove_spawns.patch
drm-vmwgfx-potential-off-by-one-in-vmw_view_add.patch
kaiser-set-_page_nx-only-if-supported.patch
kvm-x86-add-memory-barrier-on-vmcs-field-lookup.patch
rbd-set-max_segments-to-ushrt_max.patch
x86-microcode-intel-extend-bdw-late-loading-with-a-revision-check.patch

queue-4.4/bpf-add-bpf_patch_insn_single-helper.patch [new file with mode: 0644]
queue-4.4/crypto-algapi-fix-null-dereference-in-crypto_remove_spawns.patch [new file with mode: 0644]
queue-4.4/drm-vmwgfx-potential-off-by-one-in-vmw_view_add.patch [new file with mode: 0644]
queue-4.4/kaiser-set-_page_nx-only-if-supported.patch [new file with mode: 0644]
queue-4.4/kvm-x86-add-memory-barrier-on-vmcs-field-lookup.patch [new file with mode: 0644]
queue-4.4/rbd-set-max_segments-to-ushrt_max.patch [new file with mode: 0644]
queue-4.4/series
queue-4.4/x86-microcode-intel-extend-bdw-late-loading-with-a-revision-check.patch [new file with mode: 0644]

diff --git a/queue-4.4/bpf-add-bpf_patch_insn_single-helper.patch b/queue-4.4/bpf-add-bpf_patch_insn_single-helper.patch
new file mode 100644 (file)
index 0000000..ae7418e
--- /dev/null
@@ -0,0 +1,206 @@
+From c237ee5eb33bf19fe0591c04ff8db19da7323a83 Mon Sep 17 00:00:00 2001
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 13 May 2016 19:08:30 +0200
+Subject: bpf: add bpf_patch_insn_single helper
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+commit c237ee5eb33bf19fe0591c04ff8db19da7323a83 upstream.
+
+Move the functionality to patch instructions out of the verifier
+code and into the core as the new bpf_patch_insn_single() helper
+will be needed later on for blinding as well. No changes in
+functionality.
+
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index 4ff0e647598f..c4aae496f376 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -495,6 +495,9 @@ u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
+ void bpf_int_jit_compile(struct bpf_prog *fp);
+ bool bpf_helper_changes_skb_data(void *func);
++struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
++                                     const struct bpf_insn *patch, u32 len);
++
+ #ifdef CONFIG_BPF_JIT
+ extern int bpf_jit_enable;
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 5313d09d4b62..49b5538a5301 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -136,6 +136,77 @@ void __bpf_prog_free(struct bpf_prog *fp)
+       vfree(fp);
+ }
++static bool bpf_is_jmp_and_has_target(const struct bpf_insn *insn)
++{
++      return BPF_CLASS(insn->code) == BPF_JMP  &&
++             /* Call and Exit are both special jumps with no
++              * target inside the BPF instruction image.
++              */
++             BPF_OP(insn->code) != BPF_CALL &&
++             BPF_OP(insn->code) != BPF_EXIT;
++}
++
++static void bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta)
++{
++      struct bpf_insn *insn = prog->insnsi;
++      u32 i, insn_cnt = prog->len;
++
++      for (i = 0; i < insn_cnt; i++, insn++) {
++              if (!bpf_is_jmp_and_has_target(insn))
++                      continue;
++
++              /* Adjust offset of jmps if we cross boundaries. */
++              if (i < pos && i + insn->off + 1 > pos)
++                      insn->off += delta;
++              else if (i > pos + delta && i + insn->off + 1 <= pos + delta)
++                      insn->off -= delta;
++      }
++}
++
++struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
++                                     const struct bpf_insn *patch, u32 len)
++{
++      u32 insn_adj_cnt, insn_rest, insn_delta = len - 1;
++      struct bpf_prog *prog_adj;
++
++      /* Since our patchlet doesn't expand the image, we're done. */
++      if (insn_delta == 0) {
++              memcpy(prog->insnsi + off, patch, sizeof(*patch));
++              return prog;
++      }
++
++      insn_adj_cnt = prog->len + insn_delta;
++
++      /* Several new instructions need to be inserted. Make room
++       * for them. Likely, there's no need for a new allocation as
++       * last page could have large enough tailroom.
++       */
++      prog_adj = bpf_prog_realloc(prog, bpf_prog_size(insn_adj_cnt),
++                                  GFP_USER);
++      if (!prog_adj)
++              return NULL;
++
++      prog_adj->len = insn_adj_cnt;
++
++      /* Patching happens in 3 steps:
++       *
++       * 1) Move over tail of insnsi from next instruction onwards,
++       *    so we can patch the single target insn with one or more
++       *    new ones (patching is always from 1 to n insns, n > 0).
++       * 2) Inject new instructions at the target location.
++       * 3) Adjust branch offsets if necessary.
++       */
++      insn_rest = insn_adj_cnt - off - len;
++
++      memmove(prog_adj->insnsi + off + len, prog_adj->insnsi + off + 1,
++              sizeof(*patch) * insn_rest);
++      memcpy(prog_adj->insnsi + off, patch, sizeof(*patch) * len);
++
++      bpf_adj_branches(prog_adj, off, insn_delta);
++
++      return prog_adj;
++}
++
+ #ifdef CONFIG_BPF_JIT
+ struct bpf_binary_header *
+ bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 84bff68cf80e..a08d66215245 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -2587,26 +2587,6 @@ static void convert_pseudo_ld_imm64(struct verifier_env *env)
+                       insn->src_reg = 0;
+ }
+-static void adjust_branches(struct bpf_prog *prog, int pos, int delta)
+-{
+-      struct bpf_insn *insn = prog->insnsi;
+-      int insn_cnt = prog->len;
+-      int i;
+-
+-      for (i = 0; i < insn_cnt; i++, insn++) {
+-              if (BPF_CLASS(insn->code) != BPF_JMP ||
+-                  BPF_OP(insn->code) == BPF_CALL ||
+-                  BPF_OP(insn->code) == BPF_EXIT)
+-                      continue;
+-
+-              /* adjust offset of jmps if necessary */
+-              if (i < pos && i + insn->off + 1 > pos)
+-                      insn->off += delta;
+-              else if (i > pos + delta && i + insn->off + 1 <= pos + delta)
+-                      insn->off -= delta;
+-      }
+-}
+-
+ /* convert load instructions that access fields of 'struct __sk_buff'
+  * into sequence of instructions that access fields of 'struct sk_buff'
+  */
+@@ -2616,14 +2596,15 @@ static int convert_ctx_accesses(struct verifier_env *env)
+       int insn_cnt = env->prog->len;
+       struct bpf_insn insn_buf[16];
+       struct bpf_prog *new_prog;
+-      u32 cnt;
+-      int i;
+       enum bpf_access_type type;
++      int i;
+       if (!env->prog->aux->ops->convert_ctx_access)
+               return 0;
+       for (i = 0; i < insn_cnt; i++, insn++) {
++              u32 insn_delta, cnt;
++
+               if (insn->code == (BPF_LDX | BPF_MEM | BPF_W))
+                       type = BPF_READ;
+               else if (insn->code == (BPF_STX | BPF_MEM | BPF_W))
+@@ -2645,34 +2626,18 @@ static int convert_ctx_accesses(struct verifier_env *env)
+                       return -EINVAL;
+               }
+-              if (cnt == 1) {
+-                      memcpy(insn, insn_buf, sizeof(*insn));
+-                      continue;
+-              }
+-
+-              /* several new insns need to be inserted. Make room for them */
+-              insn_cnt += cnt - 1;
+-              new_prog = bpf_prog_realloc(env->prog,
+-                                          bpf_prog_size(insn_cnt),
+-                                          GFP_USER);
++              new_prog = bpf_patch_insn_single(env->prog, i, insn_buf, cnt);
+               if (!new_prog)
+                       return -ENOMEM;
+-              new_prog->len = insn_cnt;
+-
+-              memmove(new_prog->insnsi + i + cnt, new_prog->insns + i + 1,
+-                      sizeof(*insn) * (insn_cnt - i - cnt));
+-
+-              /* copy substitute insns in place of load instruction */
+-              memcpy(new_prog->insnsi + i, insn_buf, sizeof(*insn) * cnt);
+-
+-              /* adjust branches in the whole program */
+-              adjust_branches(new_prog, i, cnt - 1);
++              insn_delta = cnt - 1;
+               /* keep walking new program and skip insns we just inserted */
+               env->prog = new_prog;
+-              insn = new_prog->insnsi + i + cnt - 1;
+-              i += cnt - 1;
++              insn      = new_prog->insnsi + i + insn_delta;
++
++              insn_cnt += insn_delta;
++              i        += insn_delta;
+       }
+       return 0;
diff --git a/queue-4.4/crypto-algapi-fix-null-dereference-in-crypto_remove_spawns.patch b/queue-4.4/crypto-algapi-fix-null-dereference-in-crypto_remove_spawns.patch
new file mode 100644 (file)
index 0000000..f27a78b
--- /dev/null
@@ -0,0 +1,57 @@
+From 9a00674213a3f00394f4e3221b88f2d21fc05789 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Fri, 29 Dec 2017 14:30:19 -0600
+Subject: crypto: algapi - fix NULL dereference in crypto_remove_spawns()
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit 9a00674213a3f00394f4e3221b88f2d21fc05789 upstream.
+
+syzkaller triggered a NULL pointer dereference in crypto_remove_spawns()
+via a program that repeatedly and concurrently requests AEADs
+"authenc(cmac(des3_ede-asm),pcbc-aes-aesni)" and hashes "cmac(des3_ede)"
+through AF_ALG, where the hashes are requested as "untested"
+(CRYPTO_ALG_TESTED is set in ->salg_mask but clear in ->salg_feat; this
+causes the template to be instantiated for every request).
+
+Although AF_ALG users really shouldn't be able to request an "untested"
+algorithm, the NULL pointer dereference is actually caused by a
+longstanding race condition where crypto_remove_spawns() can encounter
+an instance which has had spawn(s) "grabbed" but hasn't yet been
+registered, resulting in ->cra_users still being NULL.
+
+We probably should properly initialize ->cra_users earlier, but that
+would require updating many templates individually.  For now just fix
+the bug in a simple way that can easily be backported: make
+crypto_remove_spawns() treat a NULL ->cra_users list as empty.
+
+Reported-by: syzbot <syzkaller@googlegroups.com>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ crypto/algapi.c |   12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/crypto/algapi.c
++++ b/crypto/algapi.c
+@@ -168,6 +168,18 @@ void crypto_remove_spawns(struct crypto_
+                       spawn->alg = NULL;
+                       spawns = &inst->alg.cra_users;
++
++                      /*
++                       * We may encounter an unregistered instance here, since
++                       * an instance's spawns are set up prior to the instance
++                       * being registered.  An unregistered instance will have
++                       * NULL ->cra_users.next, since ->cra_users isn't
++                       * properly initialized until registration.  But an
++                       * unregistered instance cannot have any users, so treat
++                       * it the same as ->cra_users being empty.
++                       */
++                      if (spawns->next == NULL)
++                              break;
+               }
+       } while ((spawns = crypto_more_spawns(alg, &stack, &top,
+                                             &secondary_spawns)));
diff --git a/queue-4.4/drm-vmwgfx-potential-off-by-one-in-vmw_view_add.patch b/queue-4.4/drm-vmwgfx-potential-off-by-one-in-vmw_view_add.patch
new file mode 100644 (file)
index 0000000..8d67dbe
--- /dev/null
@@ -0,0 +1,37 @@
+From 0d9cac0ca0429830c40fe1a4e50e60f6221fd7b6 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Wed, 10 Jan 2018 12:40:04 +0300
+Subject: drm/vmwgfx: Potential off by one in vmw_view_add()
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit 0d9cac0ca0429830c40fe1a4e50e60f6221fd7b6 upstream.
+
+The vmw_view_cmd_to_type() function returns vmw_view_max (3) on error.
+It's one element beyond the end of the vmw_view_cotables[] table.
+
+My read on this is that it's possible to hit this failure.  header->id
+comes from vmw_cmd_check() and it's a user controlled number between
+1040 and 1225 so we can hit that error.  But I don't have the hardware
+to test this code.
+
+Fixes: d80efd5cb3de ("drm/vmwgfx: Initial DX support")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+@@ -2678,6 +2678,8 @@ static int vmw_cmd_dx_view_define(struct
+       }
+       view_type = vmw_view_cmd_to_type(header->id);
++      if (view_type == vmw_view_max)
++              return -EINVAL;
+       cmd = container_of(header, typeof(*cmd), header);
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                               user_surface_converter,
diff --git a/queue-4.4/kaiser-set-_page_nx-only-if-supported.patch b/queue-4.4/kaiser-set-_page_nx-only-if-supported.patch
new file mode 100644 (file)
index 0000000..2948349
--- /dev/null
@@ -0,0 +1,34 @@
+From ytht.net@gmail.com  Sat Jan 13 15:46:36 2018
+From: Lepton Wu <ytht.net@gmail.com>
+Date: Fri, 12 Jan 2018 13:42:56 -0800
+Subject: kaiser: Set _PAGE_NX only if supported
+To: stable@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, groeck@chromium.org, hshan@google.com, Lepton Wu <ytht.net@gmail.com>
+Message-ID: <20180112214256.257463-1-ytht.net@gmail.com>
+
+From: Lepton Wu <ytht.net@gmail.com>
+
+This finally resolve crash if loaded under qemu + haxm. Haitao Shan pointed
+out that the reason of that crash is that NX bit get set for page tables.
+It seems we missed checking if _PAGE_NX is supported in kaiser_add_user_map
+
+Link: https://www.spinics.net/lists/kernel/msg2689835.html
+
+Reviewed-by: Guenter Roeck <groeck@chromium.org>
+Signed-off-by: Lepton Wu <ytht.net@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/mm/kaiser.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/x86/mm/kaiser.c
++++ b/arch/x86/mm/kaiser.c
+@@ -198,6 +198,8 @@ static int kaiser_add_user_map(const voi
+        * requires that not to be #defined to 0): so mask it off here.
+        */
+       flags &= ~_PAGE_GLOBAL;
++      if (!(__supported_pte_mask & _PAGE_NX))
++              flags &= ~_PAGE_NX;
+       for (; address < end_addr; address += PAGE_SIZE) {
+               target_address = get_pa_from_mapping(address);
diff --git a/queue-4.4/kvm-x86-add-memory-barrier-on-vmcs-field-lookup.patch b/queue-4.4/kvm-x86-add-memory-barrier-on-vmcs-field-lookup.patch
new file mode 100644 (file)
index 0000000..e581177
--- /dev/null
@@ -0,0 +1,43 @@
+From 75f139aaf896d6fdeec2e468ddfa4b2fe469bf40 Mon Sep 17 00:00:00 2001
+From: Andrew Honig <ahonig@google.com>
+Date: Wed, 10 Jan 2018 10:12:03 -0800
+Subject: KVM: x86: Add memory barrier on vmcs field lookup
+
+From: Andrew Honig <ahonig@google.com>
+
+commit 75f139aaf896d6fdeec2e468ddfa4b2fe469bf40 upstream.
+
+This adds a memory barrier when performing a lookup into
+the vmcs_field_to_offset_table.  This is related to
+CVE-2017-5753.
+
+Signed-off-by: Andrew Honig <ahonig@google.com>
+Reviewed-by: Jim Mattson <jmattson@google.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kvm/vmx.c |   12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/kvm/vmx.c
++++ b/arch/x86/kvm/vmx.c
+@@ -828,8 +828,16 @@ static inline short vmcs_field_to_offset
+ {
+       BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX);
+-      if (field >= ARRAY_SIZE(vmcs_field_to_offset_table) ||
+-          vmcs_field_to_offset_table[field] == 0)
++      if (field >= ARRAY_SIZE(vmcs_field_to_offset_table))
++              return -ENOENT;
++
++      /*
++       * FIXME: Mitigation for CVE-2017-5753.  To be replaced with a
++       * generic mechanism.
++       */
++      asm("lfence");
++
++      if (vmcs_field_to_offset_table[field] == 0)
+               return -ENOENT;
+       return vmcs_field_to_offset_table[field];
diff --git a/queue-4.4/rbd-set-max_segments-to-ushrt_max.patch b/queue-4.4/rbd-set-max_segments-to-ushrt_max.patch
new file mode 100644 (file)
index 0000000..bb07e81
--- /dev/null
@@ -0,0 +1,36 @@
+From 21acdf45f4958135940f0b4767185cf911d4b010 Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Thu, 21 Dec 2017 15:35:11 +0100
+Subject: rbd: set max_segments to USHRT_MAX
+
+From: Ilya Dryomov <idryomov@gmail.com>
+
+commit 21acdf45f4958135940f0b4767185cf911d4b010 upstream.
+
+Commit d3834fefcfe5 ("rbd: bump queue_max_segments") bumped
+max_segments (unsigned short) to max_hw_sectors (unsigned int).
+max_hw_sectors is set to the number of 512-byte sectors in an object
+and overflows unsigned short for 32M (largest possible) objects, making
+the block layer resort to handing us single segment (i.e. single page
+or even smaller) bios in that case.
+
+Fixes: d3834fefcfe5 ("rbd: bump queue_max_segments")
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Alex Elder <elder@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/rbd.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/block/rbd.c
++++ b/drivers/block/rbd.c
+@@ -3767,7 +3767,7 @@ static int rbd_init_disk(struct rbd_devi
+       segment_size = rbd_obj_bytes(&rbd_dev->header);
+       blk_queue_max_hw_sectors(q, segment_size / SECTOR_SIZE);
+       q->limits.max_sectors = queue_max_hw_sectors(q);
+-      blk_queue_max_segments(q, segment_size / SECTOR_SIZE);
++      blk_queue_max_segments(q, USHRT_MAX);
+       blk_queue_max_segment_size(q, segment_size);
+       blk_queue_io_min(q, segment_size);
+       blk_queue_io_opt(q, segment_size);
index 02ca14ec0e0934b4cad38a3775e23a8469d77415..975431c4bb7bca940dcfd9d55586be0ba7bbd992 100644 (file)
@@ -54,3 +54,10 @@ sh_eth-fix-tsu-resource-handling.patch
 sh_eth-fix-sh7757-gether-initialization.patch
 net-stmmac-enable-eee-in-mii-gmii-or-rgmii-only.patch
 ipv6-fix-possible-mem-leaks-in-ipv6_make_skb.patch
+crypto-algapi-fix-null-dereference-in-crypto_remove_spawns.patch
+rbd-set-max_segments-to-ushrt_max.patch
+x86-microcode-intel-extend-bdw-late-loading-with-a-revision-check.patch
+kvm-x86-add-memory-barrier-on-vmcs-field-lookup.patch
+drm-vmwgfx-potential-off-by-one-in-vmw_view_add.patch
+kaiser-set-_page_nx-only-if-supported.patch
+bpf-add-bpf_patch_insn_single-helper.patch
diff --git a/queue-4.4/x86-microcode-intel-extend-bdw-late-loading-with-a-revision-check.patch b/queue-4.4/x86-microcode-intel-extend-bdw-late-loading-with-a-revision-check.patch
new file mode 100644 (file)
index 0000000..3d13ffe
--- /dev/null
@@ -0,0 +1,68 @@
+From b94b7373317164402ff7728d10f7023127a02b60 Mon Sep 17 00:00:00 2001
+From: Jia Zhang <qianyue.zj@alibaba-inc.com>
+Date: Mon, 1 Jan 2018 10:04:47 +0800
+Subject: x86/microcode/intel: Extend BDW late-loading with a revision check
+
+From: Jia Zhang <qianyue.zj@alibaba-inc.com>
+
+commit b94b7373317164402ff7728d10f7023127a02b60 upstream.
+
+Instead of blacklisting all model 79 CPUs when attempting a late
+microcode loading, limit that only to CPUs with microcode revisions <
+0x0b000021 because only on those late loading may cause a system hang.
+
+For such processors either:
+
+a) a BIOS update which might contain a newer microcode revision
+
+or
+
+b) the early microcode loading method
+
+should be considered.
+
+Processors with revisions 0x0b000021 or higher will not experience such
+hangs.
+
+For more details, see erratum BDF90 in document #334165 (Intel Xeon
+Processor E7-8800/4800 v4 Product Family Specification Update) from
+September 2017.
+
+[ bp: Heavily massage commit message and pr_* statements. ]
+
+Fixes: 723f2828a98c ("x86/microcode/intel: Disable late loading on model 79")
+Signed-off-by: Jia Zhang <qianyue.zj@alibaba-inc.com>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: Tony Luck <tony.luck@intel.com>
+Cc: x86-ml <x86@kernel.org>
+Link: http://lkml.kernel.org/r/1514772287-92959-1-git-send-email-qianyue.zj@alibaba-inc.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/cpu/microcode/intel.c |   14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+--- a/arch/x86/kernel/cpu/microcode/intel.c
++++ b/arch/x86/kernel/cpu/microcode/intel.c
+@@ -994,9 +994,17 @@ static bool is_blacklisted(unsigned int
+ {
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+-      if (c->x86 == 6 && c->x86_model == 79) {
+-              pr_err_once("late loading on model 79 is disabled.\n");
+-              return true;
++      /*
++       * Late loading on model 79 with microcode revision less than 0x0b000021
++       * may result in a system hang. This behavior is documented in item
++       * BDF90, #334165 (Intel Xeon Processor E7-8800/4800 v4 Product Family).
++       */
++      if (c->x86 == 6 &&
++          c->x86_model == 79 &&
++          c->x86_mask == 0x01 &&
++          c->microcode < 0x0b000021) {
++              pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode);
++              pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n");
+       }
+       return false;