linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv5 0/5] Fix compatible mmap() return pointer over 4Gb
@ 2017-02-14 18:36 Dmitry Safonov
  2017-02-14 18:36 ` [PATCHv5 1/5] x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd Dmitry Safonov
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Dmitry Safonov @ 2017-02-14 18:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: 0x7f454c46, Dmitry Safonov, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Andy Lutomirski, Borislav Petkov, x86, linux-mm,
	Cyrill Gorcunov, Shuah Khan, linux-kselftest

There are a couple of fixes related to x86 mmap():
o 1-2 are just preparation to introduce new mmap bases
o 3 fixes 32-bit syscall returning address over 4Gb in applications,
  launched from 64-bit binaries. This is done by introducing new bases:
  mmap_compat_base and mmap_compat_legacy_base.
  Those bases are separated from 64-bit ones, which allows to use
  mmap base according to bitness of the syscall.
  Which makes the behavior of 32-bit syscalls the same independently
  of launched binary's bitness (the same for 64-bit syscalls).
  It also makes possible to allocate with 64-bit mmap() address higher
  than 4Gb in compat ELFs - that may be used when 4Gb is not enough or
  with MAP_FIXED for hiding that mapping from 32-bit address space.
o 4 fixes behavior of MAP_32BIT - at this moment it's related
  to the bitness of executed binary, not of the syscall.
o 5 is a selftest to check that 32-bit mmap() does return 32-bit
  pointer.

Changes since v4 (Thomas's review):
- rewrote changelogs (so they should be readable by humans also)
- made code simpler (fighting to ifdef horror, etc)

Changes since v3:
- fixed usage of 64-bit random mask for 32-bit mm->mmap_compat_base,
  during introducing mmap_compat{_legacy,}_base

Changes since v2:
- don't distinguish native and compat tasks by TIF_ADDR32,
  introduced mmap_compat{_legacy,}_base which allows to treat them
  the same
- fixed kbuild errors

Changes since v1:
- Recalculate mmap_base instead of using max possible virtual address
  for compat/native syscall. That will make policy for allocation the
  same in 32-bit binaries and in 32-bit syscalls in 64-bit binaries.
  I need this because sys_mmap() in restored 32-bit process shouldn't
  hit the stack area.
- Fixed mmap() with MAP_32BIT flag in the same usecases
- used in_compat_syscall() helper rather TS_COMPAT check (Andy noticed)
- introduced find_top() helper as suggested by Andy to simplify code
- fixed test error-handeling: it checked the result of sys_mmap() with
  MMAP_FAILED, which is not correct, as it calls raw syscall - now
  checks return value to be aligned to PAGE_SIZE.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@suse.de>
Cc: x86@kernel.org
Cc: linux-mm@kvack.org
Cc: Cyrill Gorcunov <gorcunov@openvz.org>

Dmitry Safonov (5):
  x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd
  x86/mm: add task_size parameter to mmap_base()
  x86/mm: introduce mmap_compat_base for 32-bit mmap()
  x86/mm: check in_compat_syscall() instead TIF_ADDR32 for
    mmap(MAP_32BIT)
  selftests/x86: add test for 32-bit mmap() return addr

 arch/Kconfig                                   |   7 +
 arch/x86/Kconfig                               |   1 +
 arch/x86/include/asm/elf.h                     |  27 ++--
 arch/x86/include/asm/processor.h               |   4 +-
 arch/x86/kernel/sys_x86_64.c                   |  27 +++-
 arch/x86/mm/mmap.c                             | 109 ++++++++-----
 include/linux/mm_types.h                       |   5 +
 tools/testing/selftests/x86/Makefile           |   2 +-
 tools/testing/selftests/x86/test_compat_mmap.c | 208 +++++++++++++++++++++++++
 9 files changed, 332 insertions(+), 58 deletions(-)
 create mode 100644 tools/testing/selftests/x86/test_compat_mmap.c

-- 
2.11.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCHv5 1/5] x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd
  2017-02-14 18:36 [PATCHv5 0/5] Fix compatible mmap() return pointer over 4Gb Dmitry Safonov
@ 2017-02-14 18:36 ` Dmitry Safonov
  2017-02-14 22:22   ` kbuild test robot
  2017-02-14 18:36 ` [PATCHv5 2/5] x86/mm: add task_size parameter to mmap_base() Dmitry Safonov
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Dmitry Safonov @ 2017-02-14 18:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: 0x7f454c46, Dmitry Safonov, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Andy Lutomirski, Borislav Petkov, x86, linux-mm,
	Cyrill Gorcunov

To fix 32-bit mmap() syscall returning pointer higher than 4Gb in
64-bit binaries, two mmap bases will be used: one for mapping with
32-bit syscalls and another for 64-bit syscall.
To correctly place those two bases, introduce arch_rnd() function,
which will return the random factor independently of mmap_is_ia32().

Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
---
 arch/x86/mm/mmap.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index d2dc0438d654..9f3ac019e51c 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -54,6 +54,14 @@ static unsigned long stack_maxrandom_size(void)
 #define MIN_GAP (128*1024*1024UL + stack_maxrandom_size())
 #define MAX_GAP (TASK_SIZE/6*5)
 
+#ifdef CONFIG_64BIT
+# define mmap32_rnd_bits  mmap_rnd_compat_bits
+# define mmap64_rnd_bits  mmap_rnd_bits
+#else
+# define mmap32_rnd_bits  mmap_rnd_bits
+# define mmap64_rnd_bits  mmap_rnd_bits
+#endif
+
 static int mmap_is_legacy(void)
 {
 	if (current->personality & ADDR_COMPAT_LAYOUT)
@@ -65,20 +73,14 @@ static int mmap_is_legacy(void)
 	return sysctl_legacy_va_layout;
 }
 
-unsigned long arch_mmap_rnd(void)
+static unsigned long arch_rnd(unsigned int rndbits)
 {
-	unsigned long rnd;
-
-	if (mmap_is_ia32())
-#ifdef CONFIG_COMPAT
-		rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1);
-#else
-		rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
-#endif
-	else
-		rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
+	return (get_random_long() & ((1UL << rndbits) - 1)) << PAGE_SHIFT;
+}
 
-	return rnd << PAGE_SHIFT;
+unsigned long arch_mmap_rnd(void)
+{
+	return arch_rnd(mmap_is_ia32() ? mmap32_rnd_bits : mmap64_rnd_bits);
 }
 
 static unsigned long mmap_base(unsigned long rnd)
