summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2012-05-21 10:40:21 -0400
committerAnthony G. Basile <blueness@gentoo.org>2012-05-21 10:40:21 -0400
commit154077e80521647e6e280dfe21534f7b01803a6a (patch)
treef844390e8d7857aa5102770e8f39c0a7cb29671f
parentGrsec/PaX: 2.9-{2.6.32.59,3.2.17,3.3.6}-201205131658 (diff)
downloadhardened-patchset-154077e80521647e6e280dfe21534f7b01803a6a.tar.gz
hardened-patchset-154077e80521647e6e280dfe21534f7b01803a6a.tar.bz2
hardened-patchset-154077e80521647e6e280dfe21534f7b01803a6a.zip
Grsec/PaX: 2.9-{2.6.32.59,3.2.17,3.3.6}-20120519112520120519
-rw-r--r--2.6.32/0000_README2
-rw-r--r--2.6.32/4420_grsecurity-2.9-2.6.32.59-201205191123.patch (renamed from 2.6.32/4420_grsecurity-2.9-2.6.32.59-201205131656.patch)131
-rw-r--r--3.2.17/0000_README2
-rw-r--r--3.2.17/4420_grsecurity-2.9-3.2.17-201205191125.patch (renamed from 3.2.17/4420_grsecurity-2.9-3.2.17-201205131657.patch)313
-rw-r--r--3.3.6/0000_README2
-rw-r--r--3.3.6/4420_grsecurity-2.9-3.3.6-201205191125.patch (renamed from 3.3.6/4420_grsecurity-2.9-3.3.6-201205131658.patch)326
6 files changed, 734 insertions, 42 deletions
diff --git a/2.6.32/0000_README b/2.6.32/0000_README
index 3655217..fc95969 100644
--- a/2.6.32/0000_README
+++ b/2.6.32/0000_README
@@ -30,7 +30,7 @@ Patch: 1058_linux-2.6.32.59.patch
From: http://www.kernel.org
Desc: Linux 2.6.32.59
-Patch: 4420_grsecurity-2.9-2.6.32.59-201205131656.patch
+Patch: 4420_grsecurity-2.9-2.6.32.59-201205191123.patch
From: http://www.grsecurity.net
Desc: hardened-sources base patch from upstream grsecurity
diff --git a/2.6.32/4420_grsecurity-2.9-2.6.32.59-201205131656.patch b/2.6.32/4420_grsecurity-2.9-2.6.32.59-201205191123.patch
index d324f88..2e42506 100644
--- a/2.6.32/4420_grsecurity-2.9-2.6.32.59-201205131656.patch
+++ b/2.6.32/4420_grsecurity-2.9-2.6.32.59-201205191123.patch
@@ -27069,10 +27069,18 @@ index f46c3407..f7e72b0 100644
}
if (mm->get_unmapped_area == arch_get_unmapped_area)
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
-index 73ffd55..f61c2a7 100644
+index 73ffd55..10ae23f 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
-@@ -69,11 +69,7 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
+@@ -13,6 +13,7 @@
+ #include <asm/tlbflush.h>
+ #include <asm/tlb.h>
+ #include <asm/proto.h>
++#include <asm/bios_ebda.h>
+
+ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+@@ -69,11 +70,7 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
* cause a hotspot and fill up ZONE_DMA. The page tables
* need roughly 0.5KB per GB.
*/
@@ -27085,7 +27093,7 @@ index 73ffd55..f61c2a7 100644
e820_table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT,
tables, PAGE_SIZE);
if (e820_table_start == -1UL)
-@@ -147,7 +143,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
+@@ -147,7 +144,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
#endif
set_nx();
@@ -27094,11 +27102,16 @@ index 73ffd55..f61c2a7 100644
printk(KERN_INFO "NX (Execute Disable) protection: active\n");
/* Enable PSE if available */
-@@ -329,10 +325,27 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
+@@ -329,10 +326,32 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
* Access has to be given to non-kernel-ram areas as well, these contain the PCI
* mmio resources as well as potential bios/acpi data regions.
*/
+
++#ifdef CONFIG_GRKERNSEC_KMEM
++static unsigned int ebda_start __read_only;
++static unsigned int ebda_end __read_only;
++#endif
++
int devmem_is_allowed(unsigned long pagenr)
{
+#ifdef CONFIG_GRKERNSEC_KMEM
@@ -27106,7 +27119,7 @@ index 73ffd55..f61c2a7 100644
+ if (!pagenr)
+ return 1;
+ /* allow EBDA */
-+ if ((0x9f000 >> PAGE_SHIFT) == pagenr)
++ if (pagenr >= ebda_start && pagenr < ebda_end)
+ return 1;
+ /* allow ISA/video mem */
+ if ((ISA_START_ADDRESS >> PAGE_SHIFT) <= pagenr && pagenr < (ISA_END_ADDRESS >> PAGE_SHIFT))
@@ -27122,18 +27135,48 @@ index 73ffd55..f61c2a7 100644
if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
return 0;
if (!page_is_ram(pagenr))
-@@ -379,6 +392,86 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
+@@ -377,8 +396,116 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
+ #endif
+ }
++#ifdef CONFIG_GRKERNSEC_KMEM
++static inline void gr_init_ebda(void)
++{
++ unsigned int ebda_addr;
++ unsigned int ebda_size = 0;
++
++ ebda_addr = get_bios_ebda();
++ if (ebda_addr) {
++ ebda_size = *(unsigned char *)phys_to_virt(ebda_addr);
++ ebda_size <<= 10;
++ }
++ if (ebda_addr && ebda_size) {
++ ebda_start = ebda_addr >> PAGE_SHIFT;
++ ebda_end = min(PAGE_ALIGN(ebda_addr + ebda_size), 0xa0000) >> PAGE_SHIFT;
++ } else {
++ ebda_start = 0x9f000 >> PAGE_SHIFT;
++ ebda_end = 0xa0000 >> PAGE_SHIFT;
++ }
++}
++#else
++static inline void gr_init_ebda(void) { }
++#endif
++
void free_initmem(void)
{
-+
+#ifdef CONFIG_PAX_KERNEXEC
+#ifdef CONFIG_X86_32
+ /* PaX: limit KERNEL_CS to actual size */
+ unsigned long addr, limit;
+ struct desc_struct d;
+ int cpu;
++#endif
++#endif
++
++ gr_init_ebda();
+
++#ifdef CONFIG_PAX_KERNEXEC
++#ifdef CONFIG_X86_32
+ limit = paravirt_enabled() ? ktva_ktla(0xffffffff) : (unsigned long)&_etext;
+ limit = (limit - 1UL) >> PAGE_SHIFT;
+
@@ -38580,6 +38623,19 @@ index 818b617..4656e38 100644
if (!*param->name) {
DMWARN("name not supplied when creating device");
return -EINVAL;
+diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
+index f1c8cae..59f0822 100644
+--- a/drivers/md/dm-log-userspace-transfer.c
++++ b/drivers/md/dm-log-userspace-transfer.c
+@@ -133,7 +133,7 @@ static void cn_ulog_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
+ {
+ struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1);
+
+- if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN))
++ if (!capable(CAP_SYS_ADMIN))
+ return;
+
+ spin_lock(&receiving_list_lock);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 6021d0a..a878643 100644
--- a/drivers/md/dm-raid1.c
@@ -53290,7 +53346,7 @@ index 7fa7a90..fef924d 100644
return -EOPNOTSUPP;
}
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
-index 266ec87..b7e1172 100644
+index 266ec87..466b2f5 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -471,13 +471,6 @@ struct ioctl_data {
@@ -53307,6 +53363,14 @@ index 266ec87..b7e1172 100644
/* The Rx and Tx buffer descriptors. */
struct netdev_desc {
__le64 next_desc;
+@@ -551,4 +544,7 @@ MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
+ #define DEFAULT_RXT 750
+ #define DEFAULT_TXC 1
+ #define MAX_TXC 8
++
++#include <linux/mii.h>
++
+ #endif /* __DL2K_H__ */
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index d1e0563..b9e129c 100644
--- a/drivers/net/e1000e/82571.c
@@ -61542,7 +61606,7 @@ index cd3910b..ff053d3 100644
.open = rpcrouter_open,
.release = rpcrouter_release,
diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c
-index c24e4e0..07665be 100644
+index c24e4e0..629999b 100644
--- a/drivers/staging/dst/dcore.c
+++ b/drivers/staging/dst/dcore.c
@@ -149,7 +149,7 @@ static int dst_bdev_release(struct gendisk *disk, fmode_t mode)
@@ -61563,6 +61627,15 @@ index c24e4e0..07665be 100644
snprintf(n->name, sizeof(n->name), "%s", ctl->name);
err = dst_node_sysfs_init(n);
+@@ -855,7 +855,7 @@ static void cn_dst_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
+ struct dst_node *n = NULL, *tmp;
+ unsigned int hash;
+
+- if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) {
++ if (!capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto out;
+ }
diff --git a/drivers/staging/dst/trans.c b/drivers/staging/dst/trans.c
index 557d372..8d84422 100644
--- a/drivers/staging/dst/trans.c
@@ -61842,6 +61915,19 @@ index 2eb8e3d..57616a7 100644
.owner = THIS_MODULE,
.open = poch_open,
.release = poch_release,
+diff --git a/drivers/staging/pohmelfs/config.c b/drivers/staging/pohmelfs/config.c
+index 5d04bf5..d4baff2 100644
+--- a/drivers/staging/pohmelfs/config.c
++++ b/drivers/staging/pohmelfs/config.c
+@@ -531,7 +531,7 @@ static void pohmelfs_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *n
+ {
+ int err;
+
+- if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN))
++ if (!capable(CAP_SYS_ADMIN))
+ return;
+
+ switch (msg->flags) {
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c
index c94de31..19402bc 100644
--- a/drivers/staging/pohmelfs/inode.c
@@ -65596,7 +65682,7 @@ index d94c57f..912984c 100644
.update_status = riva_bl_update_status,
};
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
-index 54fbb29..2c108fc 100644
+index 54fbb29..37bab4b 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -18,6 +18,7 @@
@@ -65607,6 +65693,15 @@ index 54fbb29..2c108fc 100644
#include <video/edid.h>
#include <video/uvesafb.h>
#ifdef CONFIG_X86
+@@ -72,7 +73,7 @@ static void uvesafb_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *ns
+ struct uvesafb_task *utask;
+ struct uvesafb_ktask *task;
+
+- if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN))
++ if (!capable(CAP_SYS_ADMIN))
+ return;
+
+ if (msg->seq >= UVESAFB_TASKS_MAX)
@@ -120,7 +121,7 @@ static int uvesafb_helper_start(void)
NULL,
};
@@ -102188,10 +102283,20 @@ index 58f141b..b759702 100644
(jiffies ^ (jiffies >> 7))));
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
-index f095659..adc892a 100644
+index f095659..537313b 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
-@@ -2085,6 +2085,8 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
+@@ -838,8 +838,7 @@ new_segment:
+ wait_for_sndbuf:
+ set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+ wait_for_memory:
+- if (copied)
+- tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
++ tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
+
+ if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
+ goto do_error;
+@@ -2085,6 +2084,8 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
int val;
int err = 0;
@@ -102200,7 +102305,7 @@ index f095659..adc892a 100644
/* This is a string value all the others are int's */
if (optname == TCP_CONGESTION) {
char name[TCP_CA_NAME_MAX];
-@@ -2355,6 +2357,8 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
+@@ -2355,6 +2356,8 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
struct tcp_sock *tp = tcp_sk(sk);
int val, len;
diff --git a/3.2.17/0000_README b/3.2.17/0000_README
index d74a42e..bf0e817 100644
--- a/3.2.17/0000_README
+++ b/3.2.17/0000_README
@@ -6,7 +6,7 @@ Patch: 1016_linux-3.2.17.patch
From: http://www.kernel.org
Desc: Linux 3.2.17
-Patch: 4420_grsecurity-2.9-3.2.17-201205131657.patch
+Patch: 4420_grsecurity-2.9-3.2.17-201205191125.patch
From: http://www.grsecurity.net
Desc: hardened-sources base patch from upstream grsecurity
diff --git a/3.2.17/4420_grsecurity-2.9-3.2.17-201205131657.patch b/3.2.17/4420_grsecurity-2.9-3.2.17-201205191125.patch
index 8ddeecb..23a68ae 100644
--- a/3.2.17/4420_grsecurity-2.9-3.2.17-201205131657.patch
+++ b/3.2.17/4420_grsecurity-2.9-3.2.17-201205191125.patch
@@ -11436,10 +11436,67 @@ index 98391db..8f6984e 100644
static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h
-index effff47..f9e4035 100644
+index effff47..bbb8295 100644
--- a/arch/x86/include/asm/pgtable-3level.h
+++ b/arch/x86/include/asm/pgtable-3level.h
-@@ -38,12 +38,16 @@ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
+@@ -31,6 +31,56 @@ static inline void native_set_pte(pte_t *ptep, pte_t pte)
+ ptep->pte_low = pte.pte_low;
+ }
+
++#define __HAVE_ARCH_READ_PMD_ATOMIC
++/*
++ * pte_offset_map_lock on 32bit PAE kernels was reading the pmd_t with
++ * a "*pmdp" dereference done by gcc. Problem is, in certain places
++ * where pte_offset_map_lock is called, concurrent page faults are
++ * allowed, if the mmap_sem is hold for reading. An example is mincore
++ * vs page faults vs MADV_DONTNEED. On the page fault side
++ * pmd_populate rightfully does a set_64bit, but if we're reading the
++ * pmd_t with a "*pmdp" on the mincore side, a SMP race can happen
++ * because gcc will not read the 64bit of the pmd atomically. To fix
++ * this all places running pmd_offset_map_lock() while holding the
++ * mmap_sem in read mode, shall read the pmdp pointer using this
++ * function to know if the pmd is null nor not, and in turn to know if
++ * they can run pmd_offset_map_lock or pmd_trans_huge or other pmd
++ * operations.
++ *
++ * Without THP if the mmap_sem is hold for reading, the
++ * pmd can only transition from null to not null while read_pmd_atomic runs.
++ * So there's no need of literally reading it atomically.
++ *
++ * With THP if the mmap_sem is hold for reading, the pmd can become
++ * THP or null or point to a pte (and in turn become "stable") at any
++ * time under read_pmd_atomic, so it's mandatory to read it atomically
++ * with cmpxchg8b.
++ */
++#ifndef CONFIG_TRANSPARENT_HUGEPAGE
++static inline pmd_t read_pmd_atomic(pmd_t *pmdp)
++{
++ pmdval_t ret;
++ u32 *tmp = (u32 *)pmdp;
++
++ ret = (pmdval_t) (*tmp);
++ if (ret) {
++ /*
++ * If the low part is null, we must not read the high part
++ * or we can end up with a partial pmd.
++ */
++ smp_rmb();
++ ret |= ((pmdval_t)*(tmp + 1)) << 32;
++ }
++
++ return __pmd(ret);
++}
++#else /* CONFIG_TRANSPARENT_HUGEPAGE */
++static inline pmd_t read_pmd_atomic(pmd_t *pmdp)
++{
++ return __pmd(atomic64_read((atomic64_t *)pmdp));
++}
++#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
++
+ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
+ {
+ set_64bit((unsigned long long *)(ptep), native_pte_val(pte));
+@@ -38,12 +88,16 @@ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd)
{
@@ -25048,18 +25105,19 @@ index f581a18..a269cab 100644
}
if (mm->get_unmapped_area == arch_get_unmapped_area)
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
-index 87488b9..399f416 100644
+index 87488b9..6371e97 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
-@@ -15,6 +15,7 @@
+@@ -15,6 +15,8 @@
#include <asm/tlbflush.h>
#include <asm/tlb.h>
#include <asm/proto.h>
+#include <asm/desc.h>
++#include <asm/bios_ebda.h>
unsigned long __initdata pgt_buf_start;
unsigned long __meminitdata pgt_buf_end;
-@@ -31,7 +32,7 @@ int direct_gbpages
+@@ -31,7 +33,7 @@ int direct_gbpages
static void __init find_early_table_space(unsigned long end, int use_pse,
int use_gbpages)
{
@@ -25068,8 +25126,16 @@ index 87488b9..399f416 100644
phys_addr_t base;
puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
-@@ -312,8 +313,29 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
+@@ -310,10 +312,37 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
+ * Access has to be given to non-kernel-ram areas as well, these contain the PCI
+ * mmio resources as well as potential bios/acpi data regions.
*/
++
++#ifdef CONFIG_GRKERNSEC_KMEM
++static unsigned int ebda_start __read_only;
++static unsigned int ebda_end __read_only;
++#endif
++
int devmem_is_allowed(unsigned long pagenr)
{
+#ifdef CONFIG_GRKERNSEC_KMEM
@@ -25077,7 +25143,7 @@ index 87488b9..399f416 100644
+ if (!pagenr)
+ return 1;
+ /* allow EBDA */
-+ if ((0x9f000 >> PAGE_SHIFT) == pagenr)
++ if (pagenr >= ebda_start && pagenr < ebda_end)
+ return 1;
+#else
+ if (!pagenr)
@@ -25099,18 +25165,48 @@ index 87488b9..399f416 100644
if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
return 0;
if (!page_is_ram(pagenr))
-@@ -372,6 +394,86 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
+@@ -370,8 +399,116 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
+ #endif
+ }
++#ifdef CONFIG_GRKERNSEC_KMEM
++static inline void gr_init_ebda(void)
++{
++ unsigned int ebda_addr;
++ unsigned int ebda_size = 0;
++
++ ebda_addr = get_bios_ebda();
++ if (ebda_addr) {
++ ebda_size = *(unsigned char *)phys_to_virt(ebda_addr);
++ ebda_size <<= 10;
++ }
++ if (ebda_addr && ebda_size) {
++ ebda_start = ebda_addr >> PAGE_SHIFT;
++ ebda_end = min(PAGE_ALIGN(ebda_addr + ebda_size), 0xa0000) >> PAGE_SHIFT;
++ } else {
++ ebda_start = 0x9f000 >> PAGE_SHIFT;
++ ebda_end = 0xa0000 >> PAGE_SHIFT;
++ }
++}
++#else
++static inline void gr_init_ebda(void) { }
++#endif
++
void free_initmem(void)
{
-+
+#ifdef CONFIG_PAX_KERNEXEC
+#ifdef CONFIG_X86_32
+ /* PaX: limit KERNEL_CS to actual size */
+ unsigned long addr, limit;
+ struct desc_struct d;
+ int cpu;
++#endif
++#endif
+
++ gr_init_ebda();
++
++#ifdef CONFIG_PAX_KERNEXEC
++#ifdef CONFIG_X86_32
+ limit = paravirt_enabled() ? ktva_ktla(0xffffffff) : (unsigned long)&_etext;
+ limit = (limit - 1UL) >> PAGE_SHIFT;
+
@@ -29545,9 +29641,18 @@ index 0358e55..bc33689 100644
mdev->bm_writ_cnt =
mdev->read_cnt =
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
-index af2a250..219c74b 100644
+index af2a250..0fdeb75 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
+@@ -2297,7 +2297,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms
+ return;
+ }
+
+- if (!cap_raised(current_cap(), CAP_SYS_ADMIN)) {
++ if (!capable(CAP_SYS_ADMIN)) {
+ retcode = ERR_PERM;
+ goto fail;
+ }
@@ -2359,7 +2359,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms
module_put(THIS_MODULE);
}
@@ -33943,6 +34048,19 @@ index 1ce84ed..0fdd40a 100644
if (!*param->name) {
DMWARN("name not supplied when creating device");
return -EINVAL;
+diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
+index 1f23e04..08d9a20 100644
+--- a/drivers/md/dm-log-userspace-transfer.c
++++ b/drivers/md/dm-log-userspace-transfer.c
+@@ -134,7 +134,7 @@ static void cn_ulog_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
+ {
+ struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1);
+
+- if (!cap_raised(current_cap(), CAP_SYS_ADMIN))
++ if (!capable(CAP_SYS_ADMIN))
+ return;
+
+ spin_lock(&receiving_list_lock);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 9bfd057..01180bc 100644
--- a/drivers/md/dm-raid1.c
@@ -35672,6 +35790,23 @@ index 61d2bdd..7f1154a 100644
{ "100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
{ "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR },
{ "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
+diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
+index cf480b5..de00805 100644
+--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
++++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
+@@ -494,7 +494,11 @@ out:
+ static void e1000_down_and_stop(struct e1000_adapter *adapter)
+ {
+ set_bit(__E1000_DOWN, &adapter->flags);
+- cancel_work_sync(&adapter->reset_task);
++
++ /* Only kill reset task if adapter is not resetting */
++ if (!test_bit(__E1000_RESETTING, &adapter->flags))
++ cancel_work_sync(&adapter->reset_task);
++
+ cancel_delayed_work_sync(&adapter->watchdog_task);
+ cancel_delayed_work_sync(&adapter->phy_info_task);
+ cancel_delayed_work_sync(&adapter->fifo_stall_task);
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index e1159e5..e18684d 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -42615,7 +42750,7 @@ index 41746bb..febcb44 100644
return count;
}
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
-index 8813588..1c6b358 100644
+index 8813588..7265ef8 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -19,6 +19,7 @@
@@ -42626,6 +42761,15 @@ index 8813588..1c6b358 100644
#include <video/edid.h>
#include <video/uvesafb.h>
#ifdef CONFIG_X86
+@@ -73,7 +74,7 @@ static void uvesafb_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *ns
+ struct uvesafb_task *utask;
+ struct uvesafb_ktask *task;
+
+- if (!cap_raised(current_cap(), CAP_SYS_ADMIN))
++ if (!capable(CAP_SYS_ADMIN))
+ return;
+
+ if (msg->seq >= UVESAFB_TASKS_MAX)
@@ -121,7 +122,7 @@ static int uvesafb_helper_start(void)
NULL,
};
@@ -48370,6 +48514,96 @@ index 50a15fa..ca113f9 100644
}
void nfs_fattr_init(struct nfs_fattr *fattr)
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 51f6a40..fb4bb6f 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -3581,19 +3581,23 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
+ if (npages == 0)
+ npages = 1;
+
++ /* Add an extra page to handle the bitmap returned */
++ npages++;
++
+ for (i = 0; i < npages; i++) {
+ pages[i] = alloc_page(GFP_KERNEL);
+ if (!pages[i])
+ goto out_free;
+ }
+- if (npages > 1) {
+- /* for decoding across pages */
+- res.acl_scratch = alloc_page(GFP_KERNEL);
+- if (!res.acl_scratch)
+- goto out_free;
+- }
++
++ /* for decoding across pages */
++ res.acl_scratch = alloc_page(GFP_KERNEL);
++ if (!res.acl_scratch)
++ goto out_free;
++
+ args.acl_len = npages * PAGE_SIZE;
+ args.acl_pgbase = 0;
++
+ /* Let decode_getfacl know not to fail if the ACL data is larger than
+ * the page we send as a guess */
+ if (buf == NULL)
+diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
+index 68adab4..d7e6f7b 100644
+--- a/fs/nfs/nfs4xdr.c
++++ b/fs/nfs/nfs4xdr.c
+@@ -4965,11 +4965,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
+ bitmap[3] = {0};
+ struct kvec *iov = req->rq_rcv_buf.head;
+ int status;
++ size_t page_len = xdr->buf->page_len;
+
+ res->acl_len = 0;
+ if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+ goto out;
++
+ bm_p = xdr->p;
++ res->acl_data_offset = be32_to_cpup(bm_p) + 2;
++ res->acl_data_offset <<= 2;
++ /* Check if the acl data starts beyond the allocated buffer */
++ if (res->acl_data_offset > page_len)
++ return -ERANGE;
++
+ if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+ goto out;
+ if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+@@ -4979,28 +4987,24 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
+ size_t hdrlen;
+- u32 recvd;
+
+ /* The bitmap (xdr len + bitmaps) and the attr xdr len words
+ * are stored with the acl data to handle the problem of
+ * variable length bitmaps.*/
+ xdr->p = bm_p;
+- res->acl_data_offset = be32_to_cpup(bm_p) + 2;
+- res->acl_data_offset <<= 2;
+
+ /* We ignore &savep and don't do consistency checks on
+ * the attr length. Let userspace figure it out.... */
+ hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
+ attrlen += res->acl_data_offset;
+- recvd = req->rq_rcv_buf.len - hdrlen;
+- if (attrlen > recvd) {
++ if (attrlen > page_len) {
+ if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
+ /* getxattr interface called with a NULL buf */
+ res->acl_len = attrlen;
+ goto out;
+ }
+- dprintk("NFS: acl reply: attrlen %u > recvd %u\n",
+- attrlen, recvd);
++ dprintk("NFS: acl reply: attrlen %zu > page_len %u\n",
++ attrlen, page_len);
+ return -EINVAL;
+ }
+ xdr_read_pages(xdr, attrlen);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 5c3cd82..ed535e5 100644
--- a/fs/nfsd/vfs.c
@@ -61170,10 +61404,49 @@ index 810431d..ccc3638 100644
* The "pgd_xxx()" functions here are trivial for a folded two-level
* setup: the pud is never bad, and a pud always exists (as it's folded
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
-index a03c098..7e5b223 100644
+index a03c098..19751cf 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
-@@ -502,6 +502,14 @@ static inline int pmd_trans_unstable(pmd_t *pmd)
+@@ -445,6 +445,18 @@ static inline int pmd_write(pmd_t pmd)
+ #endif /* __HAVE_ARCH_PMD_WRITE */
+ #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
++#ifndef __HAVE_ARCH_READ_PMD_ATOMIC
++static inline pmd_t read_pmd_atomic(pmd_t *pmdp)
++{
++ /*
++ * Depend on compiler for an atomic pmd read. NOTE: this is
++ * only going to work, if the pmdval_t isn't larger than
++ * an unsigned long.
++ */
++ return *pmdp;
++}
++#endif /* __HAVE_ARCH_READ_PMD_ATOMIC */
++
+ /*
+ * This function is meant to be used by sites walking pagetables with
+ * the mmap_sem hold in read mode to protect against MADV_DONTNEED and
+@@ -458,11 +470,17 @@ static inline int pmd_write(pmd_t pmd)
+ * undefined so behaving like if the pmd was none is safe (because it
+ * can return none anyway). The compiler level barrier() is critically
+ * important to compute the two checks atomically on the same pmdval.
++ *
++ * For 32bit kernels with a 64bit large pmd_t this automatically takes
++ * care of reading the pmd atomically to avoid SMP race conditions
++ * against pmd_populate() when the mmap_sem is hold for reading by the
++ * caller (a special atomic read not done by "gcc" as in the generic
++ * version above, is also needed when THP is disabled because the page
++ * fault can populate the pmd from under us).
+ */
+ static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd)
+ {
+- /* depend on compiler for an atomic pmd read */
+- pmd_t pmdval = *pmd;
++ pmd_t pmdval = read_pmd_atomic(pmd);
+ /*
+ * The barrier will stabilize the pmdval in a register or on
+ * the stack so that it will stop changing under the code.
+@@ -502,6 +520,14 @@ static inline int pmd_trans_unstable(pmd_t *pmd)
#endif
}
@@ -77251,6 +77524,20 @@ index 94cdbc5..0cb0063 100644
if (peer->tcp_ts_stamp) {
ts = peer->tcp_ts;
tsage = get_seconds() - peer->tcp_ts_stamp;
+diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
+index 7904db4..0f12572 100644
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -851,8 +851,7 @@ new_segment:
+ wait_for_sndbuf:
+ set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+ wait_for_memory:
+- if (copied)
+- tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
++ tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
+
+ if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
+ goto do_error;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index de69cec..74908e1 100644
--- a/net/ipv4/tcp_ipv4.c
diff --git a/3.3.6/0000_README b/3.3.6/0000_README
index f827d9b..f465286 100644
--- a/3.3.6/0000_README
+++ b/3.3.6/0000_README
@@ -6,7 +6,7 @@ Patch: 1005_linux-3.3.6.patch
From: http://www.kernel.org
Desc: Linux 3.3.6
-Patch: 4420_grsecurity-2.9-3.3.6-201205131658.patch
+Patch: 4420_grsecurity-2.9-3.3.6-201205191125.patch
From: http://www.grsecurity.net
Desc: hardened-sources base patch from upstream grsecurity
diff --git a/3.3.6/4420_grsecurity-2.9-3.3.6-201205131658.patch b/3.3.6/4420_grsecurity-2.9-3.3.6-201205191125.patch
index 0bad506..bfd5849 100644
--- a/3.3.6/4420_grsecurity-2.9-3.3.6-201205131658.patch
+++ b/3.3.6/4420_grsecurity-2.9-3.3.6-201205191125.patch
@@ -11386,10 +11386,67 @@ index 98391db..8f6984e 100644
static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h
-index effff47..f9e4035 100644
+index effff47..bbb8295 100644
--- a/arch/x86/include/asm/pgtable-3level.h
+++ b/arch/x86/include/asm/pgtable-3level.h
-@@ -38,12 +38,16 @@ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
+@@ -31,6 +31,56 @@ static inline void native_set_pte(pte_t *ptep, pte_t pte)
+ ptep->pte_low = pte.pte_low;
+ }
+
++#define __HAVE_ARCH_READ_PMD_ATOMIC
++/*
++ * pte_offset_map_lock on 32bit PAE kernels was reading the pmd_t with
++ * a "*pmdp" dereference done by gcc. Problem is, in certain places
++ * where pte_offset_map_lock is called, concurrent page faults are
++ * allowed, if the mmap_sem is hold for reading. An example is mincore
++ * vs page faults vs MADV_DONTNEED. On the page fault side
++ * pmd_populate rightfully does a set_64bit, but if we're reading the
++ * pmd_t with a "*pmdp" on the mincore side, a SMP race can happen
++ * because gcc will not read the 64bit of the pmd atomically. To fix
++ * this all places running pmd_offset_map_lock() while holding the
++ * mmap_sem in read mode, shall read the pmdp pointer using this
++ * function to know if the pmd is null nor not, and in turn to know if
++ * they can run pmd_offset_map_lock or pmd_trans_huge or other pmd
++ * operations.
++ *
++ * Without THP if the mmap_sem is hold for reading, the
++ * pmd can only transition from null to not null while read_pmd_atomic runs.
++ * So there's no need of literally reading it atomically.
++ *
++ * With THP if the mmap_sem is hold for reading, the pmd can become
++ * THP or null or point to a pte (and in turn become "stable") at any
++ * time under read_pmd_atomic, so it's mandatory to read it atomically
++ * with cmpxchg8b.
++ */
++#ifndef CONFIG_TRANSPARENT_HUGEPAGE
++static inline pmd_t read_pmd_atomic(pmd_t *pmdp)
++{
++ pmdval_t ret;
++ u32 *tmp = (u32 *)pmdp;
++
++ ret = (pmdval_t) (*tmp);
++ if (ret) {
++ /*
++ * If the low part is null, we must not read the high part
++ * or we can end up with a partial pmd.
++ */
++ smp_rmb();
++ ret |= ((pmdval_t)*(tmp + 1)) << 32;
++ }
++
++ return __pmd(ret);
++}
++#else /* CONFIG_TRANSPARENT_HUGEPAGE */
++static inline pmd_t read_pmd_atomic(pmd_t *pmdp)
++{
++ return __pmd(atomic64_read((atomic64_t *)pmdp));
++}
++#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
++
+ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
+ {
+ set_64bit((unsigned long long *)(ptep), native_pte_val(pte));
+@@ -38,12 +88,16 @@ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd)
{
@@ -24949,18 +25006,19 @@ index 8ecbb4b..a269cab 100644
}
if (mm->get_unmapped_area == arch_get_unmapped_area)
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
-index 6cabf65..77e9c1c 100644
+index 6cabf65..00139c4 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
-@@ -17,6 +17,7 @@
+@@ -17,6 +17,8 @@
#include <asm/tlb.h>
#include <asm/proto.h>
#include <asm/dma.h> /* for MAX_DMA_PFN */
+#include <asm/desc.h>
++#include <asm/bios_ebda.h>
unsigned long __initdata pgt_buf_start;
unsigned long __meminitdata pgt_buf_end;
-@@ -33,7 +34,7 @@ int direct_gbpages
+@@ -33,7 +35,7 @@ int direct_gbpages
static void __init find_early_table_space(unsigned long end, int use_pse,
int use_gbpages)
{
@@ -24969,8 +25027,16 @@ index 6cabf65..77e9c1c 100644
phys_addr_t base;
puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
-@@ -314,8 +315,29 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
+@@ -312,10 +314,37 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
+ * Access has to be given to non-kernel-ram areas as well, these contain the PCI
+ * mmio resources as well as potential bios/acpi data regions.
*/
++
++#ifdef CONFIG_GRKERNSEC_KMEM
++static unsigned int ebda_start __read_only;
++static unsigned int ebda_end __read_only;
++#endif
++
int devmem_is_allowed(unsigned long pagenr)
{
+#ifdef CONFIG_GRKERNSEC_KMEM
@@ -24978,7 +25044,7 @@ index 6cabf65..77e9c1c 100644
+ if (!pagenr)
+ return 1;
+ /* allow EBDA */
-+ if ((0x9f000 >> PAGE_SHIFT) == pagenr)
++ if (pagenr >= ebda_start && pagenr < ebda_end)
+ return 1;
+#else
+ if (!pagenr)
@@ -25000,18 +25066,48 @@ index 6cabf65..77e9c1c 100644
if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
return 0;
if (!page_is_ram(pagenr))
-@@ -374,6 +396,86 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
+@@ -372,8 +401,116 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
+ #endif
+ }
++#ifdef CONFIG_GRKERNSEC_KMEM
++static inline void gr_init_ebda(void)
++{
++ unsigned int ebda_addr;
++ unsigned int ebda_size = 0;
++
++ ebda_addr = get_bios_ebda();
++ if (ebda_addr) {
++ ebda_size = *(unsigned char *)phys_to_virt(ebda_addr);
++ ebda_size <<= 10;
++ }
++ if (ebda_addr && ebda_size) {
++ ebda_start = ebda_addr >> PAGE_SHIFT;
++ ebda_end = min(PAGE_ALIGN(ebda_addr + ebda_size), 0xa0000) >> PAGE_SHIFT;
++ } else {
++ ebda_start = 0x9f000 >> PAGE_SHIFT;
++ ebda_end = 0xa0000 >> PAGE_SHIFT;
++ }
++}
++#else
++static inline void gr_init_ebda(void) { }
++#endif
++
void free_initmem(void)
{
-+
+#ifdef CONFIG_PAX_KERNEXEC
+#ifdef CONFIG_X86_32
+ /* PaX: limit KERNEL_CS to actual size */
+ unsigned long addr, limit;
+ struct desc_struct d;
+ int cpu;
++#endif
++#endif
++
++ gr_init_ebda();
+
++#ifdef CONFIG_PAX_KERNEXEC
++#ifdef CONFIG_X86_32
+ limit = paravirt_enabled() ? ktva_ktla(0xffffffff) : (unsigned long)&_etext;
+ limit = (limit - 1UL) >> PAGE_SHIFT;
+
@@ -29479,9 +29575,18 @@ index 211fc44..c5116f1 100644
mdev->bm_writ_cnt =
mdev->read_cnt =
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
-index af2a250..219c74b 100644
+index af2a250..0fdeb75 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
+@@ -2297,7 +2297,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms
+ return;
+ }
+
+- if (!cap_raised(current_cap(), CAP_SYS_ADMIN)) {
++ if (!capable(CAP_SYS_ADMIN)) {
+ retcode = ERR_PERM;
+ goto fail;
+ }
@@ -2359,7 +2359,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms
module_put(THIS_MODULE);
}
@@ -33774,6 +33879,19 @@ index 1ce84ed..0fdd40a 100644
if (!*param->name) {
DMWARN("name not supplied when creating device");
return -EINVAL;
+diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
+index 1f23e04..08d9a20 100644
+--- a/drivers/md/dm-log-userspace-transfer.c
++++ b/drivers/md/dm-log-userspace-transfer.c
+@@ -134,7 +134,7 @@ static void cn_ulog_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
+ {
+ struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1);
+
+- if (!cap_raised(current_cap(), CAP_SYS_ADMIN))
++ if (!capable(CAP_SYS_ADMIN))
+ return;
+
+ spin_lock(&receiving_list_lock);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 9bfd057..5373ff3 100644
--- a/drivers/md/dm-raid1.c
@@ -35603,6 +35721,23 @@ index c82d444..0007fb4 100644
{ "100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
{ "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR },
{ "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
+diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
+index b444f21..b72d976 100644
+--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
++++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
+@@ -492,7 +492,11 @@ out:
+ static void e1000_down_and_stop(struct e1000_adapter *adapter)
+ {
+ set_bit(__E1000_DOWN, &adapter->flags);
+- cancel_work_sync(&adapter->reset_task);
++
++ /* Only kill reset task if adapter is not resetting */
++ if (!test_bit(__E1000_RESETTING, &adapter->flags))
++ cancel_work_sync(&adapter->reset_task);
++
+ cancel_delayed_work_sync(&adapter->watchdog_task);
+ cancel_delayed_work_sync(&adapter->phy_info_task);
+ cancel_delayed_work_sync(&adapter->fifo_stall_task);
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index e1159e5..e18684d 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -42391,7 +42526,7 @@ index a40c05e..785c583 100644
return count;
}
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
-index 8408543..357841c 100644
+index 8408543..d6f20f1 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -19,6 +19,7 @@
@@ -42402,6 +42537,15 @@ index 8408543..357841c 100644
#include <video/edid.h>
#include <video/uvesafb.h>
#ifdef CONFIG_X86
+@@ -73,7 +74,7 @@ static void uvesafb_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *ns
+ struct uvesafb_task *utask;
+ struct uvesafb_ktask *task;
+
+- if (!cap_raised(current_cap(), CAP_SYS_ADMIN))
++ if (!capable(CAP_SYS_ADMIN))
+ return;
+
+ if (msg->seq >= UVESAFB_TASKS_MAX)
@@ -121,7 +122,7 @@ static int uvesafb_helper_start(void)
NULL,
};
@@ -48031,6 +48175,96 @@ index f649fba..236bf92 100644
}
void nfs_fattr_init(struct nfs_fattr *fattr)
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 2612223..e0ab779 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -3588,19 +3588,23 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
+ if (npages == 0)
+ npages = 1;
+
++ /* Add an extra page to handle the bitmap returned */
++ npages++;
++
+ for (i = 0; i < npages; i++) {
+ pages[i] = alloc_page(GFP_KERNEL);
+ if (!pages[i])
+ goto out_free;
+ }
+- if (npages > 1) {
+- /* for decoding across pages */
+- res.acl_scratch = alloc_page(GFP_KERNEL);
+- if (!res.acl_scratch)
+- goto out_free;
+- }
++
++ /* for decoding across pages */
++ res.acl_scratch = alloc_page(GFP_KERNEL);
++ if (!res.acl_scratch)
++ goto out_free;
++
+ args.acl_len = npages * PAGE_SIZE;
+ args.acl_pgbase = 0;
++
+ /* Let decode_getfacl know not to fail if the ACL data is larger than
+ * the page we send as a guess */
+ if (buf == NULL)
+diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
+index 33bd8d0..9b26eaf 100644
+--- a/fs/nfs/nfs4xdr.c
++++ b/fs/nfs/nfs4xdr.c
+@@ -4975,11 +4975,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
+ bitmap[3] = {0};
+ struct kvec *iov = req->rq_rcv_buf.head;
+ int status;
++ size_t page_len = xdr->buf->page_len;
+
+ res->acl_len = 0;
+ if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+ goto out;
++
+ bm_p = xdr->p;
++ res->acl_data_offset = be32_to_cpup(bm_p) + 2;
++ res->acl_data_offset <<= 2;
++ /* Check if the acl data starts beyond the allocated buffer */
++ if (res->acl_data_offset > page_len)
++ return -ERANGE;
++
+ if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+ goto out;
+ if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+@@ -4989,28 +4997,24 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
+ size_t hdrlen;
+- u32 recvd;
+
+ /* The bitmap (xdr len + bitmaps) and the attr xdr len words
+ * are stored with the acl data to handle the problem of
+ * variable length bitmaps.*/
+ xdr->p = bm_p;
+- res->acl_data_offset = be32_to_cpup(bm_p) + 2;
+- res->acl_data_offset <<= 2;
+
+ /* We ignore &savep and don't do consistency checks on
+ * the attr length. Let userspace figure it out.... */
+ hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
+ attrlen += res->acl_data_offset;
+- recvd = req->rq_rcv_buf.len - hdrlen;
+- if (attrlen > recvd) {
++ if (attrlen > page_len) {
+ if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
+ /* getxattr interface called with a NULL buf */
+ res->acl_len = attrlen;
+ goto out;
+ }
+- dprintk("NFS: acl reply: attrlen %u > recvd %u\n",
+- attrlen, recvd);
++ dprintk("NFS: acl reply: attrlen %zu > page_len %u\n",
++ attrlen, page_len);
+ return -EINVAL;
+ }
+ xdr_read_pages(xdr, attrlen);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index b96fe94..a4dbece 100644
--- a/fs/nfsd/vfs.c
@@ -60785,10 +61019,49 @@ index 810431d..ccc3638 100644
* The "pgd_xxx()" functions here are trivial for a folded two-level
* setup: the pud is never bad, and a pud always exists (as it's folded
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
-index a03c098..7e5b223 100644
+index a03c098..19751cf 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
-@@ -502,6 +502,14 @@ static inline int pmd_trans_unstable(pmd_t *pmd)
+@@ -445,6 +445,18 @@ static inline int pmd_write(pmd_t pmd)
+ #endif /* __HAVE_ARCH_PMD_WRITE */
+ #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
++#ifndef __HAVE_ARCH_READ_PMD_ATOMIC
++static inline pmd_t read_pmd_atomic(pmd_t *pmdp)
++{
++ /*
++ * Depend on compiler for an atomic pmd read. NOTE: this is
++ * only going to work, if the pmdval_t isn't larger than
++ * an unsigned long.
++ */
++ return *pmdp;
++}
++#endif /* __HAVE_ARCH_READ_PMD_ATOMIC */
++
+ /*
+ * This function is meant to be used by sites walking pagetables with
+ * the mmap_sem hold in read mode to protect against MADV_DONTNEED and
+@@ -458,11 +470,17 @@ static inline int pmd_write(pmd_t pmd)
+ * undefined so behaving like if the pmd was none is safe (because it
+ * can return none anyway). The compiler level barrier() is critically
+ * important to compute the two checks atomically on the same pmdval.
++ *
++ * For 32bit kernels with a 64bit large pmd_t this automatically takes
++ * care of reading the pmd atomically to avoid SMP race conditions
++ * against pmd_populate() when the mmap_sem is hold for reading by the
++ * caller (a special atomic read not done by "gcc" as in the generic
++ * version above, is also needed when THP is disabled because the page
++ * fault can populate the pmd from under us).
+ */
+ static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd)
+ {
+- /* depend on compiler for an atomic pmd read */
+- pmd_t pmdval = *pmd;
++ pmd_t pmdval = read_pmd_atomic(pmd);
+ /*
+ * The barrier will stabilize the pmdval in a register or on
+ * the stack so that it will stop changing under the code.
+@@ -502,6 +520,14 @@ static inline int pmd_trans_unstable(pmd_t *pmd)
#endif
}
@@ -76614,6 +76887,20 @@ index 0197747..7adb0dc 100644
if (peer->tcp_ts_stamp) {
ts = peer->tcp_ts;
tsage = get_seconds() - peer->tcp_ts_stamp;
+diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
+index e2327db..bf29e7c 100644
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -849,8 +849,7 @@ new_segment:
+ wait_for_sndbuf:
+ set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+ wait_for_memory:
+- if (copied)
+- tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
++ tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
+
+ if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
+ goto do_error;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index fd54c5f..96d6407 100644
--- a/net/ipv4/tcp_ipv4.c
@@ -77911,6 +78198,19 @@ index 7dab229..212156f 100644
sax->fsa_ax25.sax25_call = nr->source_addr;
*uaddr_len = sizeof(struct sockaddr_ax25);
}
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
+index 2c03050..5cf68c1 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -322,7 +322,7 @@ static int queue_userspace_packet(int dp_ifindex, struct sk_buff *skb,
+ return -ENOMEM;
+
+ nskb = __vlan_put_tag(nskb, vlan_tx_tag_get(nskb));
+- if (!skb)
++ if (!nskb)
+ return -ENOMEM;
+
+ nskb->vlan_tci = 0;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 2dbb32b..a1b4722 100644
--- a/net/packet/af_packet.c