diff options
-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_README | 2 | ||||
-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_README | 2 | ||||
-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 |