aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-09-02 22:26:09 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-09-02 22:26:09 +0200
commitf7a9241155211c41fc84b293c8cd0a52c95b2108 (patch)
tree33921b16b3643dbeb7e274c0a6f66067240fdee9
parent195d05e43a203147cb2f094ce2b4122dec0a5907 (diff)
downloadqueue-3.18-f7a9241155211c41fc84b293c8cd0a52c95b2108.tar.gz
more patches
-rw-r--r--alsa-seq-fix-potential-concurrent-access-to-the-deleted-pool.patch70
-rw-r--r--alsa-usb-audio-fix-a-stack-buffer-overflow-bug-in-check_input_term.patch104
-rw-r--r--alsa-usb-audio-fix-an-oob-bug-in-parse_audio_mixer_unit.patch52
-rw-r--r--series6
-rw-r--r--x86-apic-do-not-initialize-ldr-and-dfr-for-bigsmp.patch83
-rw-r--r--x86-apic-handle-missing-global-clockevent-gracefully.patch154
-rw-r--r--x86-apic-include-the-ldr-when-clearing-out-apic-registers.patch49
7 files changed, 363 insertions, 155 deletions
diff --git a/alsa-seq-fix-potential-concurrent-access-to-the-deleted-pool.patch b/alsa-seq-fix-potential-concurrent-access-to-the-deleted-pool.patch
new file mode 100644
index 0000000..0092e62
--- /dev/null
+++ b/alsa-seq-fix-potential-concurrent-access-to-the-deleted-pool.patch
@@ -0,0 +1,70 @@
+From 75545304eba6a3d282f923b96a466dc25a81e359 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Sun, 25 Aug 2019 09:21:44 +0200
+Subject: ALSA: seq: Fix potential concurrent access to the deleted pool
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 75545304eba6a3d282f923b96a466dc25a81e359 upstream.
+
+The input pool of a client might be deleted via the resize ioctl, the
+the access to it should be covered by the proper locks. Currently the
+only missing place is the call in snd_seq_ioctl_get_client_pool(), and
+this patch papers over it.
+
+Reported-by: syzbot+4a75454b9ca2777f35c7@syzkaller.appspotmail.com
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/seq/seq_clientmgr.c | 3 +--
+ sound/core/seq/seq_fifo.c | 17 +++++++++++++++++
+ sound/core/seq/seq_fifo.h | 2 ++
+ 3 files changed, 20 insertions(+), 2 deletions(-)
+
+--- a/sound/core/seq/seq_clientmgr.c
++++ b/sound/core/seq/seq_clientmgr.c
+@@ -1911,8 +1911,7 @@ static int snd_seq_ioctl_get_client_pool
+ if (cptr->type == USER_CLIENT) {
+ info.input_pool = cptr->data.user.fifo_pool_size;
+ info.input_free = info.input_pool;
+- if (cptr->data.user.fifo)
+- info.input_free = snd_seq_unused_cells(cptr->data.user.fifo->pool);
++ info.input_free = snd_seq_fifo_unused_cells(cptr->data.user.fifo);
+ } else {
+ info.input_pool = 0;
+ info.input_free = 0;
+--- a/sound/core/seq/seq_fifo.c
++++ b/sound/core/seq/seq_fifo.c
+@@ -275,3 +275,20 @@ int snd_seq_fifo_resize(struct snd_seq_f
+
+ return 0;
+ }
++
++/* get the number of unused cells safely */
++int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f)
++{
++ unsigned long flags;
++ int cells;
++
++ if (!f)
++ return 0;
++
++ snd_use_lock_use(&f->use_lock);
++ spin_lock_irqsave(&f->lock, flags);
++ cells = snd_seq_unused_cells(f->pool);
++ spin_unlock_irqrestore(&f->lock, flags);
++ snd_use_lock_free(&f->use_lock);
++ return cells;
++}
+--- a/sound/core/seq/seq_fifo.h
++++ b/sound/core/seq/seq_fifo.h
+@@ -68,5 +68,7 @@ int snd_seq_fifo_poll_wait(struct snd_se
+ /* resize pool in fifo */
+ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize);
+
++/* get the number of unused cells safely */
++int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f);
+
+ #endif
diff --git a/alsa-usb-audio-fix-a-stack-buffer-overflow-bug-in-check_input_term.patch b/alsa-usb-audio-fix-a-stack-buffer-overflow-bug-in-check_input_term.patch
new file mode 100644
index 0000000..eb8d971
--- /dev/null
+++ b/alsa-usb-audio-fix-a-stack-buffer-overflow-bug-in-check_input_term.patch
@@ -0,0 +1,104 @@
+From 19bce474c45be69a284ecee660aa12d8f1e88f18 Mon Sep 17 00:00:00 2001
+From: Hui Peng <benquike@gmail.com>
+Date: Thu, 15 Aug 2019 00:31:34 -0400
+Subject: ALSA: usb-audio: Fix a stack buffer overflow bug in check_input_term
+
+From: Hui Peng <benquike@gmail.com>
+
+commit 19bce474c45be69a284ecee660aa12d8f1e88f18 upstream.
+
+`check_input_term` recursively calls itself with input from
+device side (e.g., uac_input_terminal_descriptor.bCSourceID)
+as argument (id). In `check_input_term`, if `check_input_term`
+is called with the same `id` argument as the caller, it triggers
+endless recursive call, resulting kernel space stack overflow.
+
+This patch fixes the bug by adding a bitmap to `struct mixer_build`
+to keep track of the checked ids and stop the execution if some id
+has been checked (similar to how parse_audio_unit handles unitid
+argument).
+
+Reported-by: Hui Peng <benquike@gmail.com>
+Reported-by: Mathias Payer <mathias.payer@nebelwelt.net>
+Signed-off-by: Hui Peng <benquike@gmail.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ sound/usb/mixer.c | 29 ++++++++++++++++++++++++-----
+ 1 file changed, 24 insertions(+), 5 deletions(-)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -81,6 +81,7 @@ struct mixer_build {
+ unsigned char *buffer;
+ unsigned int buflen;
+ DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
++ DECLARE_BITMAP(termbitmap, MAX_ID_ELEMS);
+ struct usb_audio_term oterm;
+ const struct usbmix_name_map *map;
+ const struct usbmix_selector_map *selector_map;
+@@ -695,15 +696,24 @@ static int get_term_name(struct mixer_bu
+ * parse the source unit recursively until it reaches to a terminal
+ * or a branched unit.
+ */
+-static int check_input_term(struct mixer_build *state, int id,
++static int __check_input_term(struct mixer_build *state, int id,
+ struct usb_audio_term *term)
+ {
+ int err;
+ void *p1;
++ unsigned char *hdr;
+
+ memset(term, 0, sizeof(*term));
+- while ((p1 = find_audio_control_unit(state, id)) != NULL) {
+- unsigned char *hdr = p1;
++ for (;;) {
++ /* a loop in the terminal chain? */
++ if (test_and_set_bit(id, state->termbitmap))
++ return -EINVAL;
++
++ p1 = find_audio_control_unit(state, id);
++ if (!p1)
++ break;
++
++ hdr = p1;
+ term->id = id;
+ switch (hdr[2]) {
+ case UAC_INPUT_TERMINAL:
+@@ -721,7 +731,7 @@ static int check_input_term(struct mixer
+ term->name = d->iTerminal;
+
+ /* call recursively to get the clock selectors */
+- err = check_input_term(state, d->bCSourceID, term);
++ err = __check_input_term(state, d->bCSourceID, term);
+ if (err < 0)
+ return err;
+ }
+@@ -744,7 +754,7 @@ static int check_input_term(struct mixer
+ case UAC2_CLOCK_SELECTOR: {
+ struct uac_selector_unit_descriptor *d = p1;
+ /* call recursively to retrieve the channel info */
+- err = check_input_term(state, d->baSourceID[0], term);
++ err = __check_input_term(state, d->baSourceID[0], term);
+ if (err < 0)
+ return err;
+ term->type = d->bDescriptorSubtype << 16; /* virtual type */
+@@ -791,6 +801,15 @@ static int check_input_term(struct mixer
+ return -ENODEV;
+ }
+
++
++static int check_input_term(struct mixer_build *state, int id,
++ struct usb_audio_term *term)
++{
++ memset(term, 0, sizeof(*term));
++ memset(state->termbitmap, 0, sizeof(state->termbitmap));
++ return __check_input_term(state, id, term);
++}
++
+ /*
+ * Feature Unit
+ */
diff --git a/alsa-usb-audio-fix-an-oob-bug-in-parse_audio_mixer_unit.patch b/alsa-usb-audio-fix-an-oob-bug-in-parse_audio_mixer_unit.patch
new file mode 100644
index 0000000..ba0ec06
--- /dev/null
+++ b/alsa-usb-audio-fix-an-oob-bug-in-parse_audio_mixer_unit.patch
@@ -0,0 +1,52 @@
+From daac07156b330b18eb5071aec4b3ddca1c377f2c Mon Sep 17 00:00:00 2001
+From: Hui Peng <benquike@gmail.com>
+Date: Tue, 13 Aug 2019 22:34:04 -0400
+Subject: ALSA: usb-audio: Fix an OOB bug in parse_audio_mixer_unit
+
+From: Hui Peng <benquike@gmail.com>
+
+commit daac07156b330b18eb5071aec4b3ddca1c377f2c upstream.
+
+The `uac_mixer_unit_descriptor` shown as below is read from the
+device side. In `parse_audio_mixer_unit`, `baSourceID` field is
+accessed from index 0 to `bNrInPins` - 1, the current implementation
+assumes that descriptor is always valid (the length of descriptor
+is no shorter than 5 + `bNrInPins`). If a descriptor read from
+the device side is invalid, it may trigger out-of-bound memory
+access.
+
+```
+struct uac_mixer_unit_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubtype;
+ __u8 bUnitID;
+ __u8 bNrInPins;
+ __u8 baSourceID[];
+}
+```
+
+This patch fixes the bug by add a sanity check on the length of
+the descriptor.
+
+Reported-by: Hui Peng <benquike@gmail.com>
+Reported-by: Mathias Payer <mathias.payer@nebelwelt.net>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Hui Peng <benquike@gmail.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -1622,6 +1622,7 @@ static int parse_audio_mixer_unit(struct
+ int pin, ich, err;
+
+ if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) ||
++ desc->bLength < sizeof(*desc) + desc->bNrInPins ||
+ !(num_outs = uac_mixer_unit_bNrChannels(desc))) {
+ usb_audio_err(state->chip,
+ "invalid MIXER UNIT descriptor %d\n",
diff --git a/series b/series
index 41bb24b..019b157 100644
--- a/series
+++ b/series
@@ -1,5 +1,9 @@
revert-dm-bufio-fix-deadlock-with-loop-device.patch
-x86-apic-handle-missing-global-clockevent-gracefully.patch
dm-btree-fix-order-of-block-initialization-in-btree_split_beneath.patch
dm-space-map-metadata-fix-missing-store-of-apply_bops-return-value.patch
dm-table-fix-invalid-memory-accesses-with-too-high-sector-number.patch
+alsa-usb-audio-fix-a-stack-buffer-overflow-bug-in-check_input_term.patch
+alsa-usb-audio-fix-an-oob-bug-in-parse_audio_mixer_unit.patch
+alsa-seq-fix-potential-concurrent-access-to-the-deleted-pool.patch
+x86-apic-do-not-initialize-ldr-and-dfr-for-bigsmp.patch
+x86-apic-include-the-ldr-when-clearing-out-apic-registers.patch
diff --git a/x86-apic-do-not-initialize-ldr-and-dfr-for-bigsmp.patch b/x86-apic-do-not-initialize-ldr-and-dfr-for-bigsmp.patch
new file mode 100644
index 0000000..14615a3
--- /dev/null
+++ b/x86-apic-do-not-initialize-ldr-and-dfr-for-bigsmp.patch
@@ -0,0 +1,83 @@
+From bae3a8d3308ee69a7dbdf145911b18dfda8ade0d Mon Sep 17 00:00:00 2001
+From: Bandan Das <bsd@redhat.com>
+Date: Mon, 26 Aug 2019 06:15:12 -0400
+Subject: x86/apic: Do not initialize LDR and DFR for bigsmp
+
+From: Bandan Das <bsd@redhat.com>
+
+commit bae3a8d3308ee69a7dbdf145911b18dfda8ade0d upstream.
+
+Legacy apic init uses bigsmp for smp systems with 8 and more CPUs. The
+bigsmp APIC implementation uses physical destination mode, but it
+nevertheless initializes LDR and DFR. The LDR even ends up incorrectly with
+multiple bit being set.
+
+This does not cause a functional problem because LDR and DFR are ignored
+when physical destination mode is active, but it triggered a problem on a
+32-bit KVM guest which jumps into a kdump kernel.
+
+The multiple bits set unearthed a bug in the KVM APIC implementation. The
+code which creates the logical destination map for VCPUs ignores the
+disabled state of the APIC and ends up overwriting an existing valid entry
+and as a result, APIC calibration hangs in the guest during kdump
+initialization.
+
+Remove the bogus LDR/DFR initialization.
+
+This is not intended to work around the KVM APIC bug. The LDR/DFR
+ininitalization is wrong on its own.
+
+The issue goes back into the pre git history. The fixes tag is the commit
+in the bitkeeper import which introduced bigsmp support in 2003.
+
+ git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
+
+Fixes: db7b9e9f26b8 ("[PATCH] Clustered APIC setup for >8 CPU systems")
+Suggested-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Bandan Das <bsd@redhat.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/20190826101513.5080-2-bsd@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/apic/bigsmp_32.c | 24 ++----------------------
+ 1 file changed, 2 insertions(+), 22 deletions(-)
+
+--- a/arch/x86/kernel/apic/bigsmp_32.c
++++ b/arch/x86/kernel/apic/bigsmp_32.c
+@@ -37,32 +37,12 @@ static int bigsmp_early_logical_apicid(i
+ return early_per_cpu(x86_cpu_to_apicid, cpu);
+ }
+
+-static inline unsigned long calculate_ldr(int cpu)
+-{
+- unsigned long val, id;
+-
+- val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
+- id = per_cpu(x86_bios_cpu_apicid, cpu);
+- val |= SET_APIC_LOGICAL_ID(id);
+-
+- return val;
+-}
+-
+ /*
+- * Set up the logical destination ID.
+- *
+- * Intel recommends to set DFR, LDR and TPR before enabling
+- * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
+- * document number 292116). So here it goes...
++ * bigsmp enables physical destination mode
++ * and doesn't use LDR and DFR
+ */
+ static void bigsmp_init_apic_ldr(void)
+ {
+- unsigned long val;
+- int cpu = smp_processor_id();
+-
+- apic_write(APIC_DFR, APIC_DFR_FLAT);
+- val = calculate_ldr(cpu);
+- apic_write(APIC_LDR, val);
+ }
+
+ static void bigsmp_setup_apic_routing(void)
diff --git a/x86-apic-handle-missing-global-clockevent-gracefully.patch b/x86-apic-handle-missing-global-clockevent-gracefully.patch
deleted file mode 100644
index 890f15c..0000000
--- a/x86-apic-handle-missing-global-clockevent-gracefully.patch
+++ /dev/null
@@ -1,154 +0,0 @@
-From f897e60a12f0b9146357780d317879bce2a877dc Mon Sep 17 00:00:00 2001
-From: Thomas Gleixner <tglx@linutronix.de>
-Date: Fri, 9 Aug 2019 14:54:07 +0200
-Subject: x86/apic: Handle missing global clockevent gracefully
-
-From: Thomas Gleixner <tglx@linutronix.de>
-
-commit f897e60a12f0b9146357780d317879bce2a877dc upstream.
-
-Some newer machines do not advertise legacy timers. The kernel can handle
-that situation if the TSC and the CPU frequency are enumerated by CPUID or
-MSRs and the CPU supports TSC deadline timer. If the CPU does not support
-TSC deadline timer the local APIC timer frequency has to be known as well.
-
-Some Ryzens machines do not advertize legacy timers, but there is no
-reliable way to determine the bus frequency which feeds the local APIC
-timer when the machine allows overclocking of that frequency.
-
-As there is no legacy timer the local APIC timer calibration crashes due to
-a NULL pointer dereference when accessing the not installed global clock
-event device.
-
-Switch the calibration loop to a non interrupt based one, which polls
-either TSC (if frequency is known) or jiffies. The latter requires a global
-clockevent. As the machines which do not have a global clockevent installed
-have a known TSC frequency this is a non issue. For older machines where
-TSC frequency is not known, there is no known case where the legacy timers
-do not exist as that would have been reported long ago.
-
-Reported-by: Daniel Drake <drake@endlessm.com>
-Reported-by: Jiri Slaby <jslaby@suse.cz>
-Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-Tested-by: Daniel Drake <drake@endlessm.com>
-Cc: stable@vger.kernel.org
-Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1908091443030.21433@nanos.tec.linutronix.de
-Link: http://bugzilla.opensuse.org/show_bug.cgi?id=1142926#c12
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- arch/x86/kernel/apic/apic.c | 68 ++++++++++++++++++++++++++++++++++----------
- 1 file changed, 53 insertions(+), 15 deletions(-)
-
---- a/arch/x86/kernel/apic/apic.c
-+++ b/arch/x86/kernel/apic/apic.c
-@@ -620,7 +620,7 @@ static __initdata unsigned long lapic_ca
- static __initdata unsigned long lapic_cal_j1, lapic_cal_j2;
-
- /*
-- * Temporary interrupt handler.
-+ * Temporary interrupt handler and polled calibration function.
- */
- static void __init lapic_cal_handler(struct clock_event_device *dev)
- {
-@@ -704,7 +704,8 @@ calibrate_by_pmtimer(long deltapm, long
- static int __init calibrate_APIC_clock(void)
- {
- struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
-- void (*real_handler)(struct clock_event_device *dev);
-+ u64 tsc_perj = 0, tsc_start = 0;
-+ unsigned long jif_start;
- unsigned long deltaj;
- long delta, deltatsc;
- int pm_referenced = 0;
-@@ -733,29 +734,65 @@ static int __init calibrate_APIC_clock(v
- apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
- "calibrating APIC timer ...\n");
-
-+ /*
-+ * There are platforms w/o global clockevent devices. Instead of
-+ * making the calibration conditional on that, use a polling based
-+ * approach everywhere.
-+ */
- local_irq_disable();
-
-- /* Replace the global interrupt handler */
-- real_handler = global_clock_event->event_handler;
-- global_clock_event->event_handler = lapic_cal_handler;
--
- /*
- * Setup the APIC counter to maximum. There is no way the lapic
- * can underflow in the 100ms detection time frame
- */
- __setup_APIC_LVTT(0xffffffff, 0, 0);
-
-- /* Let the interrupts run */
-+ /*
-+ * Methods to terminate the calibration loop:
-+ * 1) Global clockevent if available (jiffies)
-+ * 2) TSC if available and frequency is known
-+ */
-+ jif_start = READ_ONCE(jiffies);
-+
-+ if (tsc_khz) {
-+ tsc_start = rdtsc();
-+ tsc_perj = div_u64((u64)tsc_khz * 1000, HZ);
-+ }
-+
-+ /*
-+ * Enable interrupts so the tick can fire, if a global
-+ * clockevent device is available
-+ */
- local_irq_enable();
-
-- while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
-- cpu_relax();
-+ while (lapic_cal_loops <= LAPIC_CAL_LOOPS) {
-+ /* Wait for a tick to elapse */
-+ while (1) {
-+ if (tsc_khz) {
-+ u64 tsc_now = rdtsc();
-+ if ((tsc_now - tsc_start) >= tsc_perj) {
-+ tsc_start += tsc_perj;
-+ break;
-+ }
-+ } else {
-+ unsigned long jif_now = READ_ONCE(jiffies);
-+
-+ if (time_after(jif_now, jif_start)) {
-+ jif_start = jif_now;
-+ break;
-+ }
-+ }
-+ cpu_relax();
-+ }
-+
-+ /* Invoke the calibration routine */
-+ local_irq_disable();
-+ lapic_cal_handler(NULL);
-+ local_irq_enable();
-+ }
-
- local_irq_disable();
-
-- /* Restore the real event handler */
-- global_clock_event->event_handler = real_handler;
--
- /* Build delta t1-t2 as apic timer counts down */
- delta = lapic_cal_t1 - lapic_cal_t2;
- apic_printk(APIC_VERBOSE, "... lapic delta = %ld\n", delta);
-@@ -805,10 +842,11 @@ static int __init calibrate_APIC_clock(v
- levt->features &= ~CLOCK_EVT_FEAT_DUMMY;
-
- /*
-- * PM timer calibration failed or not turned on
-- * so lets try APIC timer based calibration
-+ * PM timer calibration failed or not turned on so lets try APIC
-+ * timer based calibration, if a global clockevent device is
-+ * available.
- */
-- if (!pm_referenced) {
-+ if (!pm_referenced && global_clock_event) {
- apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
-
- /*
diff --git a/x86-apic-include-the-ldr-when-clearing-out-apic-registers.patch b/x86-apic-include-the-ldr-when-clearing-out-apic-registers.patch
new file mode 100644
index 0000000..ad40135
--- /dev/null
+++ b/x86-apic-include-the-ldr-when-clearing-out-apic-registers.patch
@@ -0,0 +1,49 @@
+From 558682b5291937a70748d36fd9ba757fb25b99ae Mon Sep 17 00:00:00 2001
+From: Bandan Das <bsd@redhat.com>
+Date: Mon, 26 Aug 2019 06:15:13 -0400
+Subject: x86/apic: Include the LDR when clearing out APIC registers
+
+From: Bandan Das <bsd@redhat.com>
+
+commit 558682b5291937a70748d36fd9ba757fb25b99ae upstream.
+
+Although APIC initialization will typically clear out the LDR before
+setting it, the APIC cleanup code should reset the LDR.
+
+This was discovered with a 32-bit KVM guest jumping into a kdump
+kernel. The stale bits in the LDR triggered a bug in the KVM APIC
+implementation which caused the destination mapping for VCPUs to be
+corrupted.
+
+Note that this isn't intended to paper over the KVM APIC bug. The kernel
+has to clear the LDR when resetting the APIC registers except when X2APIC
+is enabled.
+
+This lacks a Fixes tag because missing to clear LDR goes way back into pre
+git history.
+
+[ tglx: Made x2apic_enabled a function call as required ]
+
+Signed-off-by: Bandan Das <bsd@redhat.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/20190826101513.5080-3-bsd@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/apic/apic.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/x86/kernel/apic/apic.c
++++ b/arch/x86/kernel/apic/apic.c
+@@ -1019,6 +1019,10 @@ void clear_local_APIC(void)
+ apic_write(APIC_LVT0, v | APIC_LVT_MASKED);
+ v = apic_read(APIC_LVT1);
+ apic_write(APIC_LVT1, v | APIC_LVT_MASKED);
++ if (!x2apic_enabled()) {
++ v = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
++ apic_write(APIC_LDR, v);
++ }
+ if (maxlvt >= 4) {
+ v = apic_read(APIC_LVTPC);
+ apic_write(APIC_LVTPC, v | APIC_LVT_MASKED);