From 8394f9abcfde617659287681aaf127c3dd3e3ea8 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 22 Oct 2010 10:43:01 -0400 Subject: [PATCH] fix some tpm, rt2x00, and an rds security vulnerability --- depessimize-rds_copy_page_user.patch | 78 ++++++++++ kernel.spec | 21 ++- ...-auto-wakeup-before-waking-up-device.patch | 122 +++++++++++++++ ...EP-AWAKE-and-AWAKE-SLEEP-transitions.patch | 146 ++++++++++++++++++ tpm-autodetect-itpm-devices.patch | 65 ++++++++ 5 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 depessimize-rds_copy_page_user.patch create mode 100644 rt2x00-disable-auto-wakeup-before-waking-up-device.patch create mode 100644 rt2x00-fix-failed-SLEEP-AWAKE-and-AWAKE-SLEEP-transitions.patch create mode 100644 tpm-autodetect-itpm-devices.patch diff --git a/depessimize-rds_copy_page_user.patch b/depessimize-rds_copy_page_user.patch new file mode 100644 index 000000000..aec8bff4d --- /dev/null +++ b/depessimize-rds_copy_page_user.patch @@ -0,0 +1,78 @@ +From 799c10559d60f159ab2232203f222f18fa3c4a5f Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Fri, 15 Oct 2010 11:09:28 -0700 +Subject: [PATCH] De-pessimize rds_page_copy_user + +Don't try to "optimize" rds_page_copy_user() by using kmap_atomic() and +the unsafe atomic user mode accessor functions. It's actually slower +than the straightforward code on any reasonable modern CPU. + +Back when the code was written (although probably not by the time it was +actually merged, though), 32-bit x86 may have been the dominant +architecture. And there kmap_atomic() can be a lot faster than kmap() +(unless you have very good locality, in which case the virtual address +caching by kmap() can overcome all the downsides). + +But these days, x86-64 may not be more populous, but it's getting there +(and if you care about performance, it's definitely already there - +you'd have upgraded your CPU's already in the last few years). And on +x86-64, the non-kmap_atomic() version is faster, simply because the code +is simpler and doesn't have the "re-try page fault" case. + +People with old hardware are not likely to care about RDS anyway, and +the optimization for the 32-bit case is simply buggy, since it doesn't +verify the user addresses properly. + +Reported-by: Dan Rosenberg +Acked-by: Andrew Morton +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +--- + net/rds/page.c | 27 +++++++-------------------- + 1 files changed, 7 insertions(+), 20 deletions(-) + +diff --git a/net/rds/page.c b/net/rds/page.c +index 595a952..1dfbfea 100644 +--- a/net/rds/page.c ++++ b/net/rds/page.c +@@ -57,30 +57,17 @@ int rds_page_copy_user(struct page *page, unsigned long offset, + unsigned long ret; + void *addr; + +- if (to_user) ++ addr = kmap(page); ++ if (to_user) { + rds_stats_add(s_copy_to_user, bytes); +- else ++ ret = copy_to_user(ptr, addr + offset, bytes); ++ } else { + rds_stats_add(s_copy_from_user, bytes); +- +- addr = kmap_atomic(page, KM_USER0); +- if (to_user) +- ret = __copy_to_user_inatomic(ptr, addr + offset, bytes); +- else +- ret = __copy_from_user_inatomic(addr + offset, ptr, bytes); +- kunmap_atomic(addr, KM_USER0); +- +- if (ret) { +- addr = kmap(page); +- if (to_user) +- ret = copy_to_user(ptr, addr + offset, bytes); +- else +- ret = copy_from_user(addr + offset, ptr, bytes); +- kunmap(page); +- if (ret) +- return -EFAULT; ++ ret = copy_from_user(addr + offset, ptr, bytes); + } ++ kunmap(page); + +- return 0; ++ return ret ? -EFAULT : 0; + } + EXPORT_SYMBOL_GPL(rds_page_copy_user); + +-- +1.7.3.2 + diff --git a/kernel.spec b/kernel.spec index 7cb3a4cb2..0de71380d 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 61 +%global baserelease 62 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -838,6 +838,12 @@ Patch13641: mmc-add-ricoh-e822-pci-id.patch Patch13642: mmc-make-sdhci-work-with-ricoh-mmc-controller.patch Patch13643: sdhci-8-bit-data-transfer-width-support.patch +Patch13645: depessimize-rds_copy_page_user.patch +Patch13646: tpm-autodetect-itpm-devices.patch + +Patch13647: rt2x00-disable-auto-wakeup-before-waking-up-device.patch +Patch13648: rt2x00-fix-failed-SLEEP-AWAKE-and-AWAKE-SLEEP-transitions.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1588,6 +1594,12 @@ ApplyPatch sdhci-8-bit-data-transfer-width-support.patch ApplyPatch mmc-make-sdhci-work-with-ricoh-mmc-controller.patch ApplyPatch mmc-add-ricoh-e822-pci-id.patch +ApplyPatch depessimize-rds_copy_page_user.patch +ApplyPatch tpm-autodetect-itpm-devices.patch + +ApplyPatch rt2x00-disable-auto-wakeup-before-waking-up-device.patch +ApplyPatch rt2x00-fix-failed-SLEEP-AWAKE-and-AWAKE-SLEEP-transitions.patch + # END OF PATCH APPLICATIONS %endif @@ -2209,6 +2221,13 @@ fi %changelog +* Fri Oct 22 2010 Kyle McMartin 2.6.34.7-62 +- tpm-autodetect-itpm-devices.patch: Auto-fix TPM issues on various + laptops which prevented suspend/resume. +- depessimize-rds_copy_page_user.patch: Fix CVE-2010-3904, local + privilege escalation via RDS protocol. +- rt2x00: Backport fixes for #642031 from Stanislaw Gruszka. + * Mon Oct 18 2010 Kyle McMartin 2.6.34.7-61 - Add Ricoh e822 support. (rhbz#596475) Thanks to sgruszka@ for sending the patches in. diff --git a/rt2x00-disable-auto-wakeup-before-waking-up-device.patch b/rt2x00-disable-auto-wakeup-before-waking-up-device.patch new file mode 100644 index 000000000..3e4183003 --- /dev/null +++ b/rt2x00-disable-auto-wakeup-before-waking-up-device.patch @@ -0,0 +1,122 @@ +From sgruszka@redhat.com Wed Oct 20 10:35:00 2010 +From: Stanislaw Gruszka +To: stable@kernel.org +Subject: [PATCH -stable 2.6.34 1/2] rt2x00: Disable auto wakeup before waking up device. +Date: Wed, 20 Oct 2010 16:37:27 +0200 + +From: Gertjan van Wingerde + +commit 5731858d0047cad309d334c4cd6ccb6199bf28fe upstream. + +Together with "rt2x00: Fix failed SLEEP->AWAKE and AWAKE->SLEEP +transitions" fix kernel oops/hang reported here: +https://bugzilla.redhat.com/show_bug.cgi?id=642031 + +In all drivers ensure that auto wakeup is disabled before waking up the device. +This is needed to prevent connection stability issues and problems in waking up +the device. + +Based upon a patch from Ondrej Zary + +Signed-off-by: Gertjan van Wingerde +Cc: Ondrej Zary +Signed-off-by: John W. Linville +--- + drivers/net/wireless/rt2x00/rt2400pci.c | 4 ++++ + drivers/net/wireless/rt2x00/rt2500pci.c | 4 ++++ + drivers/net/wireless/rt2x00/rt2500usb.c | 4 ++++ + drivers/net/wireless/rt2x00/rt2800lib.c | 4 ++-- + drivers/net/wireless/rt2x00/rt73usb.c | 6 +++--- + 5 files changed, 17 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c +index c22b040..08a4789 100644 +--- a/drivers/net/wireless/rt2x00/rt2400pci.c ++++ b/drivers/net/wireless/rt2x00/rt2400pci.c +@@ -525,6 +525,10 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, + + rt2x00_set_field32(®, CSR20_AUTOWAKE, 1); + rt2x00pci_register_write(rt2x00dev, CSR20, reg); ++ } else { ++ rt2x00pci_register_read(rt2x00dev, CSR20, ®); ++ rt2x00_set_field32(®, CSR20_AUTOWAKE, 0); ++ rt2x00pci_register_write(rt2x00dev, CSR20, reg); + } + + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); +diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c +index 52bbcf1..d084d70 100644 +--- a/drivers/net/wireless/rt2x00/rt2500pci.c ++++ b/drivers/net/wireless/rt2x00/rt2500pci.c +@@ -573,6 +573,10 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, + + rt2x00_set_field32(®, CSR20_AUTOWAKE, 1); + rt2x00pci_register_write(rt2x00dev, CSR20, reg); ++ } else { ++ rt2x00pci_register_read(rt2x00dev, CSR20, ®); ++ rt2x00_set_field32(®, CSR20_AUTOWAKE, 0); ++ rt2x00pci_register_write(rt2x00dev, CSR20, reg); + } + + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); +diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c +index ee34c13..c1eec17 100644 +--- a/drivers/net/wireless/rt2x00/rt2500usb.c ++++ b/drivers/net/wireless/rt2x00/rt2500usb.c +@@ -648,6 +648,10 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, + + rt2x00_set_field16(®, MAC_CSR18_AUTO_WAKE, 1); + rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg); ++ } else { ++ rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); ++ rt2x00_set_field16(®, MAC_CSR18_AUTO_WAKE, 0); ++ rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg); + } + + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); +diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c +index 18d4d8e..d169491 100644 +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -1014,13 +1014,13 @@ static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev, + + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + } else { +- rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); +- + rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); ++ ++ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + } + } + +diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c +index 47f3e4a..7ebe14b 100644 +--- a/drivers/net/wireless/rt2x00/rt73usb.c ++++ b/drivers/net/wireless/rt2x00/rt73usb.c +@@ -860,15 +860,15 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, + rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, + USB_MODE_SLEEP, REGISTER_TIMEOUT); + } else { +- rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, +- USB_MODE_WAKEUP, REGISTER_TIMEOUT); +- + rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®); + rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, 0); + rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0); + rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 0); + rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 0); + rt2x00usb_register_write(rt2x00dev, MAC_CSR11, reg); ++ ++ rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, ++ USB_MODE_WAKEUP, REGISTER_TIMEOUT); + } + } + +-- +1.7.2.3 + diff --git a/rt2x00-fix-failed-SLEEP-AWAKE-and-AWAKE-SLEEP-transitions.patch b/rt2x00-fix-failed-SLEEP-AWAKE-and-AWAKE-SLEEP-transitions.patch new file mode 100644 index 000000000..ee35dec37 --- /dev/null +++ b/rt2x00-fix-failed-SLEEP-AWAKE-and-AWAKE-SLEEP-transitions.patch @@ -0,0 +1,146 @@ +From sgruszka@redhat.com Wed Oct 20 10:35:02 2010 +From: Stanislaw Gruszka +To: stable@kernel.org +Subject: [PATCH -stable 2.6.34 2/2] rt2x00: Fix failed SLEEP->AWAKE and AWAKE->SLEEP transitions. +Date: Wed, 20 Oct 2010 16:37:28 +0200 + +From: Gertjan van Wingerde + +commit 9655a6ec19ca656af246fb80817aa337892aefbf upstream. + +Together with "rt2x00: Disable auto wakeup before waking up device" +fix kernel oops/hang reported here: +https://bugzilla.redhat.com/show_bug.cgi?id=642031 + +(Based on a patch created by Ondrej Zary) + +In some circumstances the Ralink devices do not properly go to sleep +or wake up, with timeouts occurring. +Fix this by retrying telling the device that it has to wake up or +sleep. + +Signed-off-by: Gertjan van Wingerde +Acked-by: Ivo van Doorn +Signed-off-by: John W. Linville +--- + drivers/net/wireless/rt2x00/rt2400pci.c | 9 +++++---- + drivers/net/wireless/rt2x00/rt2500pci.c | 9 +++++---- + drivers/net/wireless/rt2x00/rt61pci.c | 7 ++++--- + drivers/net/wireless/rt2x00/rt73usb.c | 7 ++++--- + 4 files changed, 18 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c +index 4ba7b038..ad2c98a 100644 +--- a/drivers/net/wireless/rt2x00/rt2400pci.c ++++ b/drivers/net/wireless/rt2x00/rt2400pci.c +@@ -926,7 +926,7 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev) + static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) + { +- u32 reg; ++ u32 reg, reg2; + unsigned int i; + char put_to_sleep; + char bbp_state; +@@ -947,11 +947,12 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { +- rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); +- bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE); +- rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE); ++ rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®2); ++ bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); ++ rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); + if (bbp_state == state && rf_state == state) + return 0; ++ rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg); + msleep(10); + } + +diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c +index 89d132d..41da3d2 100644 +--- a/drivers/net/wireless/rt2x00/rt2500pci.c ++++ b/drivers/net/wireless/rt2x00/rt2500pci.c +@@ -1084,7 +1084,7 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev) + static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) + { +- u32 reg; ++ u32 reg, reg2; + unsigned int i; + char put_to_sleep; + char bbp_state; +@@ -1105,11 +1105,12 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { +- rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); +- bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE); +- rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE); ++ rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®2); ++ bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); ++ rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); + if (bbp_state == state && rf_state == state) + return 0; ++ rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg); + msleep(10); + } + +diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c +index 2e3076f..6a74baf 100644 +--- a/drivers/net/wireless/rt2x00/rt61pci.c ++++ b/drivers/net/wireless/rt2x00/rt61pci.c +@@ -1689,7 +1689,7 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) + + static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) + { +- u32 reg; ++ u32 reg, reg2; + unsigned int i; + char put_to_sleep; + +@@ -1706,10 +1706,11 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { +- rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®); +- state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); ++ rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®2); ++ state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); + if (state == !put_to_sleep) + return 0; ++ rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg); + msleep(10); + } + +diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c +index e35bd19..6e0d82e 100644 +--- a/drivers/net/wireless/rt2x00/rt73usb.c ++++ b/drivers/net/wireless/rt2x00/rt73usb.c +@@ -1366,7 +1366,7 @@ static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev) + + static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) + { +- u32 reg; ++ u32 reg, reg2; + unsigned int i; + char put_to_sleep; + +@@ -1383,10 +1383,11 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { +- rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); +- state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); ++ rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®2); ++ state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); + if (state == !put_to_sleep) + return 0; ++ rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg); + msleep(10); + } + +-- +1.7.2.3 + diff --git a/tpm-autodetect-itpm-devices.patch b/tpm-autodetect-itpm-devices.patch new file mode 100644 index 000000000..57b5d07ed --- /dev/null +++ b/tpm-autodetect-itpm-devices.patch @@ -0,0 +1,65 @@ +commit 8cf5102c84dba60b2ea29b7e89f1a65100e20bb9 +Author: Matthew Garrett +Date: Thu Oct 21 17:31:56 2010 -0400 + + tpm: Autodetect itpm devices + + Some Lenovos have TPMs that require a quirk to function correctly. This can + be autodetected by checking whether the device has a _HID of INTC0102. This + is an invalid PNPid, and as such is discarded by the pnp layer - however + it's still present in the ACPI code, so we can pull it out that way. This + means that the quirk won't be automatically applied on non-ACPI systems, + but without ACPI we don't have any way to identify the chip anyway so I + don't think that's a great concern. + + Signed-off-by: Matthew Garrett + +diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c +index 1030f84..c17a305 100644 +--- a/drivers/char/tpm/tpm_tis.c ++++ b/drivers/char/tpm/tpm_tis.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include "tpm.h" + + #define TPM_HEADER_SIZE 10 +@@ -78,6 +79,26 @@ enum tis_defaults { + static LIST_HEAD(tis_chips); + static DEFINE_SPINLOCK(tis_lock); + ++#ifdef CONFIG_ACPI ++static int is_itpm(struct pnp_dev *dev) ++{ ++ struct acpi_device *acpi = pnp_acpi_device(dev); ++ struct acpi_hardware_id *id; ++ ++ list_for_each_entry(id, &acpi->pnp.ids, list) { ++ if (!strcmp("INTC0102", id->id)) ++ return 1; ++ } ++ ++ return 0; ++} ++#else ++static int is_itpm(struct pnp_dev *dev) ++{ ++ return 0; ++} ++#endif ++ + static int check_locality(struct tpm_chip *chip, int l) + { + if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) & +@@ -472,6 +493,9 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, + "1.2 TPM (device-id 0x%X, rev-id %d)\n", + vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); + ++ if (is_itpm(to_pnp_dev(dev))) ++ itpm = 1; ++ + if (itpm) + dev_info(dev, "Intel iTPM workaround enabled\n"); +