From 8d6b9b5550cdb67c170459b7c212884ca6873289 Mon Sep 17 00:00:00 2001 From: Changhyeok Bae Date: Wed, 13 Dec 2017 11:23:55 +0000 Subject: linux-yocto_4.4: Remove the bbappend rocko (Yocto 2.4) is not supported linux-yocto-4.4 and those commits are already applied in upstream 4.12. Bug-AGL: SPEC-1181 Change-Id: Ic3c39c919cc488e5eb1ef3f4cd3c3db653c3c0f7 Signed-off-by: Changhyeok Bae --- ...x-notification-of-groups-with-inode-mount.patch | 206 ----- ...01-mm-larger-stack-guard-gap-between-vmas.patch | 900 --------------------- ...w-stack-to-grow-up-to-address-space-limit.patch | 51 -- ...mm-fix-new-crash-in-unmapped_area_topdown.patch | 52 -- 4 files changed, 1209 deletions(-) delete mode 100644 meta-agl-bsp/recipes-kernel/linux/linux-yocto/0001-fanotify-fix-notification-of-groups-with-inode-mount.patch delete mode 100644 meta-agl-bsp/recipes-kernel/linux/linux-yocto/4.4-0001-mm-larger-stack-guard-gap-between-vmas.patch delete mode 100644 meta-agl-bsp/recipes-kernel/linux/linux-yocto/4.4-0002-Allow-stack-to-grow-up-to-address-space-limit.patch delete mode 100644 meta-agl-bsp/recipes-kernel/linux/linux-yocto/4.4-0003-mm-fix-new-crash-in-unmapped_area_topdown.patch (limited to 'meta-agl-bsp/recipes-kernel/linux/linux-yocto') diff --git a/meta-agl-bsp/recipes-kernel/linux/linux-yocto/0001-fanotify-fix-notification-of-groups-with-inode-mount.patch b/meta-agl-bsp/recipes-kernel/linux/linux-yocto/0001-fanotify-fix-notification-of-groups-with-inode-mount.patch deleted file mode 100644 index c50c152a1..000000000 --- a/meta-agl-bsp/recipes-kernel/linux/linux-yocto/0001-fanotify-fix-notification-of-groups-with-inode-mount.patch +++ /dev/null @@ -1,206 +0,0 @@ -From 8edc6e1688fc8f02c8c1f53a2ec4928cb1055f4d Mon Sep 17 00:00:00 2001 -From: Jan Kara -Date: Thu, 13 Nov 2014 15:19:33 -0800 -Subject: [PATCH] fanotify: fix notification of groups with inode & mount marks - -fsnotify() needs to merge inode and mount marks lists when notifying -groups about events so that ignore masks from inode marks are reflected -in mount mark notifications and groups are notified in proper order -(according to priorities). - -Currently the sorting of the lists done by fsnotify_add_inode_mark() / -fsnotify_add_vfsmount_mark() and fsnotify() differed which resulted -ignore masks not being used in some cases. - -Fix the problem by always using the same comparison function when -sorting / merging the mark lists. - -Thanks to Heinrich Schuchardt for improvements of my patch. - -Link: https://bugzilla.kernel.org/show_bug.cgi?id=87721 -Signed-off-by: Jan Kara -Reported-by: Heinrich Schuchardt -Tested-by: Heinrich Schuchardt -Signed-off-by: Andrew Morton -Signed-off-by: Linus Torvalds ---- - fs/notify/fsnotify.c | 36 +++++++++++++++++++++--------------- - fs/notify/fsnotify.h | 4 ++++ - fs/notify/inode_mark.c | 8 +++----- - fs/notify/mark.c | 36 ++++++++++++++++++++++++++++++++++++ - fs/notify/vfsmount_mark.c | 8 +++----- - 5 files changed, 67 insertions(+), 25 deletions(-) - -diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c -index 9d3e9c5..89326ac 100644 ---- a/fs/notify/fsnotify.c -+++ b/fs/notify/fsnotify.c -@@ -229,8 +229,16 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, - &fsnotify_mark_srcu); - } - -+ /* -+ * We need to merge inode & vfsmount mark lists so that inode mark -+ * ignore masks are properly reflected for mount mark notifications. -+ * That's why this traversal is so complicated... -+ */ - while (inode_node || vfsmount_node) { -- inode_group = vfsmount_group = NULL; -+ inode_group = NULL; -+ inode_mark = NULL; -+ vfsmount_group = NULL; -+ vfsmount_mark = NULL; - - if (inode_node) { - inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), -@@ -244,21 +252,19 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, - vfsmount_group = vfsmount_mark->group; - } - -- if (inode_group > vfsmount_group) { -- /* handle inode */ -- ret = send_to_group(to_tell, inode_mark, NULL, mask, -- data, data_is, cookie, file_name); -- /* we didn't use the vfsmount_mark */ -- vfsmount_group = NULL; -- } else if (vfsmount_group > inode_group) { -- ret = send_to_group(to_tell, NULL, vfsmount_mark, mask, -- data, data_is, cookie, file_name); -- inode_group = NULL; -- } else { -- ret = send_to_group(to_tell, inode_mark, vfsmount_mark, -- mask, data, data_is, cookie, -- file_name); -+ if (inode_group && vfsmount_group) { -+ int cmp = fsnotify_compare_groups(inode_group, -+ vfsmount_group); -+ if (cmp > 0) { -+ inode_group = NULL; -+ inode_mark = NULL; -+ } else if (cmp < 0) { -+ vfsmount_group = NULL; -+ vfsmount_mark = NULL; -+ } - } -+ ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask, -+ data, data_is, cookie, file_name); - - if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS)) - goto out; -diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h -index 9c0898c..3b68b0a 100644 ---- a/fs/notify/fsnotify.h -+++ b/fs/notify/fsnotify.h -@@ -12,6 +12,10 @@ extern void fsnotify_flush_notify(struct fsnotify_group *group); - /* protects reads of inode and vfsmount marks list */ - extern struct srcu_struct fsnotify_mark_srcu; - -+/* compare two groups for sorting of marks lists */ -+extern int fsnotify_compare_groups(struct fsnotify_group *a, -+ struct fsnotify_group *b); -+ - extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark, - __u32 mask); - /* add a mark to an inode */ -diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c -index e849714..dfbf544 100644 ---- a/fs/notify/inode_mark.c -+++ b/fs/notify/inode_mark.c -@@ -194,6 +194,7 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, - { - struct fsnotify_mark *lmark, *last = NULL; - int ret = 0; -+ int cmp; - - mark->flags |= FSNOTIFY_MARK_FLAG_INODE; - -@@ -219,11 +220,8 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, - goto out; - } - -- if (mark->group->priority < lmark->group->priority) -- continue; -- -- if ((mark->group->priority == lmark->group->priority) && -- (mark->group < lmark->group)) -+ cmp = fsnotify_compare_groups(lmark->group, mark->group); -+ if (cmp < 0) - continue; - - hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list); -diff --git a/fs/notify/mark.c b/fs/notify/mark.c -index d90deaa..34c38fa 100644 ---- a/fs/notify/mark.c -+++ b/fs/notify/mark.c -@@ -210,6 +210,42 @@ void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mas - } - - /* -+ * Sorting function for lists of fsnotify marks. -+ * -+ * Fanotify supports different notification classes (reflected as priority of -+ * notification group). Events shall be passed to notification groups in -+ * decreasing priority order. To achieve this marks in notification lists for -+ * inodes and vfsmounts are sorted so that priorities of corresponding groups -+ * are descending. -+ * -+ * Furthermore correct handling of the ignore mask requires processing inode -+ * and vfsmount marks of each group together. Using the group address as -+ * further sort criterion provides a unique sorting order and thus we can -+ * merge inode and vfsmount lists of marks in linear time and find groups -+ * present in both lists. -+ * -+ * A return value of 1 signifies that b has priority over a. -+ * A return value of 0 signifies that the two marks have to be handled together. -+ * A return value of -1 signifies that a has priority over b. -+ */ -+int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b) -+{ -+ if (a == b) -+ return 0; -+ if (!a) -+ return 1; -+ if (!b) -+ return -1; -+ if (a->priority < b->priority) -+ return 1; -+ if (a->priority > b->priority) -+ return -1; -+ if (a < b) -+ return 1; -+ return -1; -+} -+ -+/* - * Attach an initialized mark to a given group and fs object. - * These marks may be used for the fsnotify backend to determine which - * event types should be delivered to which group. -diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c -index ac851e8..faefa72 100644 ---- a/fs/notify/vfsmount_mark.c -+++ b/fs/notify/vfsmount_mark.c -@@ -153,6 +153,7 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, - struct mount *m = real_mount(mnt); - struct fsnotify_mark *lmark, *last = NULL; - int ret = 0; -+ int cmp; - - mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; - -@@ -178,11 +179,8 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, - goto out; - } - -- if (mark->group->priority < lmark->group->priority) -- continue; -- -- if ((mark->group->priority == lmark->group->priority) && -- (mark->group < lmark->group)) -+ cmp = fsnotify_compare_groups(lmark->group, mark->group); -+ if (cmp < 0) - continue; - - hlist_add_before_rcu(&mark->m.m_list, &lmark->m.m_list); --- -1.8.3.1 - diff --git a/meta-agl-bsp/recipes-kernel/linux/linux-yocto/4.4-0001-mm-larger-stack-guard-gap-between-vmas.patch b/meta-agl-bsp/recipes-kernel/linux/linux-yocto/4.4-0001-mm-larger-stack-guard-gap-between-vmas.patch deleted file mode 100644 index e9fafad74..000000000 --- a/meta-agl-bsp/recipes-kernel/linux/linux-yocto/4.4-0001-mm-larger-stack-guard-gap-between-vmas.patch +++ /dev/null @@ -1,900 +0,0 @@ -From 3982d0807e02909957990f194c5ed2ffb6ab6c35 Mon Sep 17 00:00:00 2001 -From: Hugh Dickins -Date: Mon, 19 Jun 2017 04:03:24 -0700 -Subject: [PATCH 1/3] mm: larger stack guard gap, between vmas - -commit 1be7107fbe18eed3e319a6c3e83c78254b693acb upstream. - -Stack guard page is a useful feature to reduce a risk of stack smashing -into a different mapping. We have been using a single page gap which -is sufficient to prevent having stack adjacent to a different mapping. -But this seems to be insufficient in the light of the stack usage in -userspace. E.g. glibc uses as large as 64kB alloca() in many commonly -used functions. Others use constructs liks gid_t buffer[NGROUPS_MAX] -which is 256kB or stack strings with MAX_ARG_STRLEN. - -This will become especially dangerous for suid binaries and the default -no limit for the stack size limit because those applications can be -tricked to consume a large portion of the stack and a single glibc call -could jump over the guard page. These attacks are not theoretical, -unfortunatelly. - -Make those attacks less probable by increasing the stack guard gap -to 1MB (on systems with 4k pages; but make it depend on the page size -because systems with larger base pages might cap stack allocations in -the PAGE_SIZE units) which should cover larger alloca() and VLA stack -allocations. It is obviously not a full fix because the problem is -somehow inherent, but it should reduce attack space a lot. - -One could argue that the gap size should be configurable from userspace, -but that can be done later when somebody finds that the new 1MB is wrong -for some special case applications. For now, add a kernel command line -option (stack_guard_gap) to specify the stack gap size (in page units). - -Implementation wise, first delete all the old code for stack guard page: -because although we could get away with accounting one extra page in a -stack vma, accounting a larger gap can break userspace - case in point, -a program run with "ulimit -S -v 20000" failed when the 1MB gap was -counted for RLIMIT_AS; similar problems could come with RLIMIT_MLOCK -and strict non-overcommit mode. - -Instead of keeping gap inside the stack vma, maintain the stack guard -gap as a gap between vmas: using vm_start_gap() in place of vm_start -(or vm_end_gap() in place of vm_end if VM_GROWSUP) in just those few -places which need to respect the gap - mainly arch_get_unmapped_area(), -and and the vma tree's subtree_gap support for that. - -Original-patch-by: Oleg Nesterov -Original-patch-by: Michal Hocko -Signed-off-by: Hugh Dickins -Acked-by: Michal Hocko -Tested-by: Helge Deller # parisc -Signed-off-by: Linus Torvalds -[wt: backport to 4.11: adjust context] -[wt: backport to 4.9: adjust context ; kernel doc was not in admin-guide] -[wt: backport to 4.4: adjust context ; drop ppc hugetlb_radix changes] -Signed-off-by: Willy Tarreau -[gkh: minor build fixes for 4.4] -Signed-off-by: Greg Kroah-Hartman ---- - Documentation/kernel-parameters.txt | 7 ++ - arch/arc/mm/mmap.c | 2 +- - arch/arm/mm/mmap.c | 4 +- - arch/frv/mm/elf-fdpic.c | 2 +- - arch/mips/mm/mmap.c | 2 +- - arch/parisc/kernel/sys_parisc.c | 15 ++-- - arch/powerpc/mm/slice.c | 2 +- - arch/s390/mm/mmap.c | 4 +- - arch/sh/mm/mmap.c | 4 +- - arch/sparc/kernel/sys_sparc_64.c | 4 +- - arch/sparc/mm/hugetlbpage.c | 2 +- - arch/tile/mm/hugetlbpage.c | 2 +- - arch/x86/kernel/sys_x86_64.c | 4 +- - arch/x86/mm/hugetlbpage.c | 2 +- - arch/xtensa/kernel/syscall.c | 2 +- - fs/hugetlbfs/inode.c | 2 +- - fs/proc/task_mmu.c | 4 - - include/linux/mm.h | 53 ++++++------- - mm/gup.c | 5 -- - mm/memory.c | 38 --------- - mm/mmap.c | 149 +++++++++++++++++++++--------------- - 21 files changed, 149 insertions(+), 160 deletions(-) - -diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt -index c360f80..9738c8b 100644 ---- a/Documentation/kernel-parameters.txt -+++ b/Documentation/kernel-parameters.txt -@@ -3576,6 +3576,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. - spia_pedr= - spia_peddr= - -+ stack_guard_gap= [MM] -+ override the default stack gap protection. The value -+ is in page units and it defines how many pages prior -+ to (for stacks growing down) resp. after (for stacks -+ growing up) the main stack are reserved for no other -+ mapping. Default value is 256 pages. -+ - stacktrace [FTRACE] - Enabled the stack tracer on boot up. - -diff --git a/arch/arc/mm/mmap.c b/arch/arc/mm/mmap.c -index 2e06d56..cf4ae69 100644 ---- a/arch/arc/mm/mmap.c -+++ b/arch/arc/mm/mmap.c -@@ -64,7 +64,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, - - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c -index 407dc78..c469c06 100644 ---- a/arch/arm/mm/mmap.c -+++ b/arch/arm/mm/mmap.c -@@ -89,7 +89,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, - - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -@@ -140,7 +140,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -diff --git a/arch/frv/mm/elf-fdpic.c b/arch/frv/mm/elf-fdpic.c -index 836f147..efa59f1 100644 ---- a/arch/frv/mm/elf-fdpic.c -+++ b/arch/frv/mm/elf-fdpic.c -@@ -74,7 +74,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi - addr = PAGE_ALIGN(addr); - vma = find_vma(current->mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - goto success; - } - -diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c -index 5c81fdd..025cb31 100644 ---- a/arch/mips/mm/mmap.c -+++ b/arch/mips/mm/mmap.c -@@ -92,7 +92,7 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, - - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c -index 5aba01a..4dda73c 100644 ---- a/arch/parisc/kernel/sys_parisc.c -+++ b/arch/parisc/kernel/sys_parisc.c -@@ -88,7 +88,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) - { - struct mm_struct *mm = current->mm; -- struct vm_area_struct *vma; -+ struct vm_area_struct *vma, *prev; - unsigned long task_size = TASK_SIZE; - int do_color_align, last_mmap; - struct vm_unmapped_area_info info; -@@ -115,9 +115,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - else - addr = PAGE_ALIGN(addr); - -- vma = find_vma(mm, addr); -+ vma = find_vma_prev(mm, addr, &prev); - if (task_size - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma)) && -+ (!prev || addr >= vm_end_gap(prev))) - goto found_addr; - } - -@@ -141,7 +142,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - const unsigned long len, const unsigned long pgoff, - const unsigned long flags) - { -- struct vm_area_struct *vma; -+ struct vm_area_struct *vma, *prev; - struct mm_struct *mm = current->mm; - unsigned long addr = addr0; - int do_color_align, last_mmap; -@@ -175,9 +176,11 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - addr = COLOR_ALIGN(addr, last_mmap, pgoff); - else - addr = PAGE_ALIGN(addr); -- vma = find_vma(mm, addr); -+ -+ vma = find_vma_prev(mm, addr, &prev); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma)) && -+ (!prev || addr >= vm_end_gap(prev))) - goto found_addr; - } - -diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c -index 0f432a7..6ad12b2 100644 ---- a/arch/powerpc/mm/slice.c -+++ b/arch/powerpc/mm/slice.c -@@ -105,7 +105,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr, - if ((mm->task_size - len) < addr) - return 0; - vma = find_vma(mm, addr); -- return (!vma || (addr + len) <= vma->vm_start); -+ return (!vma || (addr + len) <= vm_start_gap(vma)); - } - - static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice) -diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c -index f2b6b1d..126c4a9 100644 ---- a/arch/s390/mm/mmap.c -+++ b/arch/s390/mm/mmap.c -@@ -97,7 +97,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, - addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -@@ -135,7 +135,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c -index 6777177..7df7d59 100644 ---- a/arch/sh/mm/mmap.c -+++ b/arch/sh/mm/mmap.c -@@ -63,7 +63,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -@@ -113,7 +113,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c -index c690c8e..7f0f7c01 100644 ---- a/arch/sparc/kernel/sys_sparc_64.c -+++ b/arch/sparc/kernel/sys_sparc_64.c -@@ -118,7 +118,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi - - vma = find_vma(mm, addr); - if (task_size - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -@@ -181,7 +181,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - - vma = find_vma(mm, addr); - if (task_size - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c -index da11424..ffa842b 100644 ---- a/arch/sparc/mm/hugetlbpage.c -+++ b/arch/sparc/mm/hugetlbpage.c -@@ -115,7 +115,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - addr = ALIGN(addr, HPAGE_SIZE); - vma = find_vma(mm, addr); - if (task_size - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - if (mm->get_unmapped_area == arch_get_unmapped_area) -diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c -index c034dc3..c97ee6c 100644 ---- a/arch/tile/mm/hugetlbpage.c -+++ b/arch/tile/mm/hugetlbpage.c -@@ -232,7 +232,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - addr = ALIGN(addr, huge_page_size(h)); - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - if (current->mm->get_unmapped_area == arch_get_unmapped_area) -diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c -index 10e0272..136ad7c 100644 ---- a/arch/x86/kernel/sys_x86_64.c -+++ b/arch/x86/kernel/sys_x86_64.c -@@ -143,7 +143,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, - addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); - if (end - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -@@ -186,7 +186,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c -index 42982b2..39bdaf3 100644 ---- a/arch/x86/mm/hugetlbpage.c -+++ b/arch/x86/mm/hugetlbpage.c -@@ -144,7 +144,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - addr = ALIGN(addr, huge_page_size(h)); - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - if (mm->get_unmapped_area == arch_get_unmapped_area) -diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c -index 83cf496..3aaaae1 100644 ---- a/arch/xtensa/kernel/syscall.c -+++ b/arch/xtensa/kernel/syscall.c -@@ -87,7 +87,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - /* At this point: (!vmm || addr < vmm->vm_end). */ - if (TASK_SIZE - len < addr) - return -ENOMEM; -- if (!vmm || addr + len <= vmm->vm_start) -+ if (!vmm || addr + len <= vm_start_gap(vmm)) - return addr; - addr = vmm->vm_end; - if (flags & MAP_SHARED) -diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c -index 595ebdb..a17da8b5 100644 ---- a/fs/hugetlbfs/inode.c -+++ b/fs/hugetlbfs/inode.c -@@ -191,7 +191,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - addr = ALIGN(addr, huge_page_size(h)); - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - -diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c -index d598b9c..cb7020c 100644 ---- a/fs/proc/task_mmu.c -+++ b/fs/proc/task_mmu.c -@@ -295,11 +295,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) - - /* We don't show the stack guard page in /proc/maps */ - start = vma->vm_start; -- if (stack_guard_page_start(vma, start)) -- start += PAGE_SIZE; - end = vma->vm_end; -- if (stack_guard_page_end(vma, end)) -- end -= PAGE_SIZE; - - seq_setwidth(m, 25 + sizeof(void *) * 6 - 1); - seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ", -diff --git a/include/linux/mm.h b/include/linux/mm.h -index f0ffa01..55f950a 100644 ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -1278,39 +1278,11 @@ int clear_page_dirty_for_io(struct page *page); - - int get_cmdline(struct task_struct *task, char *buffer, int buflen); - --/* Is the vma a continuation of the stack vma above it? */ --static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr) --{ -- return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); --} -- - static inline bool vma_is_anonymous(struct vm_area_struct *vma) - { - return !vma->vm_ops; - } - --static inline int stack_guard_page_start(struct vm_area_struct *vma, -- unsigned long addr) --{ -- return (vma->vm_flags & VM_GROWSDOWN) && -- (vma->vm_start == addr) && -- !vma_growsdown(vma->vm_prev, addr); --} -- --/* Is the vma a continuation of the stack vma below it? */ --static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr) --{ -- return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP); --} -- --static inline int stack_guard_page_end(struct vm_area_struct *vma, -- unsigned long addr) --{ -- return (vma->vm_flags & VM_GROWSUP) && -- (vma->vm_end == addr) && -- !vma_growsup(vma->vm_next, addr); --} -- - int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t); - - extern unsigned long move_page_tables(struct vm_area_struct *vma, -@@ -2012,6 +1984,7 @@ void page_cache_async_readahead(struct address_space *mapping, - pgoff_t offset, - unsigned long size); - -+extern unsigned long stack_guard_gap; - /* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */ - extern int expand_stack(struct vm_area_struct *vma, unsigned long address); - -@@ -2040,6 +2013,30 @@ static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * m - return vma; - } - -+static inline unsigned long vm_start_gap(struct vm_area_struct *vma) -+{ -+ unsigned long vm_start = vma->vm_start; -+ -+ if (vma->vm_flags & VM_GROWSDOWN) { -+ vm_start -= stack_guard_gap; -+ if (vm_start > vma->vm_start) -+ vm_start = 0; -+ } -+ return vm_start; -+} -+ -+static inline unsigned long vm_end_gap(struct vm_area_struct *vma) -+{ -+ unsigned long vm_end = vma->vm_end; -+ -+ if (vma->vm_flags & VM_GROWSUP) { -+ vm_end += stack_guard_gap; -+ if (vm_end < vma->vm_end) -+ vm_end = -PAGE_SIZE; -+ } -+ return vm_end; -+} -+ - static inline unsigned long vma_pages(struct vm_area_struct *vma) - { - return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; -diff --git a/mm/gup.c b/mm/gup.c -index 4b0b7e7..b599526 100644 ---- a/mm/gup.c -+++ b/mm/gup.c -@@ -312,11 +312,6 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma, - /* mlock all present pages, but do not fault in new pages */ - if ((*flags & (FOLL_POPULATE | FOLL_MLOCK)) == FOLL_MLOCK) - return -ENOENT; -- /* For mm_populate(), just skip the stack guard page. */ -- if ((*flags & FOLL_POPULATE) && -- (stack_guard_page_start(vma, address) || -- stack_guard_page_end(vma, address + PAGE_SIZE))) -- return -ENOENT; - if (*flags & FOLL_WRITE) - fault_flags |= FAULT_FLAG_WRITE; - if (nonblocking) -diff --git a/mm/memory.c b/mm/memory.c -index 76dcee3..e6fa134 100644 ---- a/mm/memory.c -+++ b/mm/memory.c -@@ -2662,40 +2662,6 @@ out_release: - } - - /* -- * This is like a special single-page "expand_{down|up}wards()", -- * except we must first make sure that 'address{-|+}PAGE_SIZE' -- * doesn't hit another vma. -- */ --static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned long address) --{ -- address &= PAGE_MASK; -- if ((vma->vm_flags & VM_GROWSDOWN) && address == vma->vm_start) { -- struct vm_area_struct *prev = vma->vm_prev; -- -- /* -- * Is there a mapping abutting this one below? -- * -- * That's only ok if it's the same stack mapping -- * that has gotten split.. -- */ -- if (prev && prev->vm_end == address) -- return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; -- -- return expand_downwards(vma, address - PAGE_SIZE); -- } -- if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) { -- struct vm_area_struct *next = vma->vm_next; -- -- /* As VM_GROWSDOWN but s/below/above/ */ -- if (next && next->vm_start == address + PAGE_SIZE) -- return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; -- -- return expand_upwards(vma, address + PAGE_SIZE); -- } -- return 0; --} -- --/* - * We enter with non-exclusive mmap_sem (to exclude vma changes, - * but allow concurrent faults), and pte mapped but not yet locked. - * We return with mmap_sem still held, but pte unmapped and unlocked. -@@ -2715,10 +2681,6 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, - if (vma->vm_flags & VM_SHARED) - return VM_FAULT_SIGBUS; - -- /* Check if we need to add a guard page to the stack */ -- if (check_stack_guard_page(vma, address) < 0) -- return VM_FAULT_SIGSEGV; -- - /* Use the zero-page for reads */ - if (!(flags & FAULT_FLAG_WRITE) && !mm_forbids_zeropage(mm)) { - entry = pte_mkspecial(pfn_pte(my_zero_pfn(address), -diff --git a/mm/mmap.c b/mm/mmap.c -index 455772a..5e043dd 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -288,6 +288,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) - unsigned long retval; - unsigned long newbrk, oldbrk; - struct mm_struct *mm = current->mm; -+ struct vm_area_struct *next; - unsigned long min_brk; - bool populate; - -@@ -332,7 +333,8 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) - } - - /* Check against existing mmap mappings. */ -- if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) -+ next = find_vma(mm, oldbrk); -+ if (next && newbrk + PAGE_SIZE > vm_start_gap(next)) - goto out; - - /* Ok, looks good - let it rip. */ -@@ -355,10 +357,22 @@ out: - - static long vma_compute_subtree_gap(struct vm_area_struct *vma) - { -- unsigned long max, subtree_gap; -- max = vma->vm_start; -- if (vma->vm_prev) -- max -= vma->vm_prev->vm_end; -+ unsigned long max, prev_end, subtree_gap; -+ -+ /* -+ * Note: in the rare case of a VM_GROWSDOWN above a VM_GROWSUP, we -+ * allow two stack_guard_gaps between them here, and when choosing -+ * an unmapped area; whereas when expanding we only require one. -+ * That's a little inconsistent, but keeps the code here simpler. -+ */ -+ max = vm_start_gap(vma); -+ if (vma->vm_prev) { -+ prev_end = vm_end_gap(vma->vm_prev); -+ if (max > prev_end) -+ max -= prev_end; -+ else -+ max = 0; -+ } - if (vma->vm_rb.rb_left) { - subtree_gap = rb_entry(vma->vm_rb.rb_left, - struct vm_area_struct, vm_rb)->rb_subtree_gap; -@@ -451,7 +465,7 @@ static void validate_mm(struct mm_struct *mm) - anon_vma_unlock_read(anon_vma); - } - -- highest_address = vma->vm_end; -+ highest_address = vm_end_gap(vma); - vma = vma->vm_next; - i++; - } -@@ -620,7 +634,7 @@ void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, - if (vma->vm_next) - vma_gap_update(vma->vm_next); - else -- mm->highest_vm_end = vma->vm_end; -+ mm->highest_vm_end = vm_end_gap(vma); - - /* - * vma->vm_prev wasn't known when we followed the rbtree to find the -@@ -866,7 +880,7 @@ again: remove_next = 1 + (end > next->vm_end); - vma_gap_update(vma); - if (end_changed) { - if (!next) -- mm->highest_vm_end = end; -+ mm->highest_vm_end = vm_end_gap(vma); - else if (!adjust_next) - vma_gap_update(next); - } -@@ -909,7 +923,7 @@ again: remove_next = 1 + (end > next->vm_end); - else if (next) - vma_gap_update(next); - else -- mm->highest_vm_end = end; -+ VM_WARN_ON(mm->highest_vm_end != vm_end_gap(vma)); - } - if (insert && file) - uprobe_mmap(insert); -@@ -1741,7 +1755,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info) - - while (true) { - /* Visit left subtree if it looks promising */ -- gap_end = vma->vm_start; -+ gap_end = vm_start_gap(vma); - if (gap_end >= low_limit && vma->vm_rb.rb_left) { - struct vm_area_struct *left = - rb_entry(vma->vm_rb.rb_left, -@@ -1752,7 +1766,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info) - } - } - -- gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; -+ gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0; - check_current: - /* Check if current node has a suitable gap */ - if (gap_start > high_limit) -@@ -1779,8 +1793,8 @@ check_current: - vma = rb_entry(rb_parent(prev), - struct vm_area_struct, vm_rb); - if (prev == vma->vm_rb.rb_left) { -- gap_start = vma->vm_prev->vm_end; -- gap_end = vma->vm_start; -+ gap_start = vm_end_gap(vma->vm_prev); -+ gap_end = vm_start_gap(vma); - goto check_current; - } - } -@@ -1844,7 +1858,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) - - while (true) { - /* Visit right subtree if it looks promising */ -- gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; -+ gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0; - if (gap_start <= high_limit && vma->vm_rb.rb_right) { - struct vm_area_struct *right = - rb_entry(vma->vm_rb.rb_right, -@@ -1857,7 +1871,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) - - check_current: - /* Check if current node has a suitable gap */ -- gap_end = vma->vm_start; -+ gap_end = vm_start_gap(vma); - if (gap_end < low_limit) - return -ENOMEM; - if (gap_start <= high_limit && gap_end - gap_start >= length) -@@ -1883,7 +1897,7 @@ check_current: - struct vm_area_struct, vm_rb); - if (prev == vma->vm_rb.rb_right) { - gap_start = vma->vm_prev ? -- vma->vm_prev->vm_end : 0; -+ vm_end_gap(vma->vm_prev) : 0; - goto check_current; - } - } -@@ -1921,7 +1935,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) - { - struct mm_struct *mm = current->mm; -- struct vm_area_struct *vma; -+ struct vm_area_struct *vma, *prev; - struct vm_unmapped_area_info info; - - if (len > TASK_SIZE - mmap_min_addr) -@@ -1932,9 +1946,10 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, - - if (addr) { - addr = PAGE_ALIGN(addr); -- vma = find_vma(mm, addr); -+ vma = find_vma_prev(mm, addr, &prev); - if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma)) && -+ (!prev || addr >= vm_end_gap(prev))) - return addr; - } - -@@ -1957,7 +1972,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - const unsigned long len, const unsigned long pgoff, - const unsigned long flags) - { -- struct vm_area_struct *vma; -+ struct vm_area_struct *vma, *prev; - struct mm_struct *mm = current->mm; - unsigned long addr = addr0; - struct vm_unmapped_area_info info; -@@ -1972,9 +1987,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - /* requesting a specific address */ - if (addr) { - addr = PAGE_ALIGN(addr); -- vma = find_vma(mm, addr); -+ vma = find_vma_prev(mm, addr, &prev); - if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && -- (!vma || addr + len <= vma->vm_start)) -+ (!vma || addr + len <= vm_start_gap(vma)) && -+ (!prev || addr >= vm_end_gap(prev))) - return addr; - } - -@@ -2099,21 +2115,19 @@ find_vma_prev(struct mm_struct *mm, unsigned long addr, - * update accounting. This is shared with both the - * grow-up and grow-down cases. - */ --static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow) -+static int acct_stack_growth(struct vm_area_struct *vma, -+ unsigned long size, unsigned long grow) - { - struct mm_struct *mm = vma->vm_mm; - struct rlimit *rlim = current->signal->rlim; -- unsigned long new_start, actual_size; -+ unsigned long new_start; - - /* address space limit tests */ - if (!may_expand_vm(mm, grow)) - return -ENOMEM; - - /* Stack limit test */ -- actual_size = size; -- if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN))) -- actual_size -= PAGE_SIZE; -- if (actual_size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur)) -+ if (size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur)) - return -ENOMEM; - - /* mlock limit tests */ -@@ -2151,17 +2165,30 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns - int expand_upwards(struct vm_area_struct *vma, unsigned long address) - { - struct mm_struct *mm = vma->vm_mm; -+ struct vm_area_struct *next; -+ unsigned long gap_addr; - int error = 0; - - if (!(vma->vm_flags & VM_GROWSUP)) - return -EFAULT; - - /* Guard against wrapping around to address 0. */ -- if (address < PAGE_ALIGN(address+4)) -- address = PAGE_ALIGN(address+4); -- else -+ address &= PAGE_MASK; -+ address += PAGE_SIZE; -+ if (!address) - return -ENOMEM; - -+ /* Enforce stack_guard_gap */ -+ gap_addr = address + stack_guard_gap; -+ if (gap_addr < address) -+ return -ENOMEM; -+ next = vma->vm_next; -+ if (next && next->vm_start < gap_addr) { -+ if (!(next->vm_flags & VM_GROWSUP)) -+ return -ENOMEM; -+ /* Check that both stack segments have the same anon_vma? */ -+ } -+ - /* We must make sure the anon_vma is allocated. */ - if (unlikely(anon_vma_prepare(vma))) - return -ENOMEM; -@@ -2206,7 +2233,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) - if (vma->vm_next) - vma_gap_update(vma->vm_next); - else -- mm->highest_vm_end = address; -+ mm->highest_vm_end = vm_end_gap(vma); - spin_unlock(&mm->page_table_lock); - - perf_event_mmap(vma); -@@ -2227,6 +2254,8 @@ int expand_downwards(struct vm_area_struct *vma, - unsigned long address) - { - struct mm_struct *mm = vma->vm_mm; -+ struct vm_area_struct *prev; -+ unsigned long gap_addr; - int error; - - address &= PAGE_MASK; -@@ -2234,6 +2263,17 @@ int expand_downwards(struct vm_area_struct *vma, - if (error) - return error; - -+ /* Enforce stack_guard_gap */ -+ gap_addr = address - stack_guard_gap; -+ if (gap_addr > address) -+ return -ENOMEM; -+ prev = vma->vm_prev; -+ if (prev && prev->vm_end > gap_addr) { -+ if (!(prev->vm_flags & VM_GROWSDOWN)) -+ return -ENOMEM; -+ /* Check that both stack segments have the same anon_vma? */ -+ } -+ - /* We must make sure the anon_vma is allocated. */ - if (unlikely(anon_vma_prepare(vma))) - return -ENOMEM; -@@ -2289,28 +2329,25 @@ int expand_downwards(struct vm_area_struct *vma, - return error; - } - --/* -- * Note how expand_stack() refuses to expand the stack all the way to -- * abut the next virtual mapping, *unless* that mapping itself is also -- * a stack mapping. We want to leave room for a guard page, after all -- * (the guard page itself is not added here, that is done by the -- * actual page faulting logic) -- * -- * This matches the behavior of the guard page logic (see mm/memory.c: -- * check_stack_guard_page()), which only allows the guard page to be -- * removed under these circumstances. -- */ -+/* enforced gap between the expanding stack and other mappings. */ -+unsigned long stack_guard_gap = 256UL< -Debugged-by: Linus Torvalds -Signed-off-by: Hugh Dickins -Acked-by: Michal Hocko -Signed-off-by: Linus Torvalds -Signed-off-by: Greg Kroah-Hartman ---- - mm/mmap.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/mm/mmap.c b/mm/mmap.c -index fcf4c88..0990f8b 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -1771,7 +1771,8 @@ check_current: - /* Check if current node has a suitable gap */ - if (gap_start > high_limit) - return -ENOMEM; -- if (gap_end >= low_limit && gap_end - gap_start >= length) -+ if (gap_end >= low_limit && -+ gap_end > gap_start && gap_end - gap_start >= length) - goto found; - - /* Visit right subtree if it looks promising */ -@@ -1874,7 +1875,8 @@ check_current: - gap_end = vm_start_gap(vma); - if (gap_end < low_limit) - return -ENOMEM; -- if (gap_start <= high_limit && gap_end - gap_start >= length) -+ if (gap_start <= high_limit && -+ gap_end > gap_start && gap_end - gap_start >= length) - goto found; - - /* Visit left subtree if it looks promising */ --- -2.1.4 - -- cgit 1.2.3-korg