Re: [criu] 1M guard page ruined restore

From: Dmitry Safonov
Date: Wed Jun 21 2017 - 13:20:06 EST


On 06/21/2017 08:15 PM, Dmitry Safonov wrote:
On 06/21/2017 08:01 PM, Oleg Nesterov wrote:
On 06/21, Cyrill Gorcunov wrote:

On Wed, Jun 21, 2017 at 05:57:30PM +0200, Oleg Nesterov wrote:

p = fake_grow_down;
*p-- = 'c';

I guess this works? I mean, *p-- = 'c' should not fail...

It fails.

Hmm. Impossible ;) could you add the additional printf's to re-check?

Here is the complete code. It supposed to _extend_ stack but it fails
on the latest master + Hugh's [PATCH] mm: fix new crash in unmapped_area_topdown()
---
[root@fc2 criu]# ~/st2
start_addr 7fe6162a8000
start_addr 7fe6163d9000
Segmentation fault (core dumped)
---
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/mman.h>

#define PAGE_SIZE 4096

int main(int argc, char **argv)
{
char *start_addr, *start_addr1, *fake_grow_down, *test_addr, *grow_down;
volatile char *p;

start_addr = mmap(NULL, PAGE_SIZE * 512, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (start_addr == MAP_FAILED) {
printf("Can't mal a new region");
return 1;
}
printf("start_addr %lx\n", start_addr);
munmap(start_addr, PAGE_SIZE * 512);

start_addr += PAGE_SIZE * 300;

fake_grow_down = mmap(start_addr + PAGE_SIZE * 5, PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED | MAP_GROWSDOWN, -1, 0);
if (fake_grow_down == MAP_FAILED) {
printf("Can't mal a new region");
return 1;
}
printf("start_addr %lx\n", fake_grow_down);

p = fake_grow_down;
*p-- = 'c';

once again, I can't believe this STORE can fail...

*p = 'b';

Ah. I forgot about another kernel "feature" ;) not related to the recent guard
page changes...

Could you test the patch below?

Well, for me only the second store caused segfault.
With your patch it passes..

The only question I have - how is it connected to guard page?
Before the former patch the test has passed. Why?
And this thing seems to be in kernel since 2009.




diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 8ad91a0..edc5d68 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -1416,7 +1416,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
* and pusha to work. ("enter $65535, $31" pushes
* 32 pointers and then decrements %sp by 65535.)
*/
- if (unlikely(address + 65536 + 32 * sizeof(unsigned long) < regs->sp)) {
+if (0) if (unlikely(address + 65536 + 32 * sizeof(unsigned long) < regs->sp)) {
bad_area(regs, error_code, address);
return;
}




--
Dmitry