shared file mmap bug + fix

Eric Gisin (ericg@unixg.ubc.ca)
Wed, 26 Jul 1995 06:16:21 GMT


If you mmap a file with a non-zero file offset, shared modifications
will corrupt the file. The code to write modified pages does not use the
file offset. Here is a patch to 1.3.8/9, and a program to demonstrate
the bug. Use "a.out 4096". Notice changes to page 0 as well as 1.

[lines marked with "+" have been wrapped by stupid winsock application]
--- save/mm/filemap.c Tue Jul 25 19:45:18 1995
+++ mm/filemap.c Tue Jul 25 19:47:30 1995
@@ -141,7 +141,7 @@
mem_map[MAP_NR(pte_page(page))]++;
*pte = pte_mkclean(page);
}
- filemap_sync_page(vma, address - vma->vm_start, pte_page(page));
+ filemap_sync_page(vma, address - vma->vm_start + vma->vm_offset,
pte_page(page));
free_page(pte_page(page));
}

--- save/mm/swap.c Thu Jun 29 11:11:27 1995
+++ mm/swap.c Tue Jul 25 19:15:46 1995
@@ -370,7 +370,7 @@
return 0;
if (vma->vm_ops && vma->vm_ops->swapout) {
vma->vm_task->mm->rss--;
- vma->vm_ops->swapout(vma, address-vma->vm_start, page_table);
+ vma->vm_ops->swapout(vma, address - vma->vm_start +
vma->vm_offset, page_table);
} else {
if (!(entry = get_swap_page()))
return 0;

=== mmap-bug.c ===

/*
* Bugs in linux 1.3.8 shared file mapping. Try:
* for off in 0 2048 4096 $[4096+2048]; do
* dd if=/dev/zero of=temp bs=4096 count=2
* a.out ${off}; od -c temp
* done
*/

#define PAGE 4096

#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>

main(int ac, char **av)
{
int fd, off;
char c, *mp1, *mp2;

off = atoi(av[1]);
fd = open("temp", O_RDWR, 0666);
if (fd == -1)
perror("open");

mp1 = mmap(0, 2*PAGE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
mp2 = mmap(0, 2*PAGE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, off);
if (mp1 == (void*)-1 || mp2 == (void*)-1)
perror("mmap");
printf("mmap %p %p\n", mp1, mp2);

/* should write only two bytes at off+1 and off+2 */
mp1[1+off] = '1'; mp2[2] = '2';
/* both should output 1:31 2:32 */
printf("1:%x 2:%x\n", mp1[1+off], mp1[2+off]);
printf("1:%x 2:%x\n", mp2[1], mp2[2]);

return 0;
}

===

Eric Gisin, ericg@unixg.ubc.ca