From nobody@FreeBSD.org  Mon Jul  2 18:29:51 2012
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id CAF68106566C
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  2 Jul 2012 18:29:51 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 95F5C8FC17
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  2 Jul 2012 18:29:51 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id q62ITp1G034724
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 2 Jul 2012 18:29:51 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id q62ITpvf034723;
	Mon, 2 Jul 2012 18:29:51 GMT
	(envelope-from nobody)
Message-Id: <201207021829.q62ITpvf034723@red.freebsd.org>
Date: Mon, 2 Jul 2012 18:29:51 GMT
From: deeptech71 <deeptech71@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: the mmap(), mprotect(), and munmap() functions get fucked by some corner-case arguments
X-Send-Pr-Version: www-3.1
X-GNATS-Notify: dt71@gmx.com

>Number:         169608
>Category:       kern
>Synopsis:       [libc] the mmap(), mprotect(), and munmap() functions get screwed by some corner-case arguments
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jul 02 18:30:09 UTC 2012
>Closed-Date:    
>Last-Modified:  Sun Apr 20 02:51:14 UTC 2014
>Originator:     deeptech71
>Release:        -CURRENT
>Organization:
>Environment:
FreeBSD  10.0-CURRENT FreeBSD 10.0-CURRENT #1 r237587M: Tue Jun 26 07:19:02 CEST 2012     root@:/usr/obj/usr/src/sys/HQ  i386
>Description:
As it turns out, the mmap(), mprotect(), and munmap() functions behave
very badly when they are handed some corner-case arguments. Their behavior
is also inconsistent with the descriptions in the man pages. Not to mention
that, as I'd say, the man pages are very poor (which is definitely true
compared to Linux's man pages).

See the (to be) attached test program, execution script, and sample
output; these are for/on 32-bit machines. The WRONGly looking pieces
of output are:

* [6/30] mmap(0x0, 4294967295, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0)... success: got 0x28049000; writing here... Segmentation fault (core dumped)
  mmap() returns a "successful" pointer, but the area is not writable. Also see cases [12/30], [18/30], and [24/30] for mmap().
* [14/30] mmap(0xdeadbeef, 4096, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0)... Cannot allocate memory
  A hint (a non-NULL first argument) should not interfere with mmap()'s ability to succeed in allocating memory. Also see cases [15/30], [20/30], and [21/30] for mmap().
* [30/30] mmap(0xffffffff, 4294967295, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0)... No such file or directory
  WTF?!
* [6/30] mprotect(0x0, 4294967295, PROT_NONE)... success!
  Did mprotect() really restrict ~4GiB of memory? Also see cases [11/30], [12/30], [17/30], [18/30], [24/30], and [29/30] for mprotect(). Notably, 0xfffff000 seems to play along with 4294967295, but not 4294963200; while 0xffffffff seems to play along with 4294963200, but not 4294967295.
* [8/30] munmap(0xbeef, 4096)... success!
  0xBEEF is not page-aligned, but the man page says that it should be. Also, see many other cases for munmap().
* [11/30] munmap(0xbeef, 4294963200)... success!
  Did munmap() really unmap ~4GiB of memory? Also see case [12/30] for munmap().

As a comparison, the output on a (64-bit) Linux machine suggests that
Linux's relevant functions are more robust. 

BTW: The man page for munmap() says that the function will set errno to
EINVAL if "The addr argument was not page aligned, the len argument was
zero or negative, or some part of the region being unmapped is outside
the valid address range for a process.". Negative size_t? You've gotta
be kidding me!
>How-To-Repeat:
Compile xs.c (to a.out), and then run the r.sh script. (These files are
to be attached.)
>Fix:


>Release-Note:
>Audit-Trail:

From: deeptech71@gmail.com
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: misc/169608: the mmap(), mprotect(), and munmap() functions get
 fucked by some corner-case arguments
Date: Mon, 02 Jul 2012 20:42:32 +0200

 This is a multi-part message in MIME format.
 --------------050908070503090907040505
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 
 --------------050908070503090907040505
 Content-Type: text/plain; charset=UTF-8;
  name="xs.c"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="xs.c"
 
 #include <sys/mman.h>
 #include <stdlib.h>
 #include <stdio.h>
 
 void test1(unsigned num, unsigned total, int func, void *addr, size_t size)
 {
   switch (func)
   {
     case 1:
     {
       printf("[%u/%u] mmap(%p, %zu, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0)... ", num, total, addr, size);
       fflush(stdout);
       void *m = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
       if (m == MAP_FAILED)
         perror(NULL);
       else
       {
         printf("success: got %p; writing here... ", m);
         fflush(stdout);
         *((int *)m) = 1337;
         printf("success!\n");
       }
     }
     break;
 
     case 2:
     {
       printf("[%u/%u] mprotect(%p, %zu, PROT_NONE)... ", num, total, addr, size);
       fflush(stdout);
       int ret = mprotect(addr, size, PROT_NONE);
       if (ret)
         perror(NULL);
       else
         printf("success!\n");
     }
     break;
 
     case 3:
     {
       printf("[%u/%u] munmap(%p, %zu)... ", num, total, addr, size);
       fflush(stdout);
       int ret = munmap(addr, size);
       if (ret)
         perror(NULL);
       else
         printf("success!\n");
     }
     break;
   }
 }
 
 #define ARRAY_LEN(x) (sizeof(x) / sizeof(*(x)))
 #define PAGE_SIZE 4096
 
 int main(int argc, char *argv[])
 {
   void *addrs[] = { NULL, (void *)0xBEEF, (void *)0xDEADBEEF, (void *)-PAGE_SIZE, (void *)-1 };
   size_t sizes[] = { (size_t)0, (size_t)PAGE_SIZE, (size_t)2000000000, (size_t)4000000000, (size_t)-PAGE_SIZE, (size_t)-1 };
 
   int func = atoi(argv[1]);
   int num = atoi(argv[2]);
 
   test1(num, ARRAY_LEN(addrs) * ARRAY_LEN(sizes), func, addrs[(num - 1) / ARRAY_LEN(sizes)], sizes[(num - 1) % ARRAY_LEN(sizes)]);
 
   return 0;
 }
 
 --------------050908070503090907040505--

From: deeptech71@gmail.com
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: misc/169608: the mmap(), mprotect(), and munmap() functions get
 fucked by some corner-case arguments
Date: Mon, 02 Jul 2012 20:44:02 +0200

 This is a multi-part message in MIME format.
 --------------070904090102010906040902
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 
 --------------070904090102010906040902
 Content-Type: text/plain; charset=UTF-8;
  name="r.sh"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="r.sh"
 
 #!/bin/sh
 for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ; do
 	./a.out 1 "$i"
 done
 echo
 for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ; do
 	./a.out 2 "$i"
 done
 echo
 for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ; do
 	./a.out 3 "$i"
 done
 
 --------------070904090102010906040902--
>Unformatted:
