Skip to content
  • Oleg Nesterov's avatar
    mremap: fix the wrong !vma->vm_file check in copy_vma() · ce75799b
    Oleg Nesterov authored
    
    
    Test-case:
    
    	#define _GNU_SOURCE
    	#include <stdio.h>
    	#include <unistd.h>
    	#include <stdlib.h>
    	#include <string.h>
    	#include <sys/mman.h>
    	#include <assert.h>
    
    	void *find_vdso_vaddr(void)
    	{
    		FILE *perl;
    		char buf[32] = {};
    
    		perl = popen("perl -e 'open STDIN,qq|/proc/@{[getppid]}/maps|;"
    				"/^(.*?)-.*vdso/ && print hex $1 while <>'", "r");
    		fread(buf, sizeof(buf), 1, perl);
    		fclose(perl);
    
    		return (void *)atol(buf);
    	}
    
    	#define PAGE_SIZE	4096
    
    	void *get_unmapped_area(void)
    	{
    		void *p = mmap(0, PAGE_SIZE, PROT_NONE,
    				MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
    		assert(p != MAP_FAILED);
    		munmap(p, PAGE_SIZE);
    		return p;
    	}
    
    	char save[2][PAGE_SIZE];
    
    	int main(void)
    	{
    		void *vdso = find_vdso_vaddr();
    		void *page[2];
    
    		assert(vdso);
    		memcpy(save, vdso, sizeof (save));
    		// force another fault on the next check
    		assert(madvise(vdso, 2 * PAGE_SIZE, MADV_DONTNEED) == 0);
    
    		page[0] = mremap(vdso,
    				PAGE_SIZE, PAGE_SIZE, MREMAP_FIXED | MREMAP_MAYMOVE,
    				get_unmapped_area());
    		page[1] = mremap(vdso + PAGE_SIZE,
    				PAGE_SIZE, PAGE_SIZE, MREMAP_FIXED | MREMAP_MAYMOVE,
    				get_unmapped_area());
    
    		assert(page[0] != MAP_FAILED && page[1] != MAP_FAILED);
    		printf("match: %d %d\n",
    			!memcmp(save[0], page[0], PAGE_SIZE),
    			!memcmp(save[1], page[1], PAGE_SIZE));
    
    		return 0;
    	}
    
    fails without this patch. Before the previous commit it gets the wrong
    page, now it segfaults (which is imho better).
    
    This is because copy_vma() wrongly assumes that if vma->vm_file == NULL
    is irrelevant until the first fault which will use do_anonymous_page().
    This is obviously wrong for the special mapping.
    
    Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
    Acked-by: default avatarKirill A. Shutemov <kirill.shutemov@linux.intel.com>
    Cc: Andy Lutomirski <luto@kernel.org>
    Cc: Hugh Dickins <hughd@google.com>
    Cc: Pavel Emelyanov <xemul@parallels.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    ce75799b