From owner-freebsd-current@FreeBSD.ORG Sun Aug 5 15:26:50 2007 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0804D16A418 for ; Sun, 5 Aug 2007 15:26:50 +0000 (UTC) (envelope-from tijl@ulyssis.org) Received: from mailrelay005.isp.belgacom.be (mailrelay005.isp.belgacom.be [195.238.6.171]) by mx1.freebsd.org (Postfix) with ESMTP id A3A3313C428 for ; Sun, 5 Aug 2007 15:26:49 +0000 (UTC) (envelope-from tijl@ulyssis.org) Received: from 199.121-247-81.adsl-dyn.isp.belgacom.be (HELO kalimero.kotnet.org) ([81.247.121.199]) by mailrelay005.isp.belgacom.be with ESMTP; 05 Aug 2007 16:56:51 +0200 Received: from localhost (localhost [127.0.0.1]) by kalimero.kotnet.org (8.14.1/8.14.1) with ESMTP id l75EuoxY004005; Sun, 5 Aug 2007 16:56:50 +0200 (CEST) (envelope-from tijl@ulyssis.org) From: Tijl Coosemans To: freebsd-current@freebsd.org, Robert Watson , John Baldwin Date: Sun, 5 Aug 2007 16:56:46 +0200 User-Agent: KMail/1.9.7 MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_yUetGtvAc2aFzH2" Message-Id: <200708051656.50168.tijl@ulyssis.org> Cc: wine-freebsd@hub.org, Volker , Gardner Bell Subject: mmap(2) MAP_FIXED isn't thread-safe (+testcase) X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 05 Aug 2007 15:26:50 -0000 --Boundary-00=_yUetGtvAc2aFzH2 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hi all, While investigating ports/115092 and other reports of seemingly random page faults when running Wine, I think I've found the cause to be mmap not being thread-safe when MAP_FIXED is used. It causes mmap(MAP_FIXED) to return -1(ENOMEM) sometimes when it shouldn't, but also to return an address with wrong protections, hence the protection faults occuring. Attached is a test program that shows this. It runs two threads. The first mmap()'s a region, starts a second thread and then goes in a loop calling mmap(PROT_WRITE,MAP_FIXED) on that region, essentially replacing that mapping. This is basically what rtld does to map an ELF object for instance when dlopen(3) is called. The second thread tries to steal the mapping from the first by calling mmap(PROT_NONE) in a loop. After a while the program segfaults when the first thread tries to write to the mapped region. Some lines are commented out. If you remove the commenting, I hit on the case where mmap(MAP_FIXED) returns -1. The problem is in sys/vm/vm_mmap.c:vm_mmap(). In case of MAP_FIXED first vm_map_remove() is called and then later vm_map_find(). This would need some locking, but I don't know which lock or how to approach this, so can somebody have a look at this? --Boundary-00=_yUetGtvAc2aFzH2 Content-Type: text/plain; charset="us-ascii"; name="mmap_test.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="mmap_test.c" #include #include #include #include #define MAPSIZE ( 16 * 4096 ) void *second_thr( void *addr ) { int i; void *addr2; for( i = 0; ; i++ ) { addr2 = mmap( NULL, MAPSIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0 ); /* if( addr2 != ( addr + MAPSIZE )) break; */ munmap( addr2, MAPSIZE ); } printf( "thread2: addr(%p), addr2(%p), i(%d)\n", addr, addr2, i ); return NULL; } int main( int argc, char **argv ) { int i; void *addr; volatile char *addr_fix; pthread_t thr; addr = mmap( NULL, MAPSIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0 ); pthread_create( &thr, NULL, &second_thr, addr ); for( i = 0; ; i++ ) { addr_fix = mmap( addr, MAPSIZE, PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0 ); if( addr_fix == addr ) *addr_fix = i; /* should be writable */ /* else break; */ } printf( "thread1: addr(%p), addr_fix(%p), errno(%d), i(%d)\n", addr, addr_fix, errno, i ); pthread_join( thr, NULL ); return 0; } --Boundary-00=_yUetGtvAc2aFzH2--