Skip to contentSkip to conversation

Fix compatible mmap() return pointer over 4Gb

PATCH Superseded Dmitry Safonov 2 participants 8 messages Feb 14, 2017 – Feb 15, 2017

Subsystems (6)

v5 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v5 cover Fix compatible mmap() return pointer over 4Gb

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 <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Cyrill Gorcunov <[email protected]>

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
Signature · 7 lines
2.11.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#1 lore raw

PATCH v5 1/5 x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd

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().

---
 arch/x86/mm/mmap.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)
arch/x86/mm/mmap.c +14 -12
index d2dc0438d654..9f3ac019e51c 100644
@@ -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)
Signature · 7 lines
2.11.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#2 lore raw

Re: [PATCHv5 1/5] x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd

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…

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

#3 lore raw

Re: [PATCHv5 1/5] x86/mm: introduce arch_rnd() to compute 32/64 mmap rnd

Quoted 1 line · kbuild test robot

Hi Dmitry,

...

Quoted 8 lines

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
Quoted 6 lines
Quoted 1 line

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.

Signature · 7 lines
             Dmitry

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#4 lore raw

PATCH v5 2/5 x86/mm: add task_size parameter to mmap_base()

In reply to Dmitry Safonov

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.

---
 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(-)
arch/x86/include/asm/elf.h +13 -11
index e7f155c3045e..8aedc2a4d48c 100644
@@ -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),
arch/x86/include/asm/processor.h +3 -1
index e6cfe7ba2d65..491f5a05a133 100644
@@ -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)
 
arch/x86/mm/mmap.c +32 -18

92 lines not on this page · raw message

Signature · 7 lines
2.11.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#5 lore raw

PATCH v5 3/5 x86/mm: introduce mmap_compat_base for 32-bit mmap()

In reply to Dmitry Safonov

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.

---
 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(-)
arch/Kconfig +7 -0
index 99839c23d453..cfb2fbf3f21c 100644
@@ -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
arch/x86/Kconfig +1 -0
index e487493bbd47..b3acb836567a 100644
@@ -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
arch/x86/include/asm/elf.h +3 -0
index 8aedc2a4d48c..eb9171f172d9 100644
@@ -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)
arch/x86/kernel/sys_x86_64.c +19 -4
index a55ed63b9f91..16b43dbe78b1 100644
@@ -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) {
arch/x86/mm/mmap.c +28 -13

67 lines not on this page · raw message

include/linux/mm_types.h +5 -0
index 808751d7b737..48274a84cebe 100644
@@ -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;
Signature · 7 lines
2.11.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#6 lore raw

PATCH v5 4/5 x86/mm: check in_compat_syscall() instead TIF_ADDR32 for mmap(MAP_32BIT)

In reply to Dmitry Safonov

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.

---
 arch/x86/kernel/sys_x86_64.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/sys_x86_64.c +2 -2
index 16b43dbe78b1..cc8eaba10104 100644
@@ -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 */
Signature · 7 lines
2.11.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#7 lore raw

PATCH v5 5/5 selftests/x86: add test for 32-bit mmap() return addr

In reply to Dmitry Safonov

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

---
 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
tools/testing/selftests/x86/Makefile +1 -1
index 8c1cb423cfe6..9c3e746a6064 100644
@@ -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)
tools/testing/selftests/x86/test_compat_mmap.c new file +208 -0

208 lines not on this page · raw message

Signature · 7 lines
2.11.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>