Skip to contentSkip to conversation

Fix compatible mmap() return pointer over 4Gb

PATCH Superseded Dmitry Safonov 3 participants 8 messages Jan 11, 2017 – Jan 12, 2017

Subsystems (2)

v1 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

cover Fix compatible mmap() return pointer over 4Gb

A fix for bug in mmap() that I referenced in [1].
Also selftest for it.

I would like to mark the fix as for stable v4.9 kernel if it'll be accepted, as I try to support compatible 32-bit C/R after v4.9 and working compatible mmap() is really wanted there.

[1]: https://marc.info/?l=linux-kernel&m=148311451525315

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]>

Dmitry Safonov (2):
x86/mm: don't mmap() over 4GB with compat syscall selftests/x86: add test to check compat mmap() return addr

 arch/x86/kernel/sys_x86_64.c                   |  37 ++++-
 tools/testing/selftests/x86/Makefile           |   2 +-
 tools/testing/selftests/x86/test_compat_mmap.c | 200 +++++++++++++++++++++++++
 3 files changed, 230 insertions(+), 9 deletions(-)
 create mode 100644 tools/testing/selftests/x86/test_compat_mmap.c
Signature · 1 line
2.11.0
#1 lore raw

PATCH 1/2 x86/mm: don't mmap() over 4GB with compat syscall

During fixing CRIU bugs on ZDTM tests for 32-bit C/R, I found that compatible ia32/x32 syscalls mmap() and mmap2() can return address over 4Gb in x86_64 applications, which results in returning lower 4 bytes of address while dropping the higher bytes.
It happens because mmap() upper limit doesn't differ native/compat syscalls for 64-bit task, it's: (TASK_UNMAPPED_BASE + random_factor) which is: (PAGE_ALIGN(TASK_SIZE / 3)) + random_factor
(in case of legacy mmap it's just TASK_SIZE).
This patch limits higher address that can be mmaped with compat syscalls in 64-bit applications with IA32_PAGE_OFFSET (+randomization).

---
 arch/x86/kernel/sys_x86_64.c | 37 +++++++++++++++++++++++++++++--------
 1 file changed, 29 insertions(+), 8 deletions(-)
arch/x86/kernel/sys_x86_64.c +29 -8
index a55ed63b9f91..0893725db6e6 100644
@@ -100,7 +100,7 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 static void find_start_end(unsigned long flags, unsigned long *begin,
 			   unsigned long *end)
 {
-	if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) {
+	if (!test_thread_flag(TIF_ADDR32)) {
 		/* 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
@@ -109,14 +109,24 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
 		   malloc knows how to fall back to mmap. Give it 1GB
 		   of playground for now. -AK */
 		*begin = 0x40000000;
-		*end = 0x80000000;
-		if (current->flags & PF_RANDOMIZE) {
-			*begin = randomize_page(*begin, 0x02000000);
+
+		if (flags & MAP_32BIT) {
+			if (current->flags & PF_RANDOMIZE)
+				*begin = randomize_page(*begin, 0x02000000);
+			*end = 0x80000000;
+			return;
+		}
+		if (current->thread.status & TS_COMPAT) {
+			if (current->flags & PF_RANDOMIZE)
+				*begin = randomize_page(*begin,
+					1UL << mmap_rnd_compat_bits);
+			*end = IA32_PAGE_OFFSET;
+			return;
 		}
-	} else {
-		*begin = current->mm->mmap_legacy_base;
-		*end = TASK_SIZE;
 	}
+
+	*begin = current->mm->mmap_legacy_base;
+	*end = TASK_SIZE;
 }
 
 unsigned long
@@ -187,10 +197,21 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
 			return addr;
 	}
 
+	if (current->thread.status & TS_COMPAT) {
+		if (current->flags & PF_RANDOMIZE) {
+			unsigned long rnd = 1UL << mmap_rnd_compat_bits;
+
+			info.high_limit =
+				randomize_page(IA32_PAGE_OFFSET - rnd, rnd);
+		} else {
+			info.high_limit = IA32_PAGE_OFFSET;
+		}
+	} else {
+		info.high_limit = mm->mmap_base;
+	}
 	info.flags = VM_UNMAPPED_AREA_TOPDOWN;
 	info.length = len;
 	info.low_limit = PAGE_SIZE;
-	info.high_limit = mm->mmap_base;
 	info.align_mask = 0;
 	info.align_offset = pgoff << PAGE_SHIFT;
 	if (filp) {
Signature · 1 line
2.11.0
#2 lore raw

Re: [PATCH 1/2] x86/mm: don't mmap() over 4GB with compat syscall

Quoted 61 lines · Dmitry Safonov

During fixing CRIU bugs on ZDTM tests for 32-bit C/R, I found that compatible ia32/x32 syscalls mmap() and mmap2() can return address over 4Gb in x86_64 applications, which results in returning lower 4 bytes of address while dropping the higher bytes.
It happens because mmap() upper limit doesn't differ native/compat syscalls for 64-bit task, it's: (TASK_UNMAPPED_BASE + random_factor) which is: (PAGE_ALIGN(TASK_SIZE / 3)) + random_factor
(in case of legacy mmap it's just TASK_SIZE).
This patch limits higher address that can be mmaped with compat syscalls in 64-bit applications with IA32_PAGE_OFFSET (+randomization).

---
 arch/x86/kernel/sys_x86_64.c | 37 +++++++++++++++++++++++++++++--------
 1 file changed, 29 insertions(+), 8 deletions(-)
arch/x86/kernel/sys_x86_64.c +17 -7
index a55ed63b9f91..0893725db6e6 100644
@@ -100,7 +100,7 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 static void find_start_end(unsigned long flags, unsigned long *begin,
                           unsigned long *end)
 {
-       if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) {
+       if (!test_thread_flag(TIF_ADDR32)) {
                /* 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
@@ -109,14 +109,24 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
                   malloc knows how to fall back to mmap. Give it 1GB
                   of playground for now. -AK */
                *begin = 0x40000000;
-               *end = 0x80000000;
-               if (current->flags & PF_RANDOMIZE) {
-                       *begin = randomize_page(*begin, 0x02000000);
+
+               if (flags & MAP_32BIT) {
+                       if (current->flags & PF_RANDOMIZE)
+                               *begin = randomize_page(*begin, 0x02000000);
+                       *end = 0x80000000;
+                       return;
+               }
+               if (current->thread.status & TS_COMPAT) {
+                       if (current->flags & PF_RANDOMIZE)
+                               *begin = randomize_page(*begin,
+                                       1UL << mmap_rnd_compat_bits);
+                       *end = IA32_PAGE_OFFSET;
+                       return;
                }
-       } else {
-               *begin = current->mm->mmap_legacy_base;
-               *end = TASK_SIZE;
        }
+
+       *begin = current->mm->mmap_legacy_base;
+       *end = TASK_SIZE;
 }
 
 unsigned long

arch/x86/kernel/sys_x86_64.c arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, · line 200

Quoted 4 lines
arch/x86/kernel/sys_x86_64.c +1 -0
@@ -187,10 +197,21 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
                        return addr;
        }
 
+       if (current->thread.status & TS_COMPAT) {

in_compat_syscall(), please.

Also, we need to verify that, if this is called execve(), it does the right thing.

arch/x86/kernel/sys_x86_64.c arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, · line 211

Quoted 11 lines
arch/x86/kernel/sys_x86_64.c +11 -0
+               if (current->flags & PF_RANDOMIZE) {
+                       unsigned long rnd = 1UL << mmap_rnd_compat_bits;
+
+                       info.high_limit =
+                               randomize_page(IA32_PAGE_OFFSET - rnd, rnd);
+               } else {
+                       info.high_limit = IA32_PAGE_OFFSET;
+               }
+       } else {
+               info.high_limit = mm->mmap_base;
+       }

This code was incomprehensible before and it's worse now. Could you try to clean it up a bit? For example, a patch that simply folds find_start_end() into its sole caller as the first patch in the series without changing any semantics would probably help.

--Andy

#3 lore raw

Re: [PATCH 1/2] x86/mm: don't mmap() over 4GB with compat syscall

Quoted 60 lines · Andy Lutomirski
Quoted 59 lines · Dmitry Safonov

During fixing CRIU bugs on ZDTM tests for 32-bit C/R, I found that compatible ia32/x32 syscalls mmap() and mmap2() can return address over 4Gb in x86_64 applications, which results in returning lower 4 bytes of address while dropping the higher bytes.
It happens because mmap() upper limit doesn't differ native/compat syscalls for 64-bit task, it's: (TASK_UNMAPPED_BASE + random_factor) which is: (PAGE_ALIGN(TASK_SIZE / 3)) + random_factor
(in case of legacy mmap it's just TASK_SIZE).
This patch limits higher address that can be mmaped with compat syscalls in 64-bit applications with IA32_PAGE_OFFSET (+randomization).

---
 arch/x86/kernel/sys_x86_64.c | 37 +++++++++++++++++++++++++++++--------
 1 file changed, 29 insertions(+), 8 deletions(-)
arch/x86/kernel/sys_x86_64.c +17 -7
index a55ed63b9f91..0893725db6e6 100644
@@ -100,7 +100,7 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 static void find_start_end(unsigned long flags, unsigned long *begin,
                           unsigned long *end)
 {
-       if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) {
+       if (!test_thread_flag(TIF_ADDR32)) {
                /* 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
@@ -109,14 +109,24 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
                   malloc knows how to fall back to mmap. Give it 1GB
                   of playground for now. -AK */
                *begin = 0x40000000;
-               *end = 0x80000000;
-               if (current->flags & PF_RANDOMIZE) {
-                       *begin = randomize_page(*begin, 0x02000000);
+
+               if (flags & MAP_32BIT) {
+                       if (current->flags & PF_RANDOMIZE)
+                               *begin = randomize_page(*begin, 0x02000000);
+                       *end = 0x80000000;
+                       return;
+               }
+               if (current->thread.status & TS_COMPAT) {
+                       if (current->flags & PF_RANDOMIZE)
+                               *begin = randomize_page(*begin,
+                                       1UL << mmap_rnd_compat_bits);
+                       *end = IA32_PAGE_OFFSET;
+                       return;
                }
-       } else {
-               *begin = current->mm->mmap_legacy_base;
-               *end = TASK_SIZE;
        }
+
+       *begin = current->mm->mmap_legacy_base;
+       *end = TASK_SIZE;
 }
 
Quoted 8 lines

arch/x86/kernel/sys_x86_64.c arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, · line 200

Quoted 6 lines
arch/x86/kernel/sys_x86_64.c +1 -0
 unsigned long
@@ -187,10 +197,21 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
                        return addr;
        }
 
+       if (current->thread.status & TS_COMPAT) {

in_compat_syscall(), please.

Indeed, forgot about the helper.

Quoted 3 lines

Also, we need to verify that, if this is called execve(), it does the right thing.

Hmm, not sure I get it right.
A test for calling compat sys_execve() from and for 64-bit ELF?

Quoted 12 lines

arch/x86/kernel/sys_x86_64.c arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, · line 211

Quoted 11 lines
arch/x86/kernel/sys_x86_64.c +11 -0
+               if (current->flags & PF_RANDOMIZE) {
+                       unsigned long rnd = 1UL << mmap_rnd_compat_bits;
+
+                       info.high_limit =
+                               randomize_page(IA32_PAGE_OFFSET - rnd, rnd);
+               } else {
+                       info.high_limit = IA32_PAGE_OFFSET;
+               }
+       } else {
+               info.high_limit = mm->mmap_base;
+       }
Quoted 4 lines

This code was incomprehensible before and it's worse now. Could you try to clean it up a bit? For example, a patch that simply folds find_start_end() into its sole caller as the first patch in the series without changing any semantics would probably help.

Well, yep, I also don't like how this code looks like. That will need to add a parameter to find_start_end() whether allocation is bottom-up or up-bottom.
I'll try to cleanup for v2.

Quoted 3 lines

--Andy

Signature · 1 line
             Dmitry
#4 lore raw

Re: [PATCH 1/2] x86/mm: don't mmap() over 4GB with compat syscall

In reply to Andy Lutomirski
Quoted 65 lines · Andy Lutomirski
Quoted 64 lines · Dmitry Safonov

During fixing CRIU bugs on ZDTM tests for 32-bit C/R, I found that compatible ia32/x32 syscalls mmap() and mmap2() can return address over 4Gb in x86_64 applications, which results in returning lower 4 bytes of address while dropping the higher bytes.
It happens because mmap() upper limit doesn't differ native/compat syscalls for 64-bit task, it's: (TASK_UNMAPPED_BASE + random_factor) which is: (PAGE_ALIGN(TASK_SIZE / 3)) + random_factor
(in case of legacy mmap it's just TASK_SIZE).
This patch limits higher address that can be mmaped with compat syscalls in 64-bit applications with IA32_PAGE_OFFSET (+randomization).

---
 arch/x86/kernel/sys_x86_64.c | 37 +++++++++++++++++++++++++++++--------
 1 file changed, 29 insertions(+), 8 deletions(-)
arch/x86/kernel/sys_x86_64.c +17 -7
index a55ed63b9f91..0893725db6e6 100644
@@ -100,7 +100,7 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 static void find_start_end(unsigned long flags, unsigned long *begin,
                           unsigned long *end)
 {
-       if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) {
+       if (!test_thread_flag(TIF_ADDR32)) {
                /* 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
@@ -109,14 +109,24 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
                   malloc knows how to fall back to mmap. Give it 1GB
                   of playground for now. -AK */
                *begin = 0x40000000;
-               *end = 0x80000000;
-               if (current->flags & PF_RANDOMIZE) {
-                       *begin = randomize_page(*begin, 0x02000000);
+
+               if (flags & MAP_32BIT) {
+                       if (current->flags & PF_RANDOMIZE)
+                               *begin = randomize_page(*begin, 0x02000000);
+                       *end = 0x80000000;
+                       return;
+               }
+               if (current->thread.status & TS_COMPAT) {
+                       if (current->flags & PF_RANDOMIZE)
+                               *begin = randomize_page(*begin,
+                                       1UL << mmap_rnd_compat_bits);
+                       *end = IA32_PAGE_OFFSET;
+                       return;
                }
-       } else {
-               *begin = current->mm->mmap_legacy_base;
-               *end = TASK_SIZE;
        }
+
+       *begin = current->mm->mmap_legacy_base;
+       *end = TASK_SIZE;
 }
 
 unsigned long
@@ -187,10 +197,21 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
                        return addr;
        }
 
Quoted 6 lines

arch/x86/kernel/sys_x86_64.c arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, · line 200

Quoted 1 line
arch/x86/kernel/sys_x86_64.c +1 -0
+       if (current->thread.status & TS_COMPAT) {

in_compat_syscall(), please.

Also, we need to verify that, if this is called execve(), it does the right thing.

It definitely does not right things at this moment. Will fix to v2.

Quoted 20 lines

arch/x86/kernel/sys_x86_64.c arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, · line 211

Quoted 12 lines
arch/x86/kernel/sys_x86_64.c +11 -0
+               if (current->flags & PF_RANDOMIZE) {
+                       unsigned long rnd = 1UL << mmap_rnd_compat_bits;
+
+                       info.high_limit =
+                               randomize_page(IA32_PAGE_OFFSET - rnd, rnd);
+               } else {
+                       info.high_limit = IA32_PAGE_OFFSET;
+               }
+       } else {
+               info.high_limit = mm->mmap_base;
+       }

This code was incomprehensible before and it's worse now. Could you try to clean it up a bit? For example, a patch that simply folds find_start_end() into its sole caller as the first patch in the series without changing any semantics would probably help.

--Andy

Signature · 1 line
             Dmitry
#5 lore raw

Re: [PATCH 1/2] x86/mm: don't mmap() over 4GB with compat syscall

In reply to Andy Lutomirski
Quoted 84 lines · Andy Lutomirski
Quoted 61 lines · Dmitry Safonov

During fixing CRIU bugs on ZDTM tests for 32-bit C/R, I found that compatible ia32/x32 syscalls mmap() and mmap2() can return address over 4Gb in x86_64 applications, which results in returning lower 4 bytes of address while dropping the higher bytes.
It happens because mmap() upper limit doesn't differ native/compat syscalls for 64-bit task, it's: (TASK_UNMAPPED_BASE + random_factor) which is: (PAGE_ALIGN(TASK_SIZE / 3)) + random_factor
(in case of legacy mmap it's just TASK_SIZE).
This patch limits higher address that can be mmaped with compat syscalls in 64-bit applications with IA32_PAGE_OFFSET (+randomization).

---
 arch/x86/kernel/sys_x86_64.c | 37 +++++++++++++++++++++++++++++--------
 1 file changed, 29 insertions(+), 8 deletions(-)
arch/x86/kernel/sys_x86_64.c +17 -7
index a55ed63b9f91..0893725db6e6 100644
@@ -100,7 +100,7 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 static void find_start_end(unsigned long flags, unsigned long *begin,
                           unsigned long *end)
 {
-       if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) {
+       if (!test_thread_flag(TIF_ADDR32)) {
                /* 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
@@ -109,14 +109,24 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
                   malloc knows how to fall back to mmap. Give it 1GB
                   of playground for now. -AK */
                *begin = 0x40000000;
-               *end = 0x80000000;
-               if (current->flags & PF_RANDOMIZE) {
-                       *begin = randomize_page(*begin, 0x02000000);
+
+               if (flags & MAP_32BIT) {
+                       if (current->flags & PF_RANDOMIZE)
+                               *begin = randomize_page(*begin, 0x02000000);
+                       *end = 0x80000000;
+                       return;
+               }
+               if (current->thread.status & TS_COMPAT) {
+                       if (current->flags & PF_RANDOMIZE)
+                               *begin = randomize_page(*begin,
+                                       1UL << mmap_rnd_compat_bits);
+                       *end = IA32_PAGE_OFFSET;
+                       return;
                }
-       } else {
-               *begin = current->mm->mmap_legacy_base;
-               *end = TASK_SIZE;
        }
+
+       *begin = current->mm->mmap_legacy_base;
+       *end = TASK_SIZE;
 }
 
 unsigned long

arch/x86/kernel/sys_x86_64.c arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, · line 200

Quoted 4 lines
arch/x86/kernel/sys_x86_64.c +1 -0
@@ -187,10 +197,21 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
                        return addr;
        }
 
+       if (current->thread.status & TS_COMPAT) {

in_compat_syscall(), please.

Also, we need to verify that, if this is called execve(), it does the right thing.

arch/x86/kernel/sys_x86_64.c arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, · line 211

Quoted 11 lines
arch/x86/kernel/sys_x86_64.c +11 -0
+               if (current->flags & PF_RANDOMIZE) {
+                       unsigned long rnd = 1UL << mmap_rnd_compat_bits;
+
+                       info.high_limit =
+                               randomize_page(IA32_PAGE_OFFSET - rnd, rnd);
+               } else {
+                       info.high_limit = IA32_PAGE_OFFSET;
+               }
+       } else {
+               info.high_limit = mm->mmap_base;
+       }
Quoted 4 lines

This code was incomprehensible before and it's worse now. Could you try to clean it up a bit? For example, a patch that simply folds find_start_end() into its sole caller as the first patch in the series without changing any semantics would probably help.

So, I debugged it a little more.
Here it is: we really should mmap here not just up to IA32_PAGE_OFFSET, but also think about stack of compat applications. Need to have a gap in the end of address space the same way it's counted in mmap_base(). And here is another bug (but less painful): for 32-bit applications, that set 64-bit CS and do native x86_64 syscalls, it's not possible to map over 4Gb (or around), 32-bit mmap_base.

I think there are two ways to fix these issues:
1. Introduce mmap_compat_base (and mmap_compat_legacy_base, I guess). Initialize only one of mmap_{,compat}_base in arch_pick_mmap_layout() and initialize the second only if 64-bit app does 32-bit mmap and vice-versa. Use these two mmap bases accordingly.
2. Save random_factor in arch_pick_mmap_layout() and make mmap_base() calculations during mmap() using compat or native task_size according to in_compat_syscall() - the perf overhead in mmap_base() doesn't look that great (but I may be wrong). Need also be careful to RLIMIT_STACK and fall back to bottom-up allocations in case of infinity.

So, does (1) or (2) make sense, or maybe there is some simpler solution to these bugs?

Signature · 1 line
             Dmitry
#6 lore raw

Re: [PATCH 1/2] x86/mm: don't mmap() over 4GB with compat syscall

In reply to Dmitry Safonov
url: https://github.com/0day-ci/linux/commits/Dmitry-Safonov/Fix-compatible-mmap-return-pointer-over-4Gb/20170112-185732 config: x86_64-randconfig-x016-201702 (attached as .config) compiler: gcc-6…

Hi Dmitry,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.10-rc3 next-20170111]
[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/20170112-185732
config: x86_64-randconfig-x016-201702 (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 errors (new ones prefixed by >>):

arch/x86/kernel/sys_x86_64.c: In function 'find_start_end':

>> arch/x86/kernel/sys_x86_64.c:122:13: error: 'mmap_rnd_compat_bits' undeclared (first use in this function)
         1UL << mmap_rnd_compat_bits);
                ^~~~~~~~~~~~~~~~~~~~
   arch/x86/kernel/sys_x86_64.c:122:13: note: each undeclared identifier is reported only once for each function it appears in
   arch/x86/kernel/sys_x86_64.c: In function 'arch_get_unmapped_area_topdown':
   arch/x86/kernel/sys_x86_64.c:202:31: error: 'mmap_rnd_compat_bits' undeclared (first use in this function)
       unsigned long rnd = 1UL << mmap_rnd_compat_bits;
                                  ^~~~~~~~~~~~~~~~~~~~

vim +/mmap_rnd_compat_bits +122 arch/x86/kernel/sys_x86_64.c

116 *end = 0x80000000;
117 return;
118 }
119 if (current->thread.status & TS_COMPAT) {
120 if (current->flags & PF_RANDOMIZE)
121 *begin = randomize_page(*begin,

 > 122						1UL << mmap_rnd_compat_bits);

123 *end = IA32_PAGE_OFFSET;
124 return;
125 }

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

#7 lore raw

PATCH 2/2 selftests/x86: add test to check compat mmap() return addr

In reply to Dmitry Safonov

We can't just add segfault handler and use addr, returned by compat mmap() syscall, because the lower 4 bytes can be the same as already existed VMA. So, the test parses /proc/self/maps file, founds new VMAs those appeared after compatible sys_mmap() and checks if mmaped VMA is in that list.

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 | 200 +++++++++++++++++++++++++
 2 files changed, 201 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 +200 -0

200 lines not on this page · raw message

Signature · 1 line
2.11.0