From tijl@kalimero.kotnet.org  Sun Dec  9 16:04:45 2007
Return-Path: <tijl@kalimero.kotnet.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id D6C7616A418
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  9 Dec 2007 16:04:45 +0000 (UTC)
	(envelope-from tijl@kalimero.kotnet.org)
Received: from thumbler.kulnet.kuleuven.ac.be (thumbler.kulnet.kuleuven.ac.be [134.58.240.45])
	by mx1.freebsd.org (Postfix) with ESMTP id 9352113C44B
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  9 Dec 2007 16:04:45 +0000 (UTC)
	(envelope-from tijl@kalimero.kotnet.org)
Received: from localhost (localhost [127.0.0.1])
	by thumbler.kulnet.kuleuven.ac.be (Postfix) with ESMTP id 1FDC3138608
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  9 Dec 2007 16:38:17 +0100 (CET)
Received: from smtps02.kuleuven.be (smtpshost02.kulnet.kuleuven.be [134.58.240.75])
	by thumbler.kulnet.kuleuven.ac.be (Postfix) with ESMTP id 78DB1138601
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  9 Dec 2007 16:38:15 +0100 (CET)
Received: from kalimero.kotnet.org (kalimero.kotnet.org [10.4.16.222])
	by smtps02.kuleuven.be (Postfix) with ESMTP id 3A472F3863
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  9 Dec 2007 16:38:15 +0100 (CET)
Received: from kalimero.kotnet.org (kalimero.kotnet.org [127.0.0.1])
	by kalimero.kotnet.org (8.14.2/8.14.1) with ESMTP id lB9FcEhr002413
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 9 Dec 2007 16:38:15 +0100 (CET)
	(envelope-from tijl@kalimero.kotnet.org)
Received: (from tijl@localhost)
	by kalimero.kotnet.org (8.14.2/8.14.1/Submit) id lB9FcEjk002412;
	Sun, 9 Dec 2007 16:38:14 +0100 (CET)
	(envelope-from tijl)
Message-Id: <200712091538.lB9FcEjk002412@kalimero.kotnet.org>
Date: Sun, 9 Dec 2007 16:38:14 +0100 (CET)
From: Tijl Coosemans <tijl@ulyssis.org>
Reply-To: Tijl Coosemans <tijl@ulyssis.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: munmap(2) doesn't remove all mappings
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         118510
>Category:       kern
>Synopsis:       [vm] [patch] munmap(2) doesn't remove all mappings
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    alc
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Dec 09 16:10:00 UTC 2007
>Closed-Date:    Tue Sep 23 16:04:41 UTC 2008
>Last-Modified:  Tue Sep 23 16:04:41 UTC 2008
>Originator:     Tijl Coosemans
>Release:        FreeBSD 7.0-BETA3 i386
>Organization:
>Environment:
System: FreeBSD kalimero.kotnet.org 7.0-BETA3 FreeBSD 7.0-BETA3 #1: Sat Nov 17 19:01:40 CET 2007
>Description:
When a memory region has been partially munmap()ed, subsequent
calls to munmap() on this region have no effect.
>How-To-Repeat:
The following program should segfault, but doesn't.

It mmap()s 2 pages and munmap()s them again but the second page
is still accessible.

--- test.c begins here ---
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>

int main( int argc, char **argv ) {

    unsigned int const page_size = getpagesize();
    void *map;
    char volatile *cmap;

    map = mmap( NULL, 2 * page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0 );
    munmap( map, page_size );
    munmap( map, 2 * page_size );

    cmap = map;
    cmap[ page_size ] = 'a';
    printf( "%c\n", cmap[ page_size ] );

    return 0;
}
--- test.c ends here ---

>Fix:

>Release-Note:
>Audit-Trail:

From: Tijl Coosemans <tijl@ulyssis.org>
To: bug-followup@freebsd.org
Cc:  
Subject: Re: kern/118510: [libc] munmap(2) doesn't remove all mappings
Date: Mon, 10 Dec 2007 21:21:32 +0100

 proposed patch:
 
 --- sys/vm/vm_mmap.c.orig	2007-12-10 15:57:00.000000000 +0100
 +++ sys/vm/vm_mmap.c	2007-12-10 20:40:42.000000000 +0100
 @@ -555,13 +555,6 @@
  	if (addr < vm_map_min(map) || addr + size > vm_map_max(map))
  		return (EINVAL);
  	vm_map_lock(map);
 -	/*
 -	 * Make sure entire range is allocated.
 -	 */
 -	if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) {
 -		vm_map_unlock(map);
 -		return (EINVAL);
 -	}
  #ifdef HWPMC_HOOKS
  	/*
  	 * Inform hwpmc if the address range being unmapped contains
 
State-Changed-From-To: open->analyzed 
State-Changed-By: kris 
State-Changed-When: Thu Jan 10 21:49:39 UTC 2008 
State-Changed-Why:  
Believed not to be a bug 

http://www.freebsd.org/cgi/query-pr.cgi?pr=118510 
Responsible-Changed-From-To: freebsd-bugs->kris 
Responsible-Changed-By: kris 
Responsible-Changed-When: Thu Jan 10 21:49:53 UTC 2008 
Responsible-Changed-Why:  
Take this pending further feedback 

http://www.freebsd.org/cgi/query-pr.cgi?pr=118510 

From: Kris Kennaway <kris@FreeBSD.org>
To: Tijl Coosemans <tijl@ulyssis.org>
Cc: FreeBSD-gnats-submit@FreeBSD.org
Subject: Re: kern/118510: munmap(2) doesn't remove all mappings
Date: Thu, 10 Jan 2008 22:48:46 +0100

 Tijl Coosemans wrote:
 
 >> Description:
 > When a memory region has been partially munmap()ed, subsequent
 > calls to munmap() on this region have no effect.
 >> How-To-Repeat:
 > The following program should segfault, but doesn't.
 > 
 > It mmap()s 2 pages and munmap()s them again but the second page
 > is still accessible.
 > 
 > --- test.c begins here ---
 > #include <sys/mman.h>
 > #include <stdio.h>
 > #include <unistd.h>
 > 
 > int main( int argc, char **argv ) {
 > 
 >     unsigned int const page_size = getpagesize();
 >     void *map;
 >     char volatile *cmap;
 > 
 >     map = mmap( NULL, 2 * page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0 );
 >     munmap( map, page_size );
 >     munmap( map, 2 * page_size );
 > 
 >     cmap = map;
 >     cmap[ page_size ] = 'a';
 >     printf( "%c\n", cmap[ page_size ] );
 > 
 >     return 0;
 > }
 > --- test.c ends here ---
 
 I believe this is an incorrect use of munmap.  After the first call to 
 munmap, you have removed the first page of the mapping, leaving a 
 mapping at offset map + page_size of size page_size.  The second munmap 
 is being called with an offset that is no longer mapped, and indeed it 
 returns an EINVAL that your sample code is not testing for.
 
 Kris
 
Responsible-Changed-From-To: kris->alc 
Responsible-Changed-By: kris 
Responsible-Changed-When: Fri Jan 11 13:46:02 UTC 2008 
Responsible-Changed-Why:  
Assign to alc for evaluation.  Submitter suggests modifying the 
behaviour of munmap so that it will unmap all mappings inside 
a range, even if it encompasses regions that are unmapped. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=118510 

From: Tijl Coosemans <tijl@ulyssis.org>
To: Kris Kennaway <kris@freebsd.org>
Cc: FreeBSD-gnats-submit@freebsd.org
Subject: Re: kern/118510: munmap(2) doesn't remove all mappings
Date: Fri, 11 Jan 2008 14:11:50 +0100

 On Thursday 10 January 2008 22:48:46 Kris Kennaway wrote:
 > Tijl Coosemans wrote:
 >>> Description:
 >> When a memory region has been partially munmap()ed, subsequent
 >> calls to munmap() on this region have no effect.
 >> 
 >>> How-To-Repeat:
 >> The following program should segfault, but doesn't.
 >> 
 >> It mmap()s 2 pages and munmap()s them again but the second page
 >> is still accessible.
 >> 
 >> --- test.c begins here ---
 >> #include <sys/mman.h>
 >> #include <stdio.h>
 >> #include <unistd.h>
 >> 
 >> int main( int argc, char **argv ) {
 >> 
 >>     unsigned int const page_size = getpagesize();
 >>     void *map;
 >>     char volatile *cmap;
 >> 
 >>     map = mmap( NULL, 2 * page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0 );
 >>     munmap( map, page_size );
 >>     munmap( map, 2 * page_size );
 >> 
 >>     cmap = map;
 >>     cmap[ page_size ] = 'a';
 >>     printf( "%c\n", cmap[ page_size ] );
 >> 
 >>     return 0;
 >> }
 >> --- test.c ends here ---
 > 
 > I believe this is an incorrect use of munmap.  After the first call
 > to munmap, you have removed the first page of the mapping, leaving a
 > mapping at offset map + page_size of size page_size.  The second
 > munmap is being called with an offset that is no longer mapped, and
 > indeed it returns an EINVAL that your sample code is not testing for.
 
 Yes, but this EINVAL case isn't documented. I guess my question is: why
 does it return EINVAL if it could simply remove all mappings in the
 given address range like it says in the manpage (and how it seems to
 work on Linux at least)? In the NetBSD CVS log I also found a similar
 patch to the one I submitted:
 
 #if 0 the call to uvm_map_checkprot() in sys_munmap() -- it's not documented,
 and programs do not expect it.  Also fixes memory leaks in dlopen()/dlclose().
 http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/uvm/uvm_mmap.c#rev1.66

From: Alan Cox <alc@cs.rice.edu>
To: bug-followup@FreeBSD.org,  tijl@ulyssis.org
Cc: Kris Kennaway <kris@obsecurity.org>
Subject: Re: kern/118510: [libc] [patch] munmap(2) doesn't remove all mappings
Date: Fri, 11 Jan 2008 10:50:15 -0600

 It is documented in the man page.  See the last clause of sentence 
 describing EINVAL.
 
 ERRORS
      The munmap() system call will fail if:
 
      [EINVAL]           The addr argument was not page aligned, the len 
 argu-
                         ment was zero or negative, or some part of the 
 region
                         being unmapped is outside the valid address 
 range for
                         a process.
 
 This is also consistent with the description provided by the SuSv2 at 
 http://www.opengroup.org/pubs/online/7908799/xsh/munmap.html
 
 That said, the subtle difference between our man page and the Open 
 Group's description is the use of "some part" in our man page.  In other 
 words, it's unclear whether the Open Group intends for munmap() to 
 return EINVAL if some part of the address range is invalid or only if 
 the whole address range is invalid.  I'm not aware of them issuing any 
 clarifications on this question.
 
 Regards,
 Alan
 
 

From: Tijl Coosemans <tijl@ulyssis.org>
To: Alan Cox <alc@cs.rice.edu>
Cc: bug-followup@freebsd.org, Kris Kennaway <kris@obsecurity.org>
Subject: Re: kern/118510: [libc] [patch] munmap(2) doesn't remove all mappings
Date: Fri, 11 Jan 2008 19:00:42 +0100

 On Friday 11 January 2008 17:50:15 Alan Cox wrote:
 > It is documented in the man page.  See the last clause of sentence 
 > describing EINVAL.
 > 
 > ERRORS
 >      The munmap() system call will fail if:
 > 
 >      [EINVAL]           The addr argument was not page aligned, the len argu-
 >                         ment was zero or negative, or some part of the region
 >                         being unmapped is outside the valid address range for
 >                         a process.
 > 
 > This is also consistent with the description provided by the SuSv2 at
 > http://www.opengroup.org/pubs/online/7908799/xsh/munmap.html
 > 
 > That said, the subtle difference between our man page and the Open
 > Group's description is the use of "some part" in our man page.  In
 > other words, it's unclear whether the Open Group intends for munmap()
 > to return EINVAL if some part of the address range is invalid or only
 > if the whole address range is invalid.  I'm not aware of them issuing
 > any clarifications on this question.
 
 Ok, we are interpreting things differently then. I understand both
 manpages as simply saying that the given address range has to be within
 user space limits, and not that additionally, the full range has to be
 mapped as well. In my opinion, the EINVAL is only meant for simple
 bounds checking of the given arguments.
 
 The description part of both manpages also simply states munmap()
 removes any mappings for pages within the given range. I don't see
 where that implies the full range has to be mapped. What would the
 benefit of such a precondition be?

From: Alan Cox <alc@cs.rice.edu>
To: Tijl Coosemans <tijl@ulyssis.org>
Cc: bug-followup@freebsd.org, Kris Kennaway <kris@obsecurity.org>
Subject: Re: kern/118510: [libc] [patch] munmap(2) doesn't remove all mappings
Date: Sat, 24 May 2008 13:26:05 -0500

 Tijl Coosemans wrote:
 
 >On Friday 11 January 2008 17:50:15 Alan Cox wrote:
 >  
 >
 >>It is documented in the man page.  See the last clause of sentence 
 >>describing EINVAL.
 >>
 >>ERRORS
 >>     The munmap() system call will fail if:
 >>
 >>     [EINVAL]           The addr argument was not page aligned, the len argu-
 >>                        ment was zero or negative, or some part of the region
 >>                        being unmapped is outside the valid address range for
 >>                        a process.
 >>
 >>This is also consistent with the description provided by the SuSv2 at
 >>http://www.opengroup.org/pubs/online/7908799/xsh/munmap.html
 >>
 >>That said, the subtle difference between our man page and the Open
 >>Group's description is the use of "some part" in our man page.  In
 >>other words, it's unclear whether the Open Group intends for munmap()
 >>to return EINVAL if some part of the address range is invalid or only
 >>if the whole address range is invalid.  I'm not aware of them issuing
 >>any clarifications on this question.
 >>    
 >>
 >
 >Ok, we are interpreting things differently then. I understand both
 >manpages as simply saying that the given address range has to be within
 >user space limits, and not that additionally, the full range has to be
 >mapped as well. In my opinion, the EINVAL is only meant for simple
 >bounds checking of the given arguments.
 >
 >The description part of both manpages also simply states munmap()
 >removes any mappings for pages within the given range. I don't see
 >where that implies the full range has to be mapped. What would the
 >benefit of such a precondition be?
 >  
 >
 
 After a more careful reading of the SuSv2 pages, I've changed my mind.  
 I now agree with your interpretation.  So, I'll be committing your patch.
 
 Regards,
 Alan
  
 P.S.  I've also verified that both Solaris and Linux behave as you describe.
 
State-Changed-From-To: analyzed->patched 
State-Changed-By: alc 
State-Changed-When: Sat May 24 21:59:09 UTC 2008 
State-Changed-Why:  
Patch applied to HEAD 

http://www.freebsd.org/cgi/query-pr.cgi?pr=118510 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/118510: commit references a PR
Date: Sat, 24 May 2008 21:57:22 +0000 (UTC)

 alc         2008-05-24 21:57:16 UTC
 
   FreeBSD src repository
 
   Modified files:
     sys/vm               vm_mmap.c 
   Log:
   To date, our implementation of munmap(2) has required that the
   entirety of the specified range be mapped.  Specifically, it has
   returned EINVAL if the entire range is not mapped.  There is not,
   however, any basis for this in either SuSv2 or our own man page.
   Moreover, neither Linux nor Solaris impose this requirement.  This
   revision removes this requirement.
   
   Submitted by: Tijl Coosemans
   PR: 118510
   MFC after: 6 weeks
   
   Revision  Changes    Path
   1.221     +0 -7      src/sys/vm/vm_mmap.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: jhb 
State-Changed-When: Tue Sep 23 16:04:24 UTC 2008 
State-Changed-Why:  
Fix merged to 6.x and 7.x. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=118510 
>Unformatted:
