[kernel] r19969 - in dists/squeeze-security/linux-2.6/debian: . config patches/bugfix/all patches/bugfix/x86 patches/debian patches/features/all/openvz patches/series

Ben Hutchings benh at alioth.debian.org
Tue Apr 2 04:52:08 UTC 2013


Author: benh
Date: Tue Apr  2 04:52:07 2013
New Revision: 19969

Log:
Backport fixes for a whole bunch of security issues

The fix for CVE-2012-3552 changes ABI for a few functions.  I think
this is unavoidable, but also ignorable as it should only matter to
transport layer or congestion control modules.

Backporting of fixes for CVE-2012-2121, CVE-2012-3552, CVE-2012-4461,
CVE-2013-1796, CVE-2013-1860 was non-trivial and these particularly
need testing.

Added:
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-Fix-incorrect-strncpy-in-hidp_setup_hid.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-HCI-Fix-info-leak-in-getsockopt-HCI_FILTER.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-L2CAP-Fix-info-leak-via-getsockname.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-RFCOMM-Fix-info-leak-in-ioctl-RFCOMMGETDEV.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-RFCOMM-Fix-info-leak-via-getsockname.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/KVM-Fix-bounds-checking-in-ioapic-indirect-register-.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/NLS-improve-UTF8-UTF16-string-conversion-routine.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/USB-cdc-wdm-fix-buffer-overflow.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/atm-fix-info-leak-in-getsockopt-SO_ATMPVC.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/atm-fix-info-leak-via-getsockname.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/dcbnl-fix-various-netlink-info-leaks.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/fat-Fix-stat-f_namelen.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/inet-add-RCU-protection-to-inet-opt.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/ipvs-fix-info-leak-in-getsockopt-IP_VS_SO_GET_TIMEOU.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/isofs-avoid-info-leak-on-export.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/kernel-signal.c-use-__ARCH_HAS_SA_RESTORER-instead-o.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/llc-fix-info-leak-via-getsockname.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/net-fix-info-leak-in-compat-dev_ifconf.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/signal-Define-__ARCH_HAS_SA_RESTORER-so-we-know-whet.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/signal-always-clear-sa_restorer-on-execve.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/tmpfs-fix-use-after-free-of-mempolicy-object.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/udf-avoid-info-leak-on-export.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_policy.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_state.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_tmpl.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-return-error-pointer-instead-of-NULL-2.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-return-error-pointer-instead-of-NULL.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-lock-slots_lock-around-device-assignment.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-unmap-pages-from-the-iommu-when-slots-are-remove.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-x86-fix-for-buffer-overflow-in-handling-of-MSR_K.patch
   dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-x86-invalid-opcode-oops-on-SET_SREGS-with-OSXSAV.patch
   dists/squeeze-security/linux-2.6/debian/patches/debian/nls-Avoid-ABI-change-for-CVE-2013-1773-fix.patch
Modified:
   dists/squeeze-security/linux-2.6/debian/changelog
   dists/squeeze-security/linux-2.6/debian/config/defines
   dists/squeeze-security/linux-2.6/debian/patches/features/all/openvz/openvz.patch
   dists/squeeze-security/linux-2.6/debian/patches/series/48squeeze2

Modified: dists/squeeze-security/linux-2.6/debian/changelog
==============================================================================
--- dists/squeeze-security/linux-2.6/debian/changelog	Tue Apr  2 04:38:50 2013	(r19968)
+++ dists/squeeze-security/linux-2.6/debian/changelog	Tue Apr  2 04:52:07 2013	(r19969)
@@ -7,6 +7,32 @@
   [ Ben Hutchings ]
   * ptrace: Fix ptrace when task is in task_is_stopped() state
     (regression in 2.6.32-48squeeze1) (Closes: #704437)
+  * [x86] KVM: Fix device assignment page leak (CVE-2012-2121)
+    - unmap pages from the iommu when slots are removed
+    - lock slots_lock around device assignment
+  * inet: add RCU protection to inet->opt (CVE-2012-3552)
+  * [x86] KVM: invalid opcode oops on SET_SREGS with OSXSAVE bit set
+    (CVE-2012-4461)
+  * xfrm_user: fix info leaks in copy_to_user_{policy,state,tmpl}()
+    (CVE-2012-6537)
+  * net: fix info leak in compat dev_ifconf() (CVE-2012-6539)
+  * ipvs: fix info leak in getsockopt(IP_VS_SO_GET_TIMEOUT) (CVE-2012-6540)
+  * llc: fix info leak via getsockname() (CVE-2012-6542)
+  * Bluetooth: Fix information leaks (CVE-2012-6544, CVE-2012-6545)
+  * atm: Fix information leaks (CVE-2012-6546)
+  * udf: avoid info leak on export (CVE-2012-6548)
+  * isofs: avoid info leak on export (CVE-2012-6549)
+  * Bluetooth: Fix incorrect strncpy() in hidp_setup_hid() (CVE-2013-0349)
+  * signal: always clear sa_restorer on execve (CVE-2013-0914)
+  * tmpfs: fix use-after-free of mempolicy object (CVE-2013-1767)
+  * fat: Fix stat->f_namelen
+  * NLS: improve UTF8 -> UTF16 string conversion routine (CVE-2013-1773)
+  * KVM: x86: fix for buffer overflow in handling of MSR_KVM_SYSTEM_TIME
+    (CVE-2013-1796)
+  * KVM: Fix bounds checking in ioapic indirect register reads (CVE-2013-1798)
+  * xfrm_user: return error pointer instead of NULL (CVE-2013-1826)
+  * USB: cdc-wdm: fix buffer overflow (CVE-2013-1860)
+  * dcbnl: Fix netlink info leak (CVE-2013-2634)
 
  -- dann frazier <dannf at dannf.org>  Mon, 11 Mar 2013 08:47:43 +0100
 

Modified: dists/squeeze-security/linux-2.6/debian/config/defines
==============================================================================
--- dists/squeeze-security/linux-2.6/debian/config/defines	Tue Apr  2 04:38:50 2013	(r19968)
+++ dists/squeeze-security/linux-2.6/debian/config/defines	Tue Apr  2 04:52:07 2013	(r19969)
@@ -9,6 +9,10 @@
  scm_*
  hisax_init_pcmcia
  clocksource_*
+ module:net/dccp/dccp
+ ip_build_and_send_pkt
+ tcp_cong_avoid_ai
+ tcp_slow_start
 
 [base]
 arches:

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-Fix-incorrect-strncpy-in-hidp_setup_hid.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-Fix-incorrect-strncpy-in-hidp_setup_hid.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,41 @@
+From: Anderson Lizardo <anderson.lizardo at openbossa.org>
+Date: Sun, 6 Jan 2013 18:28:53 -0400
+Subject: Bluetooth: Fix incorrect strncpy() in hidp_setup_hid()
+
+commit 0a9ab9bdb3e891762553f667066190c1d22ad62b upstream.
+
+The length parameter should be sizeof(req->name) - 1 because there is no
+guarantee that string provided by userspace will contain the trailing
+'\0'.
+
+Can be easily reproduced by manually setting req->name to 128 non-zero
+bytes prior to ioctl(HIDPCONNADD) and checking the device name setup on
+input subsystem:
+
+$ cat /sys/devices/pnp0/00\:04/tty/ttyS0/hci0/hci0\:1/input8/name
+AAAAAA[...]AAAAAAAAf0:af:f0:af:f0:af
+
+("f0:af:f0:af:f0:af" is the device bluetooth address, taken from "phys"
+field in struct hid_device due to overflow.)
+
+Signed-off-by: Anderson Lizardo <anderson.lizardo at openbossa.org>
+Acked-by: Marcel Holtmann <marcel at holtmann.org>
+Signed-off-by: Gustavo Padovan <gustavo.padovan at collabora.co.uk>
+[bwh: Backported to 2.6.32: adjust context]
+---
+ net/bluetooth/hidp/core.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
+index 49d8495..0c2c59d 100644
+--- a/net/bluetooth/hidp/core.c
++++ b/net/bluetooth/hidp/core.c
+@@ -778,7 +778,7 @@ static int hidp_setup_hid(struct hidp_session *session,
+ 	hid->version = req->version;
+ 	hid->country = req->country;
+ 
+-	strncpy(hid->name, req->name, 128);
++	strncpy(hid->name, req->name, sizeof(req->name) - 1);
+ 	strncpy(hid->phys, batostr(&src), 64);
+ 	strncpy(hid->uniq, batostr(&dst), 64);
+ 

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-HCI-Fix-info-leak-in-getsockopt-HCI_FILTER.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-HCI-Fix-info-leak-in-getsockopt-HCI_FILTER.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,32 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 15 Aug 2012 11:31:46 +0000
+Subject: Bluetooth: HCI - Fix info leak in getsockopt(HCI_FILTER)
+
+commit e15ca9a0ef9a86f0477530b0f44a725d67f889ee upstream.
+
+The HCI code fails to initialize the two padding bytes of struct
+hci_ufilter before copying it to userland -- that for leaking two
+bytes kernel stack. Add an explicit memset(0) before filling the
+structure to avoid the info leak.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Cc: Marcel Holtmann <marcel at holtmann.org>
+Cc: Gustavo Padovan <gustavo at padovan.org>
+Cc: Johan Hedberg <johan.hedberg at gmail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/bluetooth/hci_sock.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
+index 4b48a25..7e1ea29 100644
+--- a/net/bluetooth/hci_sock.c
++++ b/net/bluetooth/hci_sock.c
+@@ -577,6 +577,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
+ 		{
+ 			struct hci_filter *f = &hci_pi(sk)->filter;
+ 
++			memset(&uf, 0, sizeof(uf));
+ 			uf.type_mask = f->type_mask;
+ 			uf.opcode    = f->opcode;
+ 			uf.event_mask[0] = *((u32 *) f->event_mask + 0);

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-L2CAP-Fix-info-leak-via-getsockname.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-L2CAP-Fix-info-leak-via-getsockname.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,33 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 15 Aug 2012 11:31:51 +0000
+Subject: Bluetooth: L2CAP - Fix info leak via getsockname()
+
+commit 792039c73cf176c8e39a6e8beef2c94ff46522ed upstream.
+
+The L2CAP code fails to initialize the l2_bdaddr_type member of struct
+sockaddr_l2 and the padding byte added for alignment. It that for leaks
+two bytes kernel stack via the getsockname() syscall. Add an explicit
+memset(0) before filling the structure to avoid the info leak.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Cc: Marcel Holtmann <marcel at holtmann.org>
+Cc: Gustavo Padovan <gustavo at padovan.org>
+Cc: Johan Hedberg <johan.hedberg at gmail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+[bwh: Backported to 2.6.32: adjust filename]
+---
+ net/bluetooth/l2cap.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
+index 71120ee..1c20bd9 100644
+--- a/net/bluetooth/l2cap.c
++++ b/net/bluetooth/l2cap.c
+@@ -1184,6 +1184,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
+ 
+ 	BT_DBG("sock %p, sk %p", sock, sk);
+ 
++	memset(la, 0, sizeof(struct sockaddr_l2));
+ 	addr->sa_family = AF_BLUETOOTH;
+ 	*len = sizeof(struct sockaddr_l2);
+ 

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-RFCOMM-Fix-info-leak-in-ioctl-RFCOMMGETDEV.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-RFCOMM-Fix-info-leak-in-ioctl-RFCOMMGETDEV.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,38 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 15 Aug 2012 11:31:49 +0000
+Subject: Bluetooth: RFCOMM - Fix info leak in ioctl(RFCOMMGETDEVLIST)
+
+commit f9432c5ec8b1e9a09b9b0e5569e3c73db8de432a upstream.
+
+The RFCOMM code fails to initialize the two padding bytes of struct
+rfcomm_dev_list_req inserted for alignment before copying it to
+userland. Additionally there are two padding bytes in each instance of
+struct rfcomm_dev_info. The ioctl() that for disclosures two bytes plus
+dev_num times two bytes uninitialized kernel heap memory.
+
+Allocate the memory using kzalloc() to fix this issue.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Cc: Marcel Holtmann <marcel at holtmann.org>
+Cc: Gustavo Padovan <gustavo at padovan.org>
+Cc: Johan Hedberg <johan.hedberg at gmail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+[bwh: Backported to 2.6.32: adjust context]
+---
+ net/bluetooth/rfcomm/tty.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
+index 5f6a305..00b8f21 100644
+--- a/net/bluetooth/rfcomm/tty.c
++++ b/net/bluetooth/rfcomm/tty.c
+@@ -472,7 +472,8 @@ static int rfcomm_get_dev_list(void __user *arg)
+ 
+ 	size = sizeof(*dl) + dev_num * sizeof(*di);
+ 
+-	if (!(dl = kmalloc(size, GFP_KERNEL)))
++	dl = kzalloc(size, GFP_KERNEL);
++	if (!dl)
+ 		return -ENOMEM;
+ 
+ 	di = dl->dev_info;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-RFCOMM-Fix-info-leak-via-getsockname.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/Bluetooth-RFCOMM-Fix-info-leak-via-getsockname.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,32 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 15 Aug 2012 11:31:50 +0000
+Subject: Bluetooth: RFCOMM - Fix info leak via getsockname()
+
+commit 9344a972961d1a6d2c04d9008b13617bcb6ec2ef upstream.
+
+The RFCOMM code fails to initialize the trailing padding byte of struct
+sockaddr_rc added for alignment. It that for leaks one byte kernel stack
+via the getsockname() syscall. Add an explicit memset(0) before filling
+the structure to avoid the info leak.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Cc: Marcel Holtmann <marcel at holtmann.org>
+Cc: Gustavo Padovan <gustavo at padovan.org>
+Cc: Johan Hedberg <johan.hedberg at gmail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/bluetooth/rfcomm/sock.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
+index 1ae3f80..c47b7c4 100644
+--- a/net/bluetooth/rfcomm/sock.c
++++ b/net/bluetooth/rfcomm/sock.c
+@@ -543,6 +543,7 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *
+ 
+ 	BT_DBG("sock %p, sk %p", sock, sk);
+ 
++	memset(sa, 0, sizeof(*sa));
+ 	sa->rc_family  = AF_BLUETOOTH;
+ 	sa->rc_channel = rfcomm_pi(sk)->channel;
+ 	if (peer)

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/KVM-Fix-bounds-checking-in-ioapic-indirect-register-.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/KVM-Fix-bounds-checking-in-ioapic-indirect-register-.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,42 @@
+From: Andy Honig <ahonig at google.com>
+Date: Wed, 20 Feb 2013 14:49:16 -0800
+Subject: KVM: Fix bounds checking in ioapic indirect register reads
+ (CVE-2013-1798)
+
+commit a2c118bfab8bc6b8bb213abfc35201e441693d55 upstream.
+
+If the guest specifies a IOAPIC_REG_SELECT with an invalid value and follows
+that with a read of the IOAPIC_REG_WINDOW KVM does not properly validate
+that request.  ioapic_read_indirect contains an
+ASSERT(redir_index < IOAPIC_NUM_PINS), but the ASSERT has no effect in
+non-debug builds.  In recent kernels this allows a guest to cause a kernel
+oops by reading invalid memory.  In older kernels (pre-3.3) this allows a
+guest to read from large ranges of host memory.
+
+Tested: tested against apic unit tests.
+
+Signed-off-by: Andrew Honig <ahonig at google.com>
+Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
+---
+ virt/kvm/ioapic.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
+index 9fe140b..69969ae 100644
+--- a/virt/kvm/ioapic.c
++++ b/virt/kvm/ioapic.c
+@@ -71,9 +71,12 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
+ 			u32 redir_index = (ioapic->ioregsel - 0x10) >> 1;
+ 			u64 redir_content;
+ 
+-			ASSERT(redir_index < IOAPIC_NUM_PINS);
++			if (redir_index < IOAPIC_NUM_PINS)
++				redir_content =
++					ioapic->redirtbl[redir_index].bits;
++			else
++				redir_content = ~0ULL;
+ 
+-			redir_content = ioapic->redirtbl[redir_index].bits;
+ 			result = (ioapic->ioregsel & 0x1) ?
+ 			    (redir_content >> 32) & 0xffffffff :
+ 			    redir_content & 0xffffffff;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/NLS-improve-UTF8-UTF16-string-conversion-routine.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/NLS-improve-UTF8-UTF16-string-conversion-routine.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,139 @@
+From: Alan Stern <stern at rowland.harvard.edu>
+Date: Thu, 17 Nov 2011 16:42:19 -0500
+Subject: NLS: improve UTF8 -> UTF16 string conversion routine
+
+commit 0720a06a7518c9d0c0125bd5d1f3b6264c55c3dd upstream.
+
+The utf8s_to_utf16s conversion routine needs to be improved.  Unlike
+its utf16s_to_utf8s sibling, it doesn't accept arguments specifying
+the maximum length of the output buffer or the endianness of its
+16-bit output.
+
+This patch (as1501) adds the two missing arguments, and adjusts the
+only two places in the kernel where the function is called.  A
+follow-on patch will add a third caller that does utilize the new
+capabilities.
+
+The two conversion routines are still annoyingly inconsistent in the
+way they handle invalid byte combinations.  But that's a subject for a
+different patch.
+
+Signed-off-by: Alan Stern <stern at rowland.harvard.edu>
+CC: Clemens Ladisch <clemens at ladisch.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+[bwh: Bakckported to 2.6.32: drop Hyper-V change]
+---
+ fs/fat/namei_vfat.c |    3 ++-
+ fs/nls/nls_base.c   |   43 +++++++++++++++++++++++++++++++++----------
+ include/linux/nls.h |    5 +++--
+ 3 files changed, 38 insertions(+), 13 deletions(-)
+
+diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
+index 67b3df1..4251f35 100644
+--- a/fs/fat/namei_vfat.c
++++ b/fs/fat/namei_vfat.c
+@@ -499,7 +499,8 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
+ 	int charlen;
+ 
+ 	if (utf8) {
+-		*outlen = utf8s_to_utf16s(name, len, (wchar_t *)outname);
++		*outlen = utf8s_to_utf16s(name, len, UTF16_HOST_ENDIAN,
++				(wchar_t *) outname, FAT_LFN_LEN + 2);
+ 		if (*outlen < 0)
+ 			return *outlen;
+ 		else if (*outlen > FAT_LFN_LEN)
+diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
+index 44a88a9..0eb059ec 100644
+--- a/fs/nls/nls_base.c
++++ b/fs/nls/nls_base.c
+@@ -114,34 +114,57 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxlen)
+ }
+ EXPORT_SYMBOL(utf32_to_utf8);
+ 
+-int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs)
++static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian)
++{
++	switch (endian) {
++	default:
++		*s = (wchar_t) c;
++		break;
++	case UTF16_LITTLE_ENDIAN:
++		*s = __cpu_to_le16(c);
++		break;
++	case UTF16_BIG_ENDIAN:
++		*s = __cpu_to_be16(c);
++		break;
++	}
++}
++
++int utf8s_to_utf16s(const u8 *s, int len, enum utf16_endian endian,
++		wchar_t *pwcs, int maxlen)
+ {
+ 	u16 *op;
+ 	int size;
+ 	unicode_t u;
+ 
+ 	op = pwcs;
+-	while (*s && len > 0) {
++	while (len > 0 && maxlen > 0 && *s) {
+ 		if (*s & 0x80) {
+ 			size = utf8_to_utf32(s, len, &u);
+ 			if (size < 0)
+ 				return -EINVAL;
++			s += size;
++			len -= size;
+ 
+ 			if (u >= PLANE_SIZE) {
++				if (maxlen < 2)
++					break;
+ 				u -= PLANE_SIZE;
+-				*op++ = (wchar_t) (SURROGATE_PAIR |
+-						((u >> 10) & SURROGATE_BITS));
+-				*op++ = (wchar_t) (SURROGATE_PAIR |
++				put_utf16(op++, SURROGATE_PAIR |
++						((u >> 10) & SURROGATE_BITS),
++						endian);
++				put_utf16(op++, SURROGATE_PAIR |
+ 						SURROGATE_LOW |
+-						(u & SURROGATE_BITS));
++						(u & SURROGATE_BITS),
++						endian);
++				maxlen -= 2;
+ 			} else {
+-				*op++ = (wchar_t) u;
++				put_utf16(op++, u, endian);
++				maxlen--;
+ 			}
+-			s += size;
+-			len -= size;
+ 		} else {
+-			*op++ = *s++;
++			put_utf16(op++, *s++, endian);
+ 			len--;
++			maxlen--;
+ 		}
+ 	}
+ 	return op - pwcs;
+diff --git a/include/linux/nls.h b/include/linux/nls.h
+index d47beef..5dc635f 100644
+--- a/include/linux/nls.h
++++ b/include/linux/nls.h
+@@ -43,7 +43,7 @@ enum utf16_endian {
+ 	UTF16_BIG_ENDIAN
+ };
+ 
+-/* nls.c */
++/* nls_base.c */
+ extern int register_nls(struct nls_table *);
+ extern int unregister_nls(struct nls_table *);
+ extern struct nls_table *load_nls(char *);
+@@ -52,7 +52,8 @@ extern struct nls_table *load_nls_default(void);
+ 
+ extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu);
+ extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen);
+-extern int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs);
++extern int utf8s_to_utf16s(const u8 *s, int len,
++		enum utf16_endian endian, wchar_t *pwcs, int maxlen);
+ extern int utf16s_to_utf8s(const wchar_t *pwcs, int len,
+ 		enum utf16_endian endian, u8 *s, int maxlen);
+ 

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/USB-cdc-wdm-fix-buffer-overflow.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/USB-cdc-wdm-fix-buffer-overflow.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,86 @@
+From: Oliver Neukum <oneukum at suse.de>
+Date: Tue, 12 Mar 2013 14:52:42 +0100
+Subject: USB: cdc-wdm: fix buffer overflow
+
+commit c0f5ecee4e741667b2493c742b60b6218d40b3aa upstream.
+
+The buffer for responses must not overflow.
+If this would happen, set a flag, drop the data and return
+an error after user space has read all remaining data.
+
+Signed-off-by: Oliver Neukum <oliver at neukum.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
+[bwh: Backported to 2.6.32: adjust context]
+---
+ drivers/usb/class/cdc-wdm.c |   23 ++++++++++++++++++++---
+ 1 file changed, 20 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
+index 37f2899..01ae519 100644
+--- a/drivers/usb/class/cdc-wdm.c
++++ b/drivers/usb/class/cdc-wdm.c
+@@ -52,6 +52,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
+ #define WDM_READ		4
+ #define WDM_INT_STALL		5
+ #define WDM_POLL_RUNNING	6
++#define WDM_OVERFLOW		10
+ 
+ 
+ #define WDM_MAX			16
+@@ -115,6 +116,7 @@ static void wdm_in_callback(struct urb *urb)
+ {
+ 	struct wdm_device *desc = urb->context;
+ 	int status = urb->status;
++	int length = urb->actual_length;
+ 
+ 	spin_lock(&desc->iuspin);
+ 
+@@ -144,9 +146,17 @@ static void wdm_in_callback(struct urb *urb)
+ 	}
+ 
+ 	desc->rerr = status;
+-	desc->reslength = urb->actual_length;
+-	memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength);
+-	desc->length += desc->reslength;
++	if (length + desc->length > desc->wMaxCommand) {
++		/* The buffer would overflow */
++		set_bit(WDM_OVERFLOW, &desc->flags);
++	} else {
++		/* we may already be in overflow */
++		if (!test_bit(WDM_OVERFLOW, &desc->flags)) {
++			memmove(desc->ubuf + desc->length, desc->inbuf, length);
++			desc->length += length;
++			desc->reslength = length;
++		}
++	}
+ 	wake_up(&desc->wait);
+ 
+ 	set_bit(WDM_READ, &desc->flags);
+@@ -398,6 +408,11 @@ retry:
+ 			rv = -ENODEV;
+ 			goto err;
+ 		}
++		if (test_bit(WDM_OVERFLOW, &desc->flags)) {
++			clear_bit(WDM_OVERFLOW, &desc->flags);
++			rv = -ENOBUFS;
++			goto err;
++		}
+ 		i++;
+ 		if (file->f_flags & O_NONBLOCK) {
+ 			if (!test_bit(WDM_READ, &desc->flags)) {
+@@ -440,6 +455,7 @@ retry:
+ 			spin_unlock_irq(&desc->iuspin);
+ 			goto retry;
+ 		}
++
+ 		if (!desc->reslength) { /* zero length read */
+ 			dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__);
+ 			clear_bit(WDM_READ, &desc->flags);
+@@ -844,6 +860,7 @@ static int wdm_post_reset(struct usb_interface *intf)
+ 	struct wdm_device *desc = usb_get_intfdata(intf);
+ 	int rv;
+ 
++	clear_bit(WDM_OVERFLOW, &desc->flags);
+ 	rv = recover_from_urb_loss(desc);
+ 	mutex_unlock(&desc->plock);
+ 	return 0;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/atm-fix-info-leak-in-getsockopt-SO_ATMPVC.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/atm-fix-info-leak-in-getsockopt-SO_ATMPVC.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,29 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 15 Aug 2012 11:31:44 +0000
+Subject: atm: fix info leak in getsockopt(SO_ATMPVC)
+
+commit e862f1a9b7df4e8196ebec45ac62295138aa3fc2 upstream.
+
+The ATM code fails to initialize the two padding bytes of struct
+sockaddr_atmpvc inserted for alignment. Add an explicit memset(0)
+before filling the structure to avoid the info leak.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+[bwh: Backported to 2.6.32: adjust context, indentation]
+---
+ net/atm/common.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/atm/common.c b/net/atm/common.c
+index 950bd16..0baf05e 100644
+--- a/net/atm/common.c
++++ b/net/atm/common.c
+@@ -749,6 +749,7 @@ int vcc_getsockopt(struct socket *sock, int level, int optname,
+ 				if (!vcc->dev ||
+ 				    !test_bit(ATM_VF_ADDR,&vcc->flags))
+ 					return -ENOTCONN;
++				memset(&pvc, 0, sizeof(pvc));
+ 				pvc.sap_family = AF_ATMPVC;
+ 				pvc.sap_addr.itf = vcc->dev->number;
+ 				pvc.sap_addr.vpi = vcc->vpi;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/atm-fix-info-leak-via-getsockname.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/atm-fix-info-leak-via-getsockname.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,29 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 15 Aug 2012 11:31:45 +0000
+Subject: atm: fix info leak via getsockname()
+
+commit 3c0c5cfdcd4d69ffc4b9c0907cec99039f30a50a upstream.
+
+The ATM code fails to initialize the two padding bytes of struct
+sockaddr_atmpvc inserted for alignment. Add an explicit memset(0)
+before filling the structure to avoid the info leak.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+[bwh: Backported to 2.6.32: adjust context]
+---
+ net/atm/pvc.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/atm/pvc.c b/net/atm/pvc.c
+index d4c0245..523c21a 100644
+--- a/net/atm/pvc.c
++++ b/net/atm/pvc.c
+@@ -93,6 +93,7 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
+ 	if (!vcc->dev || !test_bit(ATM_VF_ADDR,&vcc->flags)) return -ENOTCONN;
+ 	*sockaddr_len = sizeof(struct sockaddr_atmpvc);
+ 	addr = (struct sockaddr_atmpvc *) sockaddr;
++	memset(addr, 0, sizeof(*addr));
+ 	addr->sap_family = AF_ATMPVC;
+ 	addr->sap_addr.itf = vcc->dev->number;
+ 	addr->sap_addr.vpi = vcc->vpi;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/dcbnl-fix-various-netlink-info-leaks.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/dcbnl-fix-various-netlink-info-leaks.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,38 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Sat, 9 Mar 2013 05:52:21 +0000
+Subject: dcbnl: fix various netlink info leaks
+
+commit 29cd8ae0e1a39e239a3a7b67da1986add1199fc0 upstream.
+
+The dcb netlink interface leaks stack memory in various places:
+* perm_addr[] buffer is only filled at max with 12 of the 32 bytes but
+  copied completely,
+* no in-kernel driver fills all fields of an IEEE 802.1Qaz subcommand,
+  so we're leaking up to 58 bytes for ieee_ets structs, up to 136 bytes
+  for ieee_pfc structs, etc.,
+* the same is true for CEE -- no in-kernel driver fills the whole
+  struct,
+
+Prevent all of the above stack info leaks by properly initializing the
+buffers/structures involved.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+[bwh: Backported to 2.6.32: no support for IEEE or CEE commands, so only
+ deal with perm_addr]
+---
+ net/dcb/dcbnl.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
+index ac1205d..813fe4b 100644
+--- a/net/dcb/dcbnl.c
++++ b/net/dcb/dcbnl.c
+@@ -307,6 +307,7 @@ static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
+ 	dcb->dcb_family = AF_UNSPEC;
+ 	dcb->cmd = DCB_CMD_GPERM_HWADDR;
+ 
++	memset(perm_addr, 0, sizeof(perm_addr));
+ 	netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
+ 
+ 	ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/fat-Fix-stat-f_namelen.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/fat-Fix-stat-f_namelen.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,82 @@
+From: Kevin Dankwardt <k at kcomputing.com>
+Date: Wed, 10 Feb 2010 23:43:40 +0900
+Subject: fat: Fix stat->f_namelen
+
+commit eeb5b4ae81f4a750355fa0c15f4fea22fdf83be1 upstream.
+
+I found that the length of a file name when created cannot exceed 255
+characters, yet, pathconf(), via statfs(), returns the maximum as 260.
+
+Signed-off-by: Kevin Dankwardt <k at kcomputing.com>
+Signed-off-by: OGAWA Hirofumi <hirofumi at mail.parknet.co.jp>
+---
+ fs/fat/inode.c           |    2 +-
+ fs/fat/namei_vfat.c      |    6 +++---
+ include/linux/msdos_fs.h |    3 ++-
+ 3 files changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/fs/fat/inode.c b/fs/fat/inode.c
+index 76b7961..c187e92 100644
+--- a/fs/fat/inode.c
++++ b/fs/fat/inode.c
+@@ -558,7 +558,7 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
+ 	buf->f_bavail = sbi->free_clusters;
+ 	buf->f_fsid.val[0] = (u32)id;
+ 	buf->f_fsid.val[1] = (u32)(id >> 32);
+-	buf->f_namelen = sbi->options.isvfat ? 260 : 12;
++	buf->f_namelen = sbi->options.isvfat ? FAT_LFN_LEN : 12;
+ 
+ 	return 0;
+ }
+diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
+index 72646e2..67b3df1 100644
+--- a/fs/fat/namei_vfat.c
++++ b/fs/fat/namei_vfat.c
+@@ -502,14 +502,14 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
+ 		*outlen = utf8s_to_utf16s(name, len, (wchar_t *)outname);
+ 		if (*outlen < 0)
+ 			return *outlen;
+-		else if (*outlen > 255)
++		else if (*outlen > FAT_LFN_LEN)
+ 			return -ENAMETOOLONG;
+ 
+ 		op = &outname[*outlen * sizeof(wchar_t)];
+ 	} else {
+ 		if (nls) {
+ 			for (i = 0, ip = name, op = outname, *outlen = 0;
+-			     i < len && *outlen <= 255;
++			     i < len && *outlen <= FAT_LFN_LEN;
+ 			     *outlen += 1)
+ 			{
+ 				if (escape && (*ip == ':')) {
+@@ -549,7 +549,7 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
+ 				return -ENAMETOOLONG;
+ 		} else {
+ 			for (i = 0, ip = name, op = outname, *outlen = 0;
+-			     i < len && *outlen <= 255;
++			     i < len && *outlen <= FAT_LFN_LEN;
+ 			     i++, *outlen += 1)
+ 			{
+ 				*op++ = *ip++;
+diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
+index ce38f1c..34066e6 100644
+--- a/include/linux/msdos_fs.h
++++ b/include/linux/msdos_fs.h
+@@ -15,6 +15,7 @@
+ #define MSDOS_DPB_BITS	4		/* log2(MSDOS_DPB) */
+ #define MSDOS_DPS	(SECTOR_SIZE / sizeof(struct msdos_dir_entry))
+ #define MSDOS_DPS_BITS	4		/* log2(MSDOS_DPS) */
++#define MSDOS_LONGNAME	256		/* maximum name length */
+ #define CF_LE_W(v)	le16_to_cpu(v)
+ #define CF_LE_L(v)	le32_to_cpu(v)
+ #define CT_LE_W(v)	cpu_to_le16(v)
+@@ -47,8 +48,8 @@
+ #define DELETED_FLAG	0xe5	/* marks file as deleted when in name[0] */
+ #define IS_FREE(n)	(!*(n) || *(n) == DELETED_FLAG)
+ 
++#define FAT_LFN_LEN	255	/* maximum long name length */
+ #define MSDOS_NAME	11	/* maximum name length */
+-#define MSDOS_LONGNAME	256	/* maximum name length */
+ #define MSDOS_SLOTS	21	/* max # of slots for short and long names */
+ #define MSDOS_DOT	".          "	/* ".", padded to MSDOS_NAME chars */
+ #define MSDOS_DOTDOT	"..         "	/* "..", padded to MSDOS_NAME chars */

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/inet-add-RCU-protection-to-inet-opt.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/inet-add-RCU-protection-to-inet-opt.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,1135 @@
+From: Eric Dumazet <eric.dumazet at gmail.com>
+Date: Thu, 21 Apr 2011 09:45:37 +0000
+Subject: inet: add RCU protection to inet->opt
+
+commit f6d8bd051c391c1c0458a30b2a7abcd939329259 upstream.
+
+We lack proper synchronization to manipulate inet->opt ip_options
+
+Problem is ip_make_skb() calls ip_setup_cork() and
+ip_setup_cork() possibly makes a copy of ipc->opt (struct ip_options),
+without any protection against another thread manipulating inet->opt.
+
+Another thread can change inet->opt pointer and free old one under us.
+
+Use RCU to protect inet->opt (changed to inet->inet_opt).
+
+Instead of handling atomic refcounts, just copy ip_options when
+necessary, to avoid cache line dirtying.
+
+We cant insert an rcu_head in struct ip_options since its included in
+skb->cb[], so this patch is large because I had to introduce a new
+ip_options_rcu structure.
+
+Signed-off-by: Eric Dumazet <eric.dumazet at gmail.com>
+Cc: Herbert Xu <herbert at gondor.apana.org.au>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+[dannf/bwh: backported to Debian's 2.6.32]
+---
+ include/net/inet_sock.h         |   14 +++--
+ include/net/ip.h                |   11 ++--
+ net/dccp/ipv4.c                 |   15 +++---
+ net/dccp/ipv6.c                 |    2 +-
+ net/ipv4/af_inet.c              |   16 ++++--
+ net/ipv4/cipso_ipv4.c           |  113 ++++++++++++++++++++++-----------------
+ net/ipv4/icmp.c                 |   23 ++++----
+ net/ipv4/inet_connection_sock.c |    8 +--
+ net/ipv4/ip_options.c           |   38 +++++++------
+ net/ipv4/ip_output.c            |   50 ++++++++---------
+ net/ipv4/ip_sockglue.c          |   33 ++++++++----
+ net/ipv4/raw.c                  |   19 +++++--
+ net/ipv4/syncookies.c           |    4 +-
+ net/ipv4/tcp_ipv4.c             |   33 +++++++-----
+ net/ipv4/udp.c                  |   21 ++++++--
+ net/ipv6/tcp_ipv6.c             |    2 +-
+ 16 files changed, 235 insertions(+), 167 deletions(-)
+
+diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
+index 47004f3..cf65e77 100644
+--- a/include/net/inet_sock.h
++++ b/include/net/inet_sock.h
+@@ -56,7 +56,15 @@ struct ip_options {
+ 	unsigned char	__data[0];
+ };
+ 
+-#define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
++struct ip_options_rcu {
++	struct rcu_head rcu;
++	struct ip_options opt;
++};
++
++struct ip_options_data {
++	struct ip_options_rcu	opt;
++	char			data[40];
++};
+ 
+ struct inet_request_sock {
+ 	struct request_sock	req;
+@@ -77,7 +85,7 @@ struct inet_request_sock {
+ 				acked	   : 1,
+ 				no_srccheck: 1;
+ 	kmemcheck_bitfield_end(flags);
+-	struct ip_options	*opt;
++	struct ip_options_rcu	*opt;
+ };
+ 
+ static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk)
+@@ -122,7 +130,7 @@ struct inet_sock {
+ 	__be32			saddr;
+ 	__s16			uc_ttl;
+ 	__u16			cmsg_flags;
+-	struct ip_options	*opt;
++	struct ip_options_rcu	*inet_opt;
+ 	__be16			sport;
+ 	__u16			id;
+ 	__u8			tos;
+diff --git a/include/net/ip.h b/include/net/ip.h
+index 69db943..a7d4675 100644
+--- a/include/net/ip.h
++++ b/include/net/ip.h
+@@ -54,7 +54,7 @@ struct ipcm_cookie
+ {
+ 	__be32			addr;
+ 	int			oif;
+-	struct ip_options	*opt;
++	struct ip_options_rcu	*opt;
+ 	union skb_shared_tx	shtx;
+ };
+ 
+@@ -92,7 +92,7 @@ extern int		igmp_mc_proc_init(void);
+ 
+ extern int		ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
+ 					      __be32 saddr, __be32 daddr,
+-					      struct ip_options *opt);
++					      struct ip_options_rcu *opt);
+ extern int		ip_rcv(struct sk_buff *skb, struct net_device *dev,
+ 			       struct packet_type *pt, struct net_device *orig_dev);
+ extern int		ip_local_deliver(struct sk_buff *skb);
+@@ -362,14 +362,15 @@ extern int ip_forward(struct sk_buff *skb);
+  *	Functions provided by ip_options.c
+  */
+  
+-extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, __be32 daddr, struct rtable *rt, int is_frag);
++extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt,
++			     __be32 daddr, struct rtable *rt, int is_frag);
+ extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb);
+ extern void ip_options_fragment(struct sk_buff *skb);
+ extern int ip_options_compile(struct net *net,
+ 			      struct ip_options *opt, struct sk_buff *skb);
+-extern int ip_options_get(struct net *net, struct ip_options **optp,
++extern int ip_options_get(struct net *net, struct ip_options_rcu **optp,
+ 			  unsigned char *data, int optlen);
+-extern int ip_options_get_from_user(struct net *net, struct ip_options **optp,
++extern int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp,
+ 				    unsigned char __user *data, int optlen);
+ extern void ip_options_undo(struct ip_options * opt);
+ extern void ip_forward_options(struct sk_buff *skb);
+diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
+index d14c0a3..cef3656 100644
+--- a/net/dccp/ipv4.c
++++ b/net/dccp/ipv4.c
+@@ -47,6 +47,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+ 	__be32 daddr, nexthop;
+ 	int tmp;
+ 	int err;
++	struct ip_options_rcu *inet_opt;
+ 
+ 	dp->dccps_role = DCCP_ROLE_CLIENT;
+ 
+@@ -57,10 +58,12 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+ 		return -EAFNOSUPPORT;
+ 
+ 	nexthop = daddr = usin->sin_addr.s_addr;
+-	if (inet->opt != NULL && inet->opt->srr) {
++
++	inet_opt = inet->inet_opt;
++	if (inet_opt != NULL && inet_opt->opt.srr) {
+ 		if (daddr == 0)
+ 			return -EINVAL;
+-		nexthop = inet->opt->faddr;
++		nexthop = inet_opt->opt.faddr;
+ 	}
+ 
+ 	tmp = ip_route_connect(&rt, nexthop, inet->saddr,
+@@ -75,7 +78,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+ 		return -ENETUNREACH;
+ 	}
+ 
+-	if (inet->opt == NULL || !inet->opt->srr)
++	if (inet_opt == NULL || !inet_opt->opt.srr)
+ 		daddr = rt->rt_dst;
+ 
+ 	if (inet->saddr == 0)
+@@ -86,8 +89,8 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+ 	inet->daddr = daddr;
+ 
+ 	inet_csk(sk)->icsk_ext_hdr_len = 0;
+-	if (inet->opt != NULL)
+-		inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen;
++	if (inet_opt)
++		inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
+ 	/*
+ 	 * Socket identity is still unknown (sport may be zero).
+ 	 * However we set state to DCCP_REQUESTING and not releasing socket
+@@ -397,7 +400,7 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
+ 	newinet->daddr	   = ireq->rmt_addr;
+ 	newinet->rcv_saddr = ireq->loc_addr;
+ 	newinet->saddr	   = ireq->loc_addr;
+-	newinet->opt	   = ireq->opt;
++	newinet->inet_opt	= ireq->opt;
+ 	ireq->opt	   = NULL;
+ 	newinet->mc_index  = inet_iif(skb);
+ 	newinet->mc_ttl	   = ip_hdr(skb)->ttl;
+diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
+index 9ed1962..2f11de7 100644
+--- a/net/dccp/ipv6.c
++++ b/net/dccp/ipv6.c
+@@ -600,7 +600,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
+ 
+ 	   First: no IPv4 options.
+ 	 */
+-	newinet->opt = NULL;
++	newinet->inet_opt = NULL;
+ 
+ 	/* Clone RX bits */
+ 	newnp->rxopt.all = np->rxopt.all;
+diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
+index 57737b8..9ba4dec 100644
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -152,7 +152,7 @@ void inet_sock_destruct(struct sock *sk)
+ 	WARN_ON(sk->sk_wmem_queued);
+ 	WARN_ON(sk->sk_forward_alloc);
+ 
+-	kfree(inet->opt);
++	kfree(inet->inet_opt);
+ 	dst_release(sk->sk_dst_cache);
+ 	sk_refcnt_debug_dec(sk);
+ }
+@@ -1062,9 +1062,11 @@ static int inet_sk_reselect_saddr(struct sock *sk)
+ 	__be32 old_saddr = inet->saddr;
+ 	__be32 new_saddr;
+ 	__be32 daddr = inet->daddr;
++	struct ip_options_rcu *inet_opt;
+ 
+-	if (inet->opt && inet->opt->srr)
+-		daddr = inet->opt->faddr;
++	inet_opt = inet->inet_opt;
++	if (inet_opt && inet_opt->opt.srr)
++		daddr = inet_opt->opt.faddr;
+ 
+ 	/* Query new route. */
+ 	err = ip_route_connect(&rt, daddr, 0,
+@@ -1106,6 +1108,7 @@ int inet_sk_rebuild_header(struct sock *sk)
+ 	struct inet_sock *inet = inet_sk(sk);
+ 	struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
+ 	__be32 daddr;
++	struct ip_options_rcu *inet_opt;
+ 	int err;
+ 
+ 	/* Route is OK, nothing to do. */
+@@ -1113,9 +1116,12 @@ int inet_sk_rebuild_header(struct sock *sk)
+ 		return 0;
+ 
+ 	/* Reroute. */
++	rcu_read_lock();
++	inet_opt = rcu_dereference(inet->inet_opt);
+ 	daddr = inet->daddr;
+-	if (inet->opt && inet->opt->srr)
+-		daddr = inet->opt->faddr;
++	if (inet_opt && inet_opt->opt.srr)
++		daddr = inet_opt->opt.faddr;
++	rcu_read_unlock();
+ {
+ 	struct flowi fl = {
+ 		.oif = sk->sk_bound_dev_if,
+diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
+index 10f8f8d..b6d06d6 100644
+--- a/net/ipv4/cipso_ipv4.c
++++ b/net/ipv4/cipso_ipv4.c
+@@ -1860,6 +1860,11 @@ static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
+ 	return CIPSO_V4_HDR_LEN + ret_val;
+ }
+ 
++static void opt_kfree_rcu(struct rcu_head *head)
++{
++	kfree(container_of(head, struct ip_options_rcu, rcu));
++}
++
+ /**
+  * cipso_v4_sock_setattr - Add a CIPSO option to a socket
+  * @sk: the socket
+@@ -1882,7 +1887,7 @@ int cipso_v4_sock_setattr(struct sock *sk,
+ 	unsigned char *buf = NULL;
+ 	u32 buf_len;
+ 	u32 opt_len;
+-	struct ip_options *opt = NULL;
++	struct ip_options_rcu *old, *opt = NULL;
+ 	struct inet_sock *sk_inet;
+ 	struct inet_connection_sock *sk_conn;
+ 
+@@ -1918,22 +1923,25 @@ int cipso_v4_sock_setattr(struct sock *sk,
+ 		ret_val = -ENOMEM;
+ 		goto socket_setattr_failure;
+ 	}
+-	memcpy(opt->__data, buf, buf_len);
+-	opt->optlen = opt_len;
+-	opt->cipso = sizeof(struct iphdr);
++	memcpy(opt->opt.__data, buf, buf_len);
++	opt->opt.optlen = opt_len;
++	opt->opt.cipso = sizeof(struct iphdr);
+ 	kfree(buf);
+ 	buf = NULL;
+ 
+ 	sk_inet = inet_sk(sk);
++
++	old = sk_inet->inet_opt;
+ 	if (sk_inet->is_icsk) {
+ 		sk_conn = inet_csk(sk);
+-		if (sk_inet->opt)
+-			sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen;
+-		sk_conn->icsk_ext_hdr_len += opt->optlen;
++		if (old)
++			sk_conn->icsk_ext_hdr_len -= old->opt.optlen;
++		sk_conn->icsk_ext_hdr_len += opt->opt.optlen;
+ 		sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+ 	}
+-	opt = xchg(&sk_inet->opt, opt);
+-	kfree(opt);
++	rcu_assign_pointer(sk_inet->inet_opt, opt);
++	if (old)
++		call_rcu(&old->rcu, opt_kfree_rcu);
+ 
+ 	return 0;
+ 
+@@ -1963,7 +1971,7 @@ int cipso_v4_req_setattr(struct request_sock *req,
+ 	unsigned char *buf = NULL;
+ 	u32 buf_len;
+ 	u32 opt_len;
+-	struct ip_options *opt = NULL;
++	struct ip_options_rcu *opt = NULL;
+ 	struct inet_request_sock *req_inet;
+ 
+ 	/* We allocate the maximum CIPSO option size here so we are probably
+@@ -1991,15 +1999,16 @@ int cipso_v4_req_setattr(struct request_sock *req,
+ 		ret_val = -ENOMEM;
+ 		goto req_setattr_failure;
+ 	}
+-	memcpy(opt->__data, buf, buf_len);
+-	opt->optlen = opt_len;
+-	opt->cipso = sizeof(struct iphdr);
++	memcpy(opt->opt.__data, buf, buf_len);
++	opt->opt.optlen = opt_len;
++	opt->opt.cipso = sizeof(struct iphdr);
+ 	kfree(buf);
+ 	buf = NULL;
+ 
+ 	req_inet = inet_rsk(req);
+ 	opt = xchg(&req_inet->opt, opt);
+-	kfree(opt);
++	if (opt)
++		call_rcu(&opt->rcu, opt_kfree_rcu);
+ 
+ 	return 0;
+ 
+@@ -2019,34 +2028,34 @@ req_setattr_failure:
+  * values on failure.
+  *
+  */
+-int cipso_v4_delopt(struct ip_options **opt_ptr)
++int cipso_v4_delopt(struct ip_options_rcu **opt_ptr)
+ {
+ 	int hdr_delta = 0;
+-	struct ip_options *opt = *opt_ptr;
++	struct ip_options_rcu *opt = *opt_ptr;
+ 
+-	if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
++	if (opt->opt.srr || opt->opt.rr || opt->opt.ts || opt->opt.router_alert) {
+ 		u8 cipso_len;
+ 		u8 cipso_off;
+ 		unsigned char *cipso_ptr;
+ 		int iter;
+ 		int optlen_new;
+ 
+-		cipso_off = opt->cipso - sizeof(struct iphdr);
+-		cipso_ptr = &opt->__data[cipso_off];
++		cipso_off = opt->opt.cipso - sizeof(struct iphdr);
++		cipso_ptr = &opt->opt.__data[cipso_off];
+ 		cipso_len = cipso_ptr[1];
+ 
+-		if (opt->srr > opt->cipso)
+-			opt->srr -= cipso_len;
+-		if (opt->rr > opt->cipso)
+-			opt->rr -= cipso_len;
+-		if (opt->ts > opt->cipso)
+-			opt->ts -= cipso_len;
+-		if (opt->router_alert > opt->cipso)
+-			opt->router_alert -= cipso_len;
+-		opt->cipso = 0;
++		if (opt->opt.srr > opt->opt.cipso)
++			opt->opt.srr -= cipso_len;
++		if (opt->opt.rr > opt->opt.cipso)
++			opt->opt.rr -= cipso_len;
++		if (opt->opt.ts > opt->opt.cipso)
++			opt->opt.ts -= cipso_len;
++		if (opt->opt.router_alert > opt->opt.cipso)
++			opt->opt.router_alert -= cipso_len;
++		opt->opt.cipso = 0;
+ 
+ 		memmove(cipso_ptr, cipso_ptr + cipso_len,
+-			opt->optlen - cipso_off - cipso_len);
++			opt->opt.optlen - cipso_off - cipso_len);
+ 
+ 		/* determining the new total option length is tricky because of
+ 		 * the padding necessary, the only thing i can think to do at
+@@ -2055,21 +2064,21 @@ int cipso_v4_delopt(struct ip_options **opt_ptr)
+ 		 * from there we can determine the new total option length */
+ 		iter = 0;
+ 		optlen_new = 0;
+-		while (iter < opt->optlen)
+-			if (opt->__data[iter] != IPOPT_NOP) {
+-				iter += opt->__data[iter + 1];
++		while (iter < opt->opt.optlen)
++			if (opt->opt.__data[iter] != IPOPT_NOP) {
++				iter += opt->opt.__data[iter + 1];
+ 				optlen_new = iter;
+ 			} else
+ 				iter++;
+-		hdr_delta = opt->optlen;
+-		opt->optlen = (optlen_new + 3) & ~3;
+-		hdr_delta -= opt->optlen;
++		hdr_delta = opt->opt.optlen;
++		opt->opt.optlen = (optlen_new + 3) & ~3;
++		hdr_delta -= opt->opt.optlen;
+ 	} else {
+ 		/* only the cipso option was present on the socket so we can
+ 		 * remove the entire option struct */
+ 		*opt_ptr = NULL;
+-		hdr_delta = opt->optlen;
+-		kfree(opt);
++		hdr_delta = opt->opt.optlen;
++		call_rcu(&opt->rcu, opt_kfree_rcu);
+ 	}
+ 
+ 	return hdr_delta;
+@@ -2086,15 +2095,15 @@ int cipso_v4_delopt(struct ip_options **opt_ptr)
+ void cipso_v4_sock_delattr(struct sock *sk)
+ {
+ 	int hdr_delta;
+-	struct ip_options *opt;
++	struct ip_options_rcu *opt;
+ 	struct inet_sock *sk_inet;
+ 
+ 	sk_inet = inet_sk(sk);
+-	opt = sk_inet->opt;
+-	if (opt == NULL || opt->cipso == 0)
++	opt = sk_inet->inet_opt;
++	if (opt == NULL || opt->opt.cipso == 0)
+ 		return;
+ 
+-	hdr_delta = cipso_v4_delopt(&sk_inet->opt);
++	hdr_delta = cipso_v4_delopt(&sk_inet->inet_opt);
+ 	if (sk_inet->is_icsk && hdr_delta > 0) {
+ 		struct inet_connection_sock *sk_conn = inet_csk(sk);
+ 		sk_conn->icsk_ext_hdr_len -= hdr_delta;
+@@ -2112,12 +2121,12 @@ void cipso_v4_sock_delattr(struct sock *sk)
+  */
+ void cipso_v4_req_delattr(struct request_sock *req)
+ {
+-	struct ip_options *opt;
++	struct ip_options_rcu *opt;
+ 	struct inet_request_sock *req_inet;
+ 
+ 	req_inet = inet_rsk(req);
+ 	opt = req_inet->opt;
+-	if (opt == NULL || opt->cipso == 0)
++	if (opt == NULL || opt->opt.cipso == 0)
+ 		return;
+ 
+ 	cipso_v4_delopt(&req_inet->opt);
+@@ -2187,14 +2196,18 @@ getattr_return:
+  */
+ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
+ {
+-	struct ip_options *opt;
++	struct ip_options_rcu *opt;
++	int res = -ENOMSG;
+ 
+-	opt = inet_sk(sk)->opt;
+-	if (opt == NULL || opt->cipso == 0)
+-		return -ENOMSG;
+-
+-	return cipso_v4_getattr(opt->__data + opt->cipso - sizeof(struct iphdr),
+-				secattr);
++	rcu_read_lock();
++	opt = rcu_dereference(inet_sk(sk)->inet_opt);
++	if (opt && opt->opt.cipso)
++		res = cipso_v4_getattr(opt->opt.__data +
++						opt->opt.cipso -
++						sizeof(struct iphdr),
++				       secattr);
++	rcu_read_unlock();
++	return res;
+ }
+ 
+ /**
+diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
+index 5bc13fe..859d781 100644
+--- a/net/ipv4/icmp.c
++++ b/net/ipv4/icmp.c
+@@ -107,8 +107,7 @@ struct icmp_bxm {
+ 		__be32	       times[3];
+ 	} data;
+ 	int head_len;
+-	struct ip_options replyopts;
+-	unsigned char  optbuf[40];
++	struct ip_options_data replyopts;
+ };
+ 
+ /* An array of errno for error messages from dest unreach. */
+@@ -362,7 +361,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
+ 	struct inet_sock *inet;
+ 	__be32 daddr;
+ 
+-	if (ip_options_echo(&icmp_param->replyopts, skb))
++	if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb))
+ 		return;
+ 
+ 	sk = icmp_xmit_lock(net);
+@@ -376,10 +375,10 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
+ 	daddr = ipc.addr = rt->rt_src;
+ 	ipc.opt = NULL;
+ 	ipc.shtx.flags = 0;
+-	if (icmp_param->replyopts.optlen) {
+-		ipc.opt = &icmp_param->replyopts;
+-		if (ipc.opt->srr)
+-			daddr = icmp_param->replyopts.faddr;
++	if (icmp_param->replyopts.opt.opt.optlen) {
++		ipc.opt = &icmp_param->replyopts.opt;
++		if (ipc.opt->opt.srr)
++			daddr = icmp_param->replyopts.opt.opt.faddr;
+ 	}
+ 	{
+ 		struct flowi fl = { .nl_u = { .ip4_u =
+@@ -516,7 +515,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
+ 					   IPTOS_PREC_INTERNETCONTROL) :
+ 					  iph->tos;
+ 
+-	if (ip_options_echo(&icmp_param.replyopts, skb_in))
++	if (ip_options_echo(&icmp_param.replyopts.opt.opt, skb_in))
+ 		goto out_unlock;
+ 
+ 
+@@ -532,15 +531,15 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
+ 	icmp_param.offset = skb_network_offset(skb_in);
+ 	inet_sk(sk)->tos = tos;
+ 	ipc.addr = iph->saddr;
+-	ipc.opt = &icmp_param.replyopts;
++	ipc.opt = &icmp_param.replyopts.opt;
+ 	ipc.shtx.flags = 0;
+ 
+ 	{
+ 		struct flowi fl = {
+ 			.nl_u = {
+ 				.ip4_u = {
+-					.daddr = icmp_param.replyopts.srr ?
+-						icmp_param.replyopts.faddr :
++					.daddr = icmp_param.replyopts.opt.opt.srr ?
++						icmp_param.replyopts.opt.opt.faddr :
+ 						iph->saddr,
+ 					.saddr = saddr,
+ 					.tos = RT_TOS(tos)
+@@ -629,7 +628,7 @@ route_done:
+ 	room = dst_mtu(&rt->u.dst);
+ 	if (room > 576)
+ 		room = 576;
+-	room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
++	room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen;
+ 	room -= sizeof(struct icmphdr);
+ 
+ 	icmp_param.data_len = skb_in->len - icmp_param.offset;
+diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
+index 537731b..a3bf986 100644
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -356,11 +356,11 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
+ {
+ 	struct rtable *rt;
+ 	const struct inet_request_sock *ireq = inet_rsk(req);
+-	struct ip_options *opt = inet_rsk(req)->opt;
++	struct ip_options_rcu *opt = inet_rsk(req)->opt;
+ 	struct flowi fl = { .oif = sk->sk_bound_dev_if,
+ 			    .nl_u = { .ip4_u =
+-				      { .daddr = ((opt && opt->srr) ?
+-						  opt->faddr :
++				      { .daddr = ((opt && opt->opt.srr) ?
++						  opt->opt.faddr :
+ 						  ireq->rmt_addr),
+ 					.saddr = ireq->loc_addr,
+ 					.tos = RT_CONN_FLAGS(sk) } },
+@@ -374,7 +374,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
+ 	security_req_classify_flow(req, &fl);
+ 	if (ip_route_output_flow(net, &rt, &fl, sk, 0))
+ 		goto no_route;
+-	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
++	if (opt && opt->opt.is_strictroute && rt->rt_dst != rt->rt_gateway)
+ 		goto route_err;
+ 	return &rt->u.dst;
+ 
+diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
+index 94bf105..8a95972 100644
+--- a/net/ipv4/ip_options.c
++++ b/net/ipv4/ip_options.c
+@@ -35,7 +35,7 @@
+  * saddr is address of outgoing interface.
+  */
+ 
+-void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
++void ip_options_build(struct sk_buff *skb, struct ip_options *opt,
+ 			    __be32 daddr, struct rtable *rt, int is_frag)
+ {
+ 	unsigned char *iph = skb_network_header(skb);
+@@ -82,9 +82,9 @@ void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
+  * NOTE: dopt cannot point to skb.
+  */
+ 
+-int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
++int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb)
+ {
+-	struct ip_options *sopt;
++	const struct ip_options *sopt;
+ 	unsigned char *sptr, *dptr;
+ 	int soffset, doffset;
+ 	int	optlen;
+@@ -94,10 +94,8 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
+ 
+ 	sopt = &(IPCB(skb)->opt);
+ 
+-	if (sopt->optlen == 0) {
+-		dopt->optlen = 0;
++	if (sopt->optlen == 0)
+ 		return 0;
+-	}
+ 
+ 	sptr = skb_network_header(skb);
+ 	dptr = dopt->__data;
+@@ -156,7 +154,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
+ 		dopt->optlen += optlen;
+ 	}
+ 	if (sopt->srr) {
+-		unsigned char * start = sptr+sopt->srr;
++		unsigned char *start = sptr+sopt->srr;
+ 		__be32 faddr;
+ 
+ 		optlen  = start[1];
+@@ -499,19 +497,19 @@ void ip_options_undo(struct ip_options * opt)
+ 	}
+ }
+ 
+-static struct ip_options *ip_options_get_alloc(const int optlen)
++static struct ip_options_rcu *ip_options_get_alloc(const int optlen)
+ {
+-	return kzalloc(sizeof(struct ip_options) + ((optlen + 3) & ~3),
++	return kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3),
+ 		       GFP_KERNEL);
+ }
+ 
+-static int ip_options_get_finish(struct net *net, struct ip_options **optp,
+-				 struct ip_options *opt, int optlen)
++static int ip_options_get_finish(struct net *net, struct ip_options_rcu **optp,
++				 struct ip_options_rcu *opt, int optlen)
+ {
+ 	while (optlen & 3)
+-		opt->__data[optlen++] = IPOPT_END;
+-	opt->optlen = optlen;
+-	if (optlen && ip_options_compile(net, opt, NULL)) {
++		opt->opt.__data[optlen++] = IPOPT_END;
++	opt->opt.optlen = optlen;
++	if (optlen && ip_options_compile(net, &opt->opt, NULL)) {
+ 		kfree(opt);
+ 		return -EINVAL;
+ 	}
+@@ -520,29 +518,29 @@ static int ip_options_get_finish(struct net *net, struct ip_options **optp,
+ 	return 0;
+ }
+ 
+-int ip_options_get_from_user(struct net *net, struct ip_options **optp,
++int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp,
+ 			     unsigned char __user *data, int optlen)
+ {
+-	struct ip_options *opt = ip_options_get_alloc(optlen);
++	struct ip_options_rcu *opt = ip_options_get_alloc(optlen);
+ 
+ 	if (!opt)
+ 		return -ENOMEM;
+-	if (optlen && copy_from_user(opt->__data, data, optlen)) {
++	if (optlen && copy_from_user(opt->opt.__data, data, optlen)) {
+ 		kfree(opt);
+ 		return -EFAULT;
+ 	}
+ 	return ip_options_get_finish(net, optp, opt, optlen);
+ }
+ 
+-int ip_options_get(struct net *net, struct ip_options **optp,
++int ip_options_get(struct net *net, struct ip_options_rcu **optp,
+ 		   unsigned char *data, int optlen)
+ {
+-	struct ip_options *opt = ip_options_get_alloc(optlen);
++	struct ip_options_rcu *opt = ip_options_get_alloc(optlen);
+ 
+ 	if (!opt)
+ 		return -ENOMEM;
+ 	if (optlen)
+-		memcpy(opt->__data, data, optlen);
++		memcpy(opt->opt.__data, data, optlen);
+ 	return ip_options_get_finish(net, optp, opt, optlen);
+ }
+ 
+diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
+index 44b7910..7dde039 100644
+--- a/net/ipv4/ip_output.c
++++ b/net/ipv4/ip_output.c
+@@ -137,14 +137,14 @@ static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst)
+  *
+  */
+ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
+-			  __be32 saddr, __be32 daddr, struct ip_options *opt)
++			  __be32 saddr, __be32 daddr, struct ip_options_rcu *opt)
+ {
+ 	struct inet_sock *inet = inet_sk(sk);
+ 	struct rtable *rt = skb_rtable(skb);
+ 	struct iphdr *iph;
+ 
+ 	/* Build the IP header. */
+-	skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
++	skb_push(skb, sizeof(struct iphdr) + (opt ? opt->opt.optlen : 0));
+ 	skb_reset_network_header(skb);
+ 	iph = ip_hdr(skb);
+ 	iph->version  = 4;
+@@ -160,9 +160,9 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
+ 	iph->protocol = sk->sk_protocol;
+ 	ip_select_ident(iph, &rt->u.dst, sk);
+ 
+-	if (opt && opt->optlen) {
+-		iph->ihl += opt->optlen>>2;
+-		ip_options_build(skb, opt, daddr, rt, 0);
++	if (opt && opt->opt.optlen) {
++		iph->ihl += opt->opt.optlen>>2;
++		ip_options_build(skb, &opt->opt, daddr, rt, 0);
+ 	}
+ 
+ 	skb->priority = sk->sk_priority;
+@@ -312,9 +312,10 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
+ {
+ 	struct sock *sk = skb->sk;
+ 	struct inet_sock *inet = inet_sk(sk);
+-	struct ip_options *opt = inet->opt;
++	struct ip_options_rcu *inet_opt = NULL;
+ 	struct rtable *rt;
+ 	struct iphdr *iph;
++	int res;
+ 
+ 	/* Skip all of this if the packet is already routed,
+ 	 * f.e. by something like SCTP.
+@@ -325,13 +326,15 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
+ 
+ 	/* Make sure we can route this packet. */
+ 	rt = (struct rtable *)__sk_dst_check(sk, 0);
++	rcu_read_lock();
++	inet_opt = rcu_dereference(inet->inet_opt);
+ 	if (rt == NULL) {
+ 		__be32 daddr;
+ 
+ 		/* Use correct destination address if we have options. */
+ 		daddr = inet->daddr;
+-		if(opt && opt->srr)
+-			daddr = opt->faddr;
++		if (inet_opt && inet_opt->opt.srr)
++			daddr = inet_opt->opt.faddr;
+ 
+ 		{
+ 			struct flowi fl = { .oif = sk->sk_bound_dev_if,
+@@ -359,11 +362,11 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
+ 	skb_dst_set(skb, dst_clone(&rt->u.dst));
+ 
+ packet_routed:
+-	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
++	if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_dst != rt->rt_gateway)
+ 		goto no_route;
+ 
+ 	/* OK, we know where to send it, allocate and build IP header. */
+-	skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
++	skb_push(skb, sizeof(struct iphdr) + (inet_opt ? inet_opt->opt.optlen : 0));
+ 	skb_reset_network_header(skb);
+ 	iph = ip_hdr(skb);
+ 	*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
+@@ -377,9 +380,9 @@ packet_routed:
+ 	iph->daddr    = rt->rt_dst;
+ 	/* Transport layer set skb->h.foo itself. */
+ 
+-	if (opt && opt->optlen) {
+-		iph->ihl += opt->optlen >> 2;
+-		ip_options_build(skb, opt, inet->daddr, rt, 0);
++	if (inet_opt && inet_opt->opt.optlen) {
++		iph->ihl += inet_opt->opt.optlen >> 2;
++		ip_options_build(skb, &inet_opt->opt, inet->daddr, rt, 0);
+ 	}
+ 
+ 	ip_select_ident_more(iph, &rt->u.dst, sk,
+@@ -387,10 +390,12 @@ packet_routed:
+ 
+ 	skb->priority = sk->sk_priority;
+ 	skb->mark = sk->sk_mark;
+-
+-	return ip_local_out(skb);
++	res = ip_local_out(skb);
++	rcu_read_unlock();
++	return res;
+ 
+ no_route:
++	rcu_read_unlock();
+ 	IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
+ 	kfree_skb(skb);
+ 	return -EHOSTUNREACH;
+@@ -809,7 +814,7 @@ int ip_append_data(struct sock *sk,
+ 		/*
+ 		 * setup for corking.
+ 		 */
+-		opt = ipc->opt;
++		opt = ipc->opt ? &ipc->opt->opt : NULL;
+ 		if (opt) {
+ 			if (inet->cork.opt == NULL) {
+ 				inet->cork.opt = kmalloc(sizeof(struct ip_options) + 40, sk->sk_allocation);
+@@ -1367,26 +1372,23 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
+ 		   unsigned int len)
+ {
+ 	struct inet_sock *inet = inet_sk(sk);
+-	struct {
+-		struct ip_options	opt;
+-		char			data[40];
+-	} replyopts;
++	struct ip_options_data replyopts;
+ 	struct ipcm_cookie ipc;
+ 	__be32 daddr;
+ 	struct rtable *rt = skb_rtable(skb);
+ 
+-	if (ip_options_echo(&replyopts.opt, skb))
++	if (ip_options_echo(&replyopts.opt.opt, skb))
+ 		return;
+ 
+ 	daddr = ipc.addr = rt->rt_src;
+ 	ipc.opt = NULL;
+ 	ipc.shtx.flags = 0;
+ 
+-	if (replyopts.opt.optlen) {
++	if (replyopts.opt.opt.optlen) {
+ 		ipc.opt = &replyopts.opt;
+ 
+-		if (ipc.opt->srr)
+-			daddr = replyopts.opt.faddr;
++		if (replyopts.opt.opt.srr)
++			daddr = replyopts.opt.opt.faddr;
+ 	}
+ 
+ 	{
+diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
+index e982b5c..45d42f9 100644
+--- a/net/ipv4/ip_sockglue.c
++++ b/net/ipv4/ip_sockglue.c
+@@ -434,6 +434,11 @@ out:
+ }
+ 
+ 
++static void opt_kfree_rcu(struct rcu_head *head)
++{
++	kfree(container_of(head, struct ip_options_rcu, rcu));
++}
++
+ /*
+  *	Socket option code for IP. This is the end of the line after any
+  *	TCP,UDP etc options on an IP socket.
+@@ -479,13 +484,15 @@ static int do_ip_setsockopt(struct sock *sk, int level,
+ 	switch (optname) {
+ 	case IP_OPTIONS:
+ 	{
+-		struct ip_options *opt = NULL;
++		struct ip_options_rcu *old, *opt = NULL;
++
+ 		if (optlen > 40 || optlen < 0)
+ 			goto e_inval;
+ 		err = ip_options_get_from_user(sock_net(sk), &opt,
+ 					       optval, optlen);
+ 		if (err)
+ 			break;
++		old = inet->inet_opt;
+ 		if (inet->is_icsk) {
+ 			struct inet_connection_sock *icsk = inet_csk(sk);
+ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+@@ -494,17 +501,18 @@ static int do_ip_setsockopt(struct sock *sk, int level,
+ 			       (TCPF_LISTEN | TCPF_CLOSE)) &&
+ 			     inet->daddr != LOOPBACK4_IPV6)) {
+ #endif
+-				if (inet->opt)
+-					icsk->icsk_ext_hdr_len -= inet->opt->optlen;
++				if (old)
++					icsk->icsk_ext_hdr_len -= old->opt.optlen;
+ 				if (opt)
+-					icsk->icsk_ext_hdr_len += opt->optlen;
++					icsk->icsk_ext_hdr_len += opt->opt.optlen;
+ 				icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
+ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ 			}
+ #endif
+ 		}
+-		opt = xchg(&inet->opt, opt);
+-		kfree(opt);
++		rcu_assign_pointer(inet->inet_opt, opt);
++		if (old)
++			call_rcu(&old->rcu, opt_kfree_rcu);
+ 		break;
+ 	}
+ 	case IP_PKTINFO:
+@@ -1032,12 +1040,15 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
+ 	case IP_OPTIONS:
+ 	{
+ 		unsigned char optbuf[sizeof(struct ip_options)+40];
+-		struct ip_options * opt = (struct ip_options *)optbuf;
++		struct ip_options *opt = (struct ip_options *)optbuf;
++		struct ip_options_rcu *inet_opt;
++
++		inet_opt = inet->inet_opt;
+ 		opt->optlen = 0;
+-		if (inet->opt)
+-			memcpy(optbuf, inet->opt,
+-			       sizeof(struct ip_options)+
+-			       inet->opt->optlen);
++		if (inet_opt)
++			memcpy(optbuf, &inet_opt->opt,
++			       sizeof(struct ip_options) +
++			       inet_opt->opt.optlen);
+ 		release_sock(sk);
+ 
+ 		if (opt->optlen == 0)
+diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
+index ab996f9..07ab583 100644
+--- a/net/ipv4/raw.c
++++ b/net/ipv4/raw.c
+@@ -459,6 +459,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ 	__be32 saddr;
+ 	u8  tos;
+ 	int err;
++	struct ip_options_data opt_copy;
+ 
+ 	err = -EMSGSIZE;
+ 	if (len > 0xFFFF)
+@@ -519,8 +520,18 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ 	saddr = ipc.addr;
+ 	ipc.addr = daddr;
+ 
+-	if (!ipc.opt)
+-		ipc.opt = inet->opt;
++	if (!ipc.opt) {
++		struct ip_options_rcu *inet_opt;
++
++		rcu_read_lock();
++		inet_opt = rcu_dereference(inet->inet_opt);
++		if (inet_opt) {
++			memcpy(&opt_copy, inet_opt,
++			       sizeof(*inet_opt) + inet_opt->opt.optlen);
++			ipc.opt = &opt_copy.opt;
++		}
++		rcu_read_unlock();
++	}
+ 
+ 	if (ipc.opt) {
+ 		err = -EINVAL;
+@@ -529,10 +540,10 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ 		 */
+ 		if (inet->hdrincl)
+ 			goto done;
+-		if (ipc.opt->srr) {
++		if (ipc.opt->opt.srr) {
+ 			if (!daddr)
+ 				goto done;
+-			daddr = ipc.opt->faddr;
++			daddr = ipc.opt->opt.faddr;
+ 		}
+ 	}
+ 	tos = RT_CONN_FLAGS(sk);
+diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
+index a6e0e07..0a94b64 100644
+--- a/net/ipv4/syncookies.c
++++ b/net/ipv4/syncookies.c
+@@ -309,10 +309,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
+ 	 * the ACK carries the same options again (see RFC1122 4.2.3.8)
+ 	 */
+ 	if (opt && opt->optlen) {
+-		int opt_size = sizeof(struct ip_options) + opt->optlen;
++		int opt_size = sizeof(struct ip_options_rcu) + opt->optlen;
+ 
+ 		ireq->opt = kmalloc(opt_size, GFP_ATOMIC);
+-		if (ireq->opt != NULL && ip_options_echo(ireq->opt, skb)) {
++		if (ireq->opt != NULL && ip_options_echo(&ireq->opt->opt, skb)) {
+ 			kfree(ireq->opt);
+ 			ireq->opt = NULL;
+ 		}
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index ab1f33d..d1c0bff 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -152,6 +152,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+ 	__be32 daddr, nexthop;
+ 	int tmp;
+ 	int err;
++	struct ip_options_rcu *inet_opt;
+ 
+ 	if (addr_len < sizeof(struct sockaddr_in))
+ 		return -EINVAL;
+@@ -160,10 +161,11 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+ 		return -EAFNOSUPPORT;
+ 
+ 	nexthop = daddr = usin->sin_addr.s_addr;
+-	if (inet->opt && inet->opt->srr) {
++	inet_opt = inet->inet_opt;
++	if (inet_opt && inet_opt->opt.srr) {
+ 		if (!daddr)
+ 			return -EINVAL;
+-		nexthop = inet->opt->faddr;
++		nexthop = inet_opt->opt.faddr;
+ 	}
+ 
+ 	tmp = ip_route_connect(&rt, nexthop, inet->saddr,
+@@ -181,7 +183,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+ 		return -ENETUNREACH;
+ 	}
+ 
+-	if (!inet->opt || !inet->opt->srr)
++	if (!inet_opt || !inet_opt->opt.srr)
+ 		daddr = rt->rt_dst;
+ 
+ 	if (!inet->saddr)
+@@ -215,8 +217,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+ 	inet->daddr = daddr;
+ 
+ 	inet_csk(sk)->icsk_ext_hdr_len = 0;
+-	if (inet->opt)
+-		inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen;
++	if (inet_opt)
++		inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
+ 
+ 	tp->rx_opt.mss_clamp = 536;
+ 
+@@ -802,17 +804,18 @@ static void syn_flood_warning(struct sk_buff *skb)
+ /*
+  * Save and compile IPv4 options into the request_sock if needed.
+  */
+-static struct ip_options *tcp_v4_save_options(struct sock *sk,
+-					      struct sk_buff *skb)
++static struct ip_options_rcu *tcp_v4_save_options(struct sock *sk,
++						  struct sk_buff *skb)
+ {
+-	struct ip_options *opt = &(IPCB(skb)->opt);
+-	struct ip_options *dopt = NULL;
++	const struct ip_options *opt = &(IPCB(skb)->opt);
++	struct ip_options_rcu *dopt = NULL;
+ 
+ 	if (opt && opt->optlen) {
+-		int opt_size = optlength(opt);
++		int opt_size = sizeof(*dopt) + opt->optlen;
++
+ 		dopt = kmalloc(opt_size, GFP_ATOMIC);
+ 		if (dopt) {
+-			if (ip_options_echo(dopt, skb)) {
++			if (ip_options_echo(&dopt->opt, skb)) {
+ 				kfree(dopt);
+ 				dopt = NULL;
+ 			}
+@@ -1362,6 +1365,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+ #ifdef CONFIG_TCP_MD5SIG
+ 	struct tcp_md5sig_key *key;
+ #endif
++	struct ip_options_rcu *inet_opt;
+ 
+ 	if (sk_acceptq_is_full(sk))
+ 		goto exit_overflow;
+@@ -1382,13 +1386,14 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+ 	newinet->daddr	      = ireq->rmt_addr;
+ 	newinet->rcv_saddr    = ireq->loc_addr;
+ 	newinet->saddr	      = ireq->loc_addr;
+-	newinet->opt	      = ireq->opt;
++	inet_opt	      = ireq->opt;
++	rcu_assign_pointer(newinet->inet_opt, inet_opt);
+ 	ireq->opt	      = NULL;
+ 	newinet->mc_index     = inet_iif(skb);
+ 	newinet->mc_ttl	      = ip_hdr(skb)->ttl;
+ 	inet_csk(newsk)->icsk_ext_hdr_len = 0;
+-	if (newinet->opt)
+-		inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen;
++	if (inet_opt)
++		inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
+ 	newinet->id = newtp->write_seq ^ jiffies;
+ 
+ 	tcp_mtup_init(newsk);
+diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
+index 875cb9e..0078104 100644
+--- a/net/ipv4/udp.c
++++ b/net/ipv4/udp.c
+@@ -592,6 +592,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ 	int err, is_udplite = IS_UDPLITE(sk);
+ 	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
+ 	int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
++	struct ip_options_data opt_copy;
+ 
+ 	if (len > 0xFFFF)
+ 		return -EMSGSIZE;
+@@ -663,22 +664,32 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ 			free = 1;
+ 		connected = 0;
+ 	}
+-	if (!ipc.opt)
+-		ipc.opt = inet->opt;
++	if (!ipc.opt) {
++		struct ip_options_rcu *inet_opt;
++
++		rcu_read_lock();
++		inet_opt = rcu_dereference(inet->inet_opt);
++		if (inet_opt) {
++			memcpy(&opt_copy, inet_opt,
++			       sizeof(*inet_opt) + inet_opt->opt.optlen);
++			ipc.opt = &opt_copy.opt;
++		}
++		rcu_read_unlock();
++	}
+ 
+ 	saddr = ipc.addr;
+ 	ipc.addr = faddr = daddr;
+ 
+-	if (ipc.opt && ipc.opt->srr) {
++	if (ipc.opt && ipc.opt->opt.srr) {
+ 		if (!daddr)
+ 			return -EINVAL;
+-		faddr = ipc.opt->faddr;
++		faddr = ipc.opt->opt.faddr;
+ 		connected = 0;
+ 	}
+ 	tos = RT_TOS(inet->tos);
+ 	if (sock_flag(sk, SOCK_LOCALROUTE) ||
+ 	    (msg->msg_flags & MSG_DONTROUTE) ||
+-	    (ipc.opt && ipc.opt->is_strictroute)) {
++	    (ipc.opt && ipc.opt->opt.is_strictroute)) {
+ 		tos |= RTO_ONLINK;
+ 		connected = 0;
+ 	}
+diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
+index dc06299..b23fb31 100644
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -1391,7 +1391,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+ 
+ 	   First: no IPv4 options.
+ 	 */
+-	newinet->opt = NULL;
++	newinet->inet_opt = NULL;
+ 	newnp->ipv6_fl_list = NULL;
+ 
+ 	/* Clone RX bits */

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/ipvs-fix-info-leak-in-getsockopt-IP_VS_SO_GET_TIMEOU.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/ipvs-fix-info-leak-in-getsockopt-IP_VS_SO_GET_TIMEOU.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,34 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 15 Aug 2012 11:31:56 +0000
+Subject: ipvs: fix info leak in getsockopt(IP_VS_SO_GET_TIMEOUT)
+
+commit 2d8a041b7bfe1097af21441cb77d6af95f4f4680 upstream.
+
+If at least one of CONFIG_IP_VS_PROTO_TCP or CONFIG_IP_VS_PROTO_UDP is
+not set, __ip_vs_get_timeouts() does not fully initialize the structure
+that gets copied to userland and that for leaks up to 12 bytes of kernel
+stack. Add an explicit memset(0) before passing the structure to
+__ip_vs_get_timeouts() to avoid the info leak.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Cc: Wensong Zhang <wensong at linux-vs.org>
+Cc: Simon Horman <horms at verge.net.au>
+Cc: Julian Anastasov <ja at ssi.bg>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+[bwh: Backported to 2.6.32: adjust context]
+---
+ net/netfilter/ipvs/ip_vs_ctl.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
+index 02b2610..9bcd972 100644
+--- a/net/netfilter/ipvs/ip_vs_ctl.c
++++ b/net/netfilter/ipvs/ip_vs_ctl.c
+@@ -2455,6 +2455,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+ 	{
+ 		struct ip_vs_timeout_user t;
+ 
++		memset(&t, 0, sizeof(t));
+ 		__ip_vs_get_timeouts(&t);
+ 		if (copy_to_user(user, &t, sizeof(t)) != 0)
+ 			ret = -EFAULT;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/isofs-avoid-info-leak-on-export.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/isofs-avoid-info-leak-on-export.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,27 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Thu, 12 Jul 2012 08:46:54 +0200
+Subject: isofs: avoid info leak on export
+
+commit fe685aabf7c8c9f138e5ea900954d295bf229175 upstream.
+
+For type 1 the parent_offset member in struct isofs_fid gets copied
+uninitialized to userland. Fix this by initializing it to 0.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Signed-off-by: Jan Kara <jack at suse.cz>
+---
+ fs/isofs/export.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/isofs/export.c b/fs/isofs/export.c
+index e81a305..caec670 100644
+--- a/fs/isofs/export.c
++++ b/fs/isofs/export.c
+@@ -131,6 +131,7 @@ isofs_export_encode_fh(struct dentry *dentry,
+ 	len = 3;
+ 	fh32[0] = ei->i_iget5_block;
+  	fh16[2] = (__u16)ei->i_iget5_offset;  /* fh16 [sic] */
++	fh16[3] = 0;  /* avoid leaking uninitialized data */
+ 	fh32[2] = inode->i_generation;
+ 	if (connectable && !S_ISDIR(inode->i_mode)) {
+ 		struct inode *parent;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/kernel-signal.c-use-__ARCH_HAS_SA_RESTORER-instead-o.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/kernel-signal.c-use-__ARCH_HAS_SA_RESTORER-instead-o.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,37 @@
+From: Andrew Morton <akpm at linux-foundation.org>
+Date: Wed, 13 Mar 2013 14:59:34 -0700
+Subject: kernel/signal.c: use __ARCH_HAS_SA_RESTORER instead of SA_RESTORER
+
+commit 522cff142d7d2f9230839c9e1f21a4d8bcc22a4a upstream.
+
+__ARCH_HAS_SA_RESTORER is the preferred conditional for use in 3.9 and
+later kernels, per Kees.
+
+Cc: Emese Revfy <re.emese at gmail.com>
+Cc: Emese Revfy <re.emese at gmail.com>
+Cc: PaX Team <pageexec at freemail.hu>
+Cc: Al Viro <viro at zeniv.linux.org.uk>
+Cc: Oleg Nesterov <oleg at redhat.com>
+Cc: "Eric W. Biederman" <ebiederm at xmission.com>
+Cc: Serge Hallyn <serge.hallyn at canonical.com>
+Cc: Julien Tinnes <jln at google.com>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+Signed-off-by: Ben Hutchings <ben at decadent.org.uk>
+---
+ kernel/signal.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/signal.c b/kernel/signal.c
+index 1929014..1c6675b 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -320,7 +320,7 @@ flush_signal_handlers(struct task_struct *t, int force_default)
+ 		if (force_default || ka->sa.sa_handler != SIG_IGN)
+ 			ka->sa.sa_handler = SIG_DFL;
+ 		ka->sa.sa_flags = 0;
+-#ifdef SA_RESTORER
++#ifdef __ARCH_HAS_SA_RESTORER
+ 		ka->sa.sa_restorer = NULL;
+ #endif
+ 		sigemptyset(&ka->sa.sa_mask);

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/llc-fix-info-leak-via-getsockname.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/llc-fix-info-leak-via-getsockname.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,43 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 15 Aug 2012 11:31:53 +0000
+Subject: llc: fix info leak via getsockname()
+
+commit 3592aaeb80290bda0f2cf0b5456c97bfc638b192 upstream.
+
+The LLC code wrongly returns 0, i.e. "success", when the socket is
+zapped. Together with the uninitialized uaddrlen pointer argument from
+sys_getsockname this leads to an arbitrary memory leak of up to 128
+bytes kernel stack via the getsockname() syscall.
+
+Return an error instead when the socket is zapped to prevent the info
+leak. Also remove the unnecessary memset(0). We don't directly write to
+the memory pointed by uaddr but memcpy() a local structure at the end of
+the function that is properly initialized.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Cc: Arnaldo Carvalho de Melo <acme at ghostprotocols.net>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/llc/af_llc.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
+index 2da8d14..606b6ad 100644
+--- a/net/llc/af_llc.c
++++ b/net/llc/af_llc.c
+@@ -912,14 +912,13 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
+ 	struct sockaddr_llc sllc;
+ 	struct sock *sk = sock->sk;
+ 	struct llc_sock *llc = llc_sk(sk);
+-	int rc = 0;
++	int rc = -EBADF;
+ 
+ 	memset(&sllc, 0, sizeof(sllc));
+ 	lock_sock(sk);
+ 	if (sock_flag(sk, SOCK_ZAPPED))
+ 		goto out;
+ 	*uaddrlen = sizeof(sllc);
+-	memset(uaddr, 0, *uaddrlen);
+ 	if (peer) {
+ 		rc = -ENOTCONN;
+ 		if (sk->sk_state != TCP_ESTABLISHED)

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/net-fix-info-leak-in-compat-dev_ifconf.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/net-fix-info-leak-in-compat-dev_ifconf.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,31 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 15 Aug 2012 11:31:57 +0000
+Subject: net: fix info leak in compat dev_ifconf()
+
+commit 43da5f2e0d0c69ded3d51907d9552310a6b545e8 upstream.
+
+The implementation of dev_ifconf() for the compat ioctl interface uses
+an intermediate ifc structure allocated in userland for the duration of
+the syscall. Though, it fails to initialize the padding bytes inserted
+for alignment and that for leaks four bytes of kernel stack. Add an
+explicit memset(0) before filling the structure to avoid the info leak.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+[bwh: Backported to 2.6.32: adjust filename, context]
+---
+ fs/compat_ioctl.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
+index d84e705..c30134b 100644
+--- a/fs/compat_ioctl.c
++++ b/fs/compat_ioctl.c
+@@ -350,6 +350,7 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
+ 	if (copy_from_user(&ifc32, compat_ptr(arg), sizeof(struct ifconf32)))
+ 		return -EFAULT;
+ 
++	memset(&ifc, 0, sizeof(ifc));
+ 	if (ifc32.ifcbuf == 0) {
+ 		ifc32.ifc_len = 0;
+ 		ifc.ifc_len = 0;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/signal-Define-__ARCH_HAS_SA_RESTORER-so-we-know-whet.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/signal-Define-__ARCH_HAS_SA_RESTORER-so-we-know-whet.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,190 @@
+From: Ben Hutchings <ben at decadent.org.uk>
+Date: Sun, 25 Nov 2012 22:24:19 -0500
+Subject: signal: Define __ARCH_HAS_SA_RESTORER so we know whether to clear
+ sa_restorer
+
+flush_signal_handlers() needs to know whether sigaction::sa_restorer
+is defined, not whether SA_RESTORER is defined.  Define the
+__ARCH_HAS_SA_RESTORER macro to indicate this.
+
+Vaguely based on upstream commit 574c4866e33d 'consolidate kernel-side
+struct sigaction declarations'.
+
+Signed-off-by: Ben Hutchings <ben at decadent.org.uk>
+Cc: Al Viro <viro at zeniv.linux.org.uk>
+---
+ arch/arm/include/asm/signal.h     |    1 +
+ arch/avr32/include/asm/signal.h   |    1 +
+ arch/cris/include/asm/signal.h    |    1 +
+ arch/h8300/include/asm/signal.h   |    1 +
+ arch/m32r/include/asm/signal.h    |    1 +
+ arch/m68k/include/asm/signal.h    |    1 +
+ arch/mn10300/include/asm/signal.h |    1 +
+ arch/powerpc/include/asm/signal.h |    1 +
+ arch/s390/include/asm/signal.h    |    1 +
+ arch/sparc/include/asm/signal.h   |    1 +
+ arch/x86/include/asm/signal.h     |    2 ++
+ arch/xtensa/include/asm/signal.h  |    1 +
+ include/asm-generic/signal.h      |    4 ++++
+ 13 files changed, 17 insertions(+)
+
+diff --git a/arch/arm/include/asm/signal.h b/arch/arm/include/asm/signal.h
+index 43ba0fb..559ee24 100644
+--- a/arch/arm/include/asm/signal.h
++++ b/arch/arm/include/asm/signal.h
+@@ -127,6 +127,7 @@ struct sigaction {
+ 	__sigrestore_t sa_restorer;
+ 	sigset_t sa_mask;		/* mask last for extensibility */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ struct k_sigaction {
+ 	struct sigaction sa;
+diff --git a/arch/avr32/include/asm/signal.h b/arch/avr32/include/asm/signal.h
+index 8790dfc..e6952a0 100644
+--- a/arch/avr32/include/asm/signal.h
++++ b/arch/avr32/include/asm/signal.h
+@@ -128,6 +128,7 @@ struct sigaction {
+ 	__sigrestore_t sa_restorer;
+ 	sigset_t sa_mask;		/* mask last for extensibility */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ struct k_sigaction {
+ 	struct sigaction sa;
+diff --git a/arch/cris/include/asm/signal.h b/arch/cris/include/asm/signal.h
+index ea6af9a..057fea2 100644
+--- a/arch/cris/include/asm/signal.h
++++ b/arch/cris/include/asm/signal.h
+@@ -122,6 +122,7 @@ struct sigaction {
+ 	void (*sa_restorer)(void);
+ 	sigset_t sa_mask;		/* mask last for extensibility */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ struct k_sigaction {
+ 	struct sigaction sa;
+diff --git a/arch/h8300/include/asm/signal.h b/arch/h8300/include/asm/signal.h
+index fd8b66e..8695707 100644
+--- a/arch/h8300/include/asm/signal.h
++++ b/arch/h8300/include/asm/signal.h
+@@ -121,6 +121,7 @@ struct sigaction {
+ 	void (*sa_restorer)(void);
+ 	sigset_t sa_mask;		/* mask last for extensibility */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ struct k_sigaction {
+ 	struct sigaction sa;
+diff --git a/arch/m32r/include/asm/signal.h b/arch/m32r/include/asm/signal.h
+index 9c1acb2..a96a9f4 100644
+--- a/arch/m32r/include/asm/signal.h
++++ b/arch/m32r/include/asm/signal.h
+@@ -123,6 +123,7 @@ struct sigaction {
+ 	__sigrestore_t sa_restorer;
+ 	sigset_t sa_mask;		/* mask last for extensibility */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ struct k_sigaction {
+ 	struct sigaction sa;
+diff --git a/arch/m68k/include/asm/signal.h b/arch/m68k/include/asm/signal.h
+index 5bc09c7..01a492a 100644
+--- a/arch/m68k/include/asm/signal.h
++++ b/arch/m68k/include/asm/signal.h
+@@ -119,6 +119,7 @@ struct sigaction {
+ 	__sigrestore_t sa_restorer;
+ 	sigset_t sa_mask;		/* mask last for extensibility */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ struct k_sigaction {
+ 	struct sigaction sa;
+diff --git a/arch/mn10300/include/asm/signal.h b/arch/mn10300/include/asm/signal.h
+index 7e891fc..045d6a2 100644
+--- a/arch/mn10300/include/asm/signal.h
++++ b/arch/mn10300/include/asm/signal.h
+@@ -131,6 +131,7 @@ struct sigaction {
+ 	__sigrestore_t sa_restorer;
+ 	sigset_t sa_mask;		/* mask last for extensibility */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ struct k_sigaction {
+ 	struct sigaction sa;
+diff --git a/arch/powerpc/include/asm/signal.h b/arch/powerpc/include/asm/signal.h
+index 3eb13be..ec63a0a 100644
+--- a/arch/powerpc/include/asm/signal.h
++++ b/arch/powerpc/include/asm/signal.h
+@@ -109,6 +109,7 @@ struct sigaction {
+ 	__sigrestore_t sa_restorer;
+ 	sigset_t sa_mask;		/* mask last for extensibility */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ struct k_sigaction {
+ 	struct sigaction sa;
+diff --git a/arch/s390/include/asm/signal.h b/arch/s390/include/asm/signal.h
+index cdf5cb2..c872626 100644
+--- a/arch/s390/include/asm/signal.h
++++ b/arch/s390/include/asm/signal.h
+@@ -131,6 +131,7 @@ struct sigaction {
+         void (*sa_restorer)(void);
+         sigset_t sa_mask;               /* mask last for extensibility */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ struct k_sigaction {
+         struct sigaction sa;
+diff --git a/arch/sparc/include/asm/signal.h b/arch/sparc/include/asm/signal.h
+index e49b828..4929431 100644
+--- a/arch/sparc/include/asm/signal.h
++++ b/arch/sparc/include/asm/signal.h
+@@ -191,6 +191,7 @@ struct __old_sigaction {
+ 	unsigned long		sa_flags;
+ 	void			(*sa_restorer)(void);  /* not used by Linux/SPARC yet */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ typedef struct sigaltstack {
+ 	void			__user *ss_sp;
+diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
+index 598457c..6cbc795 100644
+--- a/arch/x86/include/asm/signal.h
++++ b/arch/x86/include/asm/signal.h
+@@ -125,6 +125,8 @@ typedef unsigned long sigset_t;
+ extern void do_notify_resume(struct pt_regs *, void *, __u32);
+ # endif /* __KERNEL__ */
+ 
++#define __ARCH_HAS_SA_RESTORER
++
+ #ifdef __i386__
+ # ifdef __KERNEL__
+ struct old_sigaction {
+diff --git a/arch/xtensa/include/asm/signal.h b/arch/xtensa/include/asm/signal.h
+index 633ba73..75edf8a 100644
+--- a/arch/xtensa/include/asm/signal.h
++++ b/arch/xtensa/include/asm/signal.h
+@@ -133,6 +133,7 @@ struct sigaction {
+ 	void (*sa_restorer)(void);
+ 	sigset_t sa_mask;		/* mask last for extensibility */
+ };
++#define __ARCH_HAS_SA_RESTORER
+ 
+ struct k_sigaction {
+ 	struct sigaction sa;
+diff --git a/include/asm-generic/signal.h b/include/asm-generic/signal.h
+index 555c0ae..743f7a5 100644
+--- a/include/asm-generic/signal.h
++++ b/include/asm-generic/signal.h
+@@ -99,6 +99,10 @@ typedef unsigned long old_sigset_t;
+ 
+ #include <asm-generic/signal-defs.h>
+ 
++#ifdef SA_RESTORER
++#define __ARCH_HAS_SA_RESTORER
++#endif
++
+ struct sigaction {
+ 	__sighandler_t sa_handler;
+ 	unsigned long sa_flags;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/signal-always-clear-sa_restorer-on-execve.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/signal-always-clear-sa_restorer-on-execve.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,66 @@
+From: Kees Cook <keescook at chromium.org>
+Date: Wed, 13 Mar 2013 14:59:33 -0700
+Subject: signal: always clear sa_restorer on execve
+
+commit 2ca39528c01a933f6689cd6505ce65bd6d68a530 upstream.
+
+When the new signal handlers are set up, the location of sa_restorer is
+not cleared, leaking a parent process's address space location to
+children.  This allows for a potential bypass of the parent's ASLR by
+examining the sa_restorer value returned when calling sigaction().
+
+Based on what should be considered "secret" about addresses, it only
+matters across the exec not the fork (since the VMAs haven't changed
+until the exec).  But since exec sets SIG_DFL and keeps sa_restorer,
+this is where it should be fixed.
+
+Given the few uses of sa_restorer, a "set" function was not written
+since this would be the only use.  Instead, we use
+__ARCH_HAS_SA_RESTORER, as already done in other places.
+
+Example of the leak before applying this patch:
+
+  $ cat /proc/$$/maps
+  ...
+  7fb9f3083000-7fb9f3238000 r-xp 00000000 fd:01 404469 .../libc-2.15.so
+  ...
+  $ ./leak
+  ...
+  7f278bc74000-7f278be29000 r-xp 00000000 fd:01 404469 .../libc-2.15.so
+  ...
+  1 0 (nil) 0x7fb9f30b94a0
+  2 4000000 (nil) 0x7f278bcaa4a0
+  3 4000000 (nil) 0x7f278bcaa4a0
+  4 0 (nil) 0x7fb9f30b94a0
+  ...
+
+[akpm at linux-foundation.org: use SA_RESTORER for backportability]
+Signed-off-by: Kees Cook <keescook at chromium.org>
+Reported-by: Emese Revfy <re.emese at gmail.com>
+Cc: Emese Revfy <re.emese at gmail.com>
+Cc: PaX Team <pageexec at freemail.hu>
+Cc: Al Viro <viro at zeniv.linux.org.uk>
+Cc: Oleg Nesterov <oleg at redhat.com>
+Cc: "Eric W. Biederman" <ebiederm at xmission.com>
+Cc: Serge Hallyn <serge.hallyn at canonical.com>
+Cc: Julien Tinnes <jln at google.com>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+---
+ kernel/signal.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/kernel/signal.c b/kernel/signal.c
+index 2bd8fab..1929014 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -320,6 +320,9 @@ flush_signal_handlers(struct task_struct *t, int force_default)
+ 		if (force_default || ka->sa.sa_handler != SIG_IGN)
+ 			ka->sa.sa_handler = SIG_DFL;
+ 		ka->sa.sa_flags = 0;
++#ifdef SA_RESTORER
++		ka->sa.sa_restorer = NULL;
++#endif
+ 		sigemptyset(&ka->sa.sa_mask);
+ 		ka++;
+ 	}

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/tmpfs-fix-use-after-free-of-mempolicy-object.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/tmpfs-fix-use-after-free-of-mempolicy-object.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,104 @@
+From: Greg Thelen <gthelen at google.com>
+Date: Fri, 22 Feb 2013 16:36:01 -0800
+Subject: tmpfs: fix use-after-free of mempolicy object
+
+commit 5f00110f7273f9ff04ac69a5f85bb535a4fd0987 upstream.
+
+The tmpfs remount logic preserves filesystem mempolicy if the mpol=M
+option is not specified in the remount request.  A new policy can be
+specified if mpol=M is given.
+
+Before this patch remounting an mpol bound tmpfs without specifying
+mpol= mount option in the remount request would set the filesystem's
+mempolicy object to a freed mempolicy object.
+
+To reproduce the problem boot a DEBUG_PAGEALLOC kernel and run:
+    # mkdir /tmp/x
+
+    # mount -t tmpfs -o size=100M,mpol=interleave nodev /tmp/x
+
+    # grep /tmp/x /proc/mounts
+    nodev /tmp/x tmpfs rw,relatime,size=102400k,mpol=interleave:0-3 0 0
+
+    # mount -o remount,size=200M nodev /tmp/x
+
+    # grep /tmp/x /proc/mounts
+    nodev /tmp/x tmpfs rw,relatime,size=204800k,mpol=??? 0 0
+        # note ? garbage in mpol=... output above
+
+    # dd if=/dev/zero of=/tmp/x/f count=1
+        # panic here
+
+Panic:
+    BUG: unable to handle kernel NULL pointer dereference at           (null)
+    IP: [<          (null)>]           (null)
+    [...]
+    Oops: 0010 [#1] SMP DEBUG_PAGEALLOC
+    Call Trace:
+      mpol_shared_policy_init+0xa5/0x160
+      shmem_get_inode+0x209/0x270
+      shmem_mknod+0x3e/0xf0
+      shmem_create+0x18/0x20
+      vfs_create+0xb5/0x130
+      do_last+0x9a1/0xea0
+      path_openat+0xb3/0x4d0
+      do_filp_open+0x42/0xa0
+      do_sys_open+0xfe/0x1e0
+      compat_sys_open+0x1b/0x20
+      cstar_dispatch+0x7/0x1f
+
+Non-debug kernels will not crash immediately because referencing the
+dangling mpol will not cause a fault.  Instead the filesystem will
+reference a freed mempolicy object, which will cause unpredictable
+behavior.
+
+The problem boils down to a dropped mpol reference below if
+shmem_parse_options() does not allocate a new mpol:
+
+    config = *sbinfo
+    shmem_parse_options(data, &config, true)
+    mpol_put(sbinfo->mpol)
+    sbinfo->mpol = config.mpol  /* BUG: saves unreferenced mpol */
+
+This patch avoids the crash by not releasing the mempolicy if
+shmem_parse_options() doesn't create a new mpol.
+
+How far back does this issue go? I see it in both 2.6.36 and 3.3.  I did
+not look back further.
+
+Signed-off-by: Greg Thelen <gthelen at google.com>
+Acked-by: Hugh Dickins <hughd at google.com>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+---
+ mm/shmem.c |   10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/mm/shmem.c b/mm/shmem.c
+index 3e0005b..e6a0c72 100644
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -2242,6 +2242,7 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
+ 	unsigned long inodes;
+ 	int error = -EINVAL;
+ 
++	config.mpol = NULL;
+ 	if (shmem_parse_options(data, &config, true))
+ 		return error;
+ 
+@@ -2269,8 +2270,13 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
+ 	sbinfo->max_inodes  = config.max_inodes;
+ 	sbinfo->free_inodes = config.max_inodes - inodes;
+ 
+-	mpol_put(sbinfo->mpol);
+-	sbinfo->mpol        = config.mpol;	/* transfers initial ref */
++	/*
++	 * Preserve previous mempolicy unless mpol remount option was specified.
++	 */
++	if (config.mpol) {
++		mpol_put(sbinfo->mpol);
++		sbinfo->mpol = config.mpol;	/* transfers initial ref */
++	}
+ out:
+ 	spin_unlock(&sbinfo->stat_lock);
+ 	return error;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/udf-avoid-info-leak-on-export.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/udf-avoid-info-leak-on-export.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,27 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Thu, 12 Jul 2012 08:46:55 +0200
+Subject: udf: avoid info leak on export
+
+commit 0143fc5e9f6f5aad4764801015bc8d4b4a278200 upstream.
+
+For type 0x51 the udf.parent_partref member in struct fid gets copied
+uninitialized to userland. Fix this by initializing it to 0.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Signed-off-by: Jan Kara <jack at suse.cz>
+---
+ fs/udf/namei.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/udf/namei.c b/fs/udf/namei.c
+index 21dad8c..b754151 100644
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -1331,6 +1331,7 @@ static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
+ 	*lenp = 3;
+ 	fid->udf.block = location.logicalBlockNum;
+ 	fid->udf.partref = location.partitionReferenceNum;
++	fid->udf.parent_partref = 0;
+ 	fid->udf.generation = inode->i_generation;
+ 
+ 	if (connectable && !S_ISDIR(inode->i_mode)) {

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_policy.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_policy.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,30 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 19 Sep 2012 11:33:40 +0000
+Subject: xfrm_user: fix info leak in copy_to_user_policy()
+
+commit 7b789836f434c87168eab067cfbed1ec4783dffd upstream.
+
+The memory reserved to dump the xfrm policy includes multiple padding
+bytes added by the compiler for alignment (padding bytes in struct
+xfrm_selector and struct xfrm_userpolicy_info). Add an explicit
+memset(0) before filling the buffer to avoid the heap info leak.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Acked-by: Steffen Klassert <steffen.klassert at secunet.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/xfrm/xfrm_user.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
+index 4823a15..3de81fe 100644
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -1076,6 +1076,7 @@ static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy
+ 
+ static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir)
+ {
++	memset(p, 0, sizeof(*p));
+ 	memcpy(&p->sel, &xp->selector, sizeof(p->sel));
+ 	memcpy(&p->lft, &xp->lft, sizeof(p->lft));
+ 	memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft));

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_state.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_state.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,30 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 19 Sep 2012 11:33:39 +0000
+Subject: xfrm_user: fix info leak in copy_to_user_state()
+
+commit f778a636713a435d3a922c60b1622a91136560c1 upstream.
+
+The memory reserved to dump the xfrm state includes the padding bytes of
+struct xfrm_usersa_info added by the compiler for alignment (7 for
+amd64, 3 for i386). Add an explicit memset(0) before filling the buffer
+to avoid the info leak.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Acked-by: Steffen Klassert <steffen.klassert at secunet.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/xfrm/xfrm_user.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
+index b95a2d6..4823a15 100644
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -506,6 +506,7 @@ out:
+ 
+ static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
+ {
++	memset(p, 0, sizeof(*p));
+ 	memcpy(&p->id, &x->id, sizeof(p->id));
+ 	memcpy(&p->sel, &x->sel, sizeof(p->sel));
+ 	memcpy(&p->lft, &x->lft, sizeof(p->lft));

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_tmpl.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_tmpl.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,33 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Wed, 19 Sep 2012 11:33:41 +0000
+Subject: xfrm_user: fix info leak in copy_to_user_tmpl()
+
+commit 1f86840f897717f86d523a13e99a447e6a5d2fa5 upstream.
+
+The memory used for the template copy is a local stack variable. As
+struct xfrm_user_tmpl contains multiple holes added by the compiler for
+alignment, not initializing the memory will lead to leaking stack bytes
+to userland. Add an explicit memset(0) to avoid the info leak.
+
+Initial version of the patch by Brad Spengler.
+
+Cc: Brad Spengler <spender at grsecurity.net>
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Acked-by: Steffen Klassert <steffen.klassert at secunet.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/xfrm/xfrm_user.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
+index 3de81fe..a8d83c4 100644
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -1178,6 +1178,7 @@ static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb)
+ 		struct xfrm_user_tmpl *up = &vec[i];
+ 		struct xfrm_tmpl *kp = &xp->xfrm_vec[i];
+ 
++		memset(up, 0, sizeof(*up));
+ 		memcpy(&up->id, &kp->id, sizeof(up->id));
+ 		up->family = kp->encap_family;
+ 		memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr));

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-return-error-pointer-instead-of-NULL-2.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-return-error-pointer-instead-of-NULL-2.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,43 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Fri, 14 Sep 2012 09:58:32 +0000
+Subject: xfrm_user: return error pointer instead of NULL #2
+
+commit c25463722509fef0ed630b271576a8c9a70236f3 upstream.
+
+When dump_one_policy() returns an error, e.g. because of a too small
+buffer to dump the whole xfrm policy, xfrm_policy_netlink() returns
+NULL instead of an error pointer. But its caller expects an error
+pointer and therefore continues to operate on a NULL skbuff.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Acked-by: Steffen Klassert <steffen.klassert at secunet.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/xfrm/xfrm_user.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
+index dff20ac..06f42f6 100644
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -1306,6 +1306,7 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
+ {
+ 	struct xfrm_dump_info info;
+ 	struct sk_buff *skb;
++	int err;
+ 
+ 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ 	if (!skb)
+@@ -1316,9 +1317,10 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
+ 	info.nlmsg_seq = seq;
+ 	info.nlmsg_flags = 0;
+ 
+-	if (dump_one_policy(xp, dir, 0, &info) < 0) {
++	err = dump_one_policy(xp, dir, 0, &info);
++	if (err) {
+ 		kfree_skb(skb);
+-		return NULL;
++		return ERR_PTR(err);
+ 	}
+ 
+ 	return skb;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-return-error-pointer-instead-of-NULL.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/all/xfrm_user-return-error-pointer-instead-of-NULL.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,47 @@
+From: Mathias Krause <minipli at googlemail.com>
+Date: Thu, 13 Sep 2012 11:41:26 +0000
+Subject: xfrm_user: return error pointer instead of NULL
+
+commit 864745d291b5ba80ea0bd0edcbe67273de368836 upstream.
+
+When dump_one_state() returns an error, e.g. because of a too small
+buffer to dump the whole xfrm state, xfrm_state_netlink() returns NULL
+instead of an error pointer. But its callers expect an error pointer
+and therefore continue to operate on a NULL skbuff.
+
+This could lead to a privilege escalation (execution of user code in
+kernel context) if the attacker has CAP_NET_ADMIN and is able to map
+address 0.
+
+Signed-off-by: Mathias Krause <minipli at googlemail.com>
+Acked-by: Steffen Klassert <steffen.klassert at secunet.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/xfrm/xfrm_user.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
+index a8d83c4..dff20ac 100644
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -647,6 +647,7 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
+ {
+ 	struct xfrm_dump_info info;
+ 	struct sk_buff *skb;
++	int err;
+ 
+ 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ 	if (!skb)
+@@ -657,9 +658,10 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
+ 	info.nlmsg_seq = seq;
+ 	info.nlmsg_flags = 0;
+ 
+-	if (dump_one_state(x, 0, &info)) {
++	err = dump_one_state(x, 0, &info);
++	if (err) {
+ 		kfree_skb(skb);
+-		return NULL;
++		return ERR_PTR(err);
+ 	}
+ 
+ 	return skb;

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-lock-slots_lock-around-device-assignment.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-lock-slots_lock-around-device-assignment.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,69 @@
+From: Alex Williamson <alex.williamson at redhat.com>
+Date: Tue, 17 Apr 2012 21:46:44 -0600
+Subject: KVM: lock slots_lock around device assignment
+
+commit 21a1416a1c945c5aeaeaf791b63c64926018eb77 upstream.
+
+As pointed out by Jason Baron, when assigning a device to a guest
+we first set the iommu domain pointer, which enables mapping
+and unmapping of memory slots to the iommu.  This leaves a window
+where this path is enabled, but we haven't synchronized the iommu
+mappings to the existing memory slots.  Thus a slot being removed
+at that point could send us down unexpected code paths removing
+non-existent pinnings and iommu mappings.  Take the slots_lock
+around creating the iommu domain and initial mappings as well as
+around iommu teardown to avoid this race.
+
+Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
+Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
+[bwh: Backported to 2.6.32:
+ - Adjust context
+ - kvm_host::slots_lock is a rw_semaphore, so use {down,up}_write() on it]
+---
+ virt/kvm/iommu.c |   20 +++++++++++++-------
+ 1 file changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
+index 3738b5f..27c2eba 100644
+--- a/virt/kvm/iommu.c
++++ b/virt/kvm/iommu.c
+@@ -169,18 +169,20 @@ int kvm_iommu_map_guest(struct kvm *kvm)
+ 		return -ENODEV;
+ 	}
+ 
++	down_write(&kvm->slots_lock);
++
+ 	kvm->arch.iommu_domain = iommu_domain_alloc();
+-	if (!kvm->arch.iommu_domain)
+-		return -ENOMEM;
++	if (!kvm->arch.iommu_domain) {
++		r = -ENOMEM;
++		goto out_unlock;
++	}
+ 
+ 	r = kvm_iommu_map_memslots(kvm);
+ 	if (r)
+-		goto out_unmap;
+-
+-	return 0;
++		kvm_iommu_unmap_memslots(kvm);
+ 
+-out_unmap:
+-	kvm_iommu_unmap_memslots(kvm);
++out_unlock:
++	up_write(&kvm->slots_lock);
+ 	return r;
+ }
+ 
+@@ -231,7 +233,11 @@ int kvm_iommu_unmap_guest(struct kvm *kvm)
+ 	if (!domain)
+ 		return 0;
+ 
++	down_write(&kvm->slots_lock);
+ 	kvm_iommu_unmap_memslots(kvm);
++	kvm->arch.iommu_domain = NULL;
++	up_write(&kvm->slots_lock);
++
+ 	iommu_domain_free(domain);
+ 	return 0;
+ }

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-unmap-pages-from-the-iommu-when-slots-are-remove.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-unmap-pages-from-the-iommu-when-slots-are-remove.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,99 @@
+From: Alex Williamson <alex.williamson at redhat.com>
+Date: Wed, 11 Apr 2012 09:51:49 -0600
+Subject: KVM: unmap pages from the iommu when slots are removed
+
+commit 32f6daad4651a748a58a3ab6da0611862175722f upstream.
+
+We've been adding new mappings, but not destroying old mappings.
+This can lead to a page leak as pages are pinned using
+get_user_pages, but only unpinned with put_page if they still
+exist in the memslots list on vm shutdown.  A memslot that is
+destroyed while an iommu domain is enabled for the guest will
+therefore result in an elevated page reference count that is
+never cleared.
+
+Additionally, without this fix, the iommu is only programmed
+with the first translation for a gpa.  This can result in
+peer-to-peer errors if a mapping is destroyed and replaced by a
+new mapping at the same gpa as the iommu will still be pointing
+to the original, pinned memory address.
+
+Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
+Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
+[bwh: Backported to 2.6.32:
+ - Adjust context
+ - In __kvm_set_memory_region(), call kvm_iommu_unmap_pages()
+   immediately before kvm_free_physmem_slot() which cleans up the old
+   memory slot.  Make this dependent on CONFIG_DMAR, consistent with
+   the use of kvm_iommu_map_pages().]
+---
+ include/linux/kvm_host.h |    6 ++++++
+ virt/kvm/iommu.c         |    8 ++++++--
+ virt/kvm/kvm_main.c      |    6 ++++++
+ 3 files changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
+index 8bfed57..7dbe682 100644
+--- a/include/linux/kvm_host.h
++++ b/include/linux/kvm_host.h
+@@ -410,6 +410,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
+ #ifdef CONFIG_IOMMU_API
+ int kvm_iommu_map_pages(struct kvm *kvm, gfn_t base_gfn,
+ 			unsigned long npages);
++void kvm_iommu_unmap_pages(struct kvm *kvm, struct kvm_memory_slot *slot);
+ int kvm_iommu_map_guest(struct kvm *kvm);
+ int kvm_iommu_unmap_guest(struct kvm *kvm);
+ int kvm_assign_device(struct kvm *kvm,
+@@ -424,6 +425,11 @@ static inline int kvm_iommu_map_pages(struct kvm *kvm,
+ 	return 0;
+ }
+ 
++static inline void kvm_iommu_unmap_pages(struct kvm *kvm,
++					 struct kvm_memory_slot *slot)
++{
++}
++
+ static inline int kvm_iommu_map_guest(struct kvm *kvm)
+ {
+ 	return -ENODEV;
+diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
+index 1514758..3738b5f 100644
+--- a/virt/kvm/iommu.c
++++ b/virt/kvm/iommu.c
+@@ -207,13 +207,17 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
+ 	iommu_unmap_range(domain, gfn_to_gpa(base_gfn), PAGE_SIZE * npages);
+ }
+ 
++void kvm_iommu_unmap_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
++{
++	kvm_iommu_put_pages(kvm, slot->base_gfn, slot->npages);
++}
++
+ static int kvm_iommu_unmap_memslots(struct kvm *kvm)
+ {
+ 	int i;
+ 
+ 	for (i = 0; i < kvm->nmemslots; i++) {
+-		kvm_iommu_put_pages(kvm, kvm->memslots[i].base_gfn,
+-				    kvm->memslots[i].npages);
++		kvm_iommu_unmap_pages(kvm, &kvm->memslots[i]);
+ 	}
+ 
+ 	return 0;
+diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
+index 82b6fdc..a510abe 100644
+--- a/virt/kvm/kvm_main.c
++++ b/virt/kvm/kvm_main.c
+@@ -1334,6 +1334,12 @@ skip_lpage:
+ 		goto out_free;
+ 	}
+ 
++#ifdef CONFIG_DMAR
++	/* unmap the pages in iommu page table */
++	if (!npages)
++		kvm_iommu_unmap_pages(kvm, &old);
++#endif
++
+ 	kvm_free_physmem_slot(&old, npages ? &new : NULL);
+ 	/* Slot deletion case: we have to update the current slot */
+ 	spin_lock(&kvm->mmu_lock);

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-x86-fix-for-buffer-overflow-in-handling-of-MSR_K.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-x86-fix-for-buffer-overflow-in-handling-of-MSR_K.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,39 @@
+From: Andy Honig <ahonig at google.com>
+Date: Mon, 11 Mar 2013 09:34:52 -0700
+Subject: KVM: x86: fix for buffer overflow in handling of MSR_KVM_SYSTEM_TIME
+ (CVE-2013-1796)
+
+commit c300aa64ddf57d9c5d9c898a64b36877345dd4a9 upstream.
+
+If the guest sets the GPA of the time_page so that the request to update the
+time straddles a page then KVM will write onto an incorrect page.  The
+write is done byusing kmap atomic to get a pointer to the page for the time
+structure and then performing a memcpy to that page starting at an offset
+that the guest controls.  Well behaved guests always provide a 32-byte aligned
+address, however a malicious guest could use this to corrupt host kernel
+memory.
+
+Tested: Tested against kvmclock unit test.
+
+Signed-off-by: Andrew Honig <ahonig at google.com>
+Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
+---
+ arch/x86/kvm/x86.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
+index e792150..3a5dab0 100644
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -957,6 +957,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+ 		/* ...but clean it before doing the actual write */
+ 		vcpu->arch.time_offset = data & ~(PAGE_MASK | 1);
+ 
++		/* Check that the address is 32-byte aligned. */
++		if (vcpu->arch.time_offset &
++				(sizeof(struct pvclock_vcpu_time_info) - 1))
++			break;
++
+ 		vcpu->arch.time_page =
+ 				gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT);
+ 

Added: dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-x86-invalid-opcode-oops-on-SET_SREGS-with-OSXSAV.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/bugfix/x86/KVM-x86-invalid-opcode-oops-on-SET_SREGS-with-OSXSAV.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,68 @@
+From: Petr Matousek <pmatouse at redhat.com>
+Date: Tue, 6 Nov 2012 19:24:07 +0100
+Subject: KVM: x86: invalid opcode oops on SET_SREGS with OSXSAVE bit set
+ (CVE-2012-4461)
+
+commit 6d1068b3a98519247d8ba4ec85cd40ac136dbdf9 upstream.
+
+On hosts without the XSAVE support unprivileged local user can trigger
+oops similar to the one below by setting X86_CR4_OSXSAVE bit in guest
+cr4 register using KVM_SET_SREGS ioctl and later issuing KVM_RUN
+ioctl.
+
+invalid opcode: 0000 [#2] SMP
+Modules linked in: tun ip6table_filter ip6_tables ebtable_nat ebtables
+...
+Pid: 24935, comm: zoog_kvm_monito Tainted: G      D      3.2.0-3-686-pae
+EIP: 0060:[<f8b9550c>] EFLAGS: 00210246 CPU: 0
+EIP is at kvm_arch_vcpu_ioctl_run+0x92a/0xd13 [kvm]
+EAX: 00000001 EBX: 000f387e ECX: 00000000 EDX: 00000000
+ESI: 00000000 EDI: 00000000 EBP: ef5a0060 ESP: d7c63e70
+ DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
+Process zoog_kvm_monito (pid: 24935, ti=d7c62000 task=ed84a0c0
+task.ti=d7c62000)
+Stack:
+ 00000001 f70a1200 f8b940a9 ef5a0060 00000000 00200202 f8769009 00000000
+ ef5a0060 000f387e eda5c020 8722f9c8 00015bae 00000000 ed84a0c0 ed84a0c0
+ c12bf02d 0000ae80 ef7f8740 fffffffb f359b740 ef5a0060 f8b85dc1 0000ae80
+Call Trace:
+ [<f8b940a9>] ? kvm_arch_vcpu_ioctl_set_sregs+0x2fe/0x308 [kvm]
+...
+ [<c12bfb44>] ? syscall_call+0x7/0xb
+Code: 89 e8 e8 14 ee ff ff ba 00 00 04 00 89 e8 e8 98 48 ff ff 85 c0 74
+1e 83 7d 48 00 75 18 8b 85 08 07 00 00 31 c9 8b 95 0c 07 00 00 <0f> 01
+d1 c7 45 48 01 00 00 00 c7 45 1c 01 00 00 00 0f ae f0 89
+EIP: [<f8b9550c>] kvm_arch_vcpu_ioctl_run+0x92a/0xd13 [kvm] SS:ESP
+0068:d7c63e70
+
+QEMU first retrieves the supported features via KVM_GET_SUPPORTED_CPUID
+and then sets them later. So guest's X86_FEATURE_XSAVE should be masked
+out on hosts without X86_FEATURE_XSAVE, making kvm_set_cr4 with
+X86_CR4_OSXSAVE fail. Userspaces that allow specifying guest cpuid with
+X86_FEATURE_XSAVE even on hosts that do not support it, might be
+susceptible to this attack from inside the guest as well.
+
+Allow setting X86_CR4_OSXSAVE bit only if host has XSAVE support.
+
+Signed-off-by: Petr Matousek <pmatouse at redhat.com>
+Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
+[bwh: Backported to 2.6.32: XSAVE is not supported at all, so always
+ deny setting OSXSAVE]
+---
+ arch/x86/kvm/x86.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
+index 2ebf763..e792150 100644
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -4840,6 +4840,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ 	int pending_vec, max_bits;
+ 	struct descriptor_table dt;
+ 
++	if (sregs->cr4 & X86_CR4_OSXSAVE)
++		return -EINVAL;
++
+ 	vcpu_load(vcpu);
+ 
+ 	dt.limit = sregs->idt.limit;

Added: dists/squeeze-security/linux-2.6/debian/patches/debian/nls-Avoid-ABI-change-for-CVE-2013-1773-fix.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze-security/linux-2.6/debian/patches/debian/nls-Avoid-ABI-change-for-CVE-2013-1773-fix.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -0,0 +1,52 @@
+From: Ben Hutchings <ben at decadent.org.uk>
+Date: Tue, 2 Apr 2013 03:43:23 +0100
+Subject: nls: Avoid ABI change for CVE-2013-1773 fix
+
+Rename the new function, redirect to it with a macro, and keep the old
+function name as a wrapper for it.  It was *possible* to use the old
+function securely, just not easy.
+---
+ fs/nls/nls_base.c   |   10 +++++++++-
+ include/linux/nls.h |    1 +
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
+index 0eb059ec..ff4afac 100644
+--- a/fs/nls/nls_base.c
++++ b/fs/nls/nls_base.c
+@@ -129,7 +129,7 @@ static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian)
+ 	}
+ }
+ 
+-int utf8s_to_utf16s(const u8 *s, int len, enum utf16_endian endian,
++int utf8s_to_utf16s_fixed(const u8 *s, int len, enum utf16_endian endian,
+ 		wchar_t *pwcs, int maxlen)
+ {
+ 	u16 *op;
+@@ -169,6 +169,14 @@ int utf8s_to_utf16s(const u8 *s, int len, enum utf16_endian endian,
+ 	}
+ 	return op - pwcs;
+ }
++EXPORT_SYMBOL(utf8s_to_utf16s_fixed);
++
++/* Backward binary-compatibility */
++#undef utf8s_to_utf16s
++int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs)
++{
++	return utf8s_to_utf16s_fixed(s, len, UTF16_HOST_ENDIAN, pwcs, INT_MAX);
++}
+ EXPORT_SYMBOL(utf8s_to_utf16s);
+ 
+ static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian)
+diff --git a/include/linux/nls.h b/include/linux/nls.h
+index 5dc635f..fe20a33 100644
+--- a/include/linux/nls.h
++++ b/include/linux/nls.h
+@@ -52,6 +52,7 @@ extern struct nls_table *load_nls_default(void);
+ 
+ extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu);
+ extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen);
++#define utf8s_to_utf16s utf8s_to_utf16s_fixed
+ extern int utf8s_to_utf16s(const u8 *s, int len,
+ 		enum utf16_endian endian, wchar_t *pwcs, int maxlen);
+ extern int utf16s_to_utf8s(const wchar_t *pwcs, int len,

Modified: dists/squeeze-security/linux-2.6/debian/patches/features/all/openvz/openvz.patch
==============================================================================
--- dists/squeeze-security/linux-2.6/debian/patches/features/all/openvz/openvz.patch	Tue Apr  2 04:38:50 2013	(r19968)
+++ dists/squeeze-security/linux-2.6/debian/patches/features/all/openvz/openvz.patch	Tue Apr  2 04:52:07 2013	(r19969)
@@ -6549,6 +6549,7 @@
 [bwh: Fix context for changes to struct file after 2.6.32.60]
 [dannf: export signal_wake_up_state instead of signal_wake_up to deal with
  wrapper introduction in 910ffdb18a6408e14febbb6e4b6840fd2c928c82]
+[bwh: Fix context for changes to ip_send_reply() in fix for CVE-2012-3552]
 
 diff --git a/COPYING.Parallels b/COPYING.Parallels
 new file mode 100644
@@ -84082,14 +84083,14 @@
 --- a/net/ipv4/ip_output.c
 +++ b/net/ipv4/ip_output.c
 @@ -1369,12 +1369,13 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
- 		char			data[40];
- 	} replyopts;
+ 	struct inet_sock *inet = inet_sk(sk);
+ 	struct ip_options_data replyopts;
  	struct ipcm_cookie ipc;
 -	__be32 daddr;
 +	__be32 saddr, daddr;
  	struct rtable *rt = skb_rtable(skb);
  
- 	if (ip_options_echo(&replyopts.opt, skb))
+ 	if (ip_options_echo(&replyopts.opt.opt, skb))
  		return;
  
 +	saddr = ip_hdr(skb)->daddr;

Modified: dists/squeeze-security/linux-2.6/debian/patches/series/48squeeze2
==============================================================================
--- dists/squeeze-security/linux-2.6/debian/patches/series/48squeeze2	Tue Apr  2 04:38:50 2013	(r19968)
+++ dists/squeeze-security/linux-2.6/debian/patches/series/48squeeze2	Tue Apr  2 04:52:07 2013	(r19969)
@@ -1,3 +1,35 @@
 + bugfix/all/USB-io_ti-Fix-Null-dereference-in-chase-port.patch
 + bugfix/all/keys-fix-race-with-concurrent-install_user_keyrings.patch
 + bugfix/all/fix-ptrace-when-task-is-in-task_is_stopped-state.patch
++ bugfix/x86/KVM-unmap-pages-from-the-iommu-when-slots-are-remove.patch
++ bugfix/x86/KVM-lock-slots_lock-around-device-assignment.patch
++ bugfix/all/inet-add-RCU-protection-to-inet-opt.patch
++ bugfix/x86/KVM-x86-invalid-opcode-oops-on-SET_SREGS-with-OSXSAV.patch
++ bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_state.patch
++ bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_policy.patch
++ bugfix/all/xfrm_user-fix-info-leak-in-copy_to_user_tmpl.patch
++ bugfix/all/net-fix-info-leak-in-compat-dev_ifconf.patch
++ bugfix/all/ipvs-fix-info-leak-in-getsockopt-IP_VS_SO_GET_TIMEOU.patch
++ bugfix/all/llc-fix-info-leak-via-getsockname.patch
++ bugfix/all/Bluetooth-L2CAP-Fix-info-leak-via-getsockname.patch 
++ bugfix/all/Bluetooth-HCI-Fix-info-leak-in-getsockopt-HCI_FILTER.patch
++ bugfix/all/Bluetooth-RFCOMM-Fix-info-leak-via-getsockname.patch
++ bugfix/all/Bluetooth-RFCOMM-Fix-info-leak-in-ioctl-RFCOMMGETDEV.patch
++ bugfix/all/atm-fix-info-leak-via-getsockname.patch 
++ bugfix/all/atm-fix-info-leak-in-getsockopt-SO_ATMPVC.patch
++ bugfix/all/udf-avoid-info-leak-on-export.patch
++ bugfix/all/isofs-avoid-info-leak-on-export.patch 
++ bugfix/all/Bluetooth-Fix-incorrect-strncpy-in-hidp_setup_hid.patch 
++ bugfix/all/signal-always-clear-sa_restorer-on-execve.patch
++ bugfix/all/signal-Define-__ARCH_HAS_SA_RESTORER-so-we-know-whet.patch
++ bugfix/all/kernel-signal.c-use-__ARCH_HAS_SA_RESTORER-instead-o.patch
++ bugfix/all/tmpfs-fix-use-after-free-of-mempolicy-object.patch
++ bugfix/all/fat-Fix-stat-f_namelen.patch
++ bugfix/all/NLS-improve-UTF8-UTF16-string-conversion-routine.patch
++ debian/nls-Avoid-ABI-change-for-CVE-2013-1773-fix.patch
++ bugfix/x86/KVM-x86-fix-for-buffer-overflow-in-handling-of-MSR_K.patch
++ bugfix/all/KVM-Fix-bounds-checking-in-ioapic-indirect-register-.patch
++ bugfix/all/xfrm_user-return-error-pointer-instead-of-NULL.patch
++ bugfix/all/xfrm_user-return-error-pointer-instead-of-NULL-2.patch 
++ bugfix/all/USB-cdc-wdm-fix-buffer-overflow.patch
++ bugfix/all/dcbnl-fix-various-netlink-info-leaks.patch



More information about the Kernel-svn-changes mailing list