diff options
author | Ben Hutchings <ben@decadent.org.uk> | 2016-02-27 14:29:12 +0000 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2016-02-27 14:29:50 +0000 |
commit | 84f094a447a3ffc3d5a4752d53527c397692381a (patch) | |
tree | 7e93316d40fc66570397635a7b3620588364914c /releases | |
parent | d66b5deb1f692022ecb93a9c0ffe071ed10a3fe6 (diff) | |
download | linux-stable-queue-84f094a447a3ffc3d5a4752d53527c397692381a.tar.gz |
Release 3.2.78
Diffstat (limited to 'releases')
68 files changed, 5017 insertions, 0 deletions
diff --git a/releases/3.2.78/af_unix-fix-struct-pid-memory-leak.patch b/releases/3.2.78/af_unix-fix-struct-pid-memory-leak.patch new file mode 100644 index 00000000..b5eeca55 --- /dev/null +++ b/releases/3.2.78/af_unix-fix-struct-pid-memory-leak.patch @@ -0,0 +1,32 @@ +From: Eric Dumazet <edumazet@google.com> +Date: Sun, 24 Jan 2016 13:53:50 -0800 +Subject: af_unix: fix struct pid memory leak + +commit fa0dc04df259ba2df3ce1920e9690c7842f8fa4b upstream. + +Dmitry reported a struct pid leak detected by a syzkaller program. + +Bug happens in unix_stream_recvmsg() when we break the loop when a +signal is pending, without properly releasing scm. + +Fixes: b3ca9b02b007 ("net: fix multithreaded signal handling in unix recv routines") +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Eric Dumazet <edumazet@google.com> +Cc: Rainer Weikusat <rweikusat@mobileactivedefense.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +[bwh: Backported to 3.2: cookie is *sicob->scm, not scm] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + net/unix/af_unix.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -2100,6 +2100,7 @@ static int unix_stream_recvmsg(struct ki + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); ++ scm_destroy(siocb->scm); + goto out; + } + diff --git a/releases/3.2.78/ahci-intel-dnv-device-ids-sata.patch b/releases/3.2.78/ahci-intel-dnv-device-ids-sata.patch new file mode 100644 index 00000000..35a94f90 --- /dev/null +++ b/releases/3.2.78/ahci-intel-dnv-device-ids-sata.patch @@ -0,0 +1,44 @@ +From: Alexandra Yates <alexandra.yates@linux.intel.com> +Date: Fri, 5 Feb 2016 15:27:49 -0800 +Subject: ahci: Intel DNV device IDs SATA + +commit 342decff2b846b46fa61eb5ee40986fab79a9a32 upstream. + +Adding Intel codename DNV platform device IDs for SATA. + +Signed-off-by: Alexandra Yates <alexandra.yates@linux.intel.com> +Signed-off-by: Tejun Heo <tj@kernel.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/ata/ahci.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -274,6 +274,26 @@ static const struct pci_device_id ahci_p + { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */ + { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */ + { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */ + { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */ + { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */ diff --git a/releases/3.2.78/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch b/releases/3.2.78/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch new file mode 100644 index 00000000..570da831 --- /dev/null +++ b/releases/3.2.78/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch @@ -0,0 +1,35 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Thu, 28 Jan 2016 07:54:16 +0100 +Subject: ALSA: dummy: Disable switching timer backend via sysfs + +commit 7ee96216c31aabe1eb42fb91ff50dae9fcd014b2 upstream. + +ALSA dummy driver can switch the timer backend between system timer +and hrtimer via its hrtimer module option. This can be also switched +dynamically via sysfs, but it may lead to a memory corruption when +switching is done while a PCM stream is running; the stream instance +for the newly switched timer method tries to access the memory that +was allocated by another timer method although the sizes differ. + +As the simplest fix, this patch just disables the switch via sysfs by +dropping the writable bit. + +BugLink: http://lkml.kernel.org/r/CACT4Y+ZGEeEBntHW5WHn2GoeE0G_kRrCmUh6=dWyy-wfzvuJLg@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/drivers/dummy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/drivers/dummy.c ++++ b/sound/drivers/dummy.c +@@ -87,7 +87,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM su + module_param(fake_buffer, bool, 0444); + MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations."); + #ifdef CONFIG_HIGH_RES_TIMERS +-module_param(hrtimer, bool, 0644); ++module_param(hrtimer, bool, 0444); + MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source."); + #endif + diff --git a/releases/3.2.78/alsa-dummy-implement-timer-backend-switching-more-safely.patch b/releases/3.2.78/alsa-dummy-implement-timer-backend-switching-more-safely.patch new file mode 100644 index 00000000..bb162c5d --- /dev/null +++ b/releases/3.2.78/alsa-dummy-implement-timer-backend-switching-more-safely.patch @@ -0,0 +1,171 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Tue, 2 Feb 2016 15:27:36 +0100 +Subject: ALSA: dummy: Implement timer backend switching more safely + +commit ddce57a6f0a2d8d1bfacfa77f06043bc760403c2 upstream. + +Currently the selected timer backend is referred at any moment from +the running PCM callbacks. When the backend is switched, it's +possible to lead to inconsistency from the running backend. This was +pointed by syzkaller fuzzer, and the commit [7ee96216c31a: ALSA: +dummy: Disable switching timer backend via sysfs] disabled the dynamic +switching for avoiding the crash. + +This patch improves the handling of timer backend switching. It keeps +the reference to the selected backend during the whole operation of an +opened stream so that it won't be changed by other streams. + +Together with this change, the hrtimer parameter is reenabled as +writable now. + +NOTE: this patch also turned out to fix the still remaining race. +Namely, ops was still replaced dynamically at dummy_pcm_open: + + static int dummy_pcm_open(struct snd_pcm_substream *substream) + { + .... + dummy->timer_ops = &dummy_systimer_ops; + if (hrtimer) + dummy->timer_ops = &dummy_hrtimer_ops; + +Since dummy->timer_ops is common among all streams, and when the +replacement happens during accesses of other streams, it may lead to a +crash. This was actually triggered by syzkaller fuzzer and KASAN. + +This patch rewrites the code not to use the ops shared by all streams +any longer, too. + +BugLink: http://lkml.kernel.org/r/CACT4Y+aZ+xisrpuM6cOXbL21DuM0yVxPYXf4cD4Md9uw0C3dBQ@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +[bwh: Backported to 3.2: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/drivers/dummy.c | 37 +++++++++++++++++++------------------ + 1 file changed, 19 insertions(+), 18 deletions(-) + +--- a/sound/drivers/dummy.c ++++ b/sound/drivers/dummy.c +@@ -87,7 +87,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM su + module_param(fake_buffer, bool, 0444); + MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations."); + #ifdef CONFIG_HIGH_RES_TIMERS +-module_param(hrtimer, bool, 0444); ++module_param(hrtimer, bool, 0644); + MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source."); + #endif + +@@ -109,6 +109,9 @@ struct dummy_timer_ops { + snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); + }; + ++#define get_dummy_ops(substream) \ ++ (*(const struct dummy_timer_ops **)(substream)->runtime->private_data) ++ + struct dummy_model { + const char *name; + int (*playback_constraints)(struct snd_pcm_runtime *runtime); +@@ -134,7 +137,6 @@ struct snd_dummy { + spinlock_t mixer_lock; + int mixer_volume[MIXER_ADDR_LAST+1][2]; + int capture_source[MIXER_ADDR_LAST+1][2]; +- const struct dummy_timer_ops *timer_ops; + }; + + /* +@@ -228,6 +230,8 @@ struct dummy_model *dummy_models[] = { + */ + + struct dummy_systimer_pcm { ++ /* ops must be the first item */ ++ const struct dummy_timer_ops *timer_ops; + spinlock_t lock; + struct timer_list timer; + unsigned long base_time; +@@ -365,6 +369,8 @@ static struct dummy_timer_ops dummy_syst + */ + + struct dummy_hrtimer_pcm { ++ /* ops must be the first item */ ++ const struct dummy_timer_ops *timer_ops; + ktime_t base_time; + ktime_t period_time; + atomic_t running; +@@ -491,31 +497,25 @@ static struct dummy_timer_ops dummy_hrti + + static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) + { +- struct snd_dummy *dummy = snd_pcm_substream_chip(substream); +- + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: +- return dummy->timer_ops->start(substream); ++ return get_dummy_ops(substream)->start(substream); + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: +- return dummy->timer_ops->stop(substream); ++ return get_dummy_ops(substream)->stop(substream); + } + return -EINVAL; + } + + static int dummy_pcm_prepare(struct snd_pcm_substream *substream) + { +- struct snd_dummy *dummy = snd_pcm_substream_chip(substream); +- +- return dummy->timer_ops->prepare(substream); ++ return get_dummy_ops(substream)->prepare(substream); + } + + static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream) + { +- struct snd_dummy *dummy = snd_pcm_substream_chip(substream); +- +- return dummy->timer_ops->pointer(substream); ++ return get_dummy_ops(substream)->pointer(substream); + } + + static struct snd_pcm_hardware dummy_pcm_hardware = { +@@ -561,17 +561,19 @@ static int dummy_pcm_open(struct snd_pcm + struct snd_dummy *dummy = snd_pcm_substream_chip(substream); + struct dummy_model *model = dummy->model; + struct snd_pcm_runtime *runtime = substream->runtime; ++ const struct dummy_timer_ops *ops; + int err; + +- dummy->timer_ops = &dummy_systimer_ops; ++ ops = &dummy_systimer_ops; + #ifdef CONFIG_HIGH_RES_TIMERS + if (hrtimer) +- dummy->timer_ops = &dummy_hrtimer_ops; ++ ops = &dummy_hrtimer_ops; + #endif + +- err = dummy->timer_ops->create(substream); ++ err = ops->create(substream); + if (err < 0) + return err; ++ get_dummy_ops(substream) = ops; + + runtime->hw = dummy->pcm_hw; + if (substream->pcm->device & 1) { +@@ -593,7 +595,7 @@ static int dummy_pcm_open(struct snd_pcm + err = model->capture_constraints(substream->runtime); + } + if (err < 0) { +- dummy->timer_ops->free(substream); ++ get_dummy_ops(substream)->free(substream); + return err; + } + return 0; +@@ -601,8 +603,7 @@ static int dummy_pcm_open(struct snd_pcm + + static int dummy_pcm_close(struct snd_pcm_substream *substream) + { +- struct snd_dummy *dummy = snd_pcm_substream_chip(substream); +- dummy->timer_ops->free(substream); ++ get_dummy_ops(substream)->free(substream); + return 0; + } + diff --git a/releases/3.2.78/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch b/releases/3.2.78/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch new file mode 100644 index 00000000..4e850e28 --- /dev/null +++ b/releases/3.2.78/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch @@ -0,0 +1,96 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Sun, 31 Jan 2016 10:32:37 +0100 +Subject: ALSA: pcm: Fix potential deadlock in OSS emulation + +commit b248371628aad599a48540962f6b85a21a8a0c3f upstream. + +There are potential deadlocks in PCM OSS emulation code while +accessing read/write and mmap concurrently. This comes from the +infamous mmap_sem usage in copy_from/to_user(). Namely, + + snd_pcm_oss_write() -> + &runtime->oss.params_lock -> + copy_to_user() -> + &mm->mmap_sem + mmap() -> + &mm->mmap_sem -> + snd_pcm_oss_mmap() -> + &runtime->oss.params_lock + +Since we can't avoid taking params_lock from mmap code path, use +trylock variant and aborts with -EAGAIN as a workaround of this AB/BA +deadlock. + +BugLink: http://lkml.kernel.org/r/CACT4Y+bVrBKDG0G2_AcUgUQa+X91VKTeS4v+wN7BSHwHtqn3kQ@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/oss/pcm_oss.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +--- a/sound/core/oss/pcm_oss.c ++++ b/sound/core/oss/pcm_oss.c +@@ -834,7 +834,8 @@ static int choose_rate(struct snd_pcm_su + return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); + } + +-static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) ++static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, ++ bool trylock) + { + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_hw_params *params, *sparams; +@@ -848,7 +849,10 @@ static int snd_pcm_oss_change_params(str + struct snd_mask sformat_mask; + struct snd_mask mask; + +- if (mutex_lock_interruptible(&runtime->oss.params_lock)) ++ if (trylock) { ++ if (!(mutex_trylock(&runtime->oss.params_lock))) ++ return -EAGAIN; ++ } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -EINTR; + sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL); + params = kmalloc(sizeof(*params), GFP_KERNEL); +@@ -1091,7 +1095,7 @@ static int snd_pcm_oss_get_active_substr + if (asubstream == NULL) + asubstream = substream; + if (substream->runtime->oss.params) { +- err = snd_pcm_oss_change_params(substream); ++ err = snd_pcm_oss_change_params(substream, false); + if (err < 0) + return err; + } +@@ -1130,7 +1134,7 @@ static int snd_pcm_oss_make_ready(struct + return 0; + runtime = substream->runtime; + if (runtime->oss.params) { +- err = snd_pcm_oss_change_params(substream); ++ err = snd_pcm_oss_change_params(substream, false); + if (err < 0) + return err; + } +@@ -2168,7 +2172,7 @@ static int snd_pcm_oss_get_space(struct + runtime = substream->runtime; + + if (runtime->oss.params && +- (err = snd_pcm_oss_change_params(substream)) < 0) ++ (err = snd_pcm_oss_change_params(substream, false)) < 0) + return err; + + info.fragsize = runtime->oss.period_bytes; +@@ -2804,7 +2808,12 @@ static int snd_pcm_oss_mmap(struct file + return -EIO; + + if (runtime->oss.params) { +- if ((err = snd_pcm_oss_change_params(substream)) < 0) ++ /* use mutex_trylock() for params_lock for avoiding a deadlock ++ * between mmap_sem and params_lock taken by ++ * copy_from/to_user() in snd_pcm_oss_write/read() ++ */ ++ err = snd_pcm_oss_change_params(substream, true); ++ if (err < 0) + return err; + } + #ifdef CONFIG_SND_PCM_OSS_PLUGINS diff --git a/releases/3.2.78/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch b/releases/3.2.78/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch new file mode 100644 index 00000000..7cb47198 --- /dev/null +++ b/releases/3.2.78/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch @@ -0,0 +1,117 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Wed, 3 Feb 2016 14:41:22 +0100 +Subject: ALSA: rawmidi: Fix race at copying & updating the position + +commit 81f577542af15640cbcb6ef68baa4caa610cbbfc upstream. + +The rawmidi read and write functions manage runtime stream status +such as runtime->appl_ptr and runtime->avail. These point where to +copy the new data and how many bytes have been copied (or to be +read). The problem is that rawmidi read/write call copy_from_user() +or copy_to_user(), and the runtime spinlock is temporarily unlocked +and relocked while copying user-space. Since the current code +advances and updates the runtime status after the spin unlock/relock, +the copy and the update may be asynchronous, and eventually +runtime->avail might go to a negative value when many concurrent +accesses are done. This may lead to memory corruption in the end. + +For fixing this race, in this patch, the status update code is +performed in the same lock before the temporary unlock. Also, the +spinlock is now taken more widely in snd_rawmidi_kernel_read1() for +protecting more properly during the whole operation. + +BugLink: http://lkml.kernel.org/r/CACT4Y+b-dCmNf1GpgPKfDO0ih+uZCL2JV4__j-r1kdhPLSgQCQ@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Tested-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/rawmidi.c | 34 ++++++++++++++++++++++------------ + 1 file changed, 22 insertions(+), 12 deletions(-) + +--- a/sound/core/rawmidi.c ++++ b/sound/core/rawmidi.c +@@ -934,31 +934,36 @@ static long snd_rawmidi_kernel_read1(str + unsigned long flags; + long result = 0, count1; + struct snd_rawmidi_runtime *runtime = substream->runtime; ++ unsigned long appl_ptr; + ++ spin_lock_irqsave(&runtime->lock, flags); + while (count > 0 && runtime->avail) { + count1 = runtime->buffer_size - runtime->appl_ptr; + if (count1 > count) + count1 = count; +- spin_lock_irqsave(&runtime->lock, flags); + if (count1 > (int)runtime->avail) + count1 = runtime->avail; ++ ++ /* update runtime->appl_ptr before unlocking for userbuf */ ++ appl_ptr = runtime->appl_ptr; ++ runtime->appl_ptr += count1; ++ runtime->appl_ptr %= runtime->buffer_size; ++ runtime->avail -= count1; ++ + if (kernelbuf) +- memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1); ++ memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); + if (userbuf) { + spin_unlock_irqrestore(&runtime->lock, flags); + if (copy_to_user(userbuf + result, +- runtime->buffer + runtime->appl_ptr, count1)) { ++ runtime->buffer + appl_ptr, count1)) { + return result > 0 ? result : -EFAULT; + } + spin_lock_irqsave(&runtime->lock, flags); + } +- runtime->appl_ptr += count1; +- runtime->appl_ptr %= runtime->buffer_size; +- runtime->avail -= count1; +- spin_unlock_irqrestore(&runtime->lock, flags); + result += count1; + count -= count1; + } ++ spin_unlock_irqrestore(&runtime->lock, flags); + return result; + } + +@@ -1207,6 +1212,7 @@ static long snd_rawmidi_kernel_write1(st + unsigned long flags; + long count1, result; + struct snd_rawmidi_runtime *runtime = substream->runtime; ++ unsigned long appl_ptr; + + if (!kernelbuf && !userbuf) + return -EINVAL; +@@ -1227,12 +1233,19 @@ static long snd_rawmidi_kernel_write1(st + count1 = count; + if (count1 > (long)runtime->avail) + count1 = runtime->avail; ++ ++ /* update runtime->appl_ptr before unlocking for userbuf */ ++ appl_ptr = runtime->appl_ptr; ++ runtime->appl_ptr += count1; ++ runtime->appl_ptr %= runtime->buffer_size; ++ runtime->avail -= count1; ++ + if (kernelbuf) +- memcpy(runtime->buffer + runtime->appl_ptr, ++ memcpy(runtime->buffer + appl_ptr, + kernelbuf + result, count1); + else if (userbuf) { + spin_unlock_irqrestore(&runtime->lock, flags); +- if (copy_from_user(runtime->buffer + runtime->appl_ptr, ++ if (copy_from_user(runtime->buffer + appl_ptr, + userbuf + result, count1)) { + spin_lock_irqsave(&runtime->lock, flags); + result = result > 0 ? result : -EFAULT; +@@ -1240,9 +1253,6 @@ static long snd_rawmidi_kernel_write1(st + } + spin_lock_irqsave(&runtime->lock, flags); + } +- runtime->appl_ptr += count1; +- runtime->appl_ptr %= runtime->buffer_size; +- runtime->avail -= count1; + result += count1; + count -= count1; + } diff --git a/releases/3.2.78/alsa-rawmidi-make-snd_rawmidi_transmit-race-free.patch b/releases/3.2.78/alsa-rawmidi-make-snd_rawmidi_transmit-race-free.patch new file mode 100644 index 00000000..d2711171 --- /dev/null +++ b/releases/3.2.78/alsa-rawmidi-make-snd_rawmidi_transmit-race-free.patch @@ -0,0 +1,300 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Sun, 31 Jan 2016 11:57:41 +0100 +Subject: ALSA: rawmidi: Make snd_rawmidi_transmit() race-free + +commit 06ab30034ed9c200a570ab13c017bde248ddb2a6 upstream. + +A kernel WARNING in snd_rawmidi_transmit_ack() is triggered by +syzkaller fuzzer: + WARNING: CPU: 1 PID: 20739 at sound/core/rawmidi.c:1136 +Call Trace: + [< inline >] __dump_stack lib/dump_stack.c:15 + [<ffffffff82999e2d>] dump_stack+0x6f/0xa2 lib/dump_stack.c:50 + [<ffffffff81352089>] warn_slowpath_common+0xd9/0x140 kernel/panic.c:482 + [<ffffffff813522b9>] warn_slowpath_null+0x29/0x30 kernel/panic.c:515 + [<ffffffff84f80bd5>] snd_rawmidi_transmit_ack+0x275/0x400 sound/core/rawmidi.c:1136 + [<ffffffff84fdb3c1>] snd_virmidi_output_trigger+0x4b1/0x5a0 sound/core/seq/seq_virmidi.c:163 + [< inline >] snd_rawmidi_output_trigger sound/core/rawmidi.c:150 + [<ffffffff84f87ed9>] snd_rawmidi_kernel_write1+0x549/0x780 sound/core/rawmidi.c:1223 + [<ffffffff84f89fd3>] snd_rawmidi_write+0x543/0xb30 sound/core/rawmidi.c:1273 + [<ffffffff817b0323>] __vfs_write+0x113/0x480 fs/read_write.c:528 + [<ffffffff817b1db7>] vfs_write+0x167/0x4a0 fs/read_write.c:577 + [< inline >] SYSC_write fs/read_write.c:624 + [<ffffffff817b50a1>] SyS_write+0x111/0x220 fs/read_write.c:616 + [<ffffffff86336c36>] entry_SYSCALL_64_fastpath+0x16/0x7a arch/x86/entry/entry_64.S:185 + +Also a similar warning is found but in another path: +Call Trace: + [< inline >] __dump_stack lib/dump_stack.c:15 + [<ffffffff82be2c0d>] dump_stack+0x6f/0xa2 lib/dump_stack.c:50 + [<ffffffff81355139>] warn_slowpath_common+0xd9/0x140 kernel/panic.c:482 + [<ffffffff81355369>] warn_slowpath_null+0x29/0x30 kernel/panic.c:515 + [<ffffffff8527e69a>] rawmidi_transmit_ack+0x24a/0x3b0 sound/core/rawmidi.c:1133 + [<ffffffff8527e851>] snd_rawmidi_transmit_ack+0x51/0x80 sound/core/rawmidi.c:1163 + [<ffffffff852d9046>] snd_virmidi_output_trigger+0x2b6/0x570 sound/core/seq/seq_virmidi.c:185 + [< inline >] snd_rawmidi_output_trigger sound/core/rawmidi.c:150 + [<ffffffff85285a0b>] snd_rawmidi_kernel_write1+0x4bb/0x760 sound/core/rawmidi.c:1252 + [<ffffffff85287b73>] snd_rawmidi_write+0x543/0xb30 sound/core/rawmidi.c:1302 + [<ffffffff817ba5f3>] __vfs_write+0x113/0x480 fs/read_write.c:528 + [<ffffffff817bc087>] vfs_write+0x167/0x4a0 fs/read_write.c:577 + [< inline >] SYSC_write fs/read_write.c:624 + [<ffffffff817bf371>] SyS_write+0x111/0x220 fs/read_write.c:616 + [<ffffffff86660276>] entry_SYSCALL_64_fastpath+0x16/0x7a arch/x86/entry/entry_64.S:185 + +In the former case, the reason is that virmidi has an open code +calling snd_rawmidi_transmit_ack() with the value calculated outside +the spinlock. We may use snd_rawmidi_transmit() in a loop just for +consuming the input data, but even there, there is a race between +snd_rawmidi_transmit_peek() and snd_rawmidi_tranmit_ack(). + +Similarly in the latter case, it calls snd_rawmidi_transmit_peek() and +snd_rawmidi_tranmit_ack() separately without protection, so they are +racy as well. + +The patch tries to address these issues by the following ways: +- Introduce the unlocked versions of snd_rawmidi_transmit_peek() and + snd_rawmidi_transmit_ack() to be called inside the explicit lock. +- Rewrite snd_rawmidi_transmit() to be race-free (the former case). +- Make the split calls (the latter case) protected in the rawmidi spin + lock. + +BugLink: http://lkml.kernel.org/r/CACT4Y+YPq1+cYLkadwjWa5XjzF1_Vki1eHnVn-Lm0hzhSpu5PA@mail.gmail.com +BugLink: http://lkml.kernel.org/r/CACT4Y+acG4iyphdOZx47Nyq_VHGbpJQK-6xNpiqUjaZYqsXOGw@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Tested-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +[bwh: Backported to 3.2: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + include/sound/rawmidi.h | 4 ++ + sound/core/rawmidi.c | 98 ++++++++++++++++++++++++++++++++------------ + sound/core/seq/seq_virmidi.c | 17 +++++--- + 3 files changed, 88 insertions(+), 31 deletions(-) + +--- a/include/sound/rawmidi.h ++++ b/include/sound/rawmidi.h +@@ -167,6 +167,10 @@ int snd_rawmidi_transmit_peek(struct snd + int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count); + int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, + unsigned char *buffer, int count); ++int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, ++ unsigned char *buffer, int count); ++int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, ++ int count); + + /* main midi functions */ + +--- a/sound/core/rawmidi.c ++++ b/sound/core/rawmidi.c +@@ -1044,23 +1044,16 @@ int snd_rawmidi_transmit_empty(struct sn + } + + /** +- * snd_rawmidi_transmit_peek - copy data from the internal buffer ++ * __snd_rawmidi_transmit_peek - copy data from the internal buffer + * @substream: the rawmidi substream + * @buffer: the buffer pointer + * @count: data size to transfer + * +- * Copies data from the internal output buffer to the given buffer. +- * +- * Call this in the interrupt handler when the midi output is ready, +- * and call snd_rawmidi_transmit_ack() after the transmission is +- * finished. +- * +- * Returns the size of copied data, or a negative error code on failure. ++ * This is a variant of snd_rawmidi_transmit_peek() without spinlock. + */ +-int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, ++int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, + unsigned char *buffer, int count) + { +- unsigned long flags; + int result, count1; + struct snd_rawmidi_runtime *runtime = substream->runtime; + +@@ -1069,7 +1062,6 @@ int snd_rawmidi_transmit_peek(struct snd + return -EINVAL; + } + result = 0; +- spin_lock_irqsave(&runtime->lock, flags); + if (runtime->avail >= runtime->buffer_size) { + /* warning: lowlevel layer MUST trigger down the hardware */ + goto __skip; +@@ -1094,31 +1086,52 @@ int snd_rawmidi_transmit_peek(struct snd + } + } + __skip: +- spin_unlock_irqrestore(&runtime->lock, flags); + return result; + } ++EXPORT_SYMBOL(__snd_rawmidi_transmit_peek); + + /** +- * snd_rawmidi_transmit_ack - acknowledge the transmission ++ * snd_rawmidi_transmit_peek - copy data from the internal buffer + * @substream: the rawmidi substream +- * @count: the tranferred count ++ * @buffer: the buffer pointer ++ * @count: data size to transfer + * +- * Advances the hardware pointer for the internal output buffer with +- * the given size and updates the condition. +- * Call after the transmission is finished. ++ * Copies data from the internal output buffer to the given buffer. + * +- * Returns the advanced size if successful, or a negative error code on failure. ++ * Call this in the interrupt handler when the midi output is ready, ++ * and call snd_rawmidi_transmit_ack() after the transmission is ++ * finished. ++ * ++ * Return: The size of copied data, or a negative error code on failure. + */ +-int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) ++int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, ++ unsigned char *buffer, int count) + { ++ struct snd_rawmidi_runtime *runtime = substream->runtime; ++ int result; + unsigned long flags; ++ ++ spin_lock_irqsave(&runtime->lock, flags); ++ result = __snd_rawmidi_transmit_peek(substream, buffer, count); ++ spin_unlock_irqrestore(&runtime->lock, flags); ++ return result; ++} ++ ++/** ++ * __snd_rawmidi_transmit_ack - acknowledge the transmission ++ * @substream: the rawmidi substream ++ * @count: the tranferred count ++ * ++ * This is a variant of __snd_rawmidi_transmit_ack() without spinlock. ++ */ ++int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) ++{ + struct snd_rawmidi_runtime *runtime = substream->runtime; + + if (runtime->buffer == NULL) { + snd_printd("snd_rawmidi_transmit_ack: output is not active!!!\n"); + return -EINVAL; + } +- spin_lock_irqsave(&runtime->lock, flags); + snd_BUG_ON(runtime->avail + count > runtime->buffer_size); + runtime->hw_ptr += count; + runtime->hw_ptr %= runtime->buffer_size; +@@ -1128,9 +1141,32 @@ int snd_rawmidi_transmit_ack(struct snd_ + if (runtime->drain || snd_rawmidi_ready(substream)) + wake_up(&runtime->sleep); + } +- spin_unlock_irqrestore(&runtime->lock, flags); + return count; + } ++EXPORT_SYMBOL(__snd_rawmidi_transmit_ack); ++ ++/** ++ * snd_rawmidi_transmit_ack - acknowledge the transmission ++ * @substream: the rawmidi substream ++ * @count: the transferred count ++ * ++ * Advances the hardware pointer for the internal output buffer with ++ * the given size and updates the condition. ++ * Call after the transmission is finished. ++ * ++ * Return: The advanced size if successful, or a negative error code on failure. ++ */ ++int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) ++{ ++ struct snd_rawmidi_runtime *runtime = substream->runtime; ++ int result; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&runtime->lock, flags); ++ result = __snd_rawmidi_transmit_ack(substream, count); ++ spin_unlock_irqrestore(&runtime->lock, flags); ++ return result; ++} + + /** + * snd_rawmidi_transmit - copy from the buffer to the device +@@ -1145,12 +1181,22 @@ int snd_rawmidi_transmit_ack(struct snd_ + int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, + unsigned char *buffer, int count) + { ++ struct snd_rawmidi_runtime *runtime = substream->runtime; ++ int result; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&runtime->lock, flags); + if (!substream->opened) +- return -EBADFD; +- count = snd_rawmidi_transmit_peek(substream, buffer, count); +- if (count < 0) +- return count; +- return snd_rawmidi_transmit_ack(substream, count); ++ result = -EBADFD; ++ else { ++ count = __snd_rawmidi_transmit_peek(substream, buffer, count); ++ if (count <= 0) ++ result = count; ++ else ++ result = __snd_rawmidi_transmit_ack(substream, count); ++ } ++ spin_unlock_irqrestore(&runtime->lock, flags); ++ return result; + } + + static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, +--- a/sound/core/seq/seq_virmidi.c ++++ b/sound/core/seq/seq_virmidi.c +@@ -155,21 +155,26 @@ static void snd_virmidi_output_trigger(s + struct snd_virmidi *vmidi = substream->runtime->private_data; + int count, res; + unsigned char buf[32], *pbuf; ++ unsigned long flags; + + if (up) { + vmidi->trigger = 1; + if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && + !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { +- snd_rawmidi_transmit_ack(substream, substream->runtime->buffer_size - substream->runtime->avail); +- return; /* ignored */ ++ while (snd_rawmidi_transmit(substream, buf, ++ sizeof(buf)) > 0) { ++ /* ignored */ ++ } ++ return; + } + if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { + if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) + return; + vmidi->event.type = SNDRV_SEQ_EVENT_NONE; + } ++ spin_lock_irqsave(&substream->runtime->lock, flags); + while (1) { +- count = snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); ++ count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); + if (count <= 0) + break; + pbuf = buf; +@@ -179,16 +184,18 @@ static void snd_virmidi_output_trigger(s + snd_midi_event_reset_encode(vmidi->parser); + continue; + } +- snd_rawmidi_transmit_ack(substream, res); ++ __snd_rawmidi_transmit_ack(substream, res); + pbuf += res; + count -= res; + if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { + if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) +- return; ++ goto out; + vmidi->event.type = SNDRV_SEQ_EVENT_NONE; + } + } + } ++ out: ++ spin_unlock_irqrestore(&substream->runtime->lock, flags); + } else { + vmidi->trigger = 0; + } diff --git a/releases/3.2.78/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch b/releases/3.2.78/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch new file mode 100644 index 00000000..47b13c4b --- /dev/null +++ b/releases/3.2.78/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch @@ -0,0 +1,29 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Mon, 1 Feb 2016 12:04:55 +0100 +Subject: ALSA: rawmidi: Remove kernel WARNING for NULL user-space buffer check + +commit cc85f7a634cfaf9f0713c6aa06d08817424db37a upstream. + +NULL user-space buffer can be passed even in a normal path, thus it's +not good to spew a kernel warning with stack trace at each time. +Just drop snd_BUG_ON() macro usage there. + +BugLink: http://lkml.kernel.org/r/CACT4Y+YfVJ3L+q0i-4vyQVyyPD7V=OMX0PWPi29x9Bo3QaBLdw@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/rawmidi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/core/rawmidi.c ++++ b/sound/core/rawmidi.c +@@ -1162,7 +1162,7 @@ static long snd_rawmidi_kernel_write1(st + long count1, result; + struct snd_rawmidi_runtime *runtime = substream->runtime; + +- if (snd_BUG_ON(!kernelbuf && !userbuf)) ++ if (!kernelbuf && !userbuf) + return -EINVAL; + if (snd_BUG_ON(!runtime->buffer)) + return -EINVAL; diff --git a/releases/3.2.78/alsa-seq-degrade-the-error-message-for-too-many-opens.patch b/releases/3.2.78/alsa-seq-degrade-the-error-message-for-too-many-opens.patch new file mode 100644 index 00000000..b7a4e715 --- /dev/null +++ b/releases/3.2.78/alsa-seq-degrade-the-error-message-for-too-many-opens.patch @@ -0,0 +1,31 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Mon, 25 Jan 2016 11:24:56 +0100 +Subject: ALSA: seq: Degrade the error message for too many opens + +commit da10816e3d923565b470fec78a674baba794ed33 upstream. + +ALSA OSS sequencer spews a kernel error message ("ALSA: seq_oss: too +many applications") when user-space tries to open more than the +limit. This means that it can easily fill the log buffer. + +Since it's merely a normal error, it's safe to suppress it via +pr_debug() instead. + +Signed-off-by: Takashi Iwai <tiwai@suse.de> +[bwh: Backported to 3.2: this was still using snd_printk()] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/seq/oss/seq_oss_init.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/core/seq/oss/seq_oss_init.c ++++ b/sound/core/seq/oss/seq_oss_init.c +@@ -196,7 +196,7 @@ snd_seq_oss_open(struct file *file, int + + dp->index = i; + if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { +- snd_printk(KERN_ERR "too many applications\n"); ++ pr_debug("ALSA: seq_oss: too many applications\n"); + rc = -ENOMEM; + goto _error; + } diff --git a/releases/3.2.78/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch b/releases/3.2.78/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch new file mode 100644 index 00000000..44bb49f4 --- /dev/null +++ b/releases/3.2.78/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch @@ -0,0 +1,31 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Mon, 25 Jan 2016 11:01:47 +0100 +Subject: ALSA: seq: Fix incorrect sanity check at snd_seq_oss_synth_cleanup() + +commit 599151336638d57b98d92338aa59c048e3a3e97d upstream. + +ALSA sequencer OSS emulation code has a sanity check for currently +opened devices, but there is a thinko there, eventually it spews +warnings and skips the operation wrongly like: + WARNING: CPU: 1 PID: 7573 at sound/core/seq/oss/seq_oss_synth.c:311 + +Fix this off-by-one error. + +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/seq/oss/seq_oss_synth.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/core/seq/oss/seq_oss_synth.c ++++ b/sound/core/seq/oss/seq_oss_synth.c +@@ -310,7 +310,7 @@ snd_seq_oss_synth_cleanup(struct seq_oss + struct seq_oss_synth *rec; + struct seq_oss_synthinfo *info; + +- if (snd_BUG_ON(dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) ++ if (snd_BUG_ON(dp->max_synthdev > SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) + return; + for (i = 0; i < dp->max_synthdev; i++) { + info = &dp->synths[i]; diff --git a/releases/3.2.78/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch b/releases/3.2.78/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch new file mode 100644 index 00000000..4853896e --- /dev/null +++ b/releases/3.2.78/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch @@ -0,0 +1,373 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Wed, 3 Feb 2016 08:32:44 +0100 +Subject: ALSA: seq: Fix lockdep warnings due to double mutex locks + +commit 7f0973e973cd74aa40747c9d38844560cd184ee8 upstream. + +The port subscription code uses double mutex locks for source and +destination ports, and this may become racy once when wrongly set up. +It leads to lockdep warning splat, typically triggered by fuzzer like +syzkaller, although the actual deadlock hasn't been seen, so far. + +This patch simplifies the handling by reducing to two single locks, so +that no lockdep warning will be trigger any longer. + +By splitting to two actions, a still-in-progress element shall be +added in one list while handling another. For ignoring this element, +a new check is added in deliver_to_subscribers(). + +Along with it, the code to add/remove the subscribers list element was +cleaned up and refactored. + +BugLink: http://lkml.kernel.org/r/CACT4Y+aKQXV7xkBW9hpQbzaDO7LrUvohxWh-UwMxXjDy-yBD=A@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Tested-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/seq/seq_clientmgr.c | 3 + + sound/core/seq/seq_ports.c | 233 +++++++++++++++++++++++------------------ + 2 files changed, 133 insertions(+), 103 deletions(-) + +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -678,6 +678,9 @@ static int deliver_to_subscribers(struct + else + down_read(&grp->list_mutex); + list_for_each_entry(subs, &grp->list_head, src_list) { ++ /* both ports ready? */ ++ if (atomic_read(&subs->ref_count) != 2) ++ continue; + event->dest = subs->info.dest; + if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) + /* convert time according to flag with subscription */ +--- a/sound/core/seq/seq_ports.c ++++ b/sound/core/seq/seq_ports.c +@@ -175,10 +175,6 @@ struct snd_seq_client_port *snd_seq_crea + } + + /* */ +-enum group_type { +- SRC_LIST, DEST_LIST +-}; +- + static int subscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_port_subs_info *grp, +@@ -205,6 +201,20 @@ static struct snd_seq_client_port *get_c + return NULL; + } + ++static void delete_and_unsubscribe_port(struct snd_seq_client *client, ++ struct snd_seq_client_port *port, ++ struct snd_seq_subscribers *subs, ++ bool is_src, bool ack); ++ ++static inline struct snd_seq_subscribers * ++get_subscriber(struct list_head *p, bool is_src) ++{ ++ if (is_src) ++ return list_entry(p, struct snd_seq_subscribers, src_list); ++ else ++ return list_entry(p, struct snd_seq_subscribers, dest_list); ++} ++ + /* + * remove all subscribers on the list + * this is called from port_delete, for each src and dest list. +@@ -212,7 +222,7 @@ static struct snd_seq_client_port *get_c + static void clear_subscriber_list(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_port_subs_info *grp, +- int grptype) ++ int is_src) + { + struct list_head *p, *n; + +@@ -221,15 +231,13 @@ static void clear_subscriber_list(struct + struct snd_seq_client *c; + struct snd_seq_client_port *aport; + +- if (grptype == SRC_LIST) { +- subs = list_entry(p, struct snd_seq_subscribers, src_list); ++ subs = get_subscriber(p, is_src); ++ if (is_src) + aport = get_client_port(&subs->info.dest, &c); +- } else { +- subs = list_entry(p, struct snd_seq_subscribers, dest_list); ++ else + aport = get_client_port(&subs->info.sender, &c); +- } +- list_del(p); +- unsubscribe_port(client, port, grp, &subs->info, 0); ++ delete_and_unsubscribe_port(client, port, subs, is_src, false); ++ + if (!aport) { + /* looks like the connected port is being deleted. + * we decrease the counter, and when both ports are deleted +@@ -237,21 +245,14 @@ static void clear_subscriber_list(struct + */ + if (atomic_dec_and_test(&subs->ref_count)) + kfree(subs); +- } else { +- /* ok we got the connected port */ +- struct snd_seq_port_subs_info *agrp; +- agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src; +- down_write(&agrp->list_mutex); +- if (grptype == SRC_LIST) +- list_del(&subs->dest_list); +- else +- list_del(&subs->src_list); +- up_write(&agrp->list_mutex); +- unsubscribe_port(c, aport, agrp, &subs->info, 1); +- kfree(subs); +- snd_seq_port_unlock(aport); +- snd_seq_client_unlock(c); ++ continue; + } ++ ++ /* ok we got the connected port */ ++ delete_and_unsubscribe_port(c, aport, subs, !is_src, true); ++ kfree(subs); ++ snd_seq_port_unlock(aport); ++ snd_seq_client_unlock(c); + } + } + +@@ -264,8 +265,8 @@ static int port_delete(struct snd_seq_cl + snd_use_lock_sync(&port->use_lock); + + /* clear subscribers info */ +- clear_subscriber_list(client, port, &port->c_src, SRC_LIST); +- clear_subscriber_list(client, port, &port->c_dest, DEST_LIST); ++ clear_subscriber_list(client, port, &port->c_src, true); ++ clear_subscriber_list(client, port, &port->c_dest, false); + + if (port->private_free) + port->private_free(port->private_data); +@@ -484,85 +485,120 @@ static int match_subs_info(struct snd_se + return 0; + } + ++static int check_and_subscribe_port(struct snd_seq_client *client, ++ struct snd_seq_client_port *port, ++ struct snd_seq_subscribers *subs, ++ bool is_src, bool exclusive, bool ack) ++{ ++ struct snd_seq_port_subs_info *grp; ++ struct list_head *p; ++ struct snd_seq_subscribers *s; ++ int err; + +-/* connect two ports */ +-int snd_seq_port_connect(struct snd_seq_client *connector, +- struct snd_seq_client *src_client, +- struct snd_seq_client_port *src_port, +- struct snd_seq_client *dest_client, +- struct snd_seq_client_port *dest_port, +- struct snd_seq_port_subscribe *info) +-{ +- struct snd_seq_port_subs_info *src = &src_port->c_src; +- struct snd_seq_port_subs_info *dest = &dest_port->c_dest; +- struct snd_seq_subscribers *subs, *s; +- int err, src_called = 0; +- unsigned long flags; +- int exclusive; +- +- subs = kzalloc(sizeof(*subs), GFP_KERNEL); +- if (! subs) +- return -ENOMEM; +- +- subs->info = *info; +- atomic_set(&subs->ref_count, 2); +- +- down_write(&src->list_mutex); +- down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); +- +- exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0; ++ grp = is_src ? &port->c_src : &port->c_dest; + err = -EBUSY; ++ down_write(&grp->list_mutex); + if (exclusive) { +- if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head)) ++ if (!list_empty(&grp->list_head)) + goto __error; + } else { +- if (src->exclusive || dest->exclusive) ++ if (grp->exclusive) + goto __error; + /* check whether already exists */ +- list_for_each_entry(s, &src->list_head, src_list) { +- if (match_subs_info(info, &s->info)) +- goto __error; +- } +- list_for_each_entry(s, &dest->list_head, dest_list) { +- if (match_subs_info(info, &s->info)) ++ list_for_each(p, &grp->list_head) { ++ s = get_subscriber(p, is_src); ++ if (match_subs_info(&subs->info, &s->info)) + goto __error; + } + } + +- if ((err = subscribe_port(src_client, src_port, src, info, +- connector->number != src_client->number)) < 0) +- goto __error; +- src_called = 1; +- +- if ((err = subscribe_port(dest_client, dest_port, dest, info, +- connector->number != dest_client->number)) < 0) ++ err = subscribe_port(client, port, grp, &subs->info, ack); ++ if (err < 0) { ++ grp->exclusive = 0; + goto __error; ++ } + + /* add to list */ +- write_lock_irqsave(&src->list_lock, flags); +- // write_lock(&dest->list_lock); // no other lock yet +- list_add_tail(&subs->src_list, &src->list_head); +- list_add_tail(&subs->dest_list, &dest->list_head); +- // write_unlock(&dest->list_lock); // no other lock yet +- write_unlock_irqrestore(&src->list_lock, flags); ++ write_lock_irq(&grp->list_lock); ++ if (is_src) ++ list_add_tail(&subs->src_list, &grp->list_head); ++ else ++ list_add_tail(&subs->dest_list, &grp->list_head); ++ grp->exclusive = exclusive; ++ atomic_inc(&subs->ref_count); ++ write_unlock_irq(&grp->list_lock); ++ err = 0; + +- src->exclusive = dest->exclusive = exclusive; ++ __error: ++ up_write(&grp->list_mutex); ++ return err; ++} ++ ++static void delete_and_unsubscribe_port(struct snd_seq_client *client, ++ struct snd_seq_client_port *port, ++ struct snd_seq_subscribers *subs, ++ bool is_src, bool ack) ++{ ++ struct snd_seq_port_subs_info *grp; ++ ++ grp = is_src ? &port->c_src : &port->c_dest; ++ down_write(&grp->list_mutex); ++ write_lock_irq(&grp->list_lock); ++ if (is_src) ++ list_del(&subs->src_list); ++ else ++ list_del(&subs->dest_list); ++ grp->exclusive = 0; ++ write_unlock_irq(&grp->list_lock); ++ up_write(&grp->list_mutex); ++ ++ unsubscribe_port(client, port, grp, &subs->info, ack); ++} ++ ++/* connect two ports */ ++int snd_seq_port_connect(struct snd_seq_client *connector, ++ struct snd_seq_client *src_client, ++ struct snd_seq_client_port *src_port, ++ struct snd_seq_client *dest_client, ++ struct snd_seq_client_port *dest_port, ++ struct snd_seq_port_subscribe *info) ++{ ++ struct snd_seq_subscribers *subs; ++ bool exclusive; ++ int err; ++ ++ subs = kzalloc(sizeof(*subs), GFP_KERNEL); ++ if (!subs) ++ return -ENOMEM; ++ ++ subs->info = *info; ++ atomic_set(&subs->ref_count, 0); ++ INIT_LIST_HEAD(&subs->src_list); ++ INIT_LIST_HEAD(&subs->dest_list); ++ ++ exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE); ++ ++ err = check_and_subscribe_port(src_client, src_port, subs, true, ++ exclusive, ++ connector->number != src_client->number); ++ if (err < 0) ++ goto error; ++ err = check_and_subscribe_port(dest_client, dest_port, subs, false, ++ exclusive, ++ connector->number != dest_client->number); ++ if (err < 0) ++ goto error_dest; + +- up_write(&dest->list_mutex); +- up_write(&src->list_mutex); + return 0; + +- __error: +- if (src_called) +- unsubscribe_port(src_client, src_port, src, info, +- connector->number != src_client->number); ++ error_dest: ++ delete_and_unsubscribe_port(src_client, src_port, subs, true, ++ connector->number != src_client->number); ++ error: + kfree(subs); +- up_write(&dest->list_mutex); +- up_write(&src->list_mutex); + return err; + } + +- + /* remove the connection */ + int snd_seq_port_disconnect(struct snd_seq_client *connector, + struct snd_seq_client *src_client, +@@ -572,37 +608,28 @@ int snd_seq_port_disconnect(struct snd_s + struct snd_seq_port_subscribe *info) + { + struct snd_seq_port_subs_info *src = &src_port->c_src; +- struct snd_seq_port_subs_info *dest = &dest_port->c_dest; + struct snd_seq_subscribers *subs; + int err = -ENOENT; +- unsigned long flags; + + down_write(&src->list_mutex); +- down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); +- + /* look for the connection */ + list_for_each_entry(subs, &src->list_head, src_list) { + if (match_subs_info(info, &subs->info)) { +- write_lock_irqsave(&src->list_lock, flags); +- // write_lock(&dest->list_lock); // no lock yet +- list_del(&subs->src_list); +- list_del(&subs->dest_list); +- // write_unlock(&dest->list_lock); +- write_unlock_irqrestore(&src->list_lock, flags); +- src->exclusive = dest->exclusive = 0; +- unsubscribe_port(src_client, src_port, src, info, +- connector->number != src_client->number); +- unsubscribe_port(dest_client, dest_port, dest, info, +- connector->number != dest_client->number); +- kfree(subs); ++ atomic_dec(&subs->ref_count); /* mark as not ready */ + err = 0; + break; + } + } +- +- up_write(&dest->list_mutex); + up_write(&src->list_mutex); +- return err; ++ if (err < 0) ++ return err; ++ ++ delete_and_unsubscribe_port(src_client, src_port, subs, true, ++ connector->number != src_client->number); ++ delete_and_unsubscribe_port(dest_client, dest_port, subs, false, ++ connector->number != dest_client->number); ++ kfree(subs); ++ return 0; + } + + diff --git a/releases/3.2.78/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch b/releases/3.2.78/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch new file mode 100644 index 00000000..72d39581 --- /dev/null +++ b/releases/3.2.78/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch @@ -0,0 +1,39 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Mon, 1 Feb 2016 12:06:42 +0100 +Subject: ALSA: seq: Fix race at closing in virmidi driver + +commit 2d1b5c08366acd46c35a2e9aba5d650cb5bf5c19 upstream. + +The virmidi driver has an open race at closing its assigned rawmidi +device, and this may lead to use-after-free in +snd_seq_deliver_single_event(). + +Plug the hole by properly protecting the linked list deletion and +calling in the right order in snd_virmidi_input_close(). + +BugLink: http://lkml.kernel.org/r/CACT4Y+Zd66+w12fNN85-425cVQT=K23kWbhnCEcMB8s3us-Frw@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Tested-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/seq/seq_virmidi.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/sound/core/seq/seq_virmidi.c ++++ b/sound/core/seq/seq_virmidi.c +@@ -254,9 +254,13 @@ static int snd_virmidi_output_open(struc + */ + static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) + { ++ struct snd_virmidi_dev *rdev = substream->rmidi->private_data; + struct snd_virmidi *vmidi = substream->runtime->private_data; +- snd_midi_event_free(vmidi->parser); ++ ++ write_lock_irq(&rdev->filelist_lock); + list_del(&vmidi->list); ++ write_unlock_irq(&rdev->filelist_lock); ++ snd_midi_event_free(vmidi->parser); + substream->runtime->private_data = NULL; + kfree(vmidi); + return 0; diff --git a/releases/3.2.78/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch b/releases/3.2.78/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch new file mode 100644 index 00000000..f2eb99df --- /dev/null +++ b/releases/3.2.78/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch @@ -0,0 +1,224 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Sat, 30 Jan 2016 23:30:25 +0100 +Subject: ALSA: seq: Fix yet another races among ALSA timer accesses + +commit 2cdc7b636d55cbcf42e1e6c8accd85e62d3e9ae8 upstream. + +ALSA sequencer may open/close and control ALSA timer instance +dynamically either via sequencer events or direct ioctls. These are +done mostly asynchronously, and it may call still some timer action +like snd_timer_start() while another is calling snd_timer_close(). +Since the instance gets removed by snd_timer_close(), it may lead to +a use-after-free. + +This patch tries to address such a race by protecting each +snd_timer_*() call via the existing spinlock and also by avoiding the +access to timer during close call. + +BugLink: http://lkml.kernel.org/r/CACT4Y+Z6RzW5MBr-HUdV-8zwg71WQfKTdPpYGvOeS7v4cyurNQ@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/seq/seq_timer.c | 87 +++++++++++++++++++++++++++++++++++----------- + 1 file changed, 67 insertions(+), 20 deletions(-) + +--- a/sound/core/seq/seq_timer.c ++++ b/sound/core/seq/seq_timer.c +@@ -92,6 +92,9 @@ void snd_seq_timer_delete(struct snd_seq + + void snd_seq_timer_defaults(struct snd_seq_timer * tmr) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tmr->lock, flags); + /* setup defaults */ + tmr->ppq = 96; /* 96 PPQ */ + tmr->tempo = 500000; /* 120 BPM */ +@@ -107,21 +110,25 @@ void snd_seq_timer_defaults(struct snd_s + tmr->preferred_resolution = seq_default_timer_resolution; + + tmr->skew = tmr->skew_base = SKEW_BASE; ++ spin_unlock_irqrestore(&tmr->lock, flags); + } + +-void snd_seq_timer_reset(struct snd_seq_timer * tmr) ++static void seq_timer_reset(struct snd_seq_timer *tmr) + { +- unsigned long flags; +- +- spin_lock_irqsave(&tmr->lock, flags); +- + /* reset time & songposition */ + tmr->cur_time.tv_sec = 0; + tmr->cur_time.tv_nsec = 0; + + tmr->tick.cur_tick = 0; + tmr->tick.fraction = 0; ++} ++ ++void snd_seq_timer_reset(struct snd_seq_timer *tmr) ++{ ++ unsigned long flags; + ++ spin_lock_irqsave(&tmr->lock, flags); ++ seq_timer_reset(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + } + +@@ -140,8 +147,11 @@ static void snd_seq_timer_interrupt(stru + tmr = q->timer; + if (tmr == NULL) + return; +- if (!tmr->running) ++ spin_lock_irqsave(&tmr->lock, flags); ++ if (!tmr->running) { ++ spin_unlock_irqrestore(&tmr->lock, flags); + return; ++ } + + resolution *= ticks; + if (tmr->skew != tmr->skew_base) { +@@ -150,8 +160,6 @@ static void snd_seq_timer_interrupt(stru + (((resolution & 0xffff) * tmr->skew) >> 16); + } + +- spin_lock_irqsave(&tmr->lock, flags); +- + /* update timer */ + snd_seq_inc_time_nsec(&tmr->cur_time, resolution); + +@@ -298,26 +306,30 @@ int snd_seq_timer_open(struct snd_seq_qu + t->callback = snd_seq_timer_interrupt; + t->callback_data = q; + t->flags |= SNDRV_TIMER_IFLG_AUTO; ++ spin_lock_irq(&tmr->lock); + tmr->timeri = t; ++ spin_unlock_irq(&tmr->lock); + return 0; + } + + int snd_seq_timer_close(struct snd_seq_queue *q) + { + struct snd_seq_timer *tmr; ++ struct snd_timer_instance *t; + + tmr = q->timer; + if (snd_BUG_ON(!tmr)) + return -EINVAL; +- if (tmr->timeri) { +- snd_timer_stop(tmr->timeri); +- snd_timer_close(tmr->timeri); +- tmr->timeri = NULL; +- } ++ spin_lock_irq(&tmr->lock); ++ t = tmr->timeri; ++ tmr->timeri = NULL; ++ spin_unlock_irq(&tmr->lock); ++ if (t) ++ snd_timer_close(t); + return 0; + } + +-int snd_seq_timer_stop(struct snd_seq_timer * tmr) ++static int seq_timer_stop(struct snd_seq_timer *tmr) + { + if (! tmr->timeri) + return -EINVAL; +@@ -328,6 +340,17 @@ int snd_seq_timer_stop(struct snd_seq_ti + return 0; + } + ++int snd_seq_timer_stop(struct snd_seq_timer *tmr) ++{ ++ unsigned long flags; ++ int err; ++ ++ spin_lock_irqsave(&tmr->lock, flags); ++ err = seq_timer_stop(tmr); ++ spin_unlock_irqrestore(&tmr->lock, flags); ++ return err; ++} ++ + static int initialize_timer(struct snd_seq_timer *tmr) + { + struct snd_timer *t; +@@ -360,13 +383,13 @@ static int initialize_timer(struct snd_s + return 0; + } + +-int snd_seq_timer_start(struct snd_seq_timer * tmr) ++static int seq_timer_start(struct snd_seq_timer *tmr) + { + if (! tmr->timeri) + return -EINVAL; + if (tmr->running) +- snd_seq_timer_stop(tmr); +- snd_seq_timer_reset(tmr); ++ seq_timer_stop(tmr); ++ seq_timer_reset(tmr); + if (initialize_timer(tmr) < 0) + return -EINVAL; + snd_timer_start(tmr->timeri, tmr->ticks); +@@ -375,14 +398,25 @@ int snd_seq_timer_start(struct snd_seq_t + return 0; + } + +-int snd_seq_timer_continue(struct snd_seq_timer * tmr) ++int snd_seq_timer_start(struct snd_seq_timer *tmr) ++{ ++ unsigned long flags; ++ int err; ++ ++ spin_lock_irqsave(&tmr->lock, flags); ++ err = seq_timer_start(tmr); ++ spin_unlock_irqrestore(&tmr->lock, flags); ++ return err; ++} ++ ++static int seq_timer_continue(struct snd_seq_timer *tmr) + { + if (! tmr->timeri) + return -EINVAL; + if (tmr->running) + return -EBUSY; + if (! tmr->initialized) { +- snd_seq_timer_reset(tmr); ++ seq_timer_reset(tmr); + if (initialize_timer(tmr) < 0) + return -EINVAL; + } +@@ -392,11 +426,24 @@ int snd_seq_timer_continue(struct snd_se + return 0; + } + ++int snd_seq_timer_continue(struct snd_seq_timer *tmr) ++{ ++ unsigned long flags; ++ int err; ++ ++ spin_lock_irqsave(&tmr->lock, flags); ++ err = seq_timer_continue(tmr); ++ spin_unlock_irqrestore(&tmr->lock, flags); ++ return err; ++} ++ + /* return current 'real' time. use timeofday() to get better granularity. */ + snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) + { + snd_seq_real_time_t cur_time; ++ unsigned long flags; + ++ spin_lock_irqsave(&tmr->lock, flags); + cur_time = tmr->cur_time; + if (tmr->running) { + struct timeval tm; +@@ -412,7 +459,7 @@ snd_seq_real_time_t snd_seq_timer_get_cu + } + snd_seq_sanity_real_time(&cur_time); + } +- ++ spin_unlock_irqrestore(&tmr->lock, flags); + return cur_time; + } + diff --git a/releases/3.2.78/alsa-timer-fix-leftover-link-at-closing.patch b/releases/3.2.78/alsa-timer-fix-leftover-link-at-closing.patch new file mode 100644 index 00000000..bb0459d3 --- /dev/null +++ b/releases/3.2.78/alsa-timer-fix-leftover-link-at-closing.patch @@ -0,0 +1,42 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Thu, 4 Feb 2016 17:06:13 +0100 +Subject: ALSA: timer: Fix leftover link at closing + +commit 094fd3be87b0f102589e2d5c3fa5d06b7e20496d upstream. + +In ALSA timer core, the active timer instance is managed in +active_list linked list. Each element is added / removed dynamically +at timer start, stop and in timer interrupt. The problem is that +snd_timer_interrupt() has a thinko and leaves the element in +active_list when it's the last opened element. This eventually leads +to list corruption or use-after-free error. + +This hasn't been revealed because we used to delete the list forcibly +in snd_timer_stop() in the past. However, the recent fix avoids the +double-stop behavior (in commit [f784beb75ce8: ALSA: timer: Fix link +corruption due to double start or stop]), and this leak hits reality. + +This patch fixes the link management in snd_timer_interrupt(). Now it +simply unlinks no matter which stream is. + +BugLink: http://lkml.kernel.org/r/CACT4Y+Yy2aukHP-EDp8-ziNqNNmb-NTf=jDWXMP7jB8HDa2vng@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/timer.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -727,8 +727,8 @@ void snd_timer_interrupt(struct snd_time + ti->cticks = ti->ticks; + } else { + ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; +- if (--timer->running) +- list_del_init(&ti->active_list); ++ --timer->running; ++ list_del_init(&ti->active_list); + } + if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || + (ti->flags & SNDRV_TIMER_IFLG_FAST)) diff --git a/releases/3.2.78/alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch b/releases/3.2.78/alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch new file mode 100644 index 00000000..d18e7718 --- /dev/null +++ b/releases/3.2.78/alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch @@ -0,0 +1,108 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Sat, 30 Jan 2016 23:09:08 +0100 +Subject: ALSA: timer: Fix link corruption due to double start or stop + +commit f784beb75ce82f4136f8a0960d3ee872f7109e09 upstream. + +Although ALSA timer code got hardening for races, it still causes +use-after-free error. This is however rather a corrupted linked list, +not actually the concurrent accesses. Namely, when timer start is +triggered twice, list_add_tail() is called twice, too. This ends +up with the link corruption and triggers KASAN error. + +The simplest fix would be replacing list_add_tail() with +list_move_tail(), but fundamentally it's the problem that we don't +check the double start/stop correctly. So, the right fix here is to +add the proper checks to snd_timer_start() and snd_timer_stop() (and +their variants). + +BugLink: http://lkml.kernel.org/r/CACT4Y+ZyPRoMQjmawbvmCEDrkBD2BQuH7R09=eOkf5ESK8kJAw@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +[bwh: Backported to 3.2: adjust context, indentation] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/timer.c | 30 ++++++++++++++++++++++++++++-- + 1 file changed, 28 insertions(+), 2 deletions(-) + +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -443,6 +443,10 @@ static int snd_timer_start_slave(struct + unsigned long flags; + + spin_lock_irqsave(&slave_active_lock, flags); ++ if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { ++ spin_unlock_irqrestore(&slave_active_lock, flags); ++ return -EBUSY; ++ } + timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; + if (timeri->master && timeri->timer) { + spin_lock(&timeri->timer->lock); +@@ -467,18 +471,26 @@ int snd_timer_start(struct snd_timer_ins + return -EINVAL; + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { + result = snd_timer_start_slave(timeri); +- snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); ++ if (result >= 0) ++ snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); + return result; + } + timer = timeri->timer; + if (timer == NULL) + return -EINVAL; + spin_lock_irqsave(&timer->lock, flags); ++ if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | ++ SNDRV_TIMER_IFLG_START)) { ++ result = -EBUSY; ++ goto unlock; ++ } + timeri->ticks = timeri->cticks = ticks; + timeri->pticks = 0; + result = snd_timer_start1(timer, timeri, ticks); ++ unlock: + spin_unlock_irqrestore(&timer->lock, flags); +- snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); ++ if (result >= 0) ++ snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); + return result; + } + +@@ -494,6 +506,10 @@ static int _snd_timer_stop(struct snd_ti + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { + if (!keep_flag) { + spin_lock_irqsave(&slave_active_lock, flags); ++ if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) { ++ spin_unlock_irqrestore(&slave_active_lock, flags); ++ return -EBUSY; ++ } + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); +@@ -505,6 +521,11 @@ static int _snd_timer_stop(struct snd_ti + if (!timer) + return -EINVAL; + spin_lock_irqsave(&timer->lock, flags); ++ if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | ++ SNDRV_TIMER_IFLG_START))) { ++ spin_unlock_irqrestore(&timer->lock, flags); ++ return -EBUSY; ++ } + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); + if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && +@@ -570,10 +591,15 @@ int snd_timer_continue(struct snd_timer_ + if (! timer) + return -EINVAL; + spin_lock_irqsave(&timer->lock, flags); ++ if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { ++ result = -EBUSY; ++ goto unlock; ++ } + if (!timeri->cticks) + timeri->cticks = 1; + timeri->pticks = 0; + result = snd_timer_start1(timer, timeri, timer->sticks); ++ unlock: + spin_unlock_irqrestore(&timer->lock, flags); + snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); + return result; diff --git a/releases/3.2.78/alsa-timer-fix-race-at-concurrent-reads.patch b/releases/3.2.78/alsa-timer-fix-race-at-concurrent-reads.patch new file mode 100644 index 00000000..1cc77af8 --- /dev/null +++ b/releases/3.2.78/alsa-timer-fix-race-at-concurrent-reads.patch @@ -0,0 +1,85 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Mon, 8 Feb 2016 17:26:58 +0100 +Subject: ALSA: timer: Fix race at concurrent reads + +commit 4dff5c7b7093b19c19d3a100f8a3ad87cb7cd9e7 upstream. + +snd_timer_user_read() has a potential race among parallel reads, as +qhead and qused are updated outside the critical section due to +copy_to_user() calls. Move them into the critical section, and also +sanitize the relevant code a bit. + +Signed-off-by: Takashi Iwai <tiwai@suse.de> +[bwh: Backported to 3.2: there's no check for tu->connected to fix up] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -1890,6 +1890,7 @@ static ssize_t snd_timer_user_read(struc + { + struct snd_timer_user *tu; + long result = 0, unit; ++ int qhead; + int err = 0; + + tu = file->private_data; +@@ -1901,7 +1902,7 @@ static ssize_t snd_timer_user_read(struc + + if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { + err = -EAGAIN; +- break; ++ goto _error; + } + + set_current_state(TASK_INTERRUPTIBLE); +@@ -1916,38 +1917,33 @@ static ssize_t snd_timer_user_read(struc + + if (signal_pending(current)) { + err = -ERESTARTSYS; +- break; ++ goto _error; + } + } + ++ qhead = tu->qhead++; ++ tu->qhead %= tu->queue_size; + spin_unlock_irq(&tu->qlock); +- if (err < 0) +- goto _error; + + if (tu->tread) { +- if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], +- sizeof(struct snd_timer_tread))) { ++ if (copy_to_user(buffer, &tu->tqueue[qhead], ++ sizeof(struct snd_timer_tread))) + err = -EFAULT; +- goto _error; +- } + } else { +- if (copy_to_user(buffer, &tu->queue[tu->qhead++], +- sizeof(struct snd_timer_read))) { ++ if (copy_to_user(buffer, &tu->queue[qhead], ++ sizeof(struct snd_timer_read))) + err = -EFAULT; +- goto _error; +- } + } + +- tu->qhead %= tu->queue_size; +- +- result += unit; +- buffer += unit; +- + spin_lock_irq(&tu->qlock); + tu->qused--; ++ if (err < 0) ++ goto _error; ++ result += unit; ++ buffer += unit; + } +- spin_unlock_irq(&tu->qlock); + _error: ++ spin_unlock_irq(&tu->qlock); + return result > 0 ? result : err; + } + diff --git a/releases/3.2.78/alsa-timer-fix-race-between-stop-and-interrupt.patch b/releases/3.2.78/alsa-timer-fix-race-between-stop-and-interrupt.patch new file mode 100644 index 00000000..df002da6 --- /dev/null +++ b/releases/3.2.78/alsa-timer-fix-race-between-stop-and-interrupt.patch @@ -0,0 +1,40 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Tue, 9 Feb 2016 12:02:32 +0100 +Subject: ALSA: timer: Fix race between stop and interrupt + +commit ed8b1d6d2c741ab26d60d499d7fbb7ac801f0f51 upstream. + +A slave timer element also unlinks at snd_timer_stop() but it takes +only slave_active_lock. When a slave is assigned to a master, +however, this may become a race against the master's interrupt +handling, eventually resulting in a list corruption. The actual bug +could be seen with a syzkaller fuzzer test case in BugLink below. + +As a fix, we need to take timeri->timer->lock when timer isn't NULL, +i.e. assigned to a master, while the assignment to a master itself is +protected by slave_active_lock. + +BugLink: http://lkml.kernel.org/r/CACT4Y+Y_Bm+7epAb=8Wi=AaWd+DYS7qawX52qxdCfOfY49vozQ@mail.gmail.com +Signed-off-by: Takashi Iwai <tiwai@suse.de> +[bwh: Backported to 3.2: adjust context, indentation] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/timer.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -510,9 +510,13 @@ static int _snd_timer_stop(struct snd_ti + spin_unlock_irqrestore(&slave_active_lock, flags); + return -EBUSY; + } ++ if (timeri->timer) ++ spin_lock(&timeri->timer->lock); + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); ++ if (timeri->timer) ++ spin_unlock(&timeri->timer->lock); + spin_unlock_irqrestore(&slave_active_lock, flags); + } + goto __end; diff --git a/releases/3.2.78/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch b/releases/3.2.78/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch new file mode 100644 index 00000000..adf3d48c --- /dev/null +++ b/releases/3.2.78/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch @@ -0,0 +1,32 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Mon, 8 Feb 2016 17:36:25 +0100 +Subject: ALSA: timer: Fix wrong instance passed to slave callbacks + +commit 117159f0b9d392fb433a7871426fad50317f06f7 upstream. + +In snd_timer_notify1(), the wrong timer instance was passed for slave +ccallback function. This leads to the access to the wrong data when +an incompatible master is handled (e.g. the master is the sequencer +timer and the slave is a user timer), as spotted by syzkaller fuzzer. + +This patch fixes that wrong assignment. + +BugLink: http://lkml.kernel.org/r/CACT4Y+Y_Bm+7epAb=8Wi=AaWd+DYS7qawX52qxdCfOfY49vozQ@mail.gmail.com +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/core/timer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -414,7 +414,7 @@ static void snd_timer_notify1(struct snd + spin_lock_irqsave(&timer->lock, flags); + list_for_each_entry(ts, &ti->slave_active_head, active_list) + if (ts->ccallback) +- ts->ccallback(ti, event + 100, &tstamp, resolution); ++ ts->ccallback(ts, event + 100, &tstamp, resolution); + spin_unlock_irqrestore(&timer->lock, flags); + } + diff --git a/releases/3.2.78/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch b/releases/3.2.78/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch new file mode 100644 index 00000000..ae22e8f5 --- /dev/null +++ b/releases/3.2.78/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch @@ -0,0 +1,30 @@ +From: Andrey Konovalov <andreyknvl@gmail.com> +Date: Sat, 13 Feb 2016 11:08:06 +0300 +Subject: ALSA: usb-audio: avoid freeing umidi object twice + +commit 07d86ca93db7e5cdf4743564d98292042ec21af7 upstream. + +The 'umidi' object will be free'd on the error path by snd_usbmidi_free() +when tearing down the rawmidi interface. So we shouldn't try to free it +in snd_usbmidi_create() after having registered the rawmidi interface. + +Found by KASAN. + +Signed-off-by: Andrey Konovalov <andreyknvl@gmail.com> +Acked-by: Clemens Ladisch <clemens@ladisch.de> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + sound/usb/midi.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/sound/usb/midi.c ++++ b/sound/usb/midi.c +@@ -2289,7 +2289,6 @@ int snd_usbmidi_create(struct snd_card * + else + err = snd_usbmidi_create_endpoints(umidi, endpoints); + if (err < 0) { +- snd_usbmidi_free(umidi); + return err; + } + diff --git a/releases/3.2.78/arm-8517-1-icst-avoid-arithmetic-overflow-in-icst_hz.patch b/releases/3.2.78/arm-8517-1-icst-avoid-arithmetic-overflow-in-icst_hz.patch new file mode 100644 index 00000000..d7e7a027 --- /dev/null +++ b/releases/3.2.78/arm-8517-1-icst-avoid-arithmetic-overflow-in-icst_hz.patch @@ -0,0 +1,70 @@ +From: Linus Walleij <linus.walleij@linaro.org> +Date: Mon, 8 Feb 2016 09:14:37 +0100 +Subject: ARM: 8517/1: ICST: avoid arithmetic overflow in icst_hz() + +commit 5070fb14a0154f075c8b418e5bc58a620ae85a45 upstream. + +When trying to set the ICST 307 clock to 25174000 Hz I ran into +this arithmetic error: the icst_hz_to_vco() correctly figure out +DIVIDE=2, RDW=100 and VDW=99 yielding a frequency of +25174000 Hz out of the VCO. (I replicated the icst_hz() function +in a spreadsheet to verify this.) + +However, when I called icst_hz() on these VCO settings it would +instead return 4122709 Hz. This causes an error in the common +clock driver for ICST as the common clock framework will call +.round_rate() on the clock which will utilize icst_hz_to_vco() +followed by icst_hz() suggesting the erroneous frequency, and +then the clock gets set to this. + +The error did not manifest in the old clock framework since +this high frequency was only used by the CLCD, which calls +clk_set_rate() without first calling clk_round_rate() and since +the old clock framework would not call clk_round_rate() before +setting the frequency, the correct values propagated into +the VCO. + +After some experimenting I figured out that it was due to a simple +arithmetic overflow: the divisor for 24Mhz reference frequency +as reference becomes 24000000*2*(99+8)=0x132212400 and the "1" +in bit 32 overflows and is lost. + +But introducing an explicit 64-by-32 bit do_div() and casting +the divisor into (u64) we get the right frequency back, and the +right frequency gets set. + +Tested on the ARM Versatile. + +Cc: linux-clk@vger.kernel.org +Cc: Pawel Moll <pawel.moll@arm.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + arch/arm/common/icst.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/arch/arm/common/icst.c ++++ b/arch/arm/common/icst.c +@@ -16,7 +16,7 @@ + */ + #include <linux/module.h> + #include <linux/kernel.h> +- ++#include <asm/div64.h> + #include <asm/hardware/icst.h> + + /* +@@ -29,7 +29,11 @@ EXPORT_SYMBOL(icst525_s2div); + + unsigned long icst_hz(const struct icst_params *p, struct icst_vco vco) + { +- return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * p->s2div[vco.s]); ++ u64 dividend = p->ref * 2 * (u64)(vco.v + 8); ++ u32 divisor = (vco.r + 2) * p->s2div[vco.s]; ++ ++ do_div(dividend, divisor); ++ return (unsigned long)dividend; + } + + EXPORT_SYMBOL(icst_hz); diff --git a/releases/3.2.78/arm-8519-1-icst-try-other-dividends-than-1.patch b/releases/3.2.78/arm-8519-1-icst-try-other-dividends-than-1.patch new file mode 100644 index 00000000..9b553716 --- /dev/null +++ b/releases/3.2.78/arm-8519-1-icst-try-other-dividends-than-1.patch @@ -0,0 +1,34 @@ +From: Linus Walleij <linus.walleij@linaro.org> +Date: Wed, 10 Feb 2016 09:25:17 +0100 +Subject: ARM: 8519/1: ICST: try other dividends than 1 + +commit e972c37459c813190461dabfeaac228e00aae259 upstream. + +Since the dawn of time the ICST code has only supported divide +by one or hang in an eternal loop. Luckily we were always dividing +by one because the reference frequency for the systems using +the ICSTs is 24MHz and the [min,max] values for the PLL input +if [10,320] MHz for ICST307 and [6,200] for ICST525, so the loop +will always terminate immediately without assigning any divisor +for the reference frequency. + +But for the code to make sense, let's insert the missing i++ + +Reported-by: David Binderman <dcb314@hotmail.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + arch/arm/common/icst.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/common/icst.c ++++ b/arch/arm/common/icst.c +@@ -62,6 +62,7 @@ icst_hz_to_vco(const struct icst_params + + if (f > p->vco_min && f <= p->vco_max) + break; ++ i++; + } while (i < 8); + + if (i >= 8) diff --git a/releases/3.2.78/btrfs-properly-set-the-termination-value-of-ctx-pos-in-readdir.patch b/releases/3.2.78/btrfs-properly-set-the-termination-value-of-ctx-pos-in-readdir.patch new file mode 100644 index 00000000..f7eaa012 --- /dev/null +++ b/releases/3.2.78/btrfs-properly-set-the-termination-value-of-ctx-pos-in-readdir.patch @@ -0,0 +1,155 @@ +From: David Sterba <dsterba@suse.com> +Date: Fri, 13 Nov 2015 13:44:28 +0100 +Subject: btrfs: properly set the termination value of ctx->pos in readdir +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit bc4ef7592f657ae81b017207a1098817126ad4cb upstream. + +The value of ctx->pos in the last readdir call is supposed to be set to +INT_MAX due to 32bit compatibility, unless 'pos' is intentially set to a +larger value, then it's LLONG_MAX. + +There's a report from PaX SIZE_OVERFLOW plugin that "ctx->pos++" +overflows (https://forums.grsecurity.net/viewtopic.php?f=1&t=4284), on a +64bit arch, where the value is 0x7fffffffffffffff ie. LLONG_MAX before +the increment. + +We can get to that situation like that: + +* emit all regular readdir entries +* still in the same call to readdir, bump the last pos to INT_MAX +* next call to readdir will not emit any entries, but will reach the + bump code again, finds pos to be INT_MAX and sets it to LLONG_MAX + +Normally this is not a problem, but if we call readdir again, we'll find +'pos' set to LLONG_MAX and the unconditional increment will overflow. + +The report from Victor at +(http://thread.gmane.org/gmane.comp.file-systems.btrfs/49500) with debugging +print shows that pattern: + + Overflow: e + Overflow: 7fffffff + Overflow: 7fffffffffffffff + PAX: size overflow detected in function btrfs_real_readdir + fs/btrfs/inode.c:5760 cicus.935_282 max, count: 9, decl: pos; num: 0; + context: dir_context; + CPU: 0 PID: 2630 Comm: polkitd Not tainted 4.2.3-grsec #1 + Hardware name: Gigabyte Technology Co., Ltd. H81ND2H/H81ND2H, BIOS F3 08/11/2015 + ffffffff81901608 0000000000000000 ffffffff819015e6 ffffc90004973d48 + ffffffff81742f0f 0000000000000007 ffffffff81901608 ffffc90004973d78 + ffffffff811cb706 0000000000000000 ffff8800d47359e0 ffffc90004973ed8 + Call Trace: + [<ffffffff81742f0f>] dump_stack+0x4c/0x7f + [<ffffffff811cb706>] report_size_overflow+0x36/0x40 + [<ffffffff812ef0bc>] btrfs_real_readdir+0x69c/0x6d0 + [<ffffffff811dafc8>] iterate_dir+0xa8/0x150 + [<ffffffff811e6d8d>] ? __fget_light+0x2d/0x70 + [<ffffffff811dba3a>] SyS_getdents+0xba/0x1c0 + Overflow: 1a + [<ffffffff811db070>] ? iterate_dir+0x150/0x150 + [<ffffffff81749b69>] entry_SYSCALL_64_fastpath+0x12/0x83 + +The jump from 7fffffff to 7fffffffffffffff happens when new dir entries +are not yet synced and are processed from the delayed list. Then the code +could go to the bump section again even though it might not emit any new +dir entries from the delayed list. + +The fix avoids entering the "bump" section again once we've finished +emitting the entries, both for synced and delayed entries. + +References: https://forums.grsecurity.net/viewtopic.php?f=1&t=4284 +Reported-by: Victor <services@swwu.com> +Signed-off-by: David Sterba <dsterba@suse.com> +Tested-by: Holger Hoffstätte <holger.hoffstaette@googlemail.com> +Signed-off-by: Chris Mason <clm@fb.com> +[bwh: Backported to 3.2: + - s/ctx->pos/filp->f_pos/ + - Adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + fs/btrfs/delayed-inode.c | 3 ++- + fs/btrfs/delayed-inode.h | 2 +- + fs/btrfs/inode.c | 14 +++++++++++++- + 3 files changed, 16 insertions(+), 3 deletions(-) + +--- a/fs/btrfs/delayed-inode.c ++++ b/fs/btrfs/delayed-inode.c +@@ -1593,7 +1593,7 @@ int btrfs_should_delete_dir_index(struct + */ + int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent, + filldir_t filldir, +- struct list_head *ins_list) ++ struct list_head *ins_list, bool *emitted) + { + struct btrfs_dir_item *di; + struct btrfs_delayed_item *curr, *next; +@@ -1637,6 +1637,7 @@ int btrfs_readdir_delayed_dir_index(stru + + if (over) + return 1; ++ *emitted = true; + } + return 0; + } +--- a/fs/btrfs/delayed-inode.h ++++ b/fs/btrfs/delayed-inode.h +@@ -133,7 +133,7 @@ int btrfs_should_delete_dir_index(struct + u64 index); + int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent, + filldir_t filldir, +- struct list_head *ins_list); ++ struct list_head *ins_list, bool *emitted); + + /* for init */ + int __init btrfs_delayed_inode_init(void); +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -4111,6 +4111,7 @@ static int btrfs_real_readdir(struct fil + char *name_ptr; + int name_len; + int is_curr = 0; /* filp->f_pos points to the current index? */ ++ bool emitted; + + /* FIXME, use a real flag for deciding about the key type */ + if (root->fs_info->tree_root == root) +@@ -4153,6 +4154,7 @@ static int btrfs_real_readdir(struct fil + if (ret < 0) + goto err; + ++ emitted = false; + while (1) { + leaf = path->nodes[0]; + slot = path->slots[0]; +@@ -4254,6 +4256,7 @@ skip: + + if (over) + goto nopos; ++ emitted = true; + di_len = btrfs_dir_name_len(leaf, di) + + btrfs_dir_data_len(leaf, di) + sizeof(*di); + di_cur += di_len; +@@ -4267,11 +4270,20 @@ next: + if (is_curr) + filp->f_pos++; + ret = btrfs_readdir_delayed_dir_index(filp, dirent, filldir, +- &ins_list); ++ &ins_list, &emitted); + if (ret) + goto nopos; + } + ++ /* ++ * If we haven't emitted any dir entry, we must not touch filp->f_pos as ++ * it was was set to the termination value in previous call. We assume ++ * that "." and ".." were emitted if we reach this point and set the ++ * termination value as well for an empty directory. ++ */ ++ if (filp->f_pos > 2 && !emitted) ++ goto nopos; ++ + /* Reached end of directory/root. Bump pos past the last item. */ + if (key_type == BTRFS_DIR_INDEX_KEY) + /* diff --git a/releases/3.2.78/cdc-acm-exclude-samsung-phone-04e8-685d.patch b/releases/3.2.78/cdc-acm-exclude-samsung-phone-04e8-685d.patch new file mode 100644 index 00000000..db3d4493 --- /dev/null +++ b/releases/3.2.78/cdc-acm-exclude-samsung-phone-04e8-685d.patch @@ -0,0 +1,30 @@ +From: Oliver Neukum <oneukum@suse.com> +Date: Mon, 18 Jan 2016 15:45:18 +0100 +Subject: cdc-acm:exclude Samsung phone 04e8:685d + +commit e912e685f372ab62a2405a1acd923597f524e94a upstream. + +This phone needs to be handled by a specialised firmware tool +and is reported to crash irrevocably if cdc-acm takes it. + +Signed-off-by: Oliver Neukum <oneukum@suse.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/usb/class/cdc-acm.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1668,6 +1668,11 @@ static const struct usb_device_id acm_id + .driver_info = NO_DATA_INTERFACE, + }, + ++ /*Samsung phone in firmware update mode */ ++ { USB_DEVICE(0x04e8, 0x685d), ++ .driver_info = IGNORE_DEVICE, ++ }, ++ + /* Exclude Infineon Flash Loader utility */ + { USB_DEVICE(0x058b, 0x0041), + .driver_info = IGNORE_DEVICE, diff --git a/releases/3.2.78/crypto-algif_hash-wait-for-crypto_ahash_init-to-complete.patch b/releases/3.2.78/crypto-algif_hash-wait-for-crypto_ahash_init-to-complete.patch new file mode 100644 index 00000000..3d925168 --- /dev/null +++ b/releases/3.2.78/crypto-algif_hash-wait-for-crypto_ahash_init-to-complete.patch @@ -0,0 +1,36 @@ +From: "Wang, Rui Y" <rui.y.wang@intel.com> +Date: Wed, 27 Jan 2016 17:08:37 +0800 +Subject: crypto: algif_hash - wait for crypto_ahash_init() to complete + +commit fe09786178f9df713a4b2dd6b93c0a722346bf5e upstream. + +hash_sendmsg/sendpage() need to wait for the completion +of crypto_ahash_init() otherwise it can cause panic. + +Signed-off-by: Rui Wang <rui.y.wang@intel.com> +Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + crypto/algif_hash.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -56,7 +56,8 @@ static int hash_sendmsg(struct kiocb *un + + lock_sock(sk); + if (!ctx->more) { +- err = crypto_ahash_init(&ctx->req); ++ err = af_alg_wait_for_completion(crypto_ahash_init(&ctx->req), ++ &ctx->completion); + if (err) + goto unlock; + } +@@ -136,6 +137,7 @@ static ssize_t hash_sendpage(struct sock + } else { + if (!ctx->more) { + err = crypto_ahash_init(&ctx->req); ++ err = af_alg_wait_for_completion(err, &ctx->completion); + if (err) + goto unlock; + } diff --git a/releases/3.2.78/crypto-algif_skcipher-do-not-dereference-ctx-without-socket-lock.patch b/releases/3.2.78/crypto-algif_skcipher-do-not-dereference-ctx-without-socket-lock.patch new file mode 100644 index 00000000..04b7be5d --- /dev/null +++ b/releases/3.2.78/crypto-algif_skcipher-do-not-dereference-ctx-without-socket-lock.patch @@ -0,0 +1,38 @@ +From: Herbert Xu <herbert@gondor.apana.org.au> +Date: Wed, 3 Feb 2016 21:39:26 +0800 +Subject: crypto: algif_skcipher - Do not dereference ctx without socket lock + +commit 6454c2b83f719057069777132b13949e4c6b6350 upstream. + +Any access to non-constant bits of the private context must be +done under the socket lock, in particular, this includes ctx->req. + +This patch moves such accesses under the lock, and fetches the +tfm from the parent socket which is guaranteed to be constant, +rather than from ctx->req. + +Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> +[bwh: Backported to 3.2: + - Drop changes to skcipher_recvmsg_async + - s/skcipher/ablkcipher/ in many places + - s/skc->skcipher/skc->base/] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + crypto/algif_skcipher.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -249,8 +249,11 @@ static int skcipher_sendmsg(struct kiocb + { + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); ++ struct sock *psk = ask->parent; ++ struct alg_sock *pask = alg_sk(psk); + struct skcipher_ctx *ctx = ask->private; +- struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req); ++ struct ablkcipher_tfm *skc = pask->private; ++ struct crypto_ablkcipher *tfm = skc->base; + unsigned ivsize = crypto_ablkcipher_ivsize(tfm); + struct skcipher_sg_list *sgl; + struct af_alg_control con = {}; diff --git a/releases/3.2.78/crypto-shash-fix-has_key-setting.patch b/releases/3.2.78/crypto-shash-fix-has_key-setting.patch new file mode 100644 index 00000000..17a61a77 --- /dev/null +++ b/releases/3.2.78/crypto-shash-fix-has_key-setting.patch @@ -0,0 +1,36 @@ +From: Herbert Xu <herbert@gondor.apana.org.au> +Date: Wed, 27 Jan 2016 00:16:37 +0800 +Subject: crypto: shash - Fix has_key setting + +commit 00420a65fa2beb3206090ead86942484df2275f3 upstream. + +The has_key logic is wrong for shash algorithms as they always +have a setkey function. So we should instead be testing against +shash_no_setkey. + +Fixes: a5596d633278 ("crypto: hash - Add crypto_ahash_has_setkey") +Reported-by: Stephan Mueller <smueller@chronox.de> +Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> +Tested-by: Stephan Mueller <smueller@chronox.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + crypto/shash.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/crypto/shash.c ++++ b/crypto/shash.c +@@ -353,11 +353,10 @@ int crypto_init_shash_ops_async(struct c + crt->final = shash_async_final; + crt->finup = shash_async_finup; + crt->digest = shash_async_digest; ++ crt->setkey = shash_async_setkey; ++ ++ crt->has_setkey = alg->setkey != shash_no_setkey; + +- if (alg->setkey) { +- crt->setkey = shash_async_setkey; +- crt->has_setkey = true; +- } + if (alg->export) + crt->export = shash_async_export; + if (alg->import) diff --git a/releases/3.2.78/crypto-user-lock-crypto_alg_list-on-alg-dump.patch b/releases/3.2.78/crypto-user-lock-crypto_alg_list-on-alg-dump.patch new file mode 100644 index 00000000..7e529b5c --- /dev/null +++ b/releases/3.2.78/crypto-user-lock-crypto_alg_list-on-alg-dump.patch @@ -0,0 +1,89 @@ +From: Mathias Krause <minipli@googlemail.com> +Date: Mon, 1 Feb 2016 14:27:30 +0100 +Subject: crypto: user - lock crypto_alg_list on alg dump + +commit 63e41ebc6630f39422d87f8a4bade1e793f37a01 upstream. + +We miss to take the crypto_alg_sem semaphore when traversing the +crypto_alg_list for CRYPTO_MSG_GETALG dumps. This allows a race with +crypto_unregister_alg() removing algorithms from the list while we're +still traversing it, thereby leading to a use-after-free as show below: + +[ 3482.071639] general protection fault: 0000 [#1] SMP +[ 3482.075639] Modules linked in: aes_x86_64 glue_helper lrw ablk_helper cryptd gf128mul ipv6 pcspkr serio_raw virtio_net microcode virtio_pci virtio_ring virtio sr_mod cdrom [last unloaded: aesni_intel] +[ 3482.075639] CPU: 1 PID: 11065 Comm: crconf Not tainted 4.3.4-grsec+ #126 +[ 3482.075639] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140531_083030-gandalf 04/01/2014 +[ 3482.075639] task: ffff88001cd41a40 ti: ffff88001cd422c8 task.ti: ffff88001cd422c8 +[ 3482.075639] RIP: 0010:[<ffffffff93722bd3>] [<ffffffff93722bd3>] strncpy+0x13/0x30 +[ 3482.075639] RSP: 0018:ffff88001f713b60 EFLAGS: 00010202 +[ 3482.075639] RAX: ffff88001f6c4430 RBX: ffff88001f6c43a0 RCX: ffff88001f6c4430 +[ 3482.075639] RDX: 0000000000000040 RSI: fefefefefefeff16 RDI: ffff88001f6c4430 +[ 3482.075639] RBP: ffff88001f713b60 R08: ffff88001f6c4470 R09: ffff88001f6c4480 +[ 3482.075639] R10: 0000000000000002 R11: 0000000000000246 R12: ffff88001ce2aa28 +[ 3482.075639] R13: ffff880000093700 R14: ffff88001f5e4bf8 R15: 0000000000003b20 +[ 3482.075639] FS: 0000033826fa2700(0000) GS:ffff88001e900000(0000) knlGS:0000000000000000 +[ 3482.075639] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 3482.075639] CR2: ffffffffff600400 CR3: 00000000139ec000 CR4: 00000000001606f0 +[ 3482.075639] Stack: +[ 3482.075639] ffff88001f713bd8 ffffffff936ccd00 ffff88001e5c4200 ffff880000093700 +[ 3482.075639] ffff88001f713bd0 ffffffff938ef4bf 0000000000000000 0000000000003b20 +[ 3482.075639] ffff88001f5e4bf8 ffff88001f5e4848 0000000000000000 0000000000003b20 +[ 3482.075639] Call Trace: +[ 3482.075639] [<ffffffff936ccd00>] crypto_report_alg+0xc0/0x3e0 +[ 3482.075639] [<ffffffff938ef4bf>] ? __alloc_skb+0x16f/0x300 +[ 3482.075639] [<ffffffff936cd08a>] crypto_dump_report+0x6a/0x90 +[ 3482.075639] [<ffffffff93935707>] netlink_dump+0x147/0x2e0 +[ 3482.075639] [<ffffffff93935f99>] __netlink_dump_start+0x159/0x190 +[ 3482.075639] [<ffffffff936ccb13>] crypto_user_rcv_msg+0xc3/0x130 +[ 3482.075639] [<ffffffff936cd020>] ? crypto_report_alg+0x3e0/0x3e0 +[ 3482.075639] [<ffffffff936cc4b0>] ? alg_test_crc32c+0x120/0x120 +[ 3482.075639] [<ffffffff93933145>] ? __netlink_lookup+0xd5/0x120 +[ 3482.075639] [<ffffffff936cca50>] ? crypto_add_alg+0x1d0/0x1d0 +[ 3482.075639] [<ffffffff93938141>] netlink_rcv_skb+0xe1/0x130 +[ 3482.075639] [<ffffffff936cc4f8>] crypto_netlink_rcv+0x28/0x40 +[ 3482.075639] [<ffffffff939375a8>] netlink_unicast+0x108/0x180 +[ 3482.075639] [<ffffffff93937c21>] netlink_sendmsg+0x541/0x770 +[ 3482.075639] [<ffffffff938e31e1>] sock_sendmsg+0x21/0x40 +[ 3482.075639] [<ffffffff938e4763>] SyS_sendto+0xf3/0x130 +[ 3482.075639] [<ffffffff93444203>] ? bad_area_nosemaphore+0x13/0x20 +[ 3482.075639] [<ffffffff93444470>] ? __do_page_fault+0x80/0x3a0 +[ 3482.075639] [<ffffffff939d80cb>] entry_SYSCALL_64_fastpath+0x12/0x6e +[ 3482.075639] Code: 88 4a ff 75 ed 5d 48 0f ba 2c 24 3f c3 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 85 d2 48 89 f8 48 89 f9 4c 8d 04 17 48 89 e5 74 15 <0f> b6 16 80 fa 01 88 11 48 83 de ff 48 83 c1 01 4c 39 c1 75 eb +[ 3482.075639] RIP [<ffffffff93722bd3>] strncpy+0x13/0x30 + +To trigger the race run the following loops simultaneously for a while: + $ while : ; do modprobe aesni-intel; rmmod aesni-intel; done + $ while : ; do crconf show all > /dev/null; done + +Fix the race by taking the crypto_alg_sem read lock, thereby preventing +crypto_unregister_alg() from modifying the algorithm list during the +dump. + +This bug has been detected by the PaX memory sanitize feature. + +Signed-off-by: Mathias Krause <minipli@googlemail.com> +Cc: Steffen Klassert <steffen.klassert@secunet.com> +Cc: PaX Team <pageexec@freemail.hu> +Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> +[bwh: Backported to 3.2: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + crypto/crypto_user.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/crypto/crypto_user.c ++++ b/crypto/crypto_user.c +@@ -390,8 +390,12 @@ static int crypto_user_rcv_msg(struct sk + if (link->dump == NULL) + return -EINVAL; + +- return netlink_dump_start(crypto_nlsk, skb, nlh, ++ down_read(&crypto_alg_sem); ++ err = netlink_dump_start(crypto_nlsk, skb, nlh, + link->dump, link->done, 0); ++ up_read(&crypto_alg_sem); ++ ++ return err; + } + + err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX, diff --git a/releases/3.2.78/drm-vmwgfx-respect-nomodeset.patch b/releases/3.2.78/drm-vmwgfx-respect-nomodeset.patch new file mode 100644 index 00000000..ce6b21f7 --- /dev/null +++ b/releases/3.2.78/drm-vmwgfx-respect-nomodeset.patch @@ -0,0 +1,37 @@ +From: Rob Clark <robdclark@gmail.com> +Date: Wed, 15 Oct 2014 15:00:47 -0400 +Subject: drm/vmwgfx: respect 'nomodeset' + +commit 96c5d076f0a5e2023ecdb44d8261f87641ee71e0 upstream. + +Signed-off-by: Rob Clark <robdclark@gmail.com> +Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>. +Signed-off-by: Dave Airlie <airlied@redhat.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +@@ -25,6 +25,7 @@ + * + **************************************************************************/ + #include <linux/module.h> ++#include <linux/console.h> + + #include "drmP.h" + #include "vmwgfx_drv.h" +@@ -1142,6 +1143,12 @@ static int vmw_probe(struct pci_dev *pde + static int __init vmwgfx_init(void) + { + int ret; ++ ++#ifdef CONFIG_VGA_CONSOLE ++ if (vgacon_text_force()) ++ return -EINVAL; ++#endif ++ + ret = drm_pci_init(&driver, &vmw_pci_driver); + if (ret) + DRM_ERROR("Failed initializing DRM.\n"); diff --git a/releases/3.2.78/hrtimer-handle-remaining-time-proper-for-time_low_res.patch b/releases/3.2.78/hrtimer-handle-remaining-time-proper-for-time_low_res.patch new file mode 100644 index 00000000..f75f49a5 --- /dev/null +++ b/releases/3.2.78/hrtimer-handle-remaining-time-proper-for-time_low_res.patch @@ -0,0 +1,224 @@ +From: Thomas Gleixner <tglx@linutronix.de> +Date: Thu, 14 Jan 2016 16:54:46 +0000 +Subject: hrtimer: Handle remaining time proper for TIME_LOW_RES + +commit 203cbf77de59fc8f13502dcfd11350c6d4a5c95f upstream. + +If CONFIG_TIME_LOW_RES is enabled we add a jiffie to the relative timeout to +prevent short sleeps, but we do not account for that in interfaces which +retrieve the remaining time. + +Helge observed that timerfd can return a remaining time larger than the +relative timeout. That's not expected and breaks userland test programs. + +Store the information that the timer was armed relative and provide functions +to adjust the remaining time. To avoid bloating the hrtimer struct make state +a u8, which as a bonus results in better code on x86 at least. + +Reported-and-tested-by: Helge Deller <deller@gmx.de> +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: John Stultz <john.stultz@linaro.org> +Cc: linux-m68k@lists.linux-m68k.org +Cc: dhowells@redhat.com +Link: http://lkml.kernel.org/r/20160114164159.273328486@linutronix.de +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +[bwh: Backported to 3.2: + - Use #ifdef instead of IS_ENABLED() as that doesn't work for config + symbols that don't exist on the current architecture + - Use KTIME_LOW_RES directly instead of hrtimer_resolution + - Use ktime_sub() instead of modifying ktime::tv64 directly + - Adjust filename, context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + include/linux/hrtimer.h | 34 +++++++++++++++++++++++++++--- + kernel/hrtimer.c | 55 ++++++++++++++++++++++++++++++++---------------- + kernel/time/timer_list.c | 2 +- + 3 files changed, 69 insertions(+), 22 deletions(-) + +--- a/include/linux/hrtimer.h ++++ b/include/linux/hrtimer.h +@@ -96,6 +96,7 @@ enum hrtimer_restart { + * @function: timer expiry callback function + * @base: pointer to the timer base (per cpu and per clock) + * @state: state information (See bit values above) ++ * @is_rel: Set if the timer was armed relative + * @start_site: timer statistics field to store the site where the timer + * was started + * @start_comm: timer statistics field to store the name of the process which +@@ -110,7 +111,8 @@ struct hrtimer { + ktime_t _softexpires; + enum hrtimer_restart (*function)(struct hrtimer *); + struct hrtimer_clock_base *base; +- unsigned long state; ++ u8 state; ++ u8 is_rel; + #ifdef CONFIG_TIMER_STATS + int start_pid; + void *start_site; +@@ -315,6 +317,29 @@ static inline void clock_was_set_delayed + + #endif + ++static inline ktime_t ++__hrtimer_expires_remaining_adjusted(const struct hrtimer *timer, ktime_t now) ++{ ++ ktime_t rem = ktime_sub(timer->node.expires, now); ++ ++ /* ++ * Adjust relative timers for the extra we added in ++ * hrtimer_start_range_ns() to prevent short timeouts. ++ */ ++#ifdef CONFIG_TIME_LOW_RES ++ if (timer->is_rel) ++ rem = ktime_sub(rem, KTIME_LOW_RES); ++#endif ++ return rem; ++} ++ ++static inline ktime_t ++hrtimer_expires_remaining_adjusted(const struct hrtimer *timer) ++{ ++ return __hrtimer_expires_remaining_adjusted(timer, ++ timer->base->get_time()); ++} ++ + extern void clock_was_set(void); + #ifdef CONFIG_TIMERFD + extern void timerfd_clock_was_set(void); +@@ -383,7 +408,12 @@ static inline int hrtimer_restart(struct + } + + /* Query timers: */ +-extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer); ++extern ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust); ++ ++static inline ktime_t hrtimer_get_remaining(const struct hrtimer *timer) ++{ ++ return __hrtimer_get_remaining(timer, false); ++} + extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp); + + extern ktime_t hrtimer_get_next_event(void); +--- a/kernel/hrtimer.c ++++ b/kernel/hrtimer.c +@@ -910,7 +910,7 @@ static int enqueue_hrtimer(struct hrtime + */ + static void __remove_hrtimer(struct hrtimer *timer, + struct hrtimer_clock_base *base, +- unsigned long newstate, int reprogram) ++ u8 newstate, int reprogram) + { + struct timerqueue_node *next_timer; + if (!(timer->state & HRTIMER_STATE_ENQUEUED)) +@@ -944,7 +944,7 @@ static inline int + remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) + { + if (hrtimer_is_queued(timer)) { +- unsigned long state; ++ u8 state; + int reprogram; + + /* +@@ -970,6 +970,22 @@ remove_hrtimer(struct hrtimer *timer, st + return 0; + } + ++static inline ktime_t hrtimer_update_lowres(struct hrtimer *timer, ktime_t tim, ++ const enum hrtimer_mode mode) ++{ ++#ifdef CONFIG_TIME_LOW_RES ++ /* ++ * CONFIG_TIME_LOW_RES indicates that the system has no way to return ++ * granular time values. For relative timers we add KTIME_LOW_RES ++ * (i.e. one jiffie) to prevent short timeouts. ++ */ ++ timer->is_rel = mode & HRTIMER_MODE_REL; ++ if (timer->is_rel) ++ tim = ktime_add_safe(tim, KTIME_LOW_RES); ++#endif ++ return tim; ++} ++ + int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + unsigned long delta_ns, const enum hrtimer_mode mode, + int wakeup) +@@ -983,19 +999,10 @@ int __hrtimer_start_range_ns(struct hrti + /* Remove an active timer from the queue: */ + ret = remove_hrtimer(timer, base); + +- if (mode & HRTIMER_MODE_REL) { ++ if (mode & HRTIMER_MODE_REL) + tim = ktime_add_safe(tim, base->get_time()); +- /* +- * CONFIG_TIME_LOW_RES is a temporary way for architectures +- * to signal that they simply return xtime in +- * do_gettimeoffset(). In this case we want to round up by +- * resolution when starting a relative timer, to avoid short +- * timeouts. This will go away with the GTOD framework. +- */ +-#ifdef CONFIG_TIME_LOW_RES +- tim = ktime_add_safe(tim, base->resolution); +-#endif +- } ++ ++ tim = hrtimer_update_lowres(timer, tim, mode); + + hrtimer_set_expires_range_ns(timer, tim, delta_ns); + +@@ -1120,19 +1127,25 @@ EXPORT_SYMBOL_GPL(hrtimer_cancel); + /** + * hrtimer_get_remaining - get remaining time for the timer + * @timer: the timer to read ++ * @adjust: adjust relative timers when CONFIG_TIME_LOW_RES=y + */ +-ktime_t hrtimer_get_remaining(const struct hrtimer *timer) ++ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust) + { + unsigned long flags; + ktime_t rem; + + lock_hrtimer_base(timer, &flags); +- rem = hrtimer_expires_remaining(timer); ++#ifdef CONFIG_TIME_LOW_RES ++ if (adjust) ++ rem = hrtimer_expires_remaining_adjusted(timer); ++ else ++#endif ++ rem = hrtimer_expires_remaining(timer); + unlock_hrtimer_base(timer, &flags); + + return rem; + } +-EXPORT_SYMBOL_GPL(hrtimer_get_remaining); ++EXPORT_SYMBOL_GPL(__hrtimer_get_remaining); + + #ifdef CONFIG_NO_HZ + /** +@@ -1249,6 +1262,15 @@ static void __run_hrtimer(struct hrtimer + fn = timer->function; + + /* ++ * Clear the 'is relative' flag for the TIME_LOW_RES case. If the ++ * timer is restarted with a period then it becomes an absolute ++ * timer. If its not restarted it does not matter. ++ */ ++#ifdef CONFIG_TIME_LOW_RES ++ timer->is_rel = false; ++#endif ++ ++ /* + * Because we run timers from hardirq context, there is no chance + * they get migrated to another cpu, therefore its safe to unlock + * the timer base. +--- a/kernel/time/timer_list.c ++++ b/kernel/time/timer_list.c +@@ -57,7 +57,7 @@ print_timer(struct seq_file *m, struct h + print_name_offset(m, taddr); + SEQ_printf(m, ", "); + print_name_offset(m, timer->function); +- SEQ_printf(m, ", S:%02lx", timer->state); ++ SEQ_printf(m, ", S:%02x", timer->state); + #ifdef CONFIG_TIMER_STATS + SEQ_printf(m, ", "); + print_name_offset(m, timer->start_site); diff --git a/releases/3.2.78/intel_scu_ipcutil-underflow-in-scu_reg_access.patch b/releases/3.2.78/intel_scu_ipcutil-underflow-in-scu_reg_access.patch new file mode 100644 index 00000000..1cab86ec --- /dev/null +++ b/releases/3.2.78/intel_scu_ipcutil-underflow-in-scu_reg_access.patch @@ -0,0 +1,29 @@ +From: Dan Carpenter <dan.carpenter@oracle.com> +Date: Tue, 26 Jan 2016 12:24:25 +0300 +Subject: intel_scu_ipcutil: underflow in scu_reg_access() + +commit b1d353ad3d5835b16724653b33c05124e1b5acf1 upstream. + +"count" is controlled by the user and it can be negative. Let's prevent +that by making it unsigned. You have to have CAP_SYS_RAWIO to call this +function so the bug is not as serious as it could be. + +Fixes: 5369c02d951a ('intel_scu_ipc: Utility driver for intel scu ipc') +Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> +Signed-off-by: Darren Hart <dvhart@linux.intel.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/platform/x86/intel_scu_ipcutil.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/platform/x86/intel_scu_ipcutil.c ++++ b/drivers/platform/x86/intel_scu_ipcutil.c +@@ -52,7 +52,7 @@ struct scu_ipc_data { + + static int scu_reg_access(u32 cmd, struct scu_ipc_data *data) + { +- int count = data->count; ++ unsigned int count = data->count; + + if (count == 0 || count == 3 || count > 4) + return -EINVAL; diff --git a/releases/3.2.78/itimers-handle-relative-timers-with-config_time_low_res-proper.patch b/releases/3.2.78/itimers-handle-relative-timers-with-config_time_low_res-proper.patch new file mode 100644 index 00000000..d566b3ff --- /dev/null +++ b/releases/3.2.78/itimers-handle-relative-timers-with-config_time_low_res-proper.patch @@ -0,0 +1,36 @@ +From: Thomas Gleixner <tglx@linutronix.de> +Date: Thu, 14 Jan 2016 16:54:48 +0000 +Subject: itimers: Handle relative timers with CONFIG_TIME_LOW_RES proper + +commit 51cbb5242a41700a3f250ecfb48dcfb7e4375ea4 upstream. + +As Helge reported for timerfd we have the same issue in itimers. We return +remaining time larger than the programmed relative time to user space in case +of CONFIG_TIME_LOW_RES=y. Use the proper function to adjust the extra time +added in hrtimer_start_range_ns(). + +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Helge Deller <deller@gmx.de> +Cc: John Stultz <john.stultz@linaro.org> +Cc: linux-m68k@lists.linux-m68k.org +Cc: dhowells@redhat.com +Link: http://lkml.kernel.org/r/20160114164159.528222587@linutronix.de +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +[bwh: Backported to 3.2: adjust filename] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + kernel/itimer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/itimer.c ++++ b/kernel/itimer.c +@@ -26,7 +26,7 @@ + */ + static struct timeval itimer_get_remtime(struct hrtimer *timer) + { +- ktime_t rem = hrtimer_get_remaining(timer); ++ ktime_t rem = __hrtimer_get_remaining(timer, true); + + /* + * Racy but safe: if the itimer expires after the above diff --git a/releases/3.2.78/iw_cxgb3-fix-incorrectly-returning-error-on-success.patch b/releases/3.2.78/iw_cxgb3-fix-incorrectly-returning-error-on-success.patch new file mode 100644 index 00000000..531c1f2e --- /dev/null +++ b/releases/3.2.78/iw_cxgb3-fix-incorrectly-returning-error-on-success.patch @@ -0,0 +1,38 @@ +From: Hariprasad S <hariprasad@chelsio.com> +Date: Fri, 11 Dec 2015 13:59:17 +0530 +Subject: iw_cxgb3: Fix incorrectly returning error on success + +commit 67f1aee6f45059fd6b0f5b0ecb2c97ad0451f6b3 upstream. + +The cxgb3_*_send() functions return NET_XMIT_ values, which are +positive integers values. So don't treat positive return values +as an error. + +Signed-off-by: Steve Wise <swise@opengridcomputing.com> +Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com> +Signed-off-by: Doug Ledford <dledford@redhat.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/infiniband/hw/cxgb3/iwch_cm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c ++++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c +@@ -150,7 +150,7 @@ static int iwch_l2t_send(struct t3cdev * + error = l2t_send(tdev, skb, l2e); + if (error < 0) + kfree_skb(skb); +- return error; ++ return error < 0 ? error : 0; + } + + int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb) +@@ -166,7 +166,7 @@ int iwch_cxgb3_ofld_send(struct t3cdev * + error = cxgb3_ofld_send(tdev, skb); + if (error < 0) + kfree_skb(skb); +- return error; ++ return error < 0 ? error : 0; + } + + static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb) diff --git a/releases/3.2.78/klist-fix-starting-point-removed-bug-in-klist-iterators.patch b/releases/3.2.78/klist-fix-starting-point-removed-bug-in-klist-iterators.patch new file mode 100644 index 00000000..5c90dcab --- /dev/null +++ b/releases/3.2.78/klist-fix-starting-point-removed-bug-in-klist-iterators.patch @@ -0,0 +1,61 @@ +From: James Bottomley <James.Bottomley@HansenPartnership.com> +Date: Wed, 13 Jan 2016 08:10:31 -0800 +Subject: klist: fix starting point removed bug in klist iterators + +commit 00cd29b799e3449f0c68b1cc77cd4a5f95b42d17 upstream. + +The starting node for a klist iteration is often passed in from +somewhere way above the klist infrastructure, meaning there's no +guarantee the node is still on the list. We've seen this in SCSI where +we use bus_find_device() to iterate through a list of devices. In the +face of heavy hotplug activity, the last device returned by +bus_find_device() can be removed before the next call. This leads to + +Dec 3 13:22:02 localhost kernel: WARNING: CPU: 2 PID: 28073 at include/linux/kref.h:47 klist_iter_init_node+0x3d/0x50() +Dec 3 13:22:02 localhost kernel: Modules linked in: scsi_debug x86_pkg_temp_thermal kvm_intel kvm irqbypass crc32c_intel joydev iTCO_wdt dcdbas ipmi_devintf acpi_power_meter iTCO_vendor_support ipmi_si imsghandler pcspkr wmi acpi_cpufreq tpm_tis tpm shpchp lpc_ich mfd_core nfsd nfs_acl lockd grace sunrpc tg3 ptp pps_core +Dec 3 13:22:02 localhost kernel: CPU: 2 PID: 28073 Comm: cat Not tainted 4.4.0-rc1+ #2 +Dec 3 13:22:02 localhost kernel: Hardware name: Dell Inc. PowerEdge R320/08VT7V, BIOS 2.0.22 11/19/2013 +Dec 3 13:22:02 localhost kernel: ffffffff81a20e77 ffff880613acfd18 ffffffff81321eef 0000000000000000 +Dec 3 13:22:02 localhost kernel: ffff880613acfd50 ffffffff8107ca52 ffff88061176b198 0000000000000000 +Dec 3 13:22:02 localhost kernel: ffffffff814542b0 ffff880610cfb100 ffff88061176b198 ffff880613acfd60 +Dec 3 13:22:02 localhost kernel: Call Trace: +Dec 3 13:22:02 localhost kernel: [<ffffffff81321eef>] dump_stack+0x44/0x55 +Dec 3 13:22:02 localhost kernel: [<ffffffff8107ca52>] warn_slowpath_common+0x82/0xc0 +Dec 3 13:22:02 localhost kernel: [<ffffffff814542b0>] ? proc_scsi_show+0x20/0x20 +Dec 3 13:22:02 localhost kernel: [<ffffffff8107cb4a>] warn_slowpath_null+0x1a/0x20 +Dec 3 13:22:02 localhost kernel: [<ffffffff8167225d>] klist_iter_init_node+0x3d/0x50 +Dec 3 13:22:02 localhost kernel: [<ffffffff81421d41>] bus_find_device+0x51/0xb0 +Dec 3 13:22:02 localhost kernel: [<ffffffff814545ad>] scsi_seq_next+0x2d/0x40 +[...] + +And an eventual crash. It can actually occur in any hotplug system +which has a device finder and a starting device. + +We can fix this globally by making sure the starting node for +klist_iter_init_node() is actually a member of the list before using it +(and by starting from the beginning if it isn't). + +Reported-by: Ewan D. Milne <emilne@redhat.com> +Tested-by: Ewan D. Milne <emilne@redhat.com> +Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + lib/klist.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/lib/klist.c ++++ b/lib/klist.c +@@ -282,9 +282,9 @@ void klist_iter_init_node(struct klist * + struct klist_node *n) + { + i->i_klist = k; +- i->i_cur = n; +- if (n) +- kref_get(&n->n_ref); ++ i->i_cur = NULL; ++ if (n && kref_get_unless_zero(&n->n_ref)) ++ i->i_cur = n; + } + EXPORT_SYMBOL_GPL(klist_iter_init_node); + diff --git a/releases/3.2.78/kvm-vmx-fix-mpx-detection.patch b/releases/3.2.78/kvm-vmx-fix-mpx-detection.patch new file mode 100644 index 00000000..111972e7 --- /dev/null +++ b/releases/3.2.78/kvm-vmx-fix-mpx-detection.patch @@ -0,0 +1,36 @@ +From: Paolo Bonzini <pbonzini@redhat.com> +Date: Wed, 26 Mar 2014 15:54:00 +0100 +Subject: KVM: vmx: fix MPX detection + +commit 920c837785699bcc48f4a729ba9ee3492f620b95 upstream. + +kvm_x86_ops is still NULL at this point. Since kvm_init_msr_list +cannot fail, it is safe to initialize it before the call. + +Fixes: 93c4adc7afedf9b0ec190066d45b6d67db5270da +Reported-by: Fengguang Wu <fengguang.wu@intel.com> +Tested-by: Jet Chen <jet.chen@intel.com> +Cc: kvm@vger.kernel.org +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> +Cc: Brad Spengler <spender@grsecurity.net> +[bwh: Dependency of "KVM: x86: expose MSR_TSC_AUX to userspace", + applied in 3.2.77] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + arch/x86/kvm/x86.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -5257,9 +5257,10 @@ int kvm_arch_init(void *opaque) + goto out; + + kvm_set_mmio_spte_mask(); +- kvm_init_msr_list(); + + kvm_x86_ops = ops; ++ kvm_init_msr_list(); ++ + kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK, + PT_DIRTY_MASK, PT64_NX_MASK, 0); + diff --git a/releases/3.2.78/libata-disable-forced-ports_impl-for-ahci-1.3.patch b/releases/3.2.78/libata-disable-forced-ports_impl-for-ahci-1.3.patch new file mode 100644 index 00000000..3c7bf3f5 --- /dev/null +++ b/releases/3.2.78/libata-disable-forced-ports_impl-for-ahci-1.3.patch @@ -0,0 +1,36 @@ +From: Tejun Heo <tj@kernel.org> +Date: Fri, 15 Jan 2016 15:13:05 -0500 +Subject: libata: disable forced PORTS_IMPL for >= AHCI 1.3 + +commit 566d1827df2ef0cbe921d3d6946ac3007b1a6938 upstream. + +Some early controllers incorrectly reported zero ports in PORTS_IMPL +register and the ahci driver fabricates PORTS_IMPL from the number of +ports in those cases. This hasn't mattered but with the new nvme +controllers there are cases where zero PORTS_IMPL is valid and should +be honored. + +Disable the workaround for >= AHCI 1.3. + +Signed-off-by: Tejun Heo <tj@kernel.org> +Reported-by: Andy Lutomirski <luto@amacapital.net> +Link: http://lkml.kernel.org/g/CALCETrU7yMvXEDhjAUShoHEhDwifJGapdw--BKxsP0jmjKGmRw@mail.gmail.com +Cc: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/ata/libahci.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/ata/libahci.c ++++ b/drivers/ata/libahci.c +@@ -480,8 +480,8 @@ void ahci_save_initial_config(struct dev + } + } + +- /* fabricate port_map from cap.nr_ports */ +- if (!port_map) { ++ /* fabricate port_map from cap.nr_ports for < AHCI 1.3 */ ++ if (!port_map && vers < 0x10300) { + port_map = (1 << ahci_nr_ports(cap)) - 1; + dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map); + diff --git a/releases/3.2.78/libata-fix-sff-host-state-machine-locking-while-polling.patch b/releases/3.2.78/libata-fix-sff-host-state-machine-locking-while-polling.patch new file mode 100644 index 00000000..95f52673 --- /dev/null +++ b/releases/3.2.78/libata-fix-sff-host-state-machine-locking-while-polling.patch @@ -0,0 +1,179 @@ +From: Tejun Heo <tj@kernel.org> +Date: Mon, 1 Feb 2016 11:33:21 -0500 +Subject: libata: fix sff host state machine locking while polling + +commit 8eee1d3ed5b6fc8e14389567c9a6f53f82bb7224 upstream. + +The bulk of ATA host state machine is implemented by +ata_sff_hsm_move(). The function is called from either the interrupt +handler or, if polling, a work item. Unlike from the interrupt path, +the polling path calls the function without holding the host lock and +ata_sff_hsm_move() selectively grabs the lock. + +This is completely broken. If an IRQ triggers while polling is in +progress, the two can easily race and end up accessing the hardware +and updating state machine state at the same time. This can put the +state machine in an illegal state and lead to a crash like the +following. + + kernel BUG at drivers/ata/libata-sff.c:1302! + invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN + Modules linked in: + CPU: 1 PID: 10679 Comm: syz-executor Not tainted 4.5.0-rc1+ #300 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 + task: ffff88002bd00000 ti: ffff88002e048000 task.ti: ffff88002e048000 + RIP: 0010:[<ffffffff83a83409>] [<ffffffff83a83409>] ata_sff_hsm_move+0x619/0x1c60 + ... + Call Trace: + <IRQ> + [<ffffffff83a84c31>] __ata_sff_port_intr+0x1e1/0x3a0 drivers/ata/libata-sff.c:1584 + [<ffffffff83a85611>] ata_bmdma_port_intr+0x71/0x400 drivers/ata/libata-sff.c:2877 + [< inline >] __ata_sff_interrupt drivers/ata/libata-sff.c:1629 + [<ffffffff83a85bf3>] ata_bmdma_interrupt+0x253/0x580 drivers/ata/libata-sff.c:2902 + [<ffffffff81479f98>] handle_irq_event_percpu+0x108/0x7e0 kernel/irq/handle.c:157 + [<ffffffff8147a717>] handle_irq_event+0xa7/0x140 kernel/irq/handle.c:205 + [<ffffffff81484573>] handle_edge_irq+0x1e3/0x8d0 kernel/irq/chip.c:623 + [< inline >] generic_handle_irq_desc include/linux/irqdesc.h:146 + [<ffffffff811a92bc>] handle_irq+0x10c/0x2a0 arch/x86/kernel/irq_64.c:78 + [<ffffffff811a7e4d>] do_IRQ+0x7d/0x1a0 arch/x86/kernel/irq.c:240 + [<ffffffff86653d4c>] common_interrupt+0x8c/0x8c arch/x86/entry/entry_64.S:520 + <EOI> + [< inline >] rcu_lock_acquire include/linux/rcupdate.h:490 + [< inline >] rcu_read_lock include/linux/rcupdate.h:874 + [<ffffffff8164b4a1>] filemap_map_pages+0x131/0xba0 mm/filemap.c:2145 + [< inline >] do_fault_around mm/memory.c:2943 + [< inline >] do_read_fault mm/memory.c:2962 + [< inline >] do_fault mm/memory.c:3133 + [< inline >] handle_pte_fault mm/memory.c:3308 + [< inline >] __handle_mm_fault mm/memory.c:3418 + [<ffffffff816efb16>] handle_mm_fault+0x2516/0x49a0 mm/memory.c:3447 + [<ffffffff8127dc16>] __do_page_fault+0x376/0x960 arch/x86/mm/fault.c:1238 + [<ffffffff8127e358>] trace_do_page_fault+0xe8/0x420 arch/x86/mm/fault.c:1331 + [<ffffffff8126f514>] do_async_page_fault+0x14/0xd0 arch/x86/kernel/kvm.c:264 + [<ffffffff86655578>] async_page_fault+0x28/0x30 arch/x86/entry/entry_64.S:986 + +Fix it by ensuring that the polling path is holding the host lock +before entering ata_sff_hsm_move() so that all hardware accesses and +state updates are performed under the host lock. + +Signed-off-by: Tejun Heo <tj@kernel.org> +Reported-and-tested-by: Dmitry Vyukov <dvyukov@google.com> +Link: http://lkml.kernel.org/g/CACT4Y+b_JsOxJu2EZyEf+mOXORc_zid5V1-pLZSroJVxyWdSpw@mail.gmail.com +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/ata/libata-sff.c | 32 +++++++++++--------------------- + 1 file changed, 11 insertions(+), 21 deletions(-) + +--- a/drivers/ata/libata-sff.c ++++ b/drivers/ata/libata-sff.c +@@ -997,12 +997,9 @@ static inline int ata_hsm_ok_in_wq(struc + static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) + { + struct ata_port *ap = qc->ap; +- unsigned long flags; + + if (ap->ops->error_handler) { + if (in_wq) { +- spin_lock_irqsave(ap->lock, flags); +- + /* EH might have kicked in while host lock is + * released. + */ +@@ -1014,8 +1011,6 @@ static void ata_hsm_qc_complete(struct a + } else + ata_port_freeze(ap); + } +- +- spin_unlock_irqrestore(ap->lock, flags); + } else { + if (likely(!(qc->err_mask & AC_ERR_HSM))) + ata_qc_complete(qc); +@@ -1024,10 +1019,8 @@ static void ata_hsm_qc_complete(struct a + } + } else { + if (in_wq) { +- spin_lock_irqsave(ap->lock, flags); + ata_sff_irq_on(ap); + ata_qc_complete(qc); +- spin_unlock_irqrestore(ap->lock, flags); + } else + ata_qc_complete(qc); + } +@@ -1048,9 +1041,10 @@ int ata_sff_hsm_move(struct ata_port *ap + { + struct ata_link *link = qc->dev->link; + struct ata_eh_info *ehi = &link->eh_info; +- unsigned long flags = 0; + int poll_next; + ++ lockdep_assert_held(ap->lock); ++ + WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0); + + /* Make sure ata_sff_qc_issue() does not throw things +@@ -1112,14 +1106,6 @@ fsm_start: + } + } + +- /* Send the CDB (atapi) or the first data block (ata pio out). +- * During the state transition, interrupt handler shouldn't +- * be invoked before the data transfer is complete and +- * hsm_task_state is changed. Hence, the following locking. +- */ +- if (in_wq) +- spin_lock_irqsave(ap->lock, flags); +- + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. +@@ -1135,9 +1121,6 @@ fsm_start: + /* send CDB */ + atapi_send_cdb(ap, qc); + +- if (in_wq) +- spin_unlock_irqrestore(ap->lock, flags); +- + /* if polling, ata_sff_pio_task() handles the rest. + * otherwise, interrupt handler takes over from here. + */ +@@ -1361,12 +1344,14 @@ static void ata_sff_pio_task(struct work + u8 status; + int poll_next; + ++ spin_lock_irq(ap->lock); ++ + BUG_ON(ap->sff_pio_task_link == NULL); + /* qc can be NULL if timeout occurred */ + qc = ata_qc_from_tag(ap, link->active_tag); + if (!qc) { + ap->sff_pio_task_link = NULL; +- return; ++ goto out_unlock; + } + + fsm_start: +@@ -1381,11 +1366,14 @@ fsm_start: + */ + status = ata_sff_busy_wait(ap, ATA_BUSY, 5); + if (status & ATA_BUSY) { ++ spin_unlock_irq(ap->lock); + ata_msleep(ap, 2); ++ spin_lock_irq(ap->lock); ++ + status = ata_sff_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE); +- return; ++ goto out_unlock; + } + } + +@@ -1402,6 +1390,8 @@ fsm_start: + */ + if (poll_next) + goto fsm_start; ++out_unlock: ++ spin_unlock_irq(ap->lock); + } + + /** diff --git a/releases/3.2.78/mm-vmstat-fix-wrong-wq-sleep-when-memory-reclaim-doesn-t-make-any.patch b/releases/3.2.78/mm-vmstat-fix-wrong-wq-sleep-when-memory-reclaim-doesn-t-make-any.patch new file mode 100644 index 00000000..7f3a4473 --- /dev/null +++ b/releases/3.2.78/mm-vmstat-fix-wrong-wq-sleep-when-memory-reclaim-doesn-t-make-any.patch @@ -0,0 +1,49 @@ +From: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp> +Date: Fri, 5 Feb 2016 15:36:30 -0800 +Subject: mm, vmstat: fix wrong WQ sleep when memory reclaim doesn't make any + progress + +commit 564e81a57f9788b1475127012e0fd44e9049e342 upstream. + +Jan Stancek has reported that system occasionally hanging after "oom01" +testcase from LTP triggers OOM. Guessing from a result that there is a +kworker thread doing memory allocation and the values between "Node 0 +Normal free:" and "Node 0 Normal:" differs when hanging, vmstat is not +up-to-date for some reason. + +According to commit 373ccbe59270 ("mm, vmstat: allow WQ concurrency to +discover memory reclaim doesn't make any progress"), it meant to force +the kworker thread to take a short sleep, but it by error used +schedule_timeout(1). We missed that schedule_timeout() in state +TASK_RUNNING doesn't do anything. + +Fix it by using schedule_timeout_uninterruptible(1) which forces the +kworker thread to take a short sleep in order to make sure that vmstat +is up-to-date. + +Fixes: 373ccbe59270 ("mm, vmstat: allow WQ concurrency to discover memory reclaim doesn't make any progress") +Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> +Reported-by: Jan Stancek <jstancek@redhat.com> +Acked-by: Michal Hocko <mhocko@suse.com> +Cc: Tejun Heo <tj@kernel.org> +Cc: Cristopher Lameter <clameter@sgi.com> +Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> +Cc: Arkadiusz Miskiewicz <arekm@maven.pl> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + mm/backing-dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/mm/backing-dev.c ++++ b/mm/backing-dev.c +@@ -879,7 +879,7 @@ long wait_iff_congested(struct zone *zon + * here rather than calling cond_resched(). + */ + if (current->flags & PF_WQ_WORKER) +- schedule_timeout(1); ++ schedule_timeout_uninterruptible(1); + else + cond_resched(); + diff --git a/releases/3.2.78/ocfs2-dlm-clear-refmap-bit-of-recovery-lock-while-doing-local.patch b/releases/3.2.78/ocfs2-dlm-clear-refmap-bit-of-recovery-lock-while-doing-local.patch new file mode 100644 index 00000000..bf8c7060 --- /dev/null +++ b/releases/3.2.78/ocfs2-dlm-clear-refmap-bit-of-recovery-lock-while-doing-local.patch @@ -0,0 +1,35 @@ +From: xuejiufei <xuejiufei@huawei.com> +Date: Fri, 5 Feb 2016 15:36:47 -0800 +Subject: ocfs2/dlm: clear refmap bit of recovery lock while doing local + recovery cleanup + +commit c95a51807b730e4681e2ecbdfd669ca52601959e upstream. + +When recovery master down, dlm_do_local_recovery_cleanup() only remove +the $RECOVERY lock owned by dead node, but do not clear the refmap bit. +Which will make umount thread falling in dead loop migrating $RECOVERY +to the dead node. + +Signed-off-by: xuejiufei <xuejiufei@huawei.com> +Reviewed-by: Joseph Qi <joseph.qi@huawei.com> +Cc: Mark Fasheh <mfasheh@suse.de> +Cc: Joel Becker <jlbec@evilplan.org> +Cc: Junxiao Bi <junxiao.bi@oracle.com> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + fs/ocfs2/dlm/dlmrecovery.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/ocfs2/dlm/dlmrecovery.c ++++ b/fs/ocfs2/dlm/dlmrecovery.c +@@ -2333,6 +2333,8 @@ static void dlm_do_local_recovery_cleanu + break; + } + } ++ dlm_lockres_clear_refmap_bit(dlm, res, ++ dead_node); + spin_unlock(&res->spinlock); + continue; + } diff --git a/releases/3.2.78/pci-aer-flush-workqueue-on-device-remove-to-avoid-use-after-free.patch b/releases/3.2.78/pci-aer-flush-workqueue-on-device-remove-to-avoid-use-after-free.patch new file mode 100644 index 00000000..e63eaf02 --- /dev/null +++ b/releases/3.2.78/pci-aer-flush-workqueue-on-device-remove-to-avoid-use-after-free.patch @@ -0,0 +1,94 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Mon, 25 Jan 2016 10:08:00 -0600 +Subject: PCI/AER: Flush workqueue on device remove to avoid use-after-free + +commit 4ae2182b1e3407de369f8c5d799543b7db74221b upstream. + +A Root Port's AER structure (rpc) contains a queue of events. aer_irq() +enqueues AER status information and schedules aer_isr() to dequeue and +process it. When we remove a device, aer_remove() waits for the queue to +be empty, then frees the rpc struct. + +But aer_isr() references the rpc struct after dequeueing and possibly +emptying the queue, which can cause a use-after-free error as in the +following scenario with two threads, aer_isr() on the left and a +concurrent aer_remove() on the right: + + Thread A Thread B + -------- -------- + aer_irq(): + rpc->prod_idx++ + aer_remove(): + wait_event(rpc->prod_idx == rpc->cons_idx) + # now blocked until queue becomes empty + aer_isr(): # ... + rpc->cons_idx++ # unblocked because queue is now empty + ... kfree(rpc) + mutex_unlock(&rpc->rpc_mutex) + +To prevent this problem, use flush_work() to wait until the last scheduled +instance of aer_isr() has completed before freeing the rpc struct in +aer_remove(). + +I reproduced this use-after-free by flashing a device FPGA and +re-enumerating the bus to find the new device. With SLUB debug, this +crashes with 0x6b bytes (POISON_FREE, the use-after-free magic number) in +GPR25: + + pcieport 0000:00:00.0: AER: Multiple Corrected error received: id=0000 + Unable to handle kernel paging request for data at address 0x27ef9e3e + Workqueue: events aer_isr + GPR24: dd6aa000 6b6b6b6b 605f8378 605f8360 d99b12c0 604fc674 606b1704 d99b12c0 + NIP [602f5328] pci_walk_bus+0xd4/0x104 + +[bhelgaas: changelog, stable tag] +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/pci/pcie/aer/aerdrv.c | 4 +--- + drivers/pci/pcie/aer/aerdrv.h | 1 - + drivers/pci/pcie/aer/aerdrv_core.c | 2 -- + 3 files changed, 1 insertion(+), 6 deletions(-) + +--- a/drivers/pci/pcie/aer/aerdrv.c ++++ b/drivers/pci/pcie/aer/aerdrv.c +@@ -263,7 +263,6 @@ static struct aer_rpc *aer_alloc_rpc(str + rpc->rpd = dev; + INIT_WORK(&rpc->dpc_handler, aer_isr); + mutex_init(&rpc->rpc_mutex); +- init_waitqueue_head(&rpc->wait_release); + + /* Use PCIe bus function to store rpc into PCIe device */ + set_service_data(dev, rpc); +@@ -286,8 +285,7 @@ static void aer_remove(struct pcie_devic + if (rpc->isr) + free_irq(dev->irq, dev); + +- wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx); +- ++ flush_work(&rpc->dpc_handler); + aer_disable_rootport(rpc); + kfree(rpc); + set_service_data(dev, NULL); +--- a/drivers/pci/pcie/aer/aerdrv.h ++++ b/drivers/pci/pcie/aer/aerdrv.h +@@ -76,7 +76,6 @@ struct aer_rpc { + * recovery on the same + * root port hierarchy + */ +- wait_queue_head_t wait_release; + }; + + struct aer_broadcast_data { +--- a/drivers/pci/pcie/aer/aerdrv_core.c ++++ b/drivers/pci/pcie/aer/aerdrv_core.c +@@ -823,8 +823,6 @@ void aer_isr(struct work_struct *work) + while (get_e_source(rpc, &e_src)) + aer_isr_one_error(p_device, &e_src); + mutex_unlock(&rpc->rpc_mutex); +- +- wake_up(&rpc->wait_release); + } + + /** diff --git a/releases/3.2.78/perf-annotate-browser-fix-behaviour-of-shift-tab-with-nothing.patch b/releases/3.2.78/perf-annotate-browser-fix-behaviour-of-shift-tab-with-nothing.patch new file mode 100644 index 00000000..05a40268 --- /dev/null +++ b/releases/3.2.78/perf-annotate-browser-fix-behaviour-of-shift-tab-with-nothing.patch @@ -0,0 +1,39 @@ +From: Markus Trippelsdorf <markus@trippelsdorf.de> +Date: Mon, 14 Dec 2015 16:44:03 +0100 +Subject: perf annotate browser: Fix behaviour of Shift-Tab with nothing + focussed + +commit d4913cbd05bab685e49c8174896e563b2487d054 upstream. + +The issue was pointed out by gcc-6's -Wmisleading-indentation. + +Signed-off-by: Markus Trippelsdorf <markus@trippelsdorf.de> +Acked-by: Ingo Molnar <mingo@kernel.org> +Cc: Ben Hutchings <ben@decadent.org.uk> +Cc: Matt Fleming <matt@codeblueprint.co.uk> +Cc: Peter Zijlstra <peterz@infradead.org> +Fixes: c97cf42219b7 ("perf top: Live TUI Annotation") +Link: http://lkml.kernel.org/r/20151214154403.GB1409@x4 +Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> +[bwh: Backported to 3.2: adjust filename, context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + tools/perf/util/ui/browsers/annotate.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/tools/perf/util/ui/browsers/annotate.c ++++ b/tools/perf/util/ui/browsers/annotate.c +@@ -276,11 +276,11 @@ static int annotate_browser__run(struct + nd = self->curr_hot; + break; + case K_UNTAB: +- if (nd != NULL) ++ if (nd != NULL) { + nd = rb_next(nd); + if (nd == NULL) + nd = rb_first(&self->entries); +- else ++ } else + nd = self->curr_hot; + break; + case 'H': diff --git a/releases/3.2.78/pipe-fix-buffer-offset-after-partially-failed-read.patch b/releases/3.2.78/pipe-fix-buffer-offset-after-partially-failed-read.patch new file mode 100644 index 00000000..1d0d29b7 --- /dev/null +++ b/releases/3.2.78/pipe-fix-buffer-offset-after-partially-failed-read.patch @@ -0,0 +1,51 @@ +From: Ben Hutchings <ben@decadent.org.uk> +Date: Sat, 13 Feb 2016 02:34:52 +0000 +Subject: pipe: Fix buffer offset after partially failed read + +Quoting the RHEL advisory: + +> It was found that the fix for CVE-2015-1805 incorrectly kept buffer +> offset and buffer length in sync on a failed atomic read, potentially +> resulting in a pipe buffer state corruption. A local, unprivileged user +> could use this flaw to crash the system or leak kernel memory to user +> space. (CVE-2016-0774, Moderate) + +The same flawed fix was applied to stable branches from 2.6.32.y to +3.14.y inclusive, and I was able to reproduce the issue on 3.2.y. +We need to give pipe_iov_copy_to_user() a separate offset variable +and only update the buffer offset if it succeeds. + +References: https://rhn.redhat.com/errata/RHSA-2016-0103.html +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -395,6 +395,7 @@ pipe_read(struct kiocb *iocb, const stru + void *addr; + size_t chars = buf->len, remaining; + int error, atomic; ++ int offset; + + if (chars > total_len) + chars = total_len; +@@ -408,9 +409,10 @@ pipe_read(struct kiocb *iocb, const stru + + atomic = !iov_fault_in_pages_write(iov, chars); + remaining = chars; ++ offset = buf->offset; + redo: + addr = ops->map(pipe, buf, atomic); +- error = pipe_iov_copy_to_user(iov, addr, &buf->offset, ++ error = pipe_iov_copy_to_user(iov, addr, &offset, + &remaining, atomic); + ops->unmap(pipe, buf, addr); + if (unlikely(error)) { +@@ -426,6 +428,7 @@ redo: + break; + } + ret += chars; ++ buf->offset += chars; + buf->len -= chars; + + /* Was it a packet buffer? Clean up and exit */ + diff --git a/releases/3.2.78/pipe-limit-the-per-user-amount-of-pages-allocated-in-pipes.patch b/releases/3.2.78/pipe-limit-the-per-user-amount-of-pages-allocated-in-pipes.patch new file mode 100644 index 00000000..546353c4 --- /dev/null +++ b/releases/3.2.78/pipe-limit-the-per-user-amount-of-pages-allocated-in-pipes.patch @@ -0,0 +1,240 @@ +From: Willy Tarreau <w@1wt.eu> +Date: Mon, 18 Jan 2016 16:36:09 +0100 +Subject: pipe: limit the per-user amount of pages allocated in pipes + +commit 759c01142a5d0f364a462346168a56de28a80f52 upstream. + +On no-so-small systems, it is possible for a single process to cause an +OOM condition by filling large pipes with data that are never read. A +typical process filling 4000 pipes with 1 MB of data will use 4 GB of +memory. On small systems it may be tricky to set the pipe max size to +prevent this from happening. + +This patch makes it possible to enforce a per-user soft limit above +which new pipes will be limited to a single page, effectively limiting +them to 4 kB each, as well as a hard limit above which no new pipes may +be created for this user. This has the effect of protecting the system +against memory abuse without hurting other users, and still allowing +pipes to work correctly though with less data at once. + +The limit are controlled by two new sysctls : pipe-user-pages-soft, and +pipe-user-pages-hard. Both may be disabled by setting them to zero. The +default soft limit allows the default number of FDs per process (1024) +to create pipes of the default size (64kB), thus reaching a limit of 64MB +before starting to create only smaller pipes. With 256 processes limited +to 1024 FDs each, this results in 1024*64kB + (256*1024 - 1024) * 4kB = +1084 MB of memory allocated for a user. The hard limit is disabled by +default to avoid breaking existing applications that make intensive use +of pipes (eg: for splicing). + +Reported-by: socketpair@gmail.com +Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> +Mitigates: CVE-2013-4312 (Linux 2.0+) +Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> +Signed-off-by: Willy Tarreau <w@1wt.eu> +Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> +[bwh: Backported to 3.2: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + Documentation/sysctl/fs.txt | 23 ++++++++++++++++++++++ + fs/pipe.c | 47 +++++++++++++++++++++++++++++++++++++++++++-- + include/linux/pipe_fs_i.h | 4 ++++ + include/linux/sched.h | 1 + + kernel/sysctl.c | 14 ++++++++++++++ + 5 files changed, 87 insertions(+), 2 deletions(-) + +--- a/Documentation/sysctl/fs.txt ++++ b/Documentation/sysctl/fs.txt +@@ -32,6 +32,8 @@ Currently, these files are in /proc/sys/ + - nr_open + - overflowuid + - overflowgid ++- pipe-user-pages-hard ++- pipe-user-pages-soft + - suid_dumpable + - super-max + - super-nr +@@ -157,6 +159,27 @@ The default is 65534. + + ============================================================== + ++pipe-user-pages-hard: ++ ++Maximum total number of pages a non-privileged user may allocate for pipes. ++Once this limit is reached, no new pipes may be allocated until usage goes ++below the limit again. When set to 0, no limit is applied, which is the default ++setting. ++ ++============================================================== ++ ++pipe-user-pages-soft: ++ ++Maximum total number of pages a non-privileged user may allocate for pipes ++before the pipe size gets limited to a single page. Once this limit is reached, ++new pipes will be limited to a single page in size for this user in order to ++limit total memory usage, and trying to increase them using fcntl() will be ++denied until usage goes below the limit again. The default value allows to ++allocate up to 1024 pipes at their default size. When set to 0, no limit is ++applied. ++ ++============================================================== ++ + suid_dumpable: + + This value can be used to query and set the core dump mode for setuid +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -35,6 +35,12 @@ unsigned int pipe_max_size = 1048576; + */ + unsigned int pipe_min_size = PAGE_SIZE; + ++/* Maximum allocatable pages per user. Hard limit is unset by default, soft ++ * matches default values. ++ */ ++unsigned long pipe_user_pages_hard; ++unsigned long pipe_user_pages_soft = PIPE_DEF_BUFFERS * INR_OPEN_CUR; ++ + /* + * We use a start+len construction, which provides full use of the + * allocated memory. +@@ -929,20 +935,49 @@ const struct file_operations rdwr_pipefi + .fasync = pipe_rdwr_fasync, + }; + ++static void account_pipe_buffers(struct pipe_inode_info *pipe, ++ unsigned long old, unsigned long new) ++{ ++ atomic_long_add(new - old, &pipe->user->pipe_bufs); ++} ++ ++static bool too_many_pipe_buffers_soft(struct user_struct *user) ++{ ++ return pipe_user_pages_soft && ++ atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_soft; ++} ++ ++static bool too_many_pipe_buffers_hard(struct user_struct *user) ++{ ++ return pipe_user_pages_hard && ++ atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_hard; ++} ++ + struct pipe_inode_info * alloc_pipe_info(struct inode *inode) + { + struct pipe_inode_info *pipe; + + pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); + if (pipe) { +- pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * PIPE_DEF_BUFFERS, GFP_KERNEL); ++ unsigned long pipe_bufs = PIPE_DEF_BUFFERS; ++ struct user_struct *user = get_current_user(); ++ ++ if (!too_many_pipe_buffers_hard(user)) { ++ if (too_many_pipe_buffers_soft(user)) ++ pipe_bufs = 1; ++ pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * pipe_bufs, GFP_KERNEL); ++ } ++ + if (pipe->bufs) { + init_waitqueue_head(&pipe->wait); + pipe->r_counter = pipe->w_counter = 1; + pipe->inode = inode; +- pipe->buffers = PIPE_DEF_BUFFERS; ++ pipe->buffers = pipe_bufs; ++ pipe->user = user; ++ account_pipe_buffers(pipe, 0, pipe_bufs); + return pipe; + } ++ free_uid(user); + kfree(pipe); + } + +@@ -953,6 +988,8 @@ void __free_pipe_info(struct pipe_inode_ + { + int i; + ++ account_pipe_buffers(pipe, pipe->buffers, 0); ++ free_uid(pipe->user); + for (i = 0; i < pipe->buffers; i++) { + struct pipe_buffer *buf = pipe->bufs + i; + if (buf->ops) +@@ -1201,6 +1238,7 @@ static long pipe_set_size(struct pipe_in + memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer)); + } + ++ account_pipe_buffers(pipe, pipe->buffers, nr_pages); + pipe->curbuf = 0; + kfree(pipe->bufs); + pipe->bufs = bufs; +@@ -1274,6 +1312,11 @@ long pipe_fcntl(struct file *file, unsig + if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { + ret = -EPERM; + goto out; ++ } else if ((too_many_pipe_buffers_hard(pipe->user) || ++ too_many_pipe_buffers_soft(pipe->user)) && ++ !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) { ++ ret = -EPERM; ++ goto out; + } + ret = pipe_set_size(pipe, nr_pages); + break; +--- a/include/linux/pipe_fs_i.h ++++ b/include/linux/pipe_fs_i.h +@@ -43,6 +43,7 @@ struct pipe_buffer { + * @fasync_writers: writer side fasync + * @inode: inode this pipe is attached to + * @bufs: the circular array of pipe buffers ++ * @user: the user who created this pipe + **/ + struct pipe_inode_info { + wait_queue_head_t wait; +@@ -57,6 +58,7 @@ struct pipe_inode_info { + struct fasync_struct *fasync_writers; + struct inode *inode; + struct pipe_buffer *bufs; ++ struct user_struct *user; + }; + + /* +@@ -142,6 +144,8 @@ void pipe_unlock(struct pipe_inode_info + void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *); + + extern unsigned int pipe_max_size, pipe_min_size; ++extern unsigned long pipe_user_pages_hard; ++extern unsigned long pipe_user_pages_soft; + int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *); + + +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -710,6 +710,7 @@ struct user_struct { + #endif + unsigned long locked_shm; /* How many pages of mlocked shm ? */ + unsigned long unix_inflight; /* How many files in flight in unix sockets */ ++ atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */ + + #ifdef CONFIG_KEYS + struct key *uid_keyring; /* UID specific keyring */ +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -1518,6 +1518,20 @@ static struct ctl_table fs_table[] = { + .proc_handler = &pipe_proc_fn, + .extra1 = &pipe_min_size, + }, ++ { ++ .procname = "pipe-user-pages-hard", ++ .data = &pipe_user_pages_hard, ++ .maxlen = sizeof(pipe_user_pages_hard), ++ .mode = 0644, ++ .proc_handler = proc_doulongvec_minmax, ++ }, ++ { ++ .procname = "pipe-user-pages-soft", ++ .data = &pipe_user_pages_soft, ++ .maxlen = sizeof(pipe_user_pages_soft), ++ .mode = 0644, ++ .proc_handler = proc_doulongvec_minmax, ++ }, + { } + }; + diff --git a/releases/3.2.78/posix-timers-handle-relative-timers-with-config_time_low_res-proper.patch b/releases/3.2.78/posix-timers-handle-relative-timers-with-config_time_low_res-proper.patch new file mode 100644 index 00000000..91b08dfd --- /dev/null +++ b/releases/3.2.78/posix-timers-handle-relative-timers-with-config_time_low_res-proper.patch @@ -0,0 +1,36 @@ +From: Thomas Gleixner <tglx@linutronix.de> +Date: Thu, 14 Jan 2016 16:54:47 +0000 +Subject: posix-timers: Handle relative timers with CONFIG_TIME_LOW_RES proper + +commit 572c39172684c3711e4a03c9a7380067e2b0661c upstream. + +As Helge reported for timerfd we have the same issue in posix timers. We +return remaining time larger than the programmed relative time to user space +in case of CONFIG_TIME_LOW_RES=y. Use the proper function to adjust the extra +time added in hrtimer_start_range_ns(). + +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Helge Deller <deller@gmx.de> +Cc: John Stultz <john.stultz@linaro.org> +Cc: linux-m68k@lists.linux-m68k.org +Cc: dhowells@redhat.com +Link: http://lkml.kernel.org/r/20160114164159.450510905@linutronix.de +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +[bwh: Backported to 3.2: adjust filename] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + kernel/posix-timers.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/posix-timers.c ++++ b/kernel/posix-timers.c +@@ -706,7 +706,7 @@ common_timer_get(struct k_itimer *timr, + (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) + timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv); + +- remaining = ktime_sub(hrtimer_get_expires(timer), now); ++ remaining = __hrtimer_expires_remaining_adjusted(timer, now); + /* Return 0 only, when the timer is expired and not pending */ + if (remaining.tv64 <= 0) { + /* diff --git a/releases/3.2.78/pptp-fix-illegal-memory-access-caused-by-multiple-bind-s.patch b/releases/3.2.78/pptp-fix-illegal-memory-access-caused-by-multiple-bind-s.patch new file mode 100644 index 00000000..96dfe708 --- /dev/null +++ b/releases/3.2.78/pptp-fix-illegal-memory-access-caused-by-multiple-bind-s.patch @@ -0,0 +1,111 @@ +From: Hannes Frederic Sowa <hannes@stressinduktion.org> +Date: Fri, 22 Jan 2016 01:39:43 +0100 +Subject: pptp: fix illegal memory access caused by multiple bind()s + +commit 9a368aff9cb370298fa02feeffa861f2db497c18 upstream. + +Several times already this has been reported as kasan reports caused by +syzkaller and trinity and people always looked at RCU races, but it is +much more simple. :) + +In case we bind a pptp socket multiple times, we simply add it to +the callid_sock list but don't remove the old binding. Thus the old +socket stays in the bucket with unused call_id indexes and doesn't get +cleaned up. This causes various forms of kasan reports which were hard +to pinpoint. + +Simply don't allow multiple binds and correct error handling in +pptp_bind. Also keep sk_state bits in place in pptp_connect. + +Fixes: 00959ade36acad ("PPTP: PPP over IPv4 (Point-to-Point Tunneling Protocol)") +Cc: Dmitry Kozlov <xeb@mail.ru> +Cc: Sasha Levin <sasha.levin@oracle.com> +Cc: Dmitry Vyukov <dvyukov@google.com> +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Cc: Dave Jones <davej@codemonkey.org.uk> +Reported-by: Dave Jones <davej@codemonkey.org.uk> +Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/net/ppp/pptp.c | 34 ++++++++++++++++++++++++---------- + 1 file changed, 24 insertions(+), 10 deletions(-) + +--- a/drivers/net/ppp/pptp.c ++++ b/drivers/net/ppp/pptp.c +@@ -131,24 +131,27 @@ static int lookup_chan_dst(u16 call_id, + return i < MAX_CALLID; + } + +-static int add_chan(struct pppox_sock *sock) ++static int add_chan(struct pppox_sock *sock, ++ struct pptp_addr *sa) + { + static int call_id; + + spin_lock(&chan_lock); +- if (!sock->proto.pptp.src_addr.call_id) { ++ if (!sa->call_id) { + call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, call_id + 1); + if (call_id == MAX_CALLID) { + call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, 1); + if (call_id == MAX_CALLID) + goto out_err; + } +- sock->proto.pptp.src_addr.call_id = call_id; +- } else if (test_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap)) ++ sa->call_id = call_id; ++ } else if (test_bit(sa->call_id, callid_bitmap)) { + goto out_err; ++ } + +- set_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap); +- rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], sock); ++ sock->proto.pptp.src_addr = *sa; ++ set_bit(sa->call_id, callid_bitmap); ++ rcu_assign_pointer(callid_sock[sa->call_id], sock); + spin_unlock(&chan_lock); + + return 0; +@@ -417,7 +420,6 @@ static int pptp_bind(struct socket *sock + struct sock *sk = sock->sk; + struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; + struct pppox_sock *po = pppox_sk(sk); +- struct pptp_opt *opt = &po->proto.pptp; + int error = 0; + + if (sockaddr_len < sizeof(struct sockaddr_pppox)) +@@ -425,10 +427,22 @@ static int pptp_bind(struct socket *sock + + lock_sock(sk); + +- opt->src_addr = sp->sa_addr.pptp; +- if (add_chan(po)) ++ if (sk->sk_state & PPPOX_DEAD) { ++ error = -EALREADY; ++ goto out; ++ } ++ ++ if (sk->sk_state & PPPOX_BOUND) { + error = -EBUSY; ++ goto out; ++ } ++ ++ if (add_chan(po, &sp->sa_addr.pptp)) ++ error = -EBUSY; ++ else ++ sk->sk_state |= PPPOX_BOUND; + ++out: + release_sock(sk); + return error; + } +@@ -499,7 +513,7 @@ static int pptp_connect(struct socket *s + } + + opt->dst_addr = sp->sa_addr.pptp; +- sk->sk_state = PPPOX_CONNECTED; ++ sk->sk_state |= PPPOX_CONNECTED; + + end: + release_sock(sk); diff --git a/releases/3.2.78/revert-xhci-don-t-finish-a-td-if-we-get-a-short-transfer-event-mid.patch b/releases/3.2.78/revert-xhci-don-t-finish-a-td-if-we-get-a-short-transfer-event-mid.patch new file mode 100644 index 00000000..30e252bc --- /dev/null +++ b/releases/3.2.78/revert-xhci-don-t-finish-a-td-if-we-get-a-short-transfer-event-mid.patch @@ -0,0 +1,58 @@ +From: Mathias Nyman <mathias.nyman@linux.intel.com> +Date: Tue, 26 Jan 2016 17:50:04 +0200 +Subject: Revert "xhci: don't finish a TD if we get a short-transfer event mid + TD" + +commit a6835090716a85f2297668ba593bd00e1051e662 upstream. + +This reverts commit e210c422b6fd ("xhci: don't finish a TD if we get a +short transfer event mid TD") + +Turns out that most host controllers do not follow the xHCI specs and never +send the second event for the last TRB in the TD if there was a short event +mid-TD. + +Returning the URB directly after the first short-transfer event is far +better than never returning the URB. (class drivers usually timeout +after 30sec). For the hosts that do send the second event we will go +back to treating it as misplaced event and print an error message for it. + +The origial patch was sent to stable kernels and needs to be reverted from +there as well + +Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +[bwh: Backported to 3.2: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/usb/host/xhci-ring.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index f1c21c40b4a6..3915657e6078 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -2187,10 +2187,6 @@ + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); + /* Fast path - was this the last TRB in the TD for this URB? */ + if (event_trb == td->last_trb) { +- if (td->urb_length_set && trb_comp_code == COMP_SHORT_TX) +- return finish_td(xhci, td, event_trb, event, ep, +- status, false); +- + if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { + td->urb->actual_length = + td->urb->transfer_buffer_length - +@@ -2242,12 +2238,6 @@ + td->urb->actual_length += + TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); +- +- if (trb_comp_code == COMP_SHORT_TX) { +- xhci_dbg(xhci, "mid bulk/intr SP, wait for last TRB event\n"); +- td->urb_length_set = true; +- return 0; +- } + } + + return finish_td(xhci, td, event_trb, event, ep, status, false); diff --git a/releases/3.2.78/rfkill-fix-rfkill_fop_read-wait_event-usage.patch b/releases/3.2.78/rfkill-fix-rfkill_fop_read-wait_event-usage.patch new file mode 100644 index 00000000..2c016cbb --- /dev/null +++ b/releases/3.2.78/rfkill-fix-rfkill_fop_read-wait_event-usage.patch @@ -0,0 +1,59 @@ +From: Johannes Berg <johannes.berg@intel.com> +Date: Tue, 26 Jan 2016 11:29:03 +0100 +Subject: rfkill: fix rfkill_fop_read wait_event usage + +commit 6736fde9672ff6717ac576e9bba2fd5f3dfec822 upstream. + +The code within wait_event_interruptible() is called with +!TASK_RUNNING, so mustn't call any functions that can sleep, +like mutex_lock(). + +Since we re-check the list_empty() in a loop after the wait, +it's safe to simply use list_empty() without locking. + +This bug has existed forever, but was only discovered now +because all userspace implementations, including the default +'rfkill' tool, use poll() or select() to get a readable fd +before attempting to read. + +Fixes: c64fb01627e24 ("rfkill: create useful userspace interface") +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: Johannes Berg <johannes.berg@intel.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + net/rfkill/core.c | 16 ++++------------ + 1 file changed, 4 insertions(+), 12 deletions(-) + +--- a/net/rfkill/core.c ++++ b/net/rfkill/core.c +@@ -1065,17 +1065,6 @@ static unsigned int rfkill_fop_poll(stru + return res; + } + +-static bool rfkill_readable(struct rfkill_data *data) +-{ +- bool r; +- +- mutex_lock(&data->mtx); +- r = !list_empty(&data->events); +- mutex_unlock(&data->mtx); +- +- return r; +-} +- + static ssize_t rfkill_fop_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) + { +@@ -1092,8 +1081,11 @@ static ssize_t rfkill_fop_read(struct fi + goto out; + } + mutex_unlock(&data->mtx); ++ /* since we re-check and it just compares pointers, ++ * using !list_empty() without locking isn't a problem ++ */ + ret = wait_event_interruptible(data->read_wait, +- rfkill_readable(data)); ++ !list_empty(&data->events)); + mutex_lock(&data->mtx); + + if (ret) diff --git a/releases/3.2.78/saa7134-alsa-only-frees-registered-sound-cards.patch b/releases/3.2.78/saa7134-alsa-only-frees-registered-sound-cards.patch new file mode 100644 index 00000000..034bbd6c --- /dev/null +++ b/releases/3.2.78/saa7134-alsa-only-frees-registered-sound-cards.patch @@ -0,0 +1,66 @@ +From: Mauro Carvalho Chehab <mchehab@osg.samsung.com> +Date: Thu, 4 Feb 2016 15:59:43 -0200 +Subject: [media] saa7134-alsa: Only frees registered sound cards + +commit ac75fe5d8fe4a0bf063be18fb29684405279e79e upstream. + +That prevents this bug: +[ 2382.269496] BUG: unable to handle kernel NULL pointer dereference at 0000000000000540 +[ 2382.270013] IP: [<ffffffffa01fe616>] snd_card_free+0x36/0x70 [snd] +[ 2382.270013] PGD 0 +[ 2382.270013] Oops: 0002 [#1] SMP +[ 2382.270013] Modules linked in: saa7134_alsa(-) tda1004x saa7134_dvb videobuf2_dvb dvb_core tda827x tda8290 tuner saa7134 tveeprom videobuf2_dma_sg videobuf2_memops videobuf2_v4l2 videobuf2_core v4l2_common videodev media auth_rpcgss nfsv4 dns_resolver nfs lockd grace sunrpc tun bridge stp llc ebtables ip6table_filter ip6_tables nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack it87 hwmon_vid snd_hda_codec_idt snd_hda_codec_generic iTCO_wdt iTCO_vendor_support snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_seq pcspkr i2c_i801 snd_seq_device snd_pcm snd_timer lpc_ich snd mfd_core soundcore binfmt_misc i915 video i2c_algo_bit drm_kms_helper drm r8169 ata_generic serio_raw pata_acpi mii i2c_core [last unloaded: videobuf2_memops] +[ 2382.270013] CPU: 0 PID: 4899 Comm: rmmod Not tainted 4.5.0-rc1+ #4 +[ 2382.270013] Hardware name: PCCHIPS P17G/P17G, BIOS 080012 05/14/2008 +[ 2382.270013] task: ffff880039c38000 ti: ffff88003c764000 task.ti: ffff88003c764000 +[ 2382.270013] RIP: 0010:[<ffffffffa01fe616>] [<ffffffffa01fe616>] snd_card_free+0x36/0x70 [snd] +[ 2382.270013] RSP: 0018:ffff88003c767ea0 EFLAGS: 00010286 +[ 2382.270013] RAX: ffff88003c767eb8 RBX: 0000000000000000 RCX: 0000000000006260 +[ 2382.270013] RDX: ffffffffa020a060 RSI: ffffffffa0206de1 RDI: ffff88003c767eb0 +[ 2382.270013] RBP: ffff88003c767ed8 R08: 0000000000019960 R09: ffffffff811a5412 +[ 2382.270013] R10: ffffea0000d7c200 R11: 0000000000000000 R12: ffff88003c767ea8 +[ 2382.270013] R13: 00007ffe760617f7 R14: 0000000000000000 R15: 0000557625d7f1e0 +[ 2382.270013] FS: 00007f80bb1c0700(0000) GS:ffff88003f400000(0000) knlGS:0000000000000000 +[ 2382.270013] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b +[ 2382.270013] CR2: 0000000000000540 CR3: 000000003c00f000 CR4: 00000000000006f0 +[ 2382.270013] Stack: +[ 2382.270013] 000000003c767ed8 ffffffff00000000 ffff880000000000 ffff88003c767eb8 +[ 2382.270013] ffff88003c767eb8 ffffffffa049a890 00007ffe76060060 ffff88003c767ef0 +[ 2382.270013] ffffffffa049889d ffffffffa049a500 ffff88003c767f48 ffffffff8111079c +[ 2382.270013] Call Trace: +[ 2382.270013] [<ffffffffa049889d>] saa7134_alsa_exit+0x1d/0x780 [saa7134_alsa] +[ 2382.270013] [<ffffffff8111079c>] SyS_delete_module+0x19c/0x1f0 +[ 2382.270013] [<ffffffff8170fc2e>] entry_SYSCALL_64_fastpath+0x12/0x71 +[ 2382.270013] Code: 20 a0 48 c7 c6 e1 6d 20 a0 48 89 e5 41 54 53 4c 8d 65 d0 48 89 fb 48 83 ec 28 c7 45 d0 00 00 00 00 49 8d 7c 24 08 e8 7a 55 ed e0 <4c> 89 a3 40 05 00 00 48 89 df e8 eb fd ff ff 85 c0 75 1a 48 8d +[ 2382.270013] RIP [<ffffffffa01fe616>] snd_card_free+0x36/0x70 [snd] +[ 2382.270013] RSP <ffff88003c767ea0> +[ 2382.270013] CR2: 0000000000000540 + +Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com> +[bwh: Backported to 3.2: adjust filename] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/media/video/saa7134/saa7134-alsa.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/media/video/saa7134/saa7134-alsa.c ++++ b/drivers/media/video/saa7134/saa7134-alsa.c +@@ -1145,6 +1145,8 @@ static int alsa_device_init(struct saa71 + + static int alsa_device_exit(struct saa7134_dev *dev) + { ++ if (!snd_saa7134_cards[dev->nr]) ++ return 1; + + snd_card_free(snd_saa7134_cards[dev->nr]); + snd_saa7134_cards[dev->nr] = NULL; +@@ -1194,7 +1196,8 @@ static void saa7134_alsa_exit(void) + int idx; + + for (idx = 0; idx < SNDRV_CARDS; idx++) { +- snd_card_free(snd_saa7134_cards[idx]); ++ if (snd_saa7134_cards[idx]) ++ snd_card_free(snd_saa7134_cards[idx]); + } + + saa7134_dmasound_init = NULL; diff --git a/releases/3.2.78/sched-fix-__sched_setscheduler-vs-load-balancing-race.patch b/releases/3.2.78/sched-fix-__sched_setscheduler-vs-load-balancing-race.patch new file mode 100644 index 00000000..279701da --- /dev/null +++ b/releases/3.2.78/sched-fix-__sched_setscheduler-vs-load-balancing-race.patch @@ -0,0 +1,50 @@ +From: Mike Galbraith <umgwanakikbuti@gmail.com> +Date: Wed, 17 Feb 2016 04:02:59 +0100 +Subject: sched: fix __sched_setscheduler() vs load balancing race + +__sched_setscheduler() may release rq->lock in pull_rt_task() as a task is +being changed rt -> fair class. load balancing may sneak in, move the task +behind __sched_setscheduler()'s back, which explodes in switched_to_fair() +when the passed but no longer valid rq is used. Tell can_migrate_task() to +say no if ->pi_lock is held. + +@stable: Kernels that predate SCHED_DEADLINE can use this simple (and tested) +check in lieu of backport of the full 18 patch mainline treatment. + +Signed-off-by: Mike Galbraith <umgwanakikbuti@gmail.com> +[bwh: Backported to 3.2: + - Adjust numbering in the comment + - Adjust filename] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +Cc: Byungchul Park <byungchul.park@lge.com> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Willy Tarreau <w@1wt.eu> +--- + kernel/sched/fair.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -2791,6 +2791,7 @@ int can_migrate_task(struct task_struct + * 1) running (obviously), or + * 2) cannot be migrated to this CPU due to cpus_allowed, or + * 3) are cache-hot on their current CPU. ++ * 4) p->pi_lock is held. + */ + if (!cpumask_test_cpu(this_cpu, tsk_cpus_allowed(p))) { + schedstat_inc(p, se.statistics.nr_failed_migrations_affine); +@@ -2804,6 +2805,14 @@ int can_migrate_task(struct task_struct + } + + /* ++ * rt -> fair class change may be in progress. If we sneak in should ++ * double_lock_balance() release rq->lock, and move the task, we will ++ * cause switched_to_fair() to meet a passed but no longer valid rq. ++ */ ++ if (raw_spin_is_locked(&p->pi_lock)) ++ return 0; ++ ++ /* + * Aggressive migration if: + * 1) task is cache cold, or + * 2) too many balance attempts have failed. diff --git a/releases/3.2.78/scsi-fix-crashes-in-sd-and-sr-runtime-pm.patch b/releases/3.2.78/scsi-fix-crashes-in-sd-and-sr-runtime-pm.patch new file mode 100644 index 00000000..6e8f351f --- /dev/null +++ b/releases/3.2.78/scsi-fix-crashes-in-sd-and-sr-runtime-pm.patch @@ -0,0 +1,53 @@ +From: Alan Stern <stern@rowland.harvard.edu> +Date: Wed, 20 Jan 2016 11:26:01 -0500 +Subject: SCSI: fix crashes in sd and sr runtime PM + +commit 13b4389143413a1f18127c07f72c74cad5b563e8 upstream. + +Runtime suspend during driver probe and removal can cause problems. +The driver's runtime_suspend or runtime_resume callbacks may invoked +before the driver has finished binding to the device or after the +driver has unbound from the device. + +This problem shows up with the sd and sr drivers, and can cause disk +or CD/DVD drives to become unusable as a result. The fix is simple. +The drivers store a pointer to the scsi_disk or scsi_cd structure as +their private device data when probing is finished, so we simply have +to be sure to clear the private data during removal and test it during +runtime suspend/resume. + +This fixes <https://bugs.debian.org/801925>. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Reported-by: Paul Menzel <paul.menzel@giantmonkey.de> +Reported-by: Erich Schubert <erich@debian.org> +Reported-by: Alexandre Rossi <alexandre.rossi@gmail.com> +Tested-by: Paul Menzel <paul.menzel@giantmonkey.de> +Tested-by: Erich Schubert <erich@debian.org> +Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> +[bwh: Backported to 3.2: drop changes to sr as it doesn't support runtime PM] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- +--- a/drivers/scsi/sd.c ++++ b/drivers/scsi/sd.c +@@ -2767,8 +2767,8 @@ static int sd_suspend(struct device *dev + struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); + int ret = 0; + +- if (!sdkp) +- return 0; /* this can happen */ ++ if (!sdkp) /* E.g.: runtime suspend following sd_remove() */ ++ return 0; + + if (sdkp->WCE) { + sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); +@@ -2792,6 +2792,9 @@ static int sd_resume(struct device *dev) + struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); + int ret = 0; + ++ if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */ ++ return 0; ++ + if (!sdkp->device->manage_start_stop) + goto done; + diff --git a/releases/3.2.78/scsi_dh_rdac-always-retry-mode-select-on-command-lock-violation.patch b/releases/3.2.78/scsi_dh_rdac-always-retry-mode-select-on-command-lock-violation.patch new file mode 100644 index 00000000..d7b67490 --- /dev/null +++ b/releases/3.2.78/scsi_dh_rdac-always-retry-mode-select-on-command-lock-violation.patch @@ -0,0 +1,40 @@ +From: Hannes Reinecke <hare@suse.de> +Date: Fri, 22 Jan 2016 15:42:41 +0100 +Subject: scsi_dh_rdac: always retry MODE SELECT on command lock violation + +commit d2d06d4fe0f2cc2df9b17fefec96e6e1a1271d91 upstream. + +If MODE SELECT returns with sense '05/91/36' (command lock violation) +it should always be retried without counting the number of retries. +During an HBA upgrade or similar circumstances one might see a flood +of MODE SELECT command from various HBAs, which will easily trigger +the sense code and exceed the retry count. + +Signed-off-by: Hannes Reinecke <hare@suse.de> +Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> +Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/scsi/device_handler/scsi_dh_rdac.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -573,7 +573,7 @@ static int mode_select_handle_sense(stru + /* + * Command Lock contention + */ +- err = SCSI_DH_RETRY; ++ err = SCSI_DH_IMM_RETRY; + break; + default: + break; +@@ -623,6 +623,8 @@ retry: + err = mode_select_handle_sense(sdev, h->sense); + if (err == SCSI_DH_RETRY && retry_cnt--) + goto retry; ++ if (err == SCSI_DH_IMM_RETRY) ++ goto retry; + } + if (err == SCSI_DH_OK) { + h->state = RDAC_STATE_ACTIVE; diff --git a/releases/3.2.78/sctp-allow-setting-sctp_sack_immediately-by-the-application.patch b/releases/3.2.78/sctp-allow-setting-sctp_sack_immediately-by-the-application.patch new file mode 100644 index 00000000..02eb4109 --- /dev/null +++ b/releases/3.2.78/sctp-allow-setting-sctp_sack_immediately-by-the-application.patch @@ -0,0 +1,37 @@ +From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> +Date: Fri, 22 Jan 2016 18:29:49 -0200 +Subject: sctp: allow setting SCTP_SACK_IMMEDIATELY by the application + +commit 27f7ed2b11d42ab6d796e96533c2076ec220affc upstream. + +This patch extends commit b93d6471748d ("sctp: implement the sender side +for SACK-IMMEDIATELY extension") as it didn't white list +SCTP_SACK_IMMEDIATELY on sctp_msghdr_parse(), causing it to be +understood as an invalid flag and returning -EINVAL to the application. + +Note that the actual handling of the flag is already there in +sctp_datamsg_from_user(). + +https://tools.ietf.org/html/rfc7053#section-7 + +Fixes: b93d6471748d ("sctp: implement the sender side for SACK-IMMEDIATELY extension") +Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> +Acked-by: Vlad Yasevich <vyasevich@gmail.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +[bwh: Backported to 3.2: drop the second hunk as we don't have SCTP_SNDINFO + cmsg support] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + net/sctp/socket.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -6241,6 +6241,7 @@ SCTP_STATIC int sctp_msghdr_parse(const + /* Minimally, validate the sinfo_flags. */ + if (cmsgs->info->sinfo_flags & + ~(SCTP_UNORDERED | SCTP_ADDR_OVER | ++ SCTP_SACK_IMMEDIATELY | + SCTP_ABORT | SCTP_EOF)) + return -EINVAL; + break; diff --git a/releases/3.2.78/sctp-translate-network-order-to-host-order-when-users-get-a-hmacid.patch b/releases/3.2.78/sctp-translate-network-order-to-host-order-when-users-get-a-hmacid.patch new file mode 100644 index 00000000..4906c6ed --- /dev/null +++ b/releases/3.2.78/sctp-translate-network-order-to-host-order-when-users-get-a-hmacid.patch @@ -0,0 +1,47 @@ +From: Xin Long <lucien.xin@gmail.com> +Date: Wed, 3 Feb 2016 23:33:30 +0800 +Subject: sctp: translate network order to host order when users get a hmacid + +commit 7a84bd46647ff181eb2659fdc99590e6f16e501d upstream. + +Commit ed5a377d87dc ("sctp: translate host order to network order when +setting a hmacid") corrected the hmacid byte-order when setting a hmacid. +but the same issue also exists on getting a hmacid. + +We fix it by changing hmacids to host order when users get them with +getsockopt. + +Fixes: Commit ed5a377d87dc ("sctp: translate host order to network order when setting a hmacid") +Signed-off-by: Xin Long <lucien.xin@gmail.com> +Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + net/sctp/socket.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -5309,6 +5309,7 @@ static int sctp_getsockopt_hmac_ident(st + struct sctp_hmac_algo_param *hmacs; + __u16 data_len = 0; + u32 num_idents; ++ int i; + + if (!sctp_auth_enable) + return -EACCES; +@@ -5326,8 +5327,12 @@ static int sctp_getsockopt_hmac_ident(st + return -EFAULT; + if (put_user(num_idents, &p->shmac_num_idents)) + return -EFAULT; +- if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len)) +- return -EFAULT; ++ for (i = 0; i < num_idents; i++) { ++ __u16 hmacid = ntohs(hmacs->hmac_ids[i]); ++ ++ if (copy_to_user(&p->shmac_idents[i], &hmacid, sizeof(__u16))) ++ return -EFAULT; ++ } + return 0; + } + diff --git a/releases/3.2.78/series b/releases/3.2.78/series new file mode 100644 index 00000000..f4d3009a --- /dev/null +++ b/releases/3.2.78/series @@ -0,0 +1,67 @@ +kvm-vmx-fix-mpx-detection.patch +hrtimer-handle-remaining-time-proper-for-time_low_res.patch +timerfd-handle-relative-timers-with-config_time_low_res-proper.patch +posix-timers-handle-relative-timers-with-config_time_low_res-proper.patch +itimers-handle-relative-timers-with-config_time_low_res-proper.patch +usb-cdc-acm-send-zero-packet-for-intel-7260-modem.patch +cdc-acm-exclude-samsung-phone-04e8-685d.patch +af_unix-fix-struct-pid-memory-leak.patch +pptp-fix-illegal-memory-access-caused-by-multiple-bind-s.patch +sctp-allow-setting-sctp_sack_immediately-by-the-application.patch +usb-cp210x-add-id-for-iai-usb-to-rs485-adaptor.patch +usb-visor-fix-null-deref-at-probe.patch +usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch +usb-serial-option-adding-support-for-telit-le922.patch +alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch +alsa-seq-degrade-the-error-message-for-too-many-opens.patch +usb-serial-ftdi_sio-add-support-for-yaesu-scu-18-cable.patch +pci-aer-flush-workqueue-on-device-remove-to-avoid-use-after-free.patch +libata-disable-forced-ports_impl-for-ahci-1.3.patch +virtio_pci-fix-use-after-free-on-release.patch +rfkill-fix-rfkill_fop_read-wait_event-usage.patch +perf-annotate-browser-fix-behaviour-of-shift-tab-with-nothing.patch +scsi-fix-crashes-in-sd-and-sr-runtime-pm.patch +tty-fix-unsafe-ldisc-reference-via-ioctl-tiocgetd.patch +crypto-shash-fix-has_key-setting.patch +alsa-dummy-disable-switching-timer-backend-via-sysfs.patch +drm-vmwgfx-respect-nomodeset.patch +x86-mm-pat-avoid-truncation-when-converting-cpa-numpages-to-address.patch +crypto-algif_hash-wait-for-crypto_ahash_init-to-complete.patch +intel_scu_ipcutil-underflow-in-scu_reg_access.patch +alsa-seq-fix-race-at-closing-in-virmidi-driver.patch +alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch +alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch +alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch +alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch +libata-fix-sff-host-state-machine-locking-while-polling.patch +alsa-rawmidi-make-snd_rawmidi_transmit-race-free.patch +alsa-rawmidi-fix-race-at-copying-updating-the-position.patch +alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch +revert-xhci-don-t-finish-a-td-if-we-get-a-short-transfer-event-mid.patch +usb-xhci-apply-xhci_pme_stuck_quirk-to-intel-broxton-m-platforms.patch +xhci-fix-list-corruption-in-urb-dequeue-at-host-removal.patch +tda1004x-only-update-the-frontend-properties-if-locked.patch +alsa-timer-fix-leftover-link-at-closing.patch +saa7134-alsa-only-frees-registered-sound-cards.patch +scsi_dh_rdac-always-retry-mode-select-on-command-lock-violation.patch +mm-vmstat-fix-wrong-wq-sleep-when-memory-reclaim-doesn-t-make-any.patch +ocfs2-dlm-clear-refmap-bit-of-recovery-lock-while-doing-local.patch +crypto-user-lock-crypto_alg_list-on-alg-dump.patch +crypto-algif_skcipher-do-not-dereference-ctx-without-socket-lock.patch +klist-fix-starting-point-removed-bug-in-klist-iterators.patch +alsa-dummy-implement-timer-backend-switching-more-safely.patch +alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch +arm-8517-1-icst-avoid-arithmetic-overflow-in-icst_hz.patch +sctp-translate-network-order-to-host-order-when-users-get-a-hmacid.patch +alsa-timer-fix-race-between-stop-and-interrupt.patch +alsa-timer-fix-race-at-concurrent-reads.patch +ahci-intel-dnv-device-ids-sata.patch +arm-8519-1-icst-try-other-dividends-than-1.patch +btrfs-properly-set-the-termination-value-of-ctx-pos-in-readdir.patch +alsa-usb-audio-avoid-freeing-umidi-object-twice.patch +unix-properly-account-for-fds-passed-over-unix-sockets.patch +unix-correctly-track-in-flight-fds-in-sending-process-user_struct.patch +pipe-limit-the-per-user-amount-of-pages-allocated-in-pipes.patch +iw_cxgb3-fix-incorrectly-returning-error-on-success.patch +pipe-fix-buffer-offset-after-partially-failed-read.patch +sched-fix-__sched_setscheduler-vs-load-balancing-race.patch diff --git a/releases/3.2.78/tda1004x-only-update-the-frontend-properties-if-locked.patch b/releases/3.2.78/tda1004x-only-update-the-frontend-properties-if-locked.patch new file mode 100644 index 00000000..4a6a5c89 --- /dev/null +++ b/releases/3.2.78/tda1004x-only-update-the-frontend-properties-if-locked.patch @@ -0,0 +1,45 @@ +From: Mauro Carvalho Chehab <mchehab@osg.samsung.com> +Date: Wed, 3 Feb 2016 17:33:48 -0200 +Subject: [media] tda1004x: only update the frontend properties if locked + +commit e8beb02343e7582980c6705816cd957cf4f74c7a upstream. + +The tda1004x was updating the properties cache before locking. +If the device is not locked, the data at the registers are just +random values with no real meaning. + +This caused the driver to fail with libdvbv5, as such library +calls GET_PROPERTY from time to time, in order to return the +DVB stats. + +Tested with a saa7134 card 78: + ASUSTeK P7131 Dual, vendor PCI ID: 1043:4862 + +Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com> +[bwh: Backported to 3.2: adjust filename] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/media/dvb/frontends/tda1004x.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/media/dvb/frontends/tda1004x.c ++++ b/drivers/media/dvb/frontends/tda1004x.c +@@ -898,9 +898,18 @@ static int tda1004x_set_fe(struct dvb_fr + static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) + { + struct tda1004x_state* state = fe->demodulator_priv; ++ int status; + + dprintk("%s\n", __func__); + ++ status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); ++ if (status == -1) ++ return -EIO; ++ ++ /* Only update the properties cache if device is locked */ ++ if (!(status & 8)) ++ return 0; ++ + // inversion status + fe_params->inversion = INVERSION_OFF; + if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) diff --git a/releases/3.2.78/timerfd-handle-relative-timers-with-config_time_low_res-proper.patch b/releases/3.2.78/timerfd-handle-relative-timers-with-config_time_low_res-proper.patch new file mode 100644 index 00000000..74ade5d2 --- /dev/null +++ b/releases/3.2.78/timerfd-handle-relative-timers-with-config_time_low_res-proper.patch @@ -0,0 +1,40 @@ +From: Thomas Gleixner <tglx@linutronix.de> +Date: Thu, 14 Jan 2016 16:54:46 +0000 +Subject: timerfd: Handle relative timers with CONFIG_TIME_LOW_RES proper + +commit b62526ed11a1fe3861ab98d40b7fdab8981d788a upstream. + +Helge reported that a relative timer can return a remaining time larger than +the programmed relative time on parisc and other architectures which have +CONFIG_TIME_LOW_RES set. This happens because we add a jiffie to the resulting +expiry time to prevent short timeouts. + +Use the new function hrtimer_expires_remaining_adjusted() to calculate the +remaining time. It takes that extra added time into account for relative +timers. + +Reported-and-tested-by: Helge Deller <deller@gmx.de> +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: John Stultz <john.stultz@linaro.org> +Cc: linux-m68k@lists.linux-m68k.org +Cc: dhowells@redhat.com +Link: http://lkml.kernel.org/r/20160114164159.354500742@linutronix.de +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +[bwh: Backported to 3.2: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + fs/timerfd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/timerfd.c ++++ b/fs/timerfd.c +@@ -123,7 +123,7 @@ static ktime_t timerfd_get_remaining(str + { + ktime_t remaining; + +- remaining = hrtimer_expires_remaining(&ctx->tmr); ++ remaining = hrtimer_expires_remaining_adjusted(&ctx->tmr); + return remaining.tv64 < 0 ? ktime_set(0, 0): remaining; + } + diff --git a/releases/3.2.78/tty-fix-unsafe-ldisc-reference-via-ioctl-tiocgetd.patch b/releases/3.2.78/tty-fix-unsafe-ldisc-reference-via-ioctl-tiocgetd.patch new file mode 100644 index 00000000..e855e53a --- /dev/null +++ b/releases/3.2.78/tty-fix-unsafe-ldisc-reference-via-ioctl-tiocgetd.patch @@ -0,0 +1,65 @@ +From: Peter Hurley <peter@hurleysoftware.com> +Date: Sun, 10 Jan 2016 22:40:55 -0800 +Subject: tty: Fix unsafe ldisc reference via ioctl(TIOCGETD) + +commit 5c17c861a357e9458001f021a7afa7aab9937439 upstream. + +ioctl(TIOCGETD) retrieves the line discipline id directly from the +ldisc because the line discipline id (c_line) in termios is untrustworthy; +userspace may have set termios via ioctl(TCSETS*) without actually +changing the line discipline via ioctl(TIOCSETD). + +However, directly accessing the current ldisc via tty->ldisc is +unsafe; the ldisc ptr dereferenced may be stale if the line discipline +is changing via ioctl(TIOCSETD) or hangup. + +Wait for the line discipline reference (just like read() or write()) +to retrieve the "current" line discipline id. + +Signed-off-by: Peter Hurley <peter@hurleysoftware.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/tty/tty_io.c | 24 +++++++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +--- a/drivers/tty/tty_io.c ++++ b/drivers/tty/tty_io.c +@@ -2475,6 +2475,28 @@ static int tiocsetd(struct tty_struct *t + } + + /** ++ * tiocgetd - get line discipline ++ * @tty: tty device ++ * @p: pointer to user data ++ * ++ * Retrieves the line discipline id directly from the ldisc. ++ * ++ * Locking: waits for ldisc reference (in case the line discipline ++ * is changing or the tty is being hungup) ++ */ ++ ++static int tiocgetd(struct tty_struct *tty, int __user *p) ++{ ++ struct tty_ldisc *ld; ++ int ret; ++ ++ ld = tty_ldisc_ref_wait(tty); ++ ret = put_user(ld->ops->num, p); ++ tty_ldisc_deref(ld); ++ return ret; ++} ++ ++/** + * send_break - performed time break + * @tty: device to break on + * @duration: timeout in mS +@@ -2684,7 +2706,7 @@ long tty_ioctl(struct file *file, unsign + case TIOCGSID: + return tiocgsid(tty, real_tty, p); + case TIOCGETD: +- return put_user(tty->ldisc->ops->num, (int __user *)p); ++ return tiocgetd(tty, p); + case TIOCSETD: + return tiocsetd(tty, p); + case TIOCVHANGUP: diff --git a/releases/3.2.78/unix-correctly-track-in-flight-fds-in-sending-process-user_struct.patch b/releases/3.2.78/unix-correctly-track-in-flight-fds-in-sending-process-user_struct.patch new file mode 100644 index 00000000..afa143b8 --- /dev/null +++ b/releases/3.2.78/unix-correctly-track-in-flight-fds-in-sending-process-user_struct.patch @@ -0,0 +1,148 @@ +From: Hannes Frederic Sowa <hannes@stressinduktion.org> +Date: Wed, 3 Feb 2016 02:11:03 +0100 +Subject: unix: correctly track in-flight fds in sending process user_struct + +commit 415e3d3e90ce9e18727e8843ae343eda5a58fad6 upstream. + +The commit referenced in the Fixes tag incorrectly accounted the number +of in-flight fds over a unix domain socket to the original opener +of the file-descriptor. This allows another process to arbitrary +deplete the original file-openers resource limit for the maximum of +open files. Instead the sending processes and its struct cred should +be credited. + +To do so, we add a reference counted struct user_struct pointer to the +scm_fp_list and use it to account for the number of inflight unix fds. + +Fixes: 712f4aad406bb1 ("unix: properly account for FDs passed over unix sockets") +Reported-by: David Herrmann <dh.herrmann@gmail.com> +Cc: David Herrmann <dh.herrmann@gmail.com> +Cc: Willy Tarreau <w@1wt.eu> +Cc: Linus Torvalds <torvalds@linux-foundation.org> +Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> +Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> +Signed-off-by: David S. Miller <davem@davemloft.net> +[bwh: Backported to 3.2: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + include/net/af_unix.h | 4 ++-- + include/net/scm.h | 1 + + net/core/scm.c | 7 +++++++ + net/unix/af_unix.c | 4 ++-- + net/unix/garbage.c | 8 ++++---- + 5 files changed, 16 insertions(+), 8 deletions(-) + +--- a/include/net/af_unix.h ++++ b/include/net/af_unix.h +@@ -6,8 +6,8 @@ + #include <linux/mutex.h> + #include <net/sock.h> + +-extern void unix_inflight(struct file *fp); +-extern void unix_notinflight(struct file *fp); ++extern void unix_inflight(struct user_struct *user, struct file *fp); ++extern void unix_notinflight(struct user_struct *user, struct file *fp); + extern void unix_gc(void); + extern void wait_for_unix_gc(void); + extern struct sock *unix_get_socket(struct file *filp); +--- a/include/net/scm.h ++++ b/include/net/scm.h +@@ -16,6 +16,7 @@ struct scm_fp_list { + struct list_head list; + short count; + short max; ++ struct user_struct *user; + struct file *fp[SCM_MAX_FD]; + }; + +--- a/net/core/scm.c ++++ b/net/core/scm.c +@@ -80,6 +80,7 @@ static int scm_fp_copy(struct cmsghdr *c + *fplp = fpl; + fpl->count = 0; + fpl->max = SCM_MAX_FD; ++ fpl->user = NULL; + } + fpp = &fpl->fp[fpl->count]; + +@@ -100,6 +101,10 @@ static int scm_fp_copy(struct cmsghdr *c + *fpp++ = file; + fpl->count++; + } ++ ++ if (!fpl->user) ++ fpl->user = get_uid(current_user()); ++ + return num; + } + +@@ -124,6 +129,7 @@ void __scm_destroy(struct scm_cookie *sc + list_del(&fpl->list); + for (i=fpl->count-1; i>=0; i--) + fput(fpl->fp[i]); ++ free_uid(fpl->user); + kfree(fpl); + } + +@@ -342,6 +348,7 @@ struct scm_fp_list *scm_fp_dup(struct sc + for (i = 0; i < fpl->count; i++) + get_file(fpl->fp[i]); + new_fpl->max = new_fpl->count; ++ new_fpl->user = get_uid(fpl->user); + } + return new_fpl; + } +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1454,7 +1454,7 @@ static void unix_detach_fds(struct scm_c + UNIXCB(skb).fp = NULL; + + for (i = scm->fp->count-1; i >= 0; i--) +- unix_notinflight(scm->fp->fp[i]); ++ unix_notinflight(scm->fp->user, scm->fp->fp[i]); + } + + static void unix_destruct_scm(struct sk_buff *skb) +@@ -1520,7 +1520,7 @@ static int unix_attach_fds(struct scm_co + return -ENOMEM; + + for (i = scm->fp->count - 1; i >= 0; i--) +- unix_inflight(scm->fp->fp[i]); ++ unix_inflight(scm->fp->user, scm->fp->fp[i]); + return max_level; + } + +--- a/net/unix/garbage.c ++++ b/net/unix/garbage.c +@@ -122,7 +122,7 @@ struct sock *unix_get_socket(struct file + * descriptor if it is for an AF_UNIX socket. + */ + +-void unix_inflight(struct file *fp) ++void unix_inflight(struct user_struct *user, struct file *fp) + { + struct sock *s = unix_get_socket(fp); + +@@ -138,11 +138,11 @@ void unix_inflight(struct file *fp) + } + unix_tot_inflight++; + } +- fp->f_cred->user->unix_inflight++; ++ user->unix_inflight++; + spin_unlock(&unix_gc_lock); + } + +-void unix_notinflight(struct file *fp) ++void unix_notinflight(struct user_struct *user, struct file *fp) + { + struct sock *s = unix_get_socket(fp); + +@@ -155,7 +155,7 @@ void unix_notinflight(struct file *fp) + list_del_init(&u->link); + unix_tot_inflight--; + } +- fp->f_cred->user->unix_inflight--; ++ user->unix_inflight--; + spin_unlock(&unix_gc_lock); + } + diff --git a/releases/3.2.78/unix-properly-account-for-fds-passed-over-unix-sockets.patch b/releases/3.2.78/unix-properly-account-for-fds-passed-over-unix-sockets.patch new file mode 100644 index 00000000..410b0bf3 --- /dev/null +++ b/releases/3.2.78/unix-properly-account-for-fds-passed-over-unix-sockets.patch @@ -0,0 +1,131 @@ +From: willy tarreau <w@1wt.eu> +Date: Sun, 10 Jan 2016 07:54:56 +0100 +Subject: unix: properly account for FDs passed over unix sockets + +commit 712f4aad406bb1ed67f3f98d04c044191f0ff593 upstream. + +It is possible for a process to allocate and accumulate far more FDs than +the process' limit by sending them over a unix socket then closing them +to keep the process' fd count low. + +This change addresses this problem by keeping track of the number of FDs +in flight per user and preventing non-privileged processes from having +more FDs in flight than their configured FD limit. + +Reported-by: socketpair@gmail.com +Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> +Mitigates: CVE-2013-4312 (Linux 2.0+) +Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> +Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> +Signed-off-by: Willy Tarreau <w@1wt.eu> +Signed-off-by: David S. Miller <davem@davemloft.net> +[carnil: Backported to 3.16: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + include/linux/sched.h | 1 + + net/unix/af_unix.c | 24 ++++++++++++++++++++---- + net/unix/garbage.c | 13 ++++++++----- + 3 files changed, 29 insertions(+), 9 deletions(-) + +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -709,6 +709,7 @@ struct user_struct { + unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */ + #endif + unsigned long locked_shm; /* How many pages of mlocked shm ? */ ++ unsigned long unix_inflight; /* How many files in flight in unix sockets */ + + #ifdef CONFIG_KEYS + struct key *uid_keyring; /* UID specific keyring */ +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1472,6 +1472,21 @@ static void unix_destruct_scm(struct sk_ + sock_wfree(skb); + } + ++/* ++ * The "user->unix_inflight" variable is protected by the garbage ++ * collection lock, and we just read it locklessly here. If you go ++ * over the limit, there might be a tiny race in actually noticing ++ * it across threads. Tough. ++ */ ++static inline bool too_many_unix_fds(struct task_struct *p) ++{ ++ struct user_struct *user = current_user(); ++ ++ if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE))) ++ return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); ++ return false; ++} ++ + #define MAX_RECURSION_LEVEL 4 + + static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) +@@ -1480,6 +1495,9 @@ static int unix_attach_fds(struct scm_co + unsigned char max_level = 0; + int unix_sock_count = 0; + ++ if (too_many_unix_fds(current)) ++ return -ETOOMANYREFS; ++ + for (i = scm->fp->count - 1; i >= 0; i--) { + struct sock *sk = unix_get_socket(scm->fp->fp[i]); + +@@ -1501,10 +1519,8 @@ static int unix_attach_fds(struct scm_co + if (!UNIXCB(skb).fp) + return -ENOMEM; + +- if (unix_sock_count) { +- for (i = scm->fp->count - 1; i >= 0; i--) +- unix_inflight(scm->fp->fp[i]); +- } ++ for (i = scm->fp->count - 1; i >= 0; i--) ++ unix_inflight(scm->fp->fp[i]); + return max_level; + } + +--- a/net/unix/garbage.c ++++ b/net/unix/garbage.c +@@ -125,9 +125,11 @@ struct sock *unix_get_socket(struct file + void unix_inflight(struct file *fp) + { + struct sock *s = unix_get_socket(fp); ++ ++ spin_lock(&unix_gc_lock); ++ + if (s) { + struct unix_sock *u = unix_sk(s); +- spin_lock(&unix_gc_lock); + if (atomic_long_inc_return(&u->inflight) == 1) { + BUG_ON(!list_empty(&u->link)); + list_add_tail(&u->link, &gc_inflight_list); +@@ -135,22 +137,26 @@ void unix_inflight(struct file *fp) + BUG_ON(list_empty(&u->link)); + } + unix_tot_inflight++; +- spin_unlock(&unix_gc_lock); + } ++ fp->f_cred->user->unix_inflight++; ++ spin_unlock(&unix_gc_lock); + } + + void unix_notinflight(struct file *fp) + { + struct sock *s = unix_get_socket(fp); ++ ++ spin_lock(&unix_gc_lock); ++ + if (s) { + struct unix_sock *u = unix_sk(s); +- spin_lock(&unix_gc_lock); + BUG_ON(list_empty(&u->link)); + if (atomic_long_dec_and_test(&u->inflight)) + list_del_init(&u->link); + unix_tot_inflight--; +- spin_unlock(&unix_gc_lock); + } ++ fp->f_cred->user->unix_inflight--; ++ spin_unlock(&unix_gc_lock); + } + + static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), diff --git a/releases/3.2.78/usb-cdc-acm-send-zero-packet-for-intel-7260-modem.patch b/releases/3.2.78/usb-cdc-acm-send-zero-packet-for-intel-7260-modem.patch new file mode 100644 index 00000000..8ab3d129 --- /dev/null +++ b/releases/3.2.78/usb-cdc-acm-send-zero-packet-for-intel-7260-modem.patch @@ -0,0 +1,49 @@ +From: Lu Baolu <baolu.lu@linux.intel.com> +Date: Wed, 6 Jan 2016 15:10:04 +0800 +Subject: usb: cdc-acm: send zero packet for intel 7260 modem + +commit ffdb1e369a73b380fce95b05f8498d92c43842b4 upstream. + +For Intel 7260 modem, it is needed for host side to send zero +packet if the BULK OUT size is equal to USB endpoint max packet +length. Otherwise, modem side may still wait for more data and +cannot give response to host side. + +Signed-off-by: Konrad Leszczynski <konrad.leszczynski@intel.com> +Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/usb/class/cdc-acm.c | 6 ++++++ + drivers/usb/class/cdc-acm.h | 1 + + 2 files changed, 7 insertions(+) + +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1237,6 +1237,8 @@ made_compressed_probe: + usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), + NULL, acm->writesize, acm_write_bulk, snd); + snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ if (quirks & SEND_ZERO_PACKET) ++ snd->urb->transfer_flags |= URB_ZERO_PACKET; + snd->instance = acm; + } + +@@ -1689,6 +1691,10 @@ static const struct usb_device_id acm_id + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_ACM_PROTO_AT_CDMA) }, + ++ { USB_DEVICE(0x1519, 0x0452), /* Intel 7260 modem */ ++ .driver_info = SEND_ZERO_PACKET, ++ }, ++ + { } + }; + +--- a/drivers/usb/class/cdc-acm.h ++++ b/drivers/usb/class/cdc-acm.h +@@ -129,3 +129,4 @@ struct acm { + #define NO_DATA_INTERFACE 16 + #define IGNORE_DEVICE 32 + #define CLEAR_HALT_CONDITIONS BIT(7) ++#define SEND_ZERO_PACKET BIT(8) diff --git a/releases/3.2.78/usb-cp210x-add-id-for-iai-usb-to-rs485-adaptor.patch b/releases/3.2.78/usb-cp210x-add-id-for-iai-usb-to-rs485-adaptor.patch new file mode 100644 index 00000000..59ab441d --- /dev/null +++ b/releases/3.2.78/usb-cp210x-add-id-for-iai-usb-to-rs485-adaptor.patch @@ -0,0 +1,26 @@ +From: Peter Dedecker <peter.dedecker@hotmail.com> +Date: Fri, 8 Jan 2016 12:34:41 +0100 +Subject: USB: cp210x: add ID for IAI USB to RS485 adaptor + +commit f487c54ddd544e1c9172cd510954f697b77b76e3 upstream. + +Added the USB serial console device ID for IAI Corp. RCB-CV-USB +USB to RS485 adaptor. + +Signed-off-by: Peter Dedecker <peter.dedecker@hotmail.com> +Signed-off-by: Johan Hovold <johan@kernel.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/usb/serial/cp210x.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/serial/cp210x.c ++++ b/drivers/usb/serial/cp210x.c +@@ -104,6 +104,7 @@ static const struct usb_device_id id_tab + { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ + { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ + { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ ++ { USB_DEVICE(0x10C4, 0x81D7) }, /* IAI Corp. RCB-CV-USB USB to RS485 Adaptor */ + { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ + { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ + { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */ diff --git a/releases/3.2.78/usb-serial-ftdi_sio-add-support-for-yaesu-scu-18-cable.patch b/releases/3.2.78/usb-serial-ftdi_sio-add-support-for-yaesu-scu-18-cable.patch new file mode 100644 index 00000000..707f74e7 --- /dev/null +++ b/releases/3.2.78/usb-serial-ftdi_sio-add-support-for-yaesu-scu-18-cable.patch @@ -0,0 +1,39 @@ +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Tue, 19 Jan 2016 23:43:13 -0800 +Subject: USB: serial: ftdi_sio: add support for Yaesu SCU-18 cable + +commit e03cdf22a2727c60307be6a729233edab3bfda9c upstream. + +Harald Linden reports that the ftdi_sio driver works properly for the +Yaesu SCU-18 cable if the device ids are added to the driver. So let's +add them. + +Reported-by: Harald Linden <harald.linden@7183.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Johan Hovold <johan@kernel.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/usb/serial/ftdi_sio.c | 1 + + drivers/usb/serial/ftdi_sio_ids.h | 1 + + 2 files changed, 2 insertions(+) + +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -848,6 +848,7 @@ static struct usb_device_id id_table_com + { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, ++ { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) }, + { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) }, + + /* Papouch devices based on FTDI chip */ +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -615,6 +615,7 @@ + */ + #define RATOC_VENDOR_ID 0x0584 + #define RATOC_PRODUCT_ID_USB60F 0xb020 ++#define RATOC_PRODUCT_ID_SCU18 0xb03a + + /* + * Acton Research Corp. diff --git a/releases/3.2.78/usb-serial-option-adding-support-for-telit-le922.patch b/releases/3.2.78/usb-serial-option-adding-support-for-telit-le922.patch new file mode 100644 index 00000000..5e216614 --- /dev/null +++ b/releases/3.2.78/usb-serial-option-adding-support-for-telit-le922.patch @@ -0,0 +1,54 @@ +From: Daniele Palmas <dnlplm@gmail.com> +Date: Tue, 12 Jan 2016 17:22:06 +0100 +Subject: USB: serial: option: Adding support for Telit LE922 + +commit ff4e2494dc17b173468e1713fdf6237fd8578bc7 upstream. + +This patch adds support for two PIDs of LE922. + +Signed-off-by: Daniele Palmas <dnlplm@gmail.com> +Signed-off-by: Johan Hovold <johan@kernel.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/usb/serial/option.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -269,6 +269,8 @@ static void option_instat_callback(struc + #define TELIT_PRODUCT_CC864_SINGLE 0x1006 + #define TELIT_PRODUCT_DE910_DUAL 0x1010 + #define TELIT_PRODUCT_UE910_V2 0x1012 ++#define TELIT_PRODUCT_LE922_USBCFG0 0x1042 ++#define TELIT_PRODUCT_LE922_USBCFG3 0x1043 + #define TELIT_PRODUCT_LE920 0x1200 + #define TELIT_PRODUCT_LE910 0x1201 + +@@ -621,6 +623,16 @@ static const struct option_blacklist_inf + .reserved = BIT(1) | BIT(5), + }; + ++static const struct option_blacklist_info telit_le922_blacklist_usbcfg0 = { ++ .sendsetup = BIT(2), ++ .reserved = BIT(0) | BIT(1) | BIT(3), ++}; ++ ++static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = { ++ .sendsetup = BIT(0), ++ .reserved = BIT(1) | BIT(2) | BIT(3), ++}; ++ + static const struct usb_device_id option_ids[] = { + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, +@@ -1166,6 +1178,10 @@ static const struct usb_device_id option + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) }, ++ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0), ++ .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, ++ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3), ++ .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), + .driver_info = (kernel_ulong_t)&telit_le910_blacklist }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), diff --git a/releases/3.2.78/usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch b/releases/3.2.78/usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch new file mode 100644 index 00000000..87a0cda9 --- /dev/null +++ b/releases/3.2.78/usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch @@ -0,0 +1,34 @@ +From: Vladis Dronov <vdronov@redhat.com> +Date: Tue, 12 Jan 2016 15:10:50 +0100 +Subject: USB: serial: visor: fix crash on detecting device without write_urbs + +commit cb3232138e37129e88240a98a1d2aba2187ff57c upstream. + +The visor driver crashes in clie_5_attach() when a specially crafted USB +device without bulk-out endpoint is detected. This fix adds a check that +the device has proper configuration expected by the driver. + +Reported-by: Ralf Spenneberg <ralf@spenneberg.net> +Signed-off-by: Vladis Dronov <vdronov@redhat.com> +Fixes: cfb8da8f69b8 ("USB: visor: fix initialisation of UX50/TH55 devices") +Signed-off-by: Johan Hovold <johan@kernel.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/usb/serial/visor.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/usb/serial/visor.c ++++ b/drivers/usb/serial/visor.c +@@ -640,8 +640,10 @@ static int clie_5_attach(struct usb_seri + */ + + /* some sanity check */ +- if (serial->num_ports < 2) +- return -1; ++ if (serial->num_bulk_out < 2) { ++ dev_err(&serial->interface->dev, "missing bulk out endpoints\n"); ++ return -ENODEV; ++ } + + /* port 0 now uses the modified endpoint Address */ + port = serial->port[0]; diff --git a/releases/3.2.78/usb-visor-fix-null-deref-at-probe.patch b/releases/3.2.78/usb-visor-fix-null-deref-at-probe.patch new file mode 100644 index 00000000..fceab3d3 --- /dev/null +++ b/releases/3.2.78/usb-visor-fix-null-deref-at-probe.patch @@ -0,0 +1,34 @@ +From: Johan Hovold <johan@kernel.org> +Date: Tue, 12 Jan 2016 12:05:20 +0100 +Subject: USB: visor: fix null-deref at probe + +commit cac9b50b0d75a1d50d6c056ff65c005f3224c8e0 upstream. + +Fix null-pointer dereference at probe should a (malicious) Treo device +lack the expected endpoints. + +Specifically, the Treo port-setup hack was dereferencing the bulk-in and +interrupt-in urbs without first making sure they had been allocated by +core. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Johan Hovold <johan@kernel.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/usb/serial/visor.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/usb/serial/visor.c ++++ b/drivers/usb/serial/visor.c +@@ -587,6 +587,11 @@ static int treo_attach(struct usb_serial + + dbg("%s", __func__); + ++ if (serial->num_bulk_in < 2 || serial->num_interrupt_in < 2) { ++ dev_err(&serial->interface->dev, "missing endpoints\n"); ++ return -ENODEV; ++ } ++ + /* + * It appears that Treos and Kyoceras want to use the + * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, diff --git a/releases/3.2.78/usb-xhci-apply-xhci_pme_stuck_quirk-to-intel-broxton-m-platforms.patch b/releases/3.2.78/usb-xhci-apply-xhci_pme_stuck_quirk-to-intel-broxton-m-platforms.patch new file mode 100644 index 00000000..201326ef --- /dev/null +++ b/releases/3.2.78/usb-xhci-apply-xhci_pme_stuck_quirk-to-intel-broxton-m-platforms.patch @@ -0,0 +1,36 @@ +From: Lu Baolu <baolu.lu@linux.intel.com> +Date: Tue, 26 Jan 2016 17:50:08 +0200 +Subject: usb: xhci: apply XHCI_PME_STUCK_QUIRK to Intel Broxton-M platforms + +commit ccc04afb72cddbdf7c0e1c17e92886405a71b754 upstream. + +Intel Broxton M was verifed to require XHCI_PME_STUCK_QUIRK quirk as well. + +Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> +Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/usb/host/xhci-pci.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -39,6 +39,7 @@ + #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5 + #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f + #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f ++#define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8 + + static const char hcd_name[] = "xhci_hcd"; + +@@ -132,7 +133,8 @@ static void xhci_pci_quirks(struct devic + if (pdev->vendor == PCI_VENDOR_ID_INTEL && + (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || +- pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) { ++ pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || ++ pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI)) { + xhci->quirks |= XHCI_PME_STUCK_QUIRK; + } + if (pdev->vendor == PCI_VENDOR_ID_ETRON && diff --git a/releases/3.2.78/virtio_pci-fix-use-after-free-on-release.patch b/releases/3.2.78/virtio_pci-fix-use-after-free-on-release.patch new file mode 100644 index 00000000..8b14402d --- /dev/null +++ b/releases/3.2.78/virtio_pci-fix-use-after-free-on-release.patch @@ -0,0 +1,42 @@ +From: "Michael S. Tsirkin" <mst@redhat.com> +Date: Thu, 14 Jan 2016 16:00:41 +0200 +Subject: virtio_pci: fix use after free on release + +commit 2989be09a8a9d62a785137586ad941f916e08f83 upstream. + +KASan detected a use-after-free error in virtio-pci remove code. In +virtio_pci_remove(), vp_dev is still used after being freed in +unregister_virtio_device() (in virtio_pci_release_dev() more +precisely). + +To fix, keep a reference until cleanup is done. + +Fixes: 63bd62a08ca4 ("virtio_pci: defer kfree until release callback") +Reported-by: Jerome Marchand <jmarchan@redhat.com> +Cc: Sasha Levin <sasha.levin@oracle.com> +Signed-off-by: Michael S. Tsirkin <mst@redhat.com> +Tested-by: Jerome Marchand <jmarchan@redhat.com> +[bwh: Backported to 3.2: adjust filename] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/virtio/virtio_pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/virtio/virtio_pci.c ++++ b/drivers/virtio/virtio_pci.c +@@ -698,6 +698,7 @@ out: + static void __devexit virtio_pci_remove(struct pci_dev *pci_dev) + { + struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); ++ struct device *dev = get_device(&vp_dev->vdev.dev); + + unregister_virtio_device(&vp_dev->vdev); + +@@ -706,6 +707,7 @@ static void __devexit virtio_pci_remove( + pci_iounmap(pci_dev, vp_dev->ioaddr); + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); ++ put_device(dev); + } + + #ifdef CONFIG_PM diff --git a/releases/3.2.78/x86-mm-pat-avoid-truncation-when-converting-cpa-numpages-to-address.patch b/releases/3.2.78/x86-mm-pat-avoid-truncation-when-converting-cpa-numpages-to-address.patch new file mode 100644 index 00000000..764c995b --- /dev/null +++ b/releases/3.2.78/x86-mm-pat-avoid-truncation-when-converting-cpa-numpages-to-address.patch @@ -0,0 +1,83 @@ +From: Matt Fleming <matt@codeblueprint.co.uk> +Date: Fri, 29 Jan 2016 11:36:10 +0000 +Subject: x86/mm/pat: Avoid truncation when converting cpa->numpages to address +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 742563777e8da62197d6cb4b99f4027f59454735 upstream. + +There are a couple of nasty truncation bugs lurking in the pageattr +code that can be triggered when mapping EFI regions, e.g. when we pass +a cpa->pgd pointer. Because cpa->numpages is a 32-bit value, shifting +left by PAGE_SHIFT will truncate the resultant address to 32-bits. + +Viorel-Cătălin managed to trigger this bug on his Dell machine that +provides a ~5GB EFI region which requires 1236992 pages to be mapped. +When calling populate_pud() the end of the region gets calculated +incorrectly in the following buggy expression, + + end = start + (cpa->numpages << PAGE_SHIFT); + +And only 188416 pages are mapped. Next, populate_pud() gets invoked +for a second time because of the loop in __change_page_attr_set_clr(), +only this time no pages get mapped because shifting the remaining +number of pages (1048576) by PAGE_SHIFT is zero. At which point the +loop in __change_page_attr_set_clr() spins forever because we fail to +map progress. + +Hitting this bug depends very much on the virtual address we pick to +map the large region at and how many pages we map on the initial run +through the loop. This explains why this issue was only recently hit +with the introduction of commit + + a5caa209ba9c ("x86/efi: Fix boot crash by mapping EFI memmap + entries bottom-up at runtime, instead of top-down") + +It's interesting to note that safe uses of cpa->numpages do exist in +the pageattr code. If instead of shifting ->numpages we multiply by +PAGE_SIZE, no truncation occurs because PAGE_SIZE is a UL value, and +so the result is unsigned long. + +To avoid surprises when users try to convert very large cpa->numpages +values to addresses, change the data type from 'int' to 'unsigned +long', thereby making it suitable for shifting by PAGE_SHIFT without +any type casting. + +The alternative would be to make liberal use of casting, but that is +far more likely to cause problems in the future when someone adds more +code and fails to cast properly; this bug was difficult enough to +track down in the first place. + +Reported-and-tested-by: Viorel-Cătălin Răpițeanu <rapiteanu.catalin@gmail.com> +Acked-by: Borislav Petkov <bp@alien8.de> +Cc: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com> +Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk> +Link: https://bugzilla.kernel.org/show_bug.cgi?id=110131 +Link: http://lkml.kernel.org/r/1454067370-10374-1-git-send-email-matt@codeblueprint.co.uk +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + arch/x86/mm/pageattr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/x86/mm/pageattr.c ++++ b/arch/x86/mm/pageattr.c +@@ -32,7 +32,7 @@ struct cpa_data { + unsigned long *vaddr; + pgprot_t mask_set; + pgprot_t mask_clr; +- int numpages; ++ unsigned long numpages; + int flags; + unsigned long pfn; + unsigned force_split : 1; +@@ -820,7 +820,7 @@ static int __change_page_attr_set_clr(st + * CPA operation. Either a large page has been + * preserved or a single page update happened. + */ +- BUG_ON(cpa->numpages > numpages); ++ BUG_ON(cpa->numpages > numpages || !cpa->numpages); + numpages -= cpa->numpages; + if (cpa->flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) + cpa->curpage++; diff --git a/releases/3.2.78/xhci-fix-list-corruption-in-urb-dequeue-at-host-removal.patch b/releases/3.2.78/xhci-fix-list-corruption-in-urb-dequeue-at-host-removal.patch new file mode 100644 index 00000000..6a169218 --- /dev/null +++ b/releases/3.2.78/xhci-fix-list-corruption-in-urb-dequeue-at-host-removal.patch @@ -0,0 +1,36 @@ +From: Mathias Nyman <mathias.nyman@linux.intel.com> +Date: Tue, 26 Jan 2016 17:50:12 +0200 +Subject: xhci: Fix list corruption in urb dequeue at host removal + +commit 5c82171167adb8e4ac77b91a42cd49fb211a81a0 upstream. + +xhci driver frees data for all devices, both usb2 and and usb3 the +first time usb_remove_hcd() is called, including td_list and and xhci_ring +structures. + +When usb_remove_hcd() is called a second time for the second xhci bus it +will try to dequeue all pending urbs, and touches td_list which is already +freed for that endpoint. + +Reported-by: Joe Lawrence <joe.lawrence@stratus.com> +Tested-by: Joe Lawrence <joe.lawrence@stratus.com> +Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/usb/host/xhci.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -1533,7 +1533,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd + if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) { + xhci_dbg(xhci, "HW died, freeing TD.\n"); + urb_priv = urb->hcpriv; +- for (i = urb_priv->td_cnt; i < urb_priv->length; i++) { ++ for (i = urb_priv->td_cnt; ++ i < urb_priv->length && xhci->devs[urb->dev->slot_id]; ++ i++) { + td = urb_priv->td[i]; + if (!list_empty(&td->td_list)) + list_del_init(&td->td_list); |