Patch for mmap code in 2.3.31 kernel

Don Dugger (n0ano@valinux.com)
Wed, 15 Dec 1999 18:48:32 -0700 (MST)


I discovered a glitch in the mmap code for the 2.3.31 kernel. When the
routine `unmap_fixup' needs to split a VMA into two separate areas it
sets the page offset for the two areas incorrectly. The following patch
fixes this problem.

I've also included a test program that demonstrates the failure. The test
creates a file with a known pattern (the integers 0 to (file size/4), uses
that file to `mmap' an area of memory and then re-mmap's a portion of
the mmap'ed area. The program then scans the mmap'ed area and verifies
that all integers match the expected value, printing out the first integer
that doesn't match on failure and printing out the sum of the mmap'ed area
no matter what.

-- 
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
n0ano@valinux.com
Ph: 303/938-9838

--- cut here for kernel patch --- diff -aur linux-2.3.31/mm/mmap.c linux-2.3.31-dev/mm/mmap.c --- linux-2.3.31/mm/mmap.c Tue Dec 14 17:37:45 1999 +++ linux-2.3.31-dev/mm/mmap.c Tue Dec 14 17:40:26 1999 @@ -545,8 +545,7 @@ mpnt->vm_page_prot = area->vm_page_prot; mpnt->vm_flags = area->vm_flags; mpnt->vm_ops = area->vm_ops; - mpnt->vm_pgoff = area->vm_pgoff; - area->vm_pgoff += (end - area->vm_start) >> PAGE_SHIFT; + mpnt->vm_pgoff = area->vm_pgoff + ((end - area->vm_start) >> PAGE_SHIFT); mpnt->vm_file = area->vm_file; mpnt->vm_private_data = area->vm_private_data; if (mpnt->vm_file) --- cut here for test program --- /* * "ld_so" - Copyright (C) 1999 Don Dugger <n0ano@valinux.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * To receive a copy of the GNU General Public License write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */

#include <stdio.h> #include <unistd.h> #include <malloc.h> #include <sys/mman.h>

#define PAGESZ (16 * 1024)

int minus = 0;

main(argc, argv) int argc; char *argv[]; { int i, fd, len, sum, off; unsigned int *ptr; unsigned char *file, *addr;

off = 0; if (argc > 1 && argv[1][0] == '-') { off = atoi(argv[1] + 1); argc--; argv++; } if (argc > 1) file = argv[1]; else { file = "tmp.f"; mk(file, 5*PAGESZ); } if ((fd = open(file, 0)) < 0) { printf("%s:cannot create\n", file); exit(1); } addr = mmap(NULL, 4*PAGESZ, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0); printf("mmap => 0x%x\n", addr); if ((unsigned long)addr == -1) { perror("mmap failed"); exit(2); } if (mmap(addr + 2*PAGESZ + off, PAGESZ, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 4*PAGESZ + off) == (void *)-1) { perror("mmap remap failed"); exit(3); } len = 2*PAGESZ; sum = 0; ptr = (unsigned int *)addr; for (i = 0; i < (len / sizeof(*ptr)); i++) { sum += ptr[i]; if (argc <= 1 && ptr[i] != i) { printf("FAILED - 0x%x: 0x%x != 0x%x\n", i, ptr[i], i); break; } } printf("%s sum: %d(0x%x, 0x%x)\n", file, sum, len, off); munmap(addr, 4*PAGESZ); close(fd); exit(0); }

mk(fn, n) char *fn; int n; { int i, fd; int *ptr;

unlink(fn); if ((fd = creat(fn, 0755)) < 0) { perror("creat failed"); return; } ptr = (unsigned int *)malloc(n); for (i = 0; i < (n / sizeof(*ptr)); i++) ptr[i] = i; write(fd, ptr, n); close(fd); return; }

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/