summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201302271816.patch (renamed from 2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201302222044.patch)246
-rw-r--r--3.2.39/0000_README2
-rw-r--r--3.2.39/4420_grsecurity-2.9.1-3.2.39-201302271819.patch (renamed from 3.2.39/4420_grsecurity-2.9.1-3.2.39-201302222046.patch)212
-rw-r--r--3.8.0/0000_README2
-rw-r--r--3.8.0/4420_grsecurity-2.9.1-3.8.0-201302271810.patch (renamed from 3.8.0/4420_grsecurity-2.9.1-3.8.0-201302231124.patch)473
5 files changed, 901 insertions, 34 deletions
diff --git a/2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201302222044.patch b/2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201302271816.patch
index f5ba675..ee04841 100644
--- a/2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201302222044.patch
+++ b/2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201302271816.patch
@@ -42821,7 +42821,7 @@ index 87c67b4..230527a 100644
.part_num = MBCS_PART_NUM,
.mfg_num = MBCS_MFG_NUM,
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
-index 1270f64..3b87405 100644
+index 1270f64..3f4b1fa 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -18,6 +18,7 @@
@@ -42955,7 +42955,19 @@ index 1270f64..3b87405 100644
return -EFAULT;
buf += sz;
p += sz;
-@@ -889,6 +941,9 @@ static const struct memdev {
+@@ -848,6 +900,11 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,
+ char *tmp;
+ ssize_t ret;
+
++#ifdef CONFIG_GRKERNSEC_DMESG
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++#endif
++
+ tmp = kmalloc(count + 1, GFP_KERNEL);
+ if (tmp == NULL)
+ return -ENOMEM;
+@@ -889,6 +946,9 @@ static const struct memdev {
#ifdef CONFIG_CRASH_DUMP
[12] = { "oldmem", 0, &oldmem_fops, NULL },
#endif
@@ -77258,10 +77270,24 @@ index d84e705..d8c364c 100644
return ioctl_preallocate(file, p);
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
-index 8e48b52..f01ed91 100644
+index 8e48b52..2c592f8 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
-@@ -1572,7 +1572,8 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
+@@ -1044,10 +1044,11 @@ static int configfs_dump(struct configfs_dirent *sd, int level)
+ static int configfs_depend_prep(struct dentry *origin,
+ struct config_item *target)
+ {
+- struct configfs_dirent *child_sd, *sd = origin->d_fsdata;
++ struct configfs_dirent *child_sd, *sd;
+ int ret = 0;
+
+- BUG_ON(!origin || !sd);
++ BUG_ON(!origin || !origin->d_fsdata);
++ sd = origin->d_fsdata;
+
+ if (sd->s_element == target) /* Boo-yah */
+ goto out;
+@@ -1572,7 +1573,8 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
}
for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
struct configfs_dirent *next;
@@ -77271,7 +77297,7 @@ index 8e48b52..f01ed91 100644
int len;
next = list_entry(p, struct configfs_dirent,
-@@ -1581,7 +1582,12 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
+@@ -1581,7 +1583,12 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
continue;
name = configfs_get_name(next);
@@ -78561,6 +78587,54 @@ index f1e7077..edd86b2 100644
.show = ext4_attr_show,
.store = ext4_attr_store,
};
+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..4251f35 100644
+--- a/fs/fat/namei_vfat.c
++++ b/fs/fat/namei_vfat.c
+@@ -499,17 +499,18 @@ 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 > 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 +550,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/fs/fcntl.c b/fs/fcntl.c
index 97e01dc..e9aab2d 100644
--- a/fs/fcntl.c
@@ -81507,6 +81581,78 @@ index f6af760..d0adf34 100644
len = argv[n].v_size * argv[n].v_nmembs;
base = (void __user *)(unsigned long)argv[n].v_base;
if (len == 0) {
+diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
+index 44a88a9..0eb059e 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/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index 7e54e52..9337248 100644
--- a/fs/notify/dnotify/dnotify.c
@@ -98947,6 +99093,28 @@ index 82a9124..8a5f622 100644
= { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\
sizeof(array[0]), array }; \
__module_param_call(MODULE_PARAM_PREFIX, name, \
+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 */
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index 878cab4..c92cb3e 100644
--- a/include/linux/mutex.h
@@ -99037,6 +99205,29 @@ index 0000000..33f4af8
+};
+
+#endif
+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);
+
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
index b359c4a..c08b334 100644
--- a/include/linux/nodemask.h
@@ -111909,7 +112100,7 @@ index dd43373..d848cd7 100644
list_add_tail(&vma->anon_vma_node, &anon_vma->head);
allocated = NULL;
diff --git a/mm/shmem.c b/mm/shmem.c
-index 3e0005b..1d659a8 100644
+index 3e0005b..eac2525 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -31,7 +31,7 @@
@@ -111948,7 +112139,31 @@ index 3e0005b..1d659a8 100644
/* do it inline */
memcpy(info, symname, len);
inode->i_op = &shmem_symlink_inline_operations;
-@@ -2310,8 +2314,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
+@@ -2242,6 +2246,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 +2274,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;
+@@ -2310,8 +2320,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
int err = -ENOMEM;
/* Round up to L1_CACHE_BYTES to resist false sharing */
@@ -113416,6 +113631,23 @@ index 75302a9..09e36d3 100644
uf.type_mask = f->type_mask;
uf.opcode = f->opcode;
uf.event_mask[0] = *((u32 *) f->event_mask + 0);
+diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
+index 49d8495..6b0a111 100644
+--- a/net/bluetooth/hidp/core.c
++++ b/net/bluetooth/hidp/core.c
+@@ -778,9 +778,9 @@ 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->phys, batostr(&src), 64);
+- strncpy(hid->uniq, batostr(&dst), 64);
++ strncpy(hid->name, req->name, sizeof(hid->name) - 1);
++ strncpy(hid->phys, batostr(&src), sizeof(hid->phys) - 1);
++ strncpy(hid->uniq, batostr(&dst), sizeof(hid->uniq) - 1);
+
+ hid->dev.parent = hidp_get_device(session);
+ hid->ll_driver = &hidp_hid_driver;
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 1ae3f80..c5d763b 100644
--- a/net/bluetooth/rfcomm/sock.c
diff --git a/3.2.39/0000_README b/3.2.39/0000_README
index 4b7b629..b8fcdf1 100644
--- a/3.2.39/0000_README
+++ b/3.2.39/0000_README
@@ -74,7 +74,7 @@ Patch: 1039_linux-3.2.39.patch
From: http://www.kernel.org
Desc: Linux 3.2.39
-Patch: 4420_grsecurity-2.9.1-3.2.39-201302222046.patch
+Patch: 4420_grsecurity-2.9.1-3.2.39-201302271819.patch
From: http://www.grsecurity.net
Desc: hardened-sources base patch from upstream grsecurity
diff --git a/3.2.39/4420_grsecurity-2.9.1-3.2.39-201302222046.patch b/3.2.39/4420_grsecurity-2.9.1-3.2.39-201302271819.patch
index ed3c4f5..b220f78 100644
--- a/3.2.39/4420_grsecurity-2.9.1-3.2.39-201302222046.patch
+++ b/3.2.39/4420_grsecurity-2.9.1-3.2.39-201302271819.patch
@@ -31455,7 +31455,7 @@ index 1aeaaba..e018570 100644
.part_num = MBCS_PART_NUM,
.mfg_num = MBCS_MFG_NUM,
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
-index 1451790..3c7dfbb 100644
+index 1451790..d42d89d 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -18,6 +18,7 @@
@@ -31580,7 +31580,19 @@ index 1451790..3c7dfbb 100644
return -EFAULT;
buf += sz;
p += sz;
-@@ -867,6 +914,9 @@ static const struct memdev {
+@@ -815,6 +862,11 @@ static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv,
+ ssize_t ret = -EFAULT;
+ size_t len = iov_length(iv, count);
+
++#ifdef CONFIG_GRKERNSEC_DMESG
++ if (!capable(CAP_SYSLOG))
++ return -EPERM;
++#endif
++
+ line = kmalloc(len + 1, GFP_KERNEL);
+ if (line == NULL)
+ return -ENOMEM;
+@@ -867,6 +919,9 @@ static const struct memdev {
#ifdef CONFIG_CRASH_DUMP
[12] = { "oldmem", 0, &oldmem_fops, NULL },
#endif
@@ -33807,6 +33819,28 @@ index 0fb100e..baf87e5 100644
__asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
"=a"(hv_status_lo) : "d" (control_hi),
+diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
+index 89f5244..0e8343f 100644
+--- a/drivers/hv/hv_kvp.c
++++ b/drivers/hv/hv_kvp.c
+@@ -212,11 +212,13 @@ kvp_respond_to_host(char *key, char *value, int error)
+ * The windows host expects the key/value pair to be encoded
+ * in utf16.
+ */
+- keylen = utf8s_to_utf16s(key_name, strlen(key_name),
+- (wchar_t *)kvp_data->data.key);
++ keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN,
++ (wchar_t *) kvp_data->data.key,
++ HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2);
+ kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */
+- valuelen = utf8s_to_utf16s(value, strlen(value),
+- (wchar_t *)kvp_data->data.value);
++ valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
++ (wchar_t *) kvp_data->data.value,
++ HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2);
+ kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */
+
+ kvp_data->data.value_type = REG_SZ; /* all our values are strings */
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 0aee112..b72d21f 100644
--- a/drivers/hv/hyperv_vmbus.h
@@ -46826,10 +46860,24 @@ index f854cf9..93292ff 100644
return 1;
if (a < b)
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
-index 9a37a9b..35792b6 100644
+index 9a37a9b..80968f3 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
-@@ -1575,7 +1575,8 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
+@@ -1047,10 +1047,11 @@ static int configfs_dump(struct configfs_dirent *sd, int level)
+ static int configfs_depend_prep(struct dentry *origin,
+ struct config_item *target)
+ {
+- struct configfs_dirent *child_sd, *sd = origin->d_fsdata;
++ struct configfs_dirent *child_sd, *sd;
+ int ret = 0;
+
+- BUG_ON(!origin || !sd);
++ BUG_ON(!origin || !origin->d_fsdata);
++ sd = origin->d_fsdata;
+
+ if (sd->s_element == target) /* Boo-yah */
+ goto out;
+@@ -1575,7 +1576,8 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
}
for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
struct configfs_dirent *next;
@@ -46839,7 +46887,7 @@ index 9a37a9b..35792b6 100644
int len;
struct inode *inode = NULL;
-@@ -1585,7 +1586,12 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
+@@ -1585,7 +1587,12 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
continue;
name = configfs_get_name(next);
@@ -48134,6 +48182,20 @@ index 24ac7a2..c596196 100644
if (!buf)
return -ENOMEM;
+diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
+index a87a656..c25cf15 100644
+--- a/fs/fat/namei_vfat.c
++++ b/fs/fat/namei_vfat.c
+@@ -512,7 +512,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/fcntl.c b/fs/fcntl.c
index 22764c7..86372c9 100644
--- a/fs/fcntl.c
@@ -50769,6 +50831,78 @@ index 1c98f53..41e6a04 100644
nilfs_set_nsegments(nilfs, le64_to_cpu(sbp->s_nsegments));
nilfs->ns_crc_seed = le32_to_cpu(sbp->s_crc_seed);
return 0;
+diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
+index 44a88a9..0eb059e 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/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 9fde1c0..14e8827 100644
--- a/fs/notify/fanotify/fanotify_user.c
@@ -66831,6 +66965,29 @@ index 0000000..33f4af8
+};
+
+#endif
+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);
+
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index d65746e..62e72c2 100644
--- a/include/linux/notifier.h
@@ -78890,7 +79047,7 @@ index 8685697..b490361 100644
struct anon_vma_chain *avc;
struct anon_vma *anon_vma;
diff --git a/mm/shmem.c b/mm/shmem.c
-index 12b9e80..5118865 100644
+index 12b9e80..a31df98 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -31,7 +31,7 @@
@@ -78939,7 +79096,31 @@ index 12b9e80..5118865 100644
if (size == 0)
value = ""; /* empty EA, do not remove */
-@@ -2189,8 +2203,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
+@@ -2121,6 +2135,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;
+
+@@ -2145,8 +2160,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;
+@@ -2189,8 +2209,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
int err = -ENOMEM;
/* Round up to L1_CACHE_BYTES to resist false sharing */
@@ -80487,6 +80668,23 @@ index 8361ee4..a4f0f18 100644
if (copy_from_user(&uf, optval, len)) {
err = -EFAULT;
break;
+diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
+index 0274157..f8afbf3c7 100644
+--- a/net/bluetooth/hidp/core.c
++++ b/net/bluetooth/hidp/core.c
+@@ -945,9 +945,9 @@ static int hidp_setup_hid(struct hidp_session *session,
+ hid->version = req->version;
+ hid->country = req->country;
+
+- strncpy(hid->name, req->name, sizeof(req->name) - 1);
+- strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
+- strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
++ strncpy(hid->name, req->name, sizeof(hid->name) - 1);
++ strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), sizeof(hid->phys) - 1);
++ strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), sizeof(hid->uniq) - 1);
+
+ hid->dev.parent = hidp_get_device(session);
+ hid->ll_driver = &hidp_hid_driver;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 04175d9..26291c1 100644
--- a/net/bluetooth/l2cap_core.c
diff --git a/3.8.0/0000_README b/3.8.0/0000_README
index 8d7fe2e..a9cab40 100644
--- a/3.8.0/0000_README
+++ b/3.8.0/0000_README
@@ -2,7 +2,7 @@ README
-----------------------------------------------------------------------------
Individual Patch Descriptions:
-----------------------------------------------------------------------------
-Patch: 4420_grsecurity-2.9.1-3.8.0-201302231124.patch
+Patch: 4420_grsecurity-2.9.1-3.8.0-201302271810.patch
From: http://www.grsecurity.net
Desc: hardened-sources base patch from upstream grsecurity
diff --git a/3.8.0/4420_grsecurity-2.9.1-3.8.0-201302231124.patch b/3.8.0/4420_grsecurity-2.9.1-3.8.0-201302271810.patch
index c065fb8..24c501f 100644
--- a/3.8.0/4420_grsecurity-2.9.1-3.8.0-201302231124.patch
+++ b/3.8.0/4420_grsecurity-2.9.1-3.8.0-201302271810.patch
@@ -41521,6 +41521,19 @@ index 681765b..d3ccdf2 100644
if (!perm) {
ret = -EPERM;
goto reterr;
+diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
+index 8fd8968..3614c9c 100644
+--- a/drivers/tty/vt/vt.c
++++ b/drivers/tty/vt/vt.c
+@@ -539,7 +539,7 @@ static void insert_char(struct vc_data *vc, unsigned int nr)
+ {
+ unsigned short *p = (unsigned short *) vc->vc_pos;
+
+- scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x) * 2);
++ scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2);
+ scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
+ vc->vc_need_wrap = 0;
+ if (DO_UPDATE(vc))
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 5110f36..8dc0a74 100644
--- a/drivers/uio/uio.c
@@ -47182,10 +47195,24 @@ index e2f57a0..3c78771 100644
return 1;
if (a < b)
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
-index 712b10f..6b54d7b 100644
+index 712b10f..c33c4ca 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
-@@ -1564,7 +1564,8 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
+@@ -1037,10 +1037,11 @@ static int configfs_dump(struct configfs_dirent *sd, int level)
+ static int configfs_depend_prep(struct dentry *origin,
+ struct config_item *target)
+ {
+- struct configfs_dirent *child_sd, *sd = origin->d_fsdata;
++ struct configfs_dirent *child_sd, *sd;
+ int ret = 0;
+
+- BUG_ON(!origin || !sd);
++ BUG_ON(!origin || !origin->d_fsdata);
++ sd = origin->d_fsdata;
+
+ if (sd->s_element == target) /* Boo-yah */
+ goto out;
+@@ -1564,7 +1565,8 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
}
for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
struct configfs_dirent *next;
@@ -47195,7 +47222,7 @@ index 712b10f..6b54d7b 100644
int len;
struct inode *inode = NULL;
-@@ -1574,7 +1575,12 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
+@@ -1574,7 +1576,12 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
continue;
name = configfs_get_name(next);
@@ -50208,7 +50235,7 @@ index a94e331..060bce3 100644
lock_flocks();
diff --git a/fs/namei.c b/fs/namei.c
-index 43a97ee..ff3f601 100644
+index 43a97ee..117e7e4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -319,16 +319,32 @@ int generic_permission(struct inode *inode, int mask)
@@ -50574,13 +50601,13 @@ index 43a97ee..ff3f601 100644
}
EXPORT_SYMBOL(user_path_create);
-+static struct dentry *user_path_create_with_name(int dfd, const char __user *pathname, struct path *path, struct filename **to, int is_dir)
++static struct dentry *user_path_create_with_name(int dfd, const char __user *pathname, struct path *path, struct filename **to, unsigned int lookup_flags)
+{
+ struct filename *tmp = getname(pathname);
+ struct dentry *res;
+ if (IS_ERR(tmp))
+ return ERR_CAST(tmp);
-+ res = kern_path_create(dfd, tmp->name, path, is_dir);
++ res = kern_path_create(dfd, tmp->name, path, lookup_flags);
+ if (IS_ERR(res))
+ putname(tmp);
+ else
@@ -50810,7 +50837,7 @@ index 43a97ee..ff3f601 100644
out:
return len;
diff --git a/fs/namespace.c b/fs/namespace.c
-index 55605c5..22e9a03 100644
+index 55605c5..f2908c8 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1215,6 +1215,9 @@ static int do_umount(struct mount *mnt, int flags)
@@ -50823,7 +50850,7 @@ index 55605c5..22e9a03 100644
return retval;
}
-@@ -1234,6 +1237,9 @@ static int do_umount(struct mount *mnt, int flags)
+@@ -1234,9 +1237,20 @@ static int do_umount(struct mount *mnt, int flags)
br_write_unlock(&vfsmount_lock);
up_write(&namespace_sem);
release_mounts(&umount_list);
@@ -50833,7 +50860,85 @@ index 55605c5..22e9a03 100644
return retval;
}
-@@ -2282,6 +2288,16 @@ long do_mount(const char *dev_name, const char *dir_name,
++/*
++ * Is the caller allowed to modify his namespace?
++ */
++static inline bool may_mount(void)
++{
++ return ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN);
++}
++
+ /*
+ * Now umount can handle mount points as well as block devices.
+ * This is important for filesystems which use unnamed block devices.
+@@ -1255,6 +1269,9 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
+ if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
+ return -EINVAL;
+
++ if (!may_mount())
++ return -EPERM;
++
+ if (!(flags & UMOUNT_NOFOLLOW))
+ lookup_flags |= LOOKUP_FOLLOW;
+
+@@ -1268,10 +1285,6 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
+ if (!check_mnt(mnt))
+ goto dput_and_out;
+
+- retval = -EPERM;
+- if (!ns_capable(mnt->mnt_ns->user_ns, CAP_SYS_ADMIN))
+- goto dput_and_out;
+-
+ retval = do_umount(mnt, flags);
+ dput_and_out:
+ /* we mustn't call path_put() as that would clear mnt_expiry_mark */
+@@ -1295,7 +1308,7 @@ SYSCALL_DEFINE1(oldumount, char __user *, name)
+
+ static int mount_is_safe(struct path *path)
+ {
+- if (ns_capable(real_mount(path->mnt)->mnt_ns->user_ns, CAP_SYS_ADMIN))
++ if (may_mount())
+ return 0;
+ return -EPERM;
+ #ifdef notyet
+@@ -1633,7 +1646,7 @@ static int do_change_type(struct path *path, int flag)
+ int type;
+ int err = 0;
+
+- if (!ns_capable(mnt->mnt_ns->user_ns, CAP_SYS_ADMIN))
++ if (!may_mount())
+ return -EPERM;
+
+ if (path->dentry != path->mnt->mnt_root)
+@@ -1797,7 +1810,7 @@ static int do_move_mount(struct path *path, const char *old_name)
+ struct mount *p;
+ struct mount *old;
+ int err = 0;
+- if (!ns_capable(real_mount(path->mnt)->mnt_ns->user_ns, CAP_SYS_ADMIN))
++ if (!may_mount())
+ return -EPERM;
+ if (!old_name || !*old_name)
+ return -EINVAL;
+@@ -1933,16 +1946,14 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
+ int mnt_flags, const char *name, void *data)
+ {
+ struct file_system_type *type;
+- struct user_namespace *user_ns;
++ struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
+ struct vfsmount *mnt;
+ int err;
+
+ if (!fstype)
+ return -EINVAL;
+
+- /* we need capabilities... */
+- user_ns = real_mount(path->mnt)->mnt_ns->user_ns;
+- if (!ns_capable(user_ns, CAP_SYS_ADMIN))
++ if (!may_mount())
+ return -EPERM;
+
+ type = get_fs_type(fstype);
+@@ -2282,6 +2293,16 @@ long do_mount(const char *dev_name, const char *dir_name,
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
MS_STRICTATIME);
@@ -50850,7 +50955,7 @@ index 55605c5..22e9a03 100644
if (flags & MS_REMOUNT)
retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
data_page);
-@@ -2296,6 +2312,9 @@ long do_mount(const char *dev_name, const char *dir_name,
+@@ -2296,6 +2317,9 @@ long do_mount(const char *dev_name, const char *dir_name,
dev_name, data_page);
dput_out:
path_put(&path);
@@ -50860,7 +50965,16 @@ index 55605c5..22e9a03 100644
return retval;
}
-@@ -2582,6 +2601,11 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
+@@ -2567,7 +2591,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
+ struct mount *new_mnt, *root_mnt;
+ int error;
+
+- if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN))
++ if (!may_mount())
+ return -EPERM;
+
+ error = user_path_dir(new_root, &new);
+@@ -2582,6 +2606,11 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
if (error)
goto out2;
@@ -50872,7 +50986,7 @@ index 55605c5..22e9a03 100644
get_fs_root(current->fs, &root);
error = lock_mount(&old);
if (error)
-@@ -2785,7 +2809,7 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
+@@ -2785,7 +2814,7 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
!nsown_capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -67595,6 +67709,42 @@ index c5d36c6..108f4f9 100644
/*
* callback functions for platform
+diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
+index b9bd2e6..4ce0093 100644
+--- a/include/linux/user_namespace.h
++++ b/include/linux/user_namespace.h
+@@ -21,7 +21,7 @@ struct user_namespace {
+ struct uid_gid_map uid_map;
+ struct uid_gid_map gid_map;
+ struct uid_gid_map projid_map;
+- struct kref kref;
++ atomic_t count;
+ struct user_namespace *parent;
+ kuid_t owner;
+ kgid_t group;
+@@ -35,18 +35,18 @@ extern struct user_namespace init_user_ns;
+ static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
+ {
+ if (ns)
+- kref_get(&ns->kref);
++ atomic_inc(&ns->count);
+ return ns;
+ }
+
+ extern int create_user_ns(struct cred *new);
+ extern int unshare_userns(unsigned long unshare_flags, struct cred **new_cred);
+-extern void free_user_ns(struct kref *kref);
++extern void free_user_ns(struct user_namespace *ns);
+
+ static inline void put_user_ns(struct user_namespace *ns)
+ {
+- if (ns)
+- kref_put(&ns->kref, free_user_ns);
++ if (ns && atomic_dec_and_test(&ns->count))
++ free_user_ns(ns);
+ }
+
+ struct seq_operations;
diff --git a/include/linux/vermagic.h b/include/linux/vermagic.h
index 6f8fbcf..8259001 100644
--- a/include/linux/vermagic.h
@@ -72066,10 +72216,37 @@ index d5a258b..4271191 100644
if (pm_wakeup_pending()) {
diff --git a/kernel/printk.c b/kernel/printk.c
-index 267ce78..952f8a8 100644
+index 267ce78..2487112 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
-@@ -834,6 +834,11 @@ static int check_syslog_permissions(int type, bool from_file)
+@@ -609,11 +609,17 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
+ return ret;
+ }
+
++static int check_syslog_permissions(int type, bool from_file);
++
+ static int devkmsg_open(struct inode *inode, struct file *file)
+ {
+ struct devkmsg_user *user;
+ int err;
+
++ err = check_syslog_permissions(SYSLOG_ACTION_OPEN, SYSLOG_FROM_FILE);
++ if (err)
++ return err;
++
+ /* write-only does not need any file context */
+ if ((file->f_flags & O_ACCMODE) == O_WRONLY)
+ return 0;
+@@ -822,7 +828,7 @@ static int syslog_action_restricted(int type)
+ if (dmesg_restrict)
+ return 1;
+ /* Unless restricted, we allow "read all" and "get buffer size" for everybody */
+- return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER;
++ return type != SYSLOG_ACTION_OPEN && type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER;
+ }
+
+ static int check_syslog_permissions(int type, bool from_file)
+@@ -834,6 +840,11 @@ static int check_syslog_permissions(int type, bool from_file)
if (from_file && type != SYSLOG_ACTION_OPEN)
return 0;
@@ -73028,7 +73205,7 @@ index 26058d0..06f15dd 100644
.priority = CPU_PRI_MIGRATION,
};
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
-index 81fa536..80fa821 100644
+index 81fa536..6ccf96a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -830,7 +830,7 @@ void task_numa_fault(int node, int pages, bool migrated)
@@ -73040,7 +73217,48 @@ index 81fa536..80fa821 100644
p->mm->numa_scan_offset = 0;
}
-@@ -5663,7 +5663,7 @@ static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle) { }
+@@ -3254,25 +3254,18 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
+ */
+ static int select_idle_sibling(struct task_struct *p, int target)
+ {
+- int cpu = smp_processor_id();
+- int prev_cpu = task_cpu(p);
+ struct sched_domain *sd;
+ struct sched_group *sg;
+- int i;
++ int i = task_cpu(p);
+
+- /*
+- * If the task is going to be woken-up on this cpu and if it is
+- * already idle, then it is the right target.
+- */
+- if (target == cpu && idle_cpu(cpu))
+- return cpu;
++ if (idle_cpu(target))
++ return target;
+
+ /*
+- * If the task is going to be woken-up on the cpu where it previously
+- * ran and if it is currently idle, then it the right target.
++ * If the prevous cpu is cache affine and idle, don't be stupid.
+ */
+- if (target == prev_cpu && idle_cpu(prev_cpu))
+- return prev_cpu;
++ if (i != target && cpus_share_cache(i, target) && idle_cpu(i))
++ return i;
+
+ /*
+ * Otherwise, iterate the domains and find an elegible idle cpu.
+@@ -3286,7 +3279,7 @@ static int select_idle_sibling(struct task_struct *p, int target)
+ goto next;
+
+ for_each_cpu(i, sched_group_cpus(sg)) {
+- if (!idle_cpu(i))
++ if (i == target || !idle_cpu(i))
+ goto next;
+ }
+
+@@ -5663,7 +5656,7 @@ static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle) { }
* run_rebalance_domains is triggered when needed from the scheduler tick.
* Also triggered for nohz idle balancing (with nohz_balancing_kick set).
*/
@@ -74508,6 +74726,58 @@ index 42ca822..cdcacc6 100644
return;
local_irq_save(flags);
+diff --git a/kernel/user.c b/kernel/user.c
+index 33acb5e..57ebfd4 100644
+--- a/kernel/user.c
++++ b/kernel/user.c
+@@ -47,9 +47,7 @@ struct user_namespace init_user_ns = {
+ .count = 4294967295U,
+ },
+ },
+- .kref = {
+- .refcount = ATOMIC_INIT(3),
+- },
++ .count = ATOMIC_INIT(3),
+ .owner = GLOBAL_ROOT_UID,
+ .group = GLOBAL_ROOT_GID,
+ .proc_inum = PROC_USER_INIT_INO,
+diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
+index 2b042c4..24f8ec3 100644
+--- a/kernel/user_namespace.c
++++ b/kernel/user_namespace.c
+@@ -78,7 +78,7 @@ int create_user_ns(struct cred *new)
+ return ret;
+ }
+
+- kref_init(&ns->kref);
++ atomic_set(&ns->count, 1);
+ /* Leave the new->user_ns reference with the new user namespace. */
+ ns->parent = parent_ns;
+ ns->owner = owner;
+@@ -104,15 +104,16 @@ int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
+ return create_user_ns(cred);
+ }
+
+-void free_user_ns(struct kref *kref)
++void free_user_ns(struct user_namespace *ns)
+ {
+- struct user_namespace *parent, *ns =
+- container_of(kref, struct user_namespace, kref);
++ struct user_namespace *parent;
+
+- parent = ns->parent;
+- proc_free_inum(ns->proc_inum);
+- kmem_cache_free(user_ns_cachep, ns);
+- put_user_ns(parent);
++ do {
++ parent = ns->parent;
++ proc_free_inum(ns->proc_inum);
++ kmem_cache_free(user_ns_cachep, ns);
++ ns = parent;
++ } while (atomic_dec_and_test(&parent->count));
+ }
+ EXPORT_SYMBOL(free_user_ns);
+
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 67604e5..3ebb003 100644
--- a/lib/Kconfig.debug
@@ -77437,6 +77707,136 @@ index d1e4124..32a6988 100644
vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND;
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
+index 8a5ac8c..f5c3d96 100644
+--- a/mm/mmu_notifier.c
++++ b/mm/mmu_notifier.c
+@@ -37,49 +37,51 @@ static struct srcu_struct srcu;
+ void __mmu_notifier_release(struct mm_struct *mm)
+ {
+ struct mmu_notifier *mn;
+- struct hlist_node *n;
+ int id;
+
+ /*
+- * SRCU here will block mmu_notifier_unregister until
+- * ->release returns.
++ * srcu_read_lock() here will block synchronize_srcu() in
++ * mmu_notifier_unregister() until all registered
++ * ->release() callouts this function makes have
++ * returned.
+ */
+ id = srcu_read_lock(&srcu);
+- hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist)
+- /*
+- * if ->release runs before mmu_notifier_unregister it
+- * must be handled as it's the only way for the driver
+- * to flush all existing sptes and stop the driver
+- * from establishing any more sptes before all the
+- * pages in the mm are freed.
+- */
+- if (mn->ops->release)
+- mn->ops->release(mn, mm);
+- srcu_read_unlock(&srcu, id);
+-
+ spin_lock(&mm->mmu_notifier_mm->lock);
+ while (unlikely(!hlist_empty(&mm->mmu_notifier_mm->list))) {
+ mn = hlist_entry(mm->mmu_notifier_mm->list.first,
+ struct mmu_notifier,
+ hlist);
++
+ /*
+- * We arrived before mmu_notifier_unregister so
+- * mmu_notifier_unregister will do nothing other than
+- * to wait ->release to finish and
+- * mmu_notifier_unregister to return.
++ * Unlink. This will prevent mmu_notifier_unregister()
++ * from also making the ->release() callout.
+ */
+ hlist_del_init_rcu(&mn->hlist);
++ spin_unlock(&mm->mmu_notifier_mm->lock);
++
++ /*
++ * Clear sptes. (see 'release' description in mmu_notifier.h)
++ */
++ if (mn->ops->release)
++ mn->ops->release(mn, mm);
++
++ spin_lock(&mm->mmu_notifier_mm->lock);
+ }
+ spin_unlock(&mm->mmu_notifier_mm->lock);
+
+ /*
+- * synchronize_srcu here prevents mmu_notifier_release to
+- * return to exit_mmap (which would proceed freeing all pages
+- * in the mm) until the ->release method returns, if it was
+- * invoked by mmu_notifier_unregister.
+- *
+- * The mmu_notifier_mm can't go away from under us because one
+- * mm_count is hold by exit_mmap.
++ * All callouts to ->release() which we have done are complete.
++ * Allow synchronize_srcu() in mmu_notifier_unregister() to complete
++ */
++ srcu_read_unlock(&srcu, id);
++
++ /*
++ * mmu_notifier_unregister() may have unlinked a notifier and may
++ * still be calling out to it. Additionally, other notifiers
++ * may have been active via vmtruncate() et. al. Block here
++ * to ensure that all notifier callouts for this mm have been
++ * completed and the sptes are really cleaned up before returning
++ * to exit_mmap().
+ */
+ synchronize_srcu(&srcu);
+ }
+@@ -294,31 +296,31 @@ void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm)
+ {
+ BUG_ON(atomic_read(&mm->mm_count) <= 0);
+
++ spin_lock(&mm->mmu_notifier_mm->lock);
+ if (!hlist_unhashed(&mn->hlist)) {
+- /*
+- * SRCU here will force exit_mmap to wait ->release to finish
+- * before freeing the pages.
+- */
+ int id;
+
++ /*
++ * Ensure we synchronize up with __mmu_notifier_release().
++ */
+ id = srcu_read_lock(&srcu);
+- /*
+- * exit_mmap will block in mmu_notifier_release to
+- * guarantee ->release is called before freeing the
+- * pages.
+- */
+- if (mn->ops->release)
+- mn->ops->release(mn, mm);
+- srcu_read_unlock(&srcu, id);
+
+- spin_lock(&mm->mmu_notifier_mm->lock);
+ hlist_del_rcu(&mn->hlist);
+ spin_unlock(&mm->mmu_notifier_mm->lock);
+- }
++
++ if (mn->ops->release)
++ mn->ops->release(mn, mm);
++
++ /*
++ * Allow __mmu_notifier_release() to complete.
++ */
++ srcu_read_unlock(&srcu, id);
++ } else
++ spin_unlock(&mm->mmu_notifier_mm->lock);
+
+ /*
+- * Wait any running method to finish, of course including
+- * ->release if it was run by mmu_notifier_relase instead of us.
++ * Wait for any running method to finish, including ->release() if it
++ * was run by __mmu_notifier_release() instead of us.
+ */
+ synchronize_srcu(&srcu);
+
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 94722a4..9837984 100644
--- a/mm/mprotect.c
@@ -78041,7 +78441,7 @@ index 2c78f8c..9e9c624 100644
struct anon_vma_chain *avc;
struct anon_vma *anon_vma;
diff --git a/mm/shmem.c b/mm/shmem.c
-index 5dd56f6..7c51725 100644
+index 5dd56f6..994b702 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -31,7 +31,7 @@
@@ -78090,7 +78490,31 @@ index 5dd56f6..7c51725 100644
return simple_xattr_set(&info->xattrs, name, value, size, flags);
}
-@@ -2556,8 +2570,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
+@@ -2487,6 +2501,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;
+
+@@ -2511,8 +2526,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;
+@@ -2556,8 +2576,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
int err = -ENOMEM;
/* Round up to L1_CACHE_BYTES to resist false sharing */
@@ -84936,6 +85360,19 @@ index 6ece7f2..ecdb55c 100644
goto error;
buflen -= tmp;
+diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
+index 20e4bf5..58dfe08 100644
+--- a/security/keys/process_keys.c
++++ b/security/keys/process_keys.c
+@@ -367,6 +367,8 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
+
+ switch (PTR_ERR(key_ref)) {
+ case -EAGAIN: /* no key */
++ if (ret)
++ break;
+ case -ENOKEY: /* negative key */
+ ret = key_ref;
+ break;
diff --git a/security/min_addr.c b/security/min_addr.c
index f728728..6457a0c 100644
--- a/security/min_addr.c