Re: [PATCH v3] mm: Fix mremap not considering huge pmd devmap

From: Fan Yang
Date: Fri Jun 05 2020 - 01:09:31 EST


Hi Ajay,

> On Jun 5, 2020 at 02:23ïAjay Kaher <akaher@xxxxxxxxxx> wroteï
>
> So, v4.9.y should be vulnerable, however not able to reproduce on v4.9.y.
> Does any specific scenerio need to test for v4.9.y?
>
> For v4.9, modified test program as MAP_SHARED_VALIDATE is not available:
> - return mmap(NULL, REGION_PM_SIZE, PROT, MAP_SHARED_VALIDATE|MAP_SYNC,
> + return mmap(NULL, REGION_PM_SIZE, PROT, MAP_SHARED|MAP_SYNC,
>
> Let me know if I need to test some other way for v4.9.y.
>

I further looked into this. In v4.9, fsdax (mount a dax file
system, then open, mmap, mremap) does not suffer this issue
because fsdax does not use huge page (FS_DAX_PMD is marked
BROKEN).

fs/dax.c:dax_pmd_fault:

if (!IS_ENABLED(CONFIG_FS_DAX_PMD))
return VM_FAULT_FALLBACK;

fs/Kconfig:

config FS_DAX_PMD
bool
default FS_DAX
depends on FS_DAX
depends on ZONE_DEVICE
depends on TRANSPARENT_HUGEPAGE
depends on BROKEN


However, I can re-produce the issue for the devdax mode. Here is how
I re-produce it:

1. It seems some interface changed for ndctl. So I use an old
commit (4295f1ea614a26e1304ed590fb7209c8c78270ab) in the repo
https://github.com/pmem/ndctl.
2. sudo ./ndctl/ndctl create-namespace -f -t pmem -m dax -e 'namespace0.0'
3. then use the following program:

#define _GNU_SOURCE
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>

#define PROT PROT_READ|PROT_WRITE

#define REGION_PM_TMP_PATH "/dev/dax0.0"

#define REGION_MEM_SIZE 1024ULL*1024*1024*2
#define REGION_PM_SIZE 1024ULL*1024*1024*4
#define REMAP_MEM_OFF 1024ULL*1024*1024*1
#define REMAP_PM_OFF 1024ULL*1024*1024*3
#define REMAP_SIZE 1024ULL*1024*1024*1

#define REGION_MEM_PTR ((void *)0x7fd400000000ULL)
#define REGION_PM_PTR ((void *)0x4fd300000000ULL)

char * map_tmp_pm_region(void)
{
int fd;

fd = open(REGION_PM_TMP_PATH, O_RDWR, 0644);
if (fd < 0) {
perror(REGION_PM_TMP_PATH);
exit(-1);
}

return mmap(REGION_PM_PTR, REGION_PM_SIZE, PROT, MAP_SHARED|MAP_SYNC,
fd, 0);
}

int main(int argc, char **argv)
{
char *regm, *regp, *remap;
int ret;

regm = mmap(REGION_MEM_PTR, REGION_MEM_SIZE, PROT, MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0);
if (regm == MAP_FAILED) {
perror("regm");
return -1;
}

regp = map_tmp_pm_region();
if (regp == MAP_FAILED) {
perror("regp");
return -1;
}

memset(regm, 'a', REGION_MEM_SIZE);
memset(regp, 'i', REGION_PM_SIZE);

remap = mremap(regp + REMAP_PM_OFF, REMAP_SIZE, REMAP_SIZE,
MREMAP_MAYMOVE|MREMAP_FIXED, regm + REMAP_MEM_OFF);
if (remap != regm + REMAP_MEM_OFF) {
perror("mremap");
return -1;
}

*(regm + REMAP_MEM_OFF) = 0x00;
return 0;
}

4. Then I was able to see the "Corrupted page table" message in dmesg.

Best regards,
Fan