-- 
2.11.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCHv5 2/5] x86/mm: add task_size parameter to mmap_base()
  2017-02-14 18:36 [PATCHv5 0/5] Fix compatible mmap() return pointer over 4Gb Dmitry Safonov
  2017-02-14 18:36 ` [PATCHv5 1/5] x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd Dmitry Safonov
@ 2017-02-14 18:36 ` Dmitry Safonov
  2017-02-14 18:36 ` [PATCHv5 3/5] x86/mm: introduce mmap_compat_base for 32-bit mmap() Dmitry Safonov
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Dmitry Safonov @ 2017-02-14 18:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: 0x7f454c46, Dmitry Safonov, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Andy Lutomirski, Borislav Petkov, x86, linux-mm,
	Cyrill Gorcunov

To correctly handle 32-bit and 64-bit mmap() syscalls, we need different
mmap bases to start allocation from. So, introduce mmap_legacy_base()
helper and change mmap_base() to return base address according to
specified task size.
It'll prepare the mmap base computing code for splitting mmap_base
on two bases: for 64-bit syscall and for 32-bit syscalls.

Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
---
 arch/x86/include/asm/elf.h       | 24 ++++++++++---------
 arch/x86/include/asm/processor.h |  4 +++-
 arch/x86/mm/mmap.c               | 50 +++++++++++++++++++++++++---------------
 3 files changed, 48 insertions(+), 30 deletions(-)

diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index e7f155c3045e..8aedc2a4d48c 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -284,8 +284,19 @@ do {									\
 	}								\
 } while (0)
 
+/*
+ * True on X86_32 or when emulating IA32 on X86_64
+ */
+static inline int mmap_is_ia32(void)
+{
+	return IS_ENABLED(CONFIG_X86_32) ||
+	       (IS_ENABLED(CONFIG_COMPAT) &&
+		test_thread_flag(TIF_ADDR32));
+}
+
 #ifdef CONFIG_X86_32
 
+#define __STACK_RND_MASK(is32bit) (0x7ff)
 #define STACK_RND_MASK (0x7ff)
 
 #define ARCH_DLINFO		ARCH_DLINFO_IA32
@@ -295,7 +306,8 @@ do {									\
 #else /* CONFIG_X86_32 */
 
 /* 1GB for 64bit, 8MB for 32bit */
-#define STACK_RND_MASK (test_thread_flag(TIF_ADDR32) ? 0x7ff : 0x3fffff)
+#define __STACK_RND_MASK(is32bit) ((is32bit) ? 0x7ff : 0x3fffff)
+#define STACK_RND_MASK __STACK_RND_MASK(mmap_is_ia32())
 
 #define ARCH_DLINFO							\
 do {									\
@@ -339,16 +351,6 @@ extern int compat_arch_setup_additional_pages(struct linux_binprm *bprm,
 					      int uses_interp);
 #define compat_arch_setup_additional_pages compat_arch_setup_additional_pages
 
-/*
- * True on X86_32 or when emulating IA32 on X86_64
- */
-static inline int mmap_is_ia32(void)
-{
-	return IS_ENABLED(CONFIG_X86_32) ||
-	       (IS_ENABLED(CONFIG_COMPAT) &&
-		test_thread_flag(TIF_ADDR32));
-}
-
 /* Do not change the values. See get_align_mask() */
 enum align_flags {
 	ALIGN_VA_32	= BIT(0),
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index e6cfe7ba2d65..491f5a05a133 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -787,6 +787,7 @@ static inline void spin_lock_prefetch(const void *x)
 /*
  * User space process size: 3GB (default).
  */
+#define IA32_PAGE_OFFSET	PAGE_OFFSET
 #define TASK_SIZE		PAGE_OFFSET
 #define TASK_SIZE_MAX		TASK_SIZE
 #define STACK_TOP		TASK_SIZE
@@ -863,7 +864,8 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip,
  * This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_BASE	(PAGE_ALIGN(TASK_SIZE / 3))
+#define __TASK_UNMAPPED_BASE(task_size)	(PAGE_ALIGN(task_size / 3))
+#define TASK_UNMAPPED_BASE		__TASK_UNMAPPED_BASE(TASK_SIZE)
 
 #define KSTK_EIP(task)		(task_pt_regs(task)->ip)
 
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index 9f3ac019e51c..88ef0c1b0e51 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -35,25 +35,23 @@ struct va_alignment __read_mostly va_align = {
 	.flags = -1,
 };
 
-static unsigned long stack_maxrandom_size(void)
+static inline unsigned long tasksize_32bit(void)
+{
+	return IA32_PAGE_OFFSET;
+}
+
+static unsigned long stack_maxrandom_size(unsigned long task_size)
 {
 	unsigned long max = 0;
 	if ((current->flags & PF_RANDOMIZE) &&
 		!(current->personality & ADDR_NO_RANDOMIZE)) {
-		max = ((-1UL) & STACK_RND_MASK) << PAGE_SHIFT;
+		max = (-1UL) & __STACK_RND_MASK(task_size == tasksize_32bit());
+		max <<= PAGE_SHIFT;
 	}
 
 	return max;
 }
 
-/*
- * Top of mmap area (just below the process stack).
- *
- * Leave an at least ~128 MB hole with possible stack randomization.
- */
-#define MIN_GAP (128*1024*1024UL + stack_maxrandom_size())
-#define MAX_GAP (TASK_SIZE/6*5)
-
 #ifdef CONFIG_64BIT
 # define mmap32_rnd_bits  mmap_rnd_compat_bits
 # define mmap64_rnd_bits  mmap_rnd_bits
@@ -62,6 +60,8 @@ static unsigned long stack_maxrandom_size(void)
 # define mmap64_rnd_bits  mmap_rnd_bits
 #endif
 
+#define SIZE_128M    (128 * 1024 * 1024UL)
+
 static int mmap_is_legacy(void)
 {
 	if (current->personality & ADDR_COMPAT_LAYOUT)
@@ -83,16 +83,30 @@ unsigned long arch_mmap_rnd(void)
 	return arch_rnd(mmap_is_ia32() ? mmap32_rnd_bits : mmap64_rnd_bits);
 }
 
-static unsigned long mmap_base(unsigned long rnd)
+static unsigned long mmap_base(unsigned long rnd, unsigned long task_size)
 {
 	unsigned long gap = rlimit(RLIMIT_STACK);
+	unsigned long gap_min, gap_max;
+
+	/*
+	 * Top of mmap area (just below the process stack).
+	 * Leave an at least ~128 MB hole with possible stack randomization.
+	 */
+	gap_min = SIZE_128M + stack_maxrandom_size(task_size);
+	gap_max = (task_size / 6) * 5;
 
-	if (gap < MIN_GAP)
-		gap = MIN_GAP;
-	else if (gap > MAX_GAP)
-		gap = MAX_GAP;
+	if (gap < gap_min)
+		gap = gap_min;
+	else if (gap > gap_max)
+		gap = gap_max;
 
-	return PAGE_ALIGN(TASK_SIZE - gap - rnd);
+	return PAGE_ALIGN(task_size - gap - rnd);
+}
+
+static unsigned long mmap_legacy_base(unsigned long rnd,
+				      unsigned long task_size)
+{
+	return __TASK_UNMAPPED_BASE(task_size) + rnd;
 }
 
 /*
@@ -106,13 +120,13 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
 	if (current->flags & PF_RANDOMIZE)
 		random_factor = arch_mmap_rnd();
 
-	mm->mmap_legacy_base = TASK_UNMAPPED_BASE + random_factor;
+	mm->mmap_legacy_base = mmap_legacy_base(random_factor, TASK_SIZE);
 
 	if (mmap_is_legacy()) {
 		mm->mmap_base = mm->mmap_legacy_base;
 		mm->get_unmapped_area = arch_get_unmapped_area;
 	} else {
-		mm->mmap_base = mmap_base(random_factor);
+		mm->mmap_base = mmap_base(random_factor, TASK_SIZE);
 		mm->get_unmapped_area = arch_get_unmapped_area_topdown;
 	}
 }
-- 
2.11.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCHv5 3/5] x86/mm: introduce mmap_compat_base for 32-bit mmap()
  2017-02-14 18:36 [PATCHv5 0/5] Fix compatible mmap() return pointer over 4Gb Dmitry Safonov
  2017-02-14 18:36 ` [PATCHv5 1/5] x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd Dmitry Safonov
  2017-02-14 18:36 ` [PATCHv5 2/5] x86/mm: add task_size parameter to mmap_base() Dmitry Safonov
@ 2017-02-14 18:36 ` Dmitry Safonov
  2017-02-14 18:36 ` [PATCHv5 4/5] x86/mm: check in_compat_syscall() instead TIF_ADDR32 for mmap(MAP_32BIT) Dmitry Safonov
  2017-02-14 18:36 ` [PATCHv5 5/5] selftests/x86: add test for 32-bit mmap() return addr Dmitry Safonov
  4 siblings, 0 replies; 8+ messages in thread
From: Dmitry Safonov @ 2017-02-14 18:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: 0x7f454c46, Dmitry Safonov, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Andy Lutomirski, Borislav Petkov, x86, linux-mm,
	Cyrill Gorcunov

mmap() uses base address, from which it starts to look for a free space
for allocation. At this moment there is one mm->mmap_base, which is
calculated during exec(). The address depends on task's size, set rlimit
for stack, ASLR randomization. As task size and number of random bits
differ between 64 and 32 bit applications, calculated mmap_base will
be valid only for the same bitness.
That means e.g., that calculated mmap_base for ELF64 lies upper than
4Gb, which results in bug that 32-bit mmap() syscall will start to
search for a free address over 32-bit address space and returns only
lower 4-bytes of allocated mapping.
As 64-bit applications can do 32-bit syscalls and vice-versa, we need
to correctly chose mmap_base address for syscalls of different bitness.
For this purpose introduce mmap_compat_base and mmap_compat_legacy_base,
use them accordingly in top-down and bottom-up allocations in 32-bit
syscalls, use existed bases mmap_base and mmap_legacy_base for 64-bit
syscalls.
That means that each application on x86_64 will have now two bases
(or four if count legacy bases also) which are calculated on application
exec(). I guess we can relax the calculation of bases until first mmap()
call, but don't think it's worth.

Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
---
 arch/Kconfig                 |  7 +++++++
 arch/x86/Kconfig             |  1 +
 arch/x86/include/asm/elf.h   |  3 +++
 arch/x86/kernel/sys_x86_64.c | 23 +++++++++++++++++++----
 arch/x86/mm/mmap.c           | 41 ++++++++++++++++++++++++++++-------------
 include/linux/mm_types.h     |  5 +++++
 6 files changed, 63 insertions(+), 17 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 99839c23d453..cfb2fbf3f21c 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -671,6 +671,13 @@ config ARCH_MMAP_RND_COMPAT_BITS
 	  This value can be changed after boot using the
 	  /proc/sys/vm/mmap_rnd_compat_bits tunable
 
+config HAVE_ARCH_COMPAT_MMAP_BASES
+	bool
+	help
+	  This allows 64bit applications to invoke 32-bit mmap() syscall
+	  and vice-versa 32-bit applications to call 64-bit mmap().
+	  Required for applications doing different bitness syscalls.
+
 config HAVE_COPY_THREAD_TLS
 	bool
 	help
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index e487493bbd47..b3acb836567a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -102,6 +102,7 @@ config X86
 	select HAVE_ARCH_KMEMCHECK
 	select HAVE_ARCH_MMAP_RND_BITS		if MMU
 	select HAVE_ARCH_MMAP_RND_COMPAT_BITS	if MMU && COMPAT
+	select HAVE_ARCH_COMPAT_MMAP_BASES	if MMU && COMPAT
 	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 8aedc2a4d48c..eb9171f172d9 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -294,6 +294,9 @@ static inline int mmap_is_ia32(void)
 		test_thread_flag(TIF_ADDR32));
 }
 
+extern unsigned long tasksize_32bit(void);
+extern unsigned long tasksize_64bit(void);
+
 #ifdef CONFIG_X86_32
 
 #define __STACK_RND_MASK(is32bit) (0x7ff)
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
index a55ed63b9f91..16b43dbe78b1 100644
--- a/arch/x86/kernel/sys_x86_64.c
+++ b/arch/x86/kernel/sys_x86_64.c
@@ -16,6 +16,8 @@
 #include <linux/uaccess.h>
 #include <linux/elf.h>
 
+#include <asm/elf.h>
+#include <asm/compat.h>
 #include <asm/ia32.h>
 #include <asm/syscalls.h>
 
@@ -97,6 +99,18 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 	return error;
 }
 
+static unsigned long get_mmap_base(int is_legacy)
+{
+	struct mm_struct *mm = current->mm;
+
+#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES
+	if (in_compat_syscall())
+		return is_legacy ? mm->mmap_compat_legacy_base
+				 : mm->mmap_compat_base;
+#endif
+	return is_legacy ? mm->mmap_legacy_base : mm->mmap_base;
+}
+
 static void find_start_end(unsigned long flags, unsigned long *begin,
 			   unsigned long *end)
 {
@@ -113,10 +127,11 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
 		if (current->flags & PF_RANDOMIZE) {
 			*begin = randomize_page(*begin, 0x02000000);
 		}
-	} else {
-		*begin = current->mm->mmap_legacy_base;
-		*end = TASK_SIZE;
+		return;
 	}
+
+	*begin	= get_mmap_base(1);
+	*end	= in_compat_syscall() ? tasksize_32bit() : tasksize_64bit();
 }
 
 unsigned long
@@ -190,7 +205,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
 	info.flags = VM_UNMAPPED_AREA_TOPDOWN;
 	info.length = len;
 	info.low_limit = PAGE_SIZE;
-	info.high_limit = mm->mmap_base;
+	info.high_limit = get_mmap_base(0);
 	info.align_mask = 0;
 	info.align_offset = pgoff << PAGE_SHIFT;
 	if (filp) {
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index 88ef0c1b0e51..688b51a09e67 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -35,11 +35,16 @@ struct va_alignment __read_mostly va_align = {
 	.flags = -1,
 };
 
-static inline unsigned long tasksize_32bit(void)
+unsigned long tasksize_32bit(void)
 {
 	return IA32_PAGE_OFFSET;
 }
 
+unsigned long tasksize_64bit(void)
+{
+	return TASK_SIZE_MAX;
+}
+
 static unsigned long stack_maxrandom_size(unsigned long task_size)
 {
 	unsigned long max = 0;
@@ -80,6 +85,8 @@ static unsigned long arch_rnd(unsigned int rndbits)
 
 unsigned long arch_mmap_rnd(void)
 {
+	if (!(current->flags & PF_RANDOMIZE))
+		return 0;
 	return arch_rnd(mmap_is_ia32() ? mmap32_rnd_bits : mmap64_rnd_bits);
 }
 
@@ -113,22 +120,30 @@ static unsigned long mmap_legacy_base(unsigned long rnd,
  * This function, called very early during the creation of a new
  * process VM image, sets up which VM layout function to use:
  */
-void arch_pick_mmap_layout(struct mm_struct *mm)
+static void arch_pick_mmap_base(unsigned long *base, unsigned long *legacy_base,
+		unsigned long random_factor, unsigned long task_size)
 {
-	unsigned long random_factor = 0UL;
-
-	if (current->flags & PF_RANDOMIZE)
-		random_factor = arch_mmap_rnd();
-
-	mm->mmap_legacy_base = mmap_legacy_base(random_factor, TASK_SIZE);
+	*legacy_base = mmap_legacy_base(random_factor, task_size);
+	if (mmap_is_legacy())
+		*base = *legacy_base;
+	else
+		*base = mmap_base(random_factor, task_size);
+}
 
-	if (mmap_is_legacy()) {
-		mm->mmap_base = mm->mmap_legacy_base;
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+	if (mmap_is_legacy())
 		mm->get_unmapped_area = arch_get_unmapped_area;
-	} else {
-		mm->mmap_base = mmap_base(random_factor, TASK_SIZE);
+	else
 		mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-	}
+
+	arch_pick_mmap_base(&mm->mmap_base, &mm->mmap_legacy_base,
+			arch_rnd(mmap64_rnd_bits), tasksize_64bit());
+
+#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES
+	arch_pick_mmap_base(&mm->mmap_compat_base, &mm->mmap_compat_legacy_base,
+			arch_rnd(mmap32_rnd_bits), tasksize_32bit());
+#endif
 }
 
 const char *arch_vma_name(struct vm_area_struct *vma)
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 808751d7b737..48274a84cebe 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -404,6 +404,11 @@ struct mm_struct {
 #endif
 	unsigned long mmap_base;		/* base of mmap area */
 	unsigned long mmap_legacy_base;         /* base of mmap area in bottom-up allocations */
+#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES
+	/* Base adresses for compatible mmap() */
+	unsigned long mmap_compat_base;
+	unsigned long mmap_compat_legacy_base;
+#endif
 	unsigned long task_size;		/* size of task vm space */
 	unsigned long highest_vm_end;		/* highest vma end address */
 	pgd_t * pgd;
-- 
2.11.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCHv5 4/5] x86/mm: check in_compat_syscall() instead TIF_ADDR32 for mmap(MAP_32BIT)
  2017-02-14 18:36 [PATCHv5 0/5] Fix compatible mmap() return pointer over 4Gb Dmitry Safonov
                   ` (2 preceding siblings ...)
  2017-02-14 18:36 ` [PATCHv5 3/5] x86/mm: introduce mmap_compat_base for 32-bit mmap() Dmitry Safonov
@ 2017-02-14 18:36 ` Dmitry Safonov
  2017-02-14 18:36 ` [PATCHv5 5/5] selftests/x86: add test for 32-bit mmap() return addr Dmitry Safonov
  4 siblings, 0 replies; 8+ messages in thread
From: Dmitry Safonov @ 2017-02-14 18:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: 0x7f454c46, Dmitry Safonov, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Andy Lutomirski, Borislav Petkov, x86, linux-mm,
	Cyrill Gorcunov

Result of mmap() calls with MAP_32BIT flag at this moment depends
on thread flag TIF_ADDR32, which is set during exec() for 32-bit apps.
It's broken as the behavior of mmap() shouldn't depend on exec-ed
application's bitness. Instead, it should check the bitness of mmap()
syscall.
How it worked before:
o for 32-bit compatible binaries it is completely ignored. Which was
fine when there were one mmap_base, computed for 32-bit syscalls.
After introducing mmap_compat_base 64-bit syscalls do use computed
for 64-bit syscalls mmap_base, which means that we can allocate 64-bit
address with 64-bit syscall in application launched from 32-bit
compatible binary. And ignoring this flag is not expected behavior.
o for 64-bit ELFs it forces legacy bottom-up allocations and 1Gb address
space restriction for allocations: [0x40000000, 0x80000000) - look at
find_start_end(). Which means that it was wrongly handled for 32-bit
syscalls - they don't need nor this restriction nor legacy mmap
(as we try to keep 32-bit syscalls behavior the same independently of
native/compat mode of ELF being executed).

Changed mmap() behavior for MAP_32BIT flag the way that for 32-bit
syscalls it will be always ignored and for 64-bit syscalls it'll
always return 32-bit pointer restricted with 1Gb adress space,
independently of the binary's bitness of executed application.

Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
---
 arch/x86/kernel/sys_x86_64.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
index 16b43dbe78b1..cc8eaba10104 100644
--- a/arch/x86/kernel/sys_x86_64.c
+++ b/arch/x86/kernel/sys_x86_64.c
@@ -114,7 +114,7 @@ static unsigned long get_mmap_base(int is_legacy)
 static void find_start_end(unsigned long flags, unsigned long *begin,
 			   unsigned long *end)
 {
-	if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) {
+	if (!in_compat_syscall() && (flags & MAP_32BIT)) {
 		/* This is usually used needed to map code in small
 		   model, so it needs to be in the first 31bit. Limit
 		   it to that.  This means we need to move the
@@ -190,7 +190,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
 		return addr;
 
 	/* for MAP_32BIT mappings we force the legacy mmap base */
-	if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT))
+	if (!in_compat_syscall() && (flags & MAP_32BIT))
 		goto bottomup;
 
 	/* requesting a specific address */
-- 
2.11.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCHv5 5/5] selftests/x86: add test for 32-bit mmap() return addr
  2017-02-14 18:36 [PATCHv5 0/5] Fix compatible mmap() return pointer over 4Gb Dmitry Safonov
                   ` (3 preceding siblings ...)
  2017-02-14 18:36 ` [PATCHv5 4/5] x86/mm: check in_compat_syscall() instead TIF_ADDR32 for mmap(MAP_32BIT) Dmitry Safonov
@ 2017-02-14 18:36 ` Dmitry Safonov
  4 siblings, 0 replies; 8+ messages in thread
From: Dmitry Safonov @ 2017-02-14 18:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: 0x7f454c46, Dmitry Safonov, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Andy Lutomirski, Borislav Petkov, x86, linux-mm,
	Cyrill Gorcunov, Shuah Khan, linux-kselftest

This test calls 32-bit mmap() through int 0x80 and checks /proc/self/maps
for allocated VMA's address - it should be downer than 4 Gb. Just
accessing allocated with mmap pointer will not work, as we could have
some VMA placed on the same address as lower 4 bytes of the new mapping.
As allocation is top-down by default (unless legacy personality was set),
we can expect that mmap() will allocate memory over 4Gb if mmap_base
has been computed not correctly.

On failure it prints:
[NOTE]	Allocated mmap 0x6f36a000, sized 0x400000
[NOTE]	New mapping appeared: 0x7f936f36a000
[FAIL]	Found VMA [0x7f936f36a000, 0x7f936f76a000] in maps file, that was allocated with compat syscall

Cc: Shuah Khan <shuah@kernel.org>
Cc: linux-kselftest@vger.kernel.org
Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
---
 tools/testing/selftests/x86/Makefile           |   2 +-
 tools/testing/selftests/x86/test_compat_mmap.c | 208 +++++++++++++++++++++++++
 2 files changed, 209 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/x86/test_compat_mmap.c

diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index 8c1cb423cfe6..9c3e746a6064 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -10,7 +10,7 @@ TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_sysc
 TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
 			test_FCMOV test_FCOMI test_FISTTP \
 			vdso_restorer
-TARGETS_C_64BIT_ONLY := fsgsbase
+TARGETS_C_64BIT_ONLY := fsgsbase test_compat_mmap
 
 TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
 TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY)
diff --git a/tools/testing/selftests/x86/test_compat_mmap.c b/tools/testing/selftests/x86/test_compat_mmap.c
new file mode 100644
index 000000000000..245d9407653e
--- /dev/null
+++ b/tools/testing/selftests/x86/test_compat_mmap.c
@@ -0,0 +1,208 @@
+/*
+ * Check that compat 32-bit mmap() returns address < 4Gb on 64-bit.
+ *
+ * Copyright (c) 2017 Dmitry Safonov (Virtuozzo)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <signal.h>
+#include <stdlib.h>
+
+#define PAGE_SIZE 4096
+#define MMAP_SIZE (PAGE_SIZE*1024)
+#define MAX_VMAS 50
+#define BUF_SIZE 1024
+
+#ifndef __NR32_mmap2
+#define __NR32_mmap2 192
+#endif
+
+struct syscall_args32 {
+	uint32_t nr, arg0, arg1, arg2, arg3, arg4, arg5;
+};
+
+static void do_full_int80(struct syscall_args32 *args)
+{
+	asm volatile ("int $0x80"
+		      : "+a" (args->nr),
+			"+b" (args->arg0), "+c" (args->arg1), "+d" (args->arg2),
+			"+S" (args->arg3), "+D" (args->arg4),
+			"+rbp" (args->arg5)
+			: : "r8", "r9", "r10", "r11");
+}
+
+void *mmap2(void *addr, size_t len, int prot, int flags,
+	int fildes, off_t off)
+{
+	struct syscall_args32 s;
+
+	s.nr	= __NR32_mmap2;
+	s.arg0	= (uint32_t)(uintptr_t)addr;
+	s.arg1	= (uint32_t)len;
+	s.arg2	= prot;
+	s.arg3	= flags;
+	s.arg4	= fildes;
+	s.arg5	= (uint32_t)off;
+
+	do_full_int80(&s);
+
+	return (void *)(uintptr_t)s.nr;
+}
+
+struct vm_area {
+	unsigned long start;
+	unsigned long end;
+};
+
+static struct vm_area vmas_before_mmap[MAX_VMAS];
+static struct vm_area vmas_after_mmap[MAX_VMAS];
+
+static char buf[BUF_SIZE];
+
+int parse_maps(struct vm_area *vmas)
+{
+	FILE *maps;
+	int i;
+
+	maps = fopen("/proc/self/maps", "r");
+	if (maps == NULL) {
+		printf("[ERROR]\tFailed to open maps file: %m\n");
+		return -1;
+	}
+
+	for (i = 0; i < MAX_VMAS; i++) {
+		struct vm_area *v = &vmas[i];
+		char *end;
+
+		if (fgets(buf, BUF_SIZE, maps) == NULL)
+			break;
+
+		v->start = strtoul(buf, &end, 16);
+		v->end = strtoul(end + 1, NULL, 16);
+		//printf("[NOTE]\tVMA: [%#lx, %#lx]\n", v->start, v->end);
+	}
+
+	if (i == MAX_VMAS) {
+		printf("[ERROR]\tNumber of VMAs is bigger than reserved array's size\n");
+		return -1;
+	}
+
+	if (fclose(maps)) {
+		printf("[ERROR]\tFailed to close maps file: %m\n");
+		return -1;
+	}
+	return 0;
+}
+
+int compare_vmas(struct vm_area *vmax, struct vm_area *vmay)
+{
+	if (vmax->start > vmay->start)
+		return 1;
+	if (vmax->start < vmay->start)
+		return -1;
+	if (vmax->end > vmay->end)
+		return 1;
+	if (vmax->end < vmay->end)
+		return -1;
+	return 0;
+}
+
+unsigned long vma_size(struct vm_area *v)
+{
+	return v->end - v->start;
+}
+
+int find_new_vma_like(struct vm_area *vma)
+{
+	int i, j = 0, found_alike = -1;
+
+	for (i = 0; i < MAX_VMAS && j < MAX_VMAS; i++, j++) {
+		int cmp = compare_vmas(&vmas_before_mmap[i],
+				&vmas_after_mmap[j]);
+
+		if (cmp == 0)
+			continue;
+		if (cmp < 0) {/* Lost mapping */
+			printf("[NOTE]\tLost mapping: %#lx\n",
+				vmas_before_mmap[i].start);
+			j--;
+			continue;
+		}
+
+		printf("[NOTE]\tNew mapping appeared: %#lx\n",
+				vmas_after_mmap[j].start);
+		i--;
+		if (!compare_vmas(&vmas_after_mmap[j], vma))
+			return 0;
+
+		if (((vmas_after_mmap[j].start & 0xffffffff) == vma->start) &&
+				(vma_size(&vmas_after_mmap[j]) == vma_size(vma)))
+			found_alike = j;
+	}
+
+	/* Left new vmas in tail */
+	for (; i < MAX_VMAS; i++)
+		if (!compare_vmas(&vmas_after_mmap[j], vma))
+			return 0;
+
+	if (found_alike != -1) {
+		printf("[FAIL]\tFound VMA [%#lx, %#lx] in maps file, that was allocated with compat syscall\n",
+			vmas_after_mmap[found_alike].start,
+			vmas_after_mmap[found_alike].end);
+		return -1;
+	}
+
+	printf("[ERROR]\tCan't find [%#lx, %#lx] in maps file\n",
+		vma->start, vma->end);
+	return -1;
+}
+
+int main(int argc, char **argv)
+{
+	void *map;
+	struct vm_area vma;
+
+	if (parse_maps(vmas_before_mmap)) {
+		printf("[ERROR]\tFailed to parse maps file\n");
+		return 1;
+	}
+
+	map = mmap2(0, MMAP_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_PRIVATE | MAP_ANON, -1, 0);
+	if (((uintptr_t)map) % PAGE_SIZE) {
+		printf("[ERROR]\tmmap2 failed: %d\n",
+				(~(uint32_t)(uintptr_t)map) + 1);
+		return 1;
+	} else {
+		printf("[NOTE]\tAllocated mmap %p, sized %#x\n", map, MMAP_SIZE);
+	}
+
+	if (parse_maps(vmas_after_mmap)) {
+		printf("[ERROR]\tFailed to parse maps file\n");
+		return 1;
+	}
+
+	munmap(map, MMAP_SIZE);
+
+	vma.start = (unsigned long)(uintptr_t)map;
+	vma.end = vma.start + MMAP_SIZE;
+	if (find_new_vma_like(&vma))
+		return 1;
+
+	printf("[OK]\n");
+
+	return 0;
+}
-- 
2.11.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCHv5 1/5] x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd
  2017-02-14 18:36 ` [PATCHv5 1/5] x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd Dmitry Safonov
@ 2017-02-14 22:22   ` kbuild test robot
  2017-02-15  9:34     ` Dmitry Safonov
  0 siblings, 1 reply; 8+ messages in thread
From: kbuild test robot @ 2017-02-14 22:22 UTC (permalink / raw)
  To: Dmitry Safonov
  Cc: kbuild-all, linux-kernel, 0x7f454c46, Dmitry Safonov,
	Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Andy Lutomirski,
	Borislav Petkov, x86, linux-mm, Cyrill Gorcunov

[-- Attachment #1: Type: text/plain, Size: 2857 bytes --]

Hi Dmitry,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.10-rc8 next-20170214]
[cannot apply to tip/x86/core]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Dmitry-Safonov/Fix-compatible-mmap-return-pointer-over-4Gb/20170215-025132
config: x86_64-randconfig-x014-201707 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All error/warnings (new ones prefixed by >>):

   arch/x86/mm/mmap.c: In function 'arch_mmap_rnd':
>> arch/x86/mm/mmap.c:58:27: error: 'mmap_rnd_compat_bits' undeclared (first use in this function)
    # define mmap32_rnd_bits  mmap_rnd_compat_bits
                              ^
>> arch/x86/mm/mmap.c:83:35: note: in expansion of macro 'mmap32_rnd_bits'
     return arch_rnd(mmap_is_ia32() ? mmap32_rnd_bits : mmap64_rnd_bits);
                                      ^~~~~~~~~~~~~~~
   arch/x86/mm/mmap.c:58:27: note: each undeclared identifier is reported only once for each function it appears in
    # define mmap32_rnd_bits  mmap_rnd_compat_bits
                              ^
>> arch/x86/mm/mmap.c:83:35: note: in expansion of macro 'mmap32_rnd_bits'
     return arch_rnd(mmap_is_ia32() ? mmap32_rnd_bits : mmap64_rnd_bits);
                                      ^~~~~~~~~~~~~~~
>> arch/x86/mm/mmap.c:84:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^

vim +/mmap_rnd_compat_bits +58 arch/x86/mm/mmap.c

    52	 * Leave an at least ~128 MB hole with possible stack randomization.
    53	 */
    54	#define MIN_GAP (128*1024*1024UL + stack_maxrandom_size())
    55	#define MAX_GAP (TASK_SIZE/6*5)
    56	
    57	#ifdef CONFIG_64BIT
  > 58	# define mmap32_rnd_bits  mmap_rnd_compat_bits
    59	# define mmap64_rnd_bits  mmap_rnd_bits
    60	#else
    61	# define mmap32_rnd_bits  mmap_rnd_bits
    62	# define mmap64_rnd_bits  mmap_rnd_bits
    63	#endif
    64	
    65	static int mmap_is_legacy(void)
    66	{
    67		if (current->personality & ADDR_COMPAT_LAYOUT)
    68			return 1;
    69	
    70		if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
    71			return 1;
    72	
    73		return sysctl_legacy_va_layout;
    74	}
    75	
    76	static unsigned long arch_rnd(unsigned int rndbits)
    77	{
    78		return (get_random_long() & ((1UL << rndbits) - 1)) << PAGE_SHIFT;
    79	}
    80	
    81	unsigned long arch_mmap_rnd(void)
    82	{
  > 83		return arch_rnd(mmap_is_ia32() ? mmap32_rnd_bits : mmap64_rnd_bits);
  > 84	}
    85	
    86	static unsigned long mmap_base(unsigned long rnd)
    87	{

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 25588 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCHv5 1/5] x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd
  2017-02-14 22:22   ` kbuild test robot
@ 2017-02-15  9:34     ` Dmitry Safonov
  0 siblings, 0 replies; 8+ messages in thread
From: Dmitry Safonov @ 2017-02-15  9:34 UTC (permalink / raw)
  To: kbuild test robot
  Cc: kbuild-all, linux-kernel, 0x7f454c46, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin, Andy Lutomirski, Borislav Petkov,
	x86, linux-mm, Cyrill Gorcunov

On 02/15/2017 01:22 AM, kbuild test robot wrote:
> Hi Dmitry,
...
> vim +/mmap_rnd_compat_bits +58 arch/x86/mm/mmap.c
>
>     52	 * Leave an at least ~128 MB hole with possible stack randomization.
>     53	 */
>     54	#define MIN_GAP (128*1024*1024UL + stack_maxrandom_size())
>     55	#define MAX_GAP (TASK_SIZE/6*5)
>     56	
>     57	#ifdef CONFIG_64BIT
>   > 58	# define mmap32_rnd_bits  mmap_rnd_compat_bits
>     59	# define mmap64_rnd_bits  mmap_rnd_bits
>     60	#else
>     61	# define mmap32_rnd_bits  mmap_rnd_bits
>     62	# define mmap64_rnd_bits  mmap_rnd_bits
>     63	#endif

Yep, thanks - it's better be ifdef CONFIG_COMPAT.
Will resend today with this trivial fixup.

-- 
              Dmitry

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-02-15  9:39 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-14 18:36 [PATCHv5 0/5] Fix compatible mmap() return pointer over 4Gb Dmitry Safonov
2017-02-14 18:36 ` [PATCHv5 1/5] x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd Dmitry Safonov
2017-02-14 22:22   ` kbuild test robot
2017-02-15  9:34     ` Dmitry Safonov
2017-02-14 18:36 ` [PATCHv5 2/5] x86/mm: add task_size parameter to mmap_base() Dmitry Safonov
2017-02-14 18:36 ` [PATCHv5 3/5] x86/mm: introduce mmap_compat_base for 32-bit mmap() Dmitry Safonov
2017-02-14 18:36 ` [PATCHv5 4/5] x86/mm: check in_compat_syscall() instead TIF_ADDR32 for mmap(MAP_32BIT) Dmitry Safonov
2017-02-14 18:36 ` [PATCHv5 5/5] selftests/x86: add test for 32-bit mmap() return addr Dmitry Safonov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).