Subject: port-i386/3927: mmap doens't behave rigth in linux emulation
To: None <gnats-bugs@gnats.netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: netbsd-bugs
Date: 07/30/1997 11:04:37
>Number:         3927
>Category:       port-i386
>Synopsis:       mmap doens't behave rigth in linux emulation
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Jul 30 02:20:02 1997
>Last-Modified:
>Originator:     Manuel Bouyer
>Organization:

LIP6, Universite Paris VI.

>Release:        NetBSD-current as of a few days ago
>Environment:
	
NetBSD antioche.lip6.fr 1.2G NetBSD 1.2G (ANTIOCHE) #0: Wed Jul 23 13:16:32 MEST 1997     bouyer@chassiron.ensta.fr:/usr/src/sources/src_current/sys/arch/i386/compile/ANTIOCHE i386

>Description:
	
	Some linux programs (e.g. mkdep from the kernel sources) actually uses
	mmap to read a text file. They mmap an area of size (file_size + a little),
	and uses the fact that the vm system fills the extra space with NULL's
	to detect the end of the file. Under NetBSD, the wm subsystem seems to
	use the size of the file to compute the number of pages needed, and not
	the argument passed to mmap. This implies that, on a file with a size
	just multiple of a page size, mmap will not map the last page (which
	would be filled in with NULLs only), and thus the program will get a
	SIGSEV at the end of the file.

>How-To-Repeat:
	The following code will trigger the problem: compile it on a linux machine,
	and uses it with 2 files: one of exactly 4k, and one of random size :
	-rw-r--r--  1 bouyer  wheel  4096 Jul 30 10:31 /tmp/titi
	-rwxr-xr-x  1 root  wheel  1333771 Jul 24 17:24 /netbsd*
	antifer:/promethee/bouyer>./badprog /netbsd
	6512484
	0
	antifer:/promethee/bouyer>./badprog /tmp/titi 
	-350051
	Segmentation fault (core dumped)
	
	On a linux machine you get:
	mooney:/promethee/bouyer>./badprog titi
	-350051
	0

#include <stdio.h>
#include <stdlib.h>

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

int main(int argc, char **argv)
{
	char *map;
	int mapsize;
	int pagesizem1 = getpagesize()-1;
	int fd = open(argv[1], O_RDONLY);
	struct stat st;
	int len;
	char * hpath;

	if (fd < 0) {
		perror("open");
		return;
	}
	fstat(fd, &st);
	if (st.st_size == 0) {
		fprintf(stderr,"%s is empty\n",argv[1]);
		return;
	}
	mapsize = st.st_size + sizeof(unsigned int) * 2;
	mapsize = (mapsize+pagesizem1) & ~pagesizem1;
	map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
	if (-1 == (long)map) {
		perror("mkdep: mmap");
		close(fd);
		return;
	}
	close(fd);
	printf("%d\n", *(int *)(map + st.st_size - sizeof(int)));
	printf("%d\n", *(int *)(map + st.st_size));
	munmap(map, mapsize);
}

>Fix:
	Unknown (to me). I guess this is rather trivial to fix for someone
	who used to hack the VM system.
	I don't know how mmap should behave in this environement.
	SunoS and Solaris mmap behave like NetBSD's one. But in any case, the
	linux emulation is currently brocken.
>Audit-Trail:
>Unformatted: