2  * Copyright (c) 2007 Apple Inc. All Rights Reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  29  * Copyright (c) 1988 University of Utah. 
  30  * Copyright (c) 1991, 1993 
  31  *      The Regents of the University of California.  All rights reserved. 
  33  * This code is derived from software contributed to Berkeley by 
  34  * the Systems Programming Group of the University of Utah Computer 
  37  * Redistribution and use in source and binary forms, with or without 
  38  * modification, are permitted provided that the following conditions 
  40  * 1. Redistributions of source code must retain the above copyright 
  41  *    notice, this list of conditions and the following disclaimer. 
  42  * 2. Redistributions in binary form must reproduce the above copyright 
  43  *    notice, this list of conditions and the following disclaimer in the 
  44  *    documentation and/or other materials provided with the distribution. 
  45  * 3. All advertising materials mentioning features or use of this software 
  46  *    must display the following acknowledgement: 
  47  *      This product includes software developed by the University of 
  48  *      California, Berkeley and its contributors. 
  49  * 4. Neither the name of the University nor the names of its contributors 
  50  *    may be used to endorse or promote products derived from this software 
  51  *    without specific prior written permission. 
  53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 
  54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 
  57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  65  * from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$ 
  67  *      @(#)vm_mmap.c   8.10 (Berkeley) 2/19/95 
  70  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 
  71  * support for mandatory and extensible security protections.  This notice 
  72  * is included in support of clause 2.2 (b) of the Apple Public License, 
  77  * Mapped file (mmap) interface to VM 
  80 #include <sys/param.h> 
  81 #include <sys/systm.h> 
  82 #include <sys/filedesc.h> 
  83 #include <sys/proc_internal.h> 
  84 #include <sys/kauth.h> 
  85 #include <sys/resourcevar.h> 
  86 #include <sys/vnode_internal.h> 
  89 #include <sys/file_internal.h> 
  90 #include <sys/vadvise.h> 
  91 #include <sys/trace.h> 
  96 #include <sys/ubc_internal.h> 
  97 #include <sys/sysproto.h> 
  99 #include <sys/syscall.h> 
 100 #include <sys/kdebug.h> 
 102 #include <bsm/audit_kernel.h> 
 103 #include <bsm/audit_kevents.h> 
 105 #include <mach/mach_types.h> 
 106 #include <mach/mach_traps.h> 
 107 #include <mach/vm_sync.h> 
 108 #include <mach/vm_behavior.h> 
 109 #include <mach/vm_inherit.h> 
 110 #include <mach/vm_statistics.h> 
 111 #include <mach/mach_vm.h> 
 112 #include <mach/vm_map.h> 
 113 #include <mach/host_priv.h> 
 115 #include <kern/cpu_number.h> 
 116 #include <kern/host.h> 
 118 #include <vm/vm_map.h> 
 119 #include <vm/vm_kern.h> 
 120 #include <vm/vm_pager.h> 
 131 /* XXX the following function should probably be static */ 
 132 kern_return_t 
map_fd_funneled(int, vm_object_offset_t
, vm_offset_t 
*, 
 133                                 boolean_t
, vm_size_t
); 
 135 /* XXX the following two functions aren't used anywhere */ 
 136 int osmmap(proc_t 
, struct osmmap_args 
*, register_t 
*); 
 140 sbrk(__unused proc_t p
, __unused 
struct sbrk_args 
*uap
, __unused register_t 
*retval
) 
 142         /* Not yet implemented */ 
 147 sstk(__unused proc_t p
, __unused 
struct sstk_args 
*uap
, __unused register_t 
*retval
) 
 149         /* Not yet implemented */ 
 157         struct osmmap_args 
*uap
, 
 160         struct mmap_args newargs
; 
 164         if ((uap
->share 
==  MAP_SHARED 
)|| (uap
->share 
==  MAP_PRIVATE 
)) { 
 165                 newargs
.addr 
= CAST_USER_ADDR_T(uap
->addr
); 
 166                 newargs
.len 
= CAST_USER_ADDR_T(uap
->len
); 
 167                 newargs
.prot 
= uap
->prot
; 
 168                 newargs
.flags 
= uap
->share
; 
 169                 newargs
.fd 
= uap
->fd
; 
 170                 newargs
.pos 
= (off_t
)uap
->pos
; 
 171                 ret 
= mmap(curp
, &newargs
, &addr
); 
 173                         *retval 
= CAST_DOWN(register_t
, addr
); 
 181  * XXX Internally, we use VM_PROT_* somewhat interchangeably, but the correct 
 182  * XXX usage is PROT_* from an interface perspective.  Thus the values of 
 183  * XXX VM_PROT_* and PROT_* need to correspond. 
 186 mmap(proc_t p
, struct mmap_args 
*uap
, user_addr_t 
*retval
) 
 189          *      Map in special device (must be SHARED) or file 
 192         register struct         vnode 
*vp
; 
 197         kern_return_t           result
; 
 198         mach_vm_offset_t        user_addr
; 
 199         mach_vm_size_t          user_size
; 
 200         vm_object_offset_t      pageoff
; 
 201         vm_object_offset_t      file_pos
; 
 212         user_addr 
= (mach_vm_offset_t
)uap
->addr
; 
 213         user_size 
= (mach_vm_size_t
) uap
->len
; 
 215         AUDIT_ARG(addr
, user_addr
); 
 216         AUDIT_ARG(len
, user_size
); 
 217         AUDIT_ARG(fd
, uap
->fd
); 
 219         prot 
= (uap
->prot 
& VM_PROT_ALL
); 
 222          * Since the hardware currently does not support writing without 
 223          * read-before-write, or execution-without-read, if the request is 
 224          * for write or execute access, we must imply read access as well; 
 225          * otherwise programs expecting this to work will fail to operate. 
 227         if (prot 
& (VM_PROT_EXECUTE 
| VM_PROT_WRITE
)) 
 228                 prot 
|= VM_PROT_READ
; 
 229 #endif  /* radar 3777787 */ 
 235          * The vm code does not have prototypes & compiler doesn't do the' 
 236          * the right thing when you cast 64bit value and pass it in function  
 237          * call. So here it is. 
 239         file_pos 
= (vm_object_offset_t
)uap
->pos
; 
 242         /* make sure mapping fits into numeric range etc */ 
 243         if (file_pos 
+ user_size 
> (vm_object_offset_t
)-PAGE_SIZE_64
) 
 247          * Align the file position to a page boundary, 
 248          * and save its page offset component. 
 250         pageoff 
= (file_pos 
& PAGE_MASK
); 
 251         file_pos 
-= (vm_object_offset_t
)pageoff
; 
 254         /* Adjust size for rounding (on both ends). */ 
 255         user_size 
+= pageoff
;                   /* low end... */ 
 256         user_size 
= mach_vm_round_page(user_size
);      /* hi end */ 
 260          * Check for illegal addresses.  Watch out for address wrap... Note 
 261          * that VM_*_ADDRESS are not constants due to casts (argh). 
 263         if (flags 
& MAP_FIXED
) { 
 265                  * The specified address must have the same remainder 
 266                  * as the file offset taken modulo PAGE_SIZE, so it 
 267                  * should be aligned after adjustment by pageoff. 
 269                 user_addr 
-= pageoff
; 
 270                 if (user_addr 
& PAGE_MASK
) 
 274         /* DO not have apis to get this info, need to wait till then*/ 
 276          * XXX for non-fixed mappings where no hint is provided or 
 277          * the hint would fall in the potential heap space, 
 278          * place it after the end of the largest possible heap. 
 280          * There should really be a pmap call to determine a reasonable 
 283         else if (addr 
< mach_vm_round_page(p
->p_vmspace
->vm_daddr 
+ MAXDSIZ
)) 
 284                 addr 
= mach_vm_round_page(p
->p_vmspace
->vm_daddr 
+ MAXDSIZ
); 
 290         if (flags 
& MAP_ANON
) { 
 292                  * Mapping blank space is trivial.  Use positive fds as the alias 
 293                  * value for memory tracking.  
 297                          * Use "fd" to pass (some) Mach VM allocation flags, 
 298                          * (see the VM_FLAGS_* definitions). 
 300                         alloc_flags 
= fd 
& (VM_FLAGS_ALIAS_MASK 
| 
 302                         if (alloc_flags 
!= fd
) { 
 303                                 /* reject if there are any extra flags */ 
 309                 maxprot 
= VM_PROT_ALL
; 
 313                 struct vnode_attr va
; 
 314                 vfs_context_t ctx 
= vfs_context_current(); 
 317                  * Mapping file, get fp for validation. Obtain vnode and make 
 318                  * sure it is of appropriate type. 
 320                 err 
= fp_lookup(p
, fd
, &fp
, 0); 
 324                 if(fp
->f_fglob
->fg_type 
== DTYPE_PSXSHM
) { 
 325                         uap
->addr 
= (user_addr_t
)user_addr
; 
 326                         uap
->len 
= (user_size_t
)user_size
; 
 330                         error 
= pshm_mmap(p
, uap
, retval
, fp
, (off_t
)pageoff
); 
 334                 if (fp
->f_fglob
->fg_type 
!= DTYPE_VNODE
) { 
 338                 vp 
= (struct vnode 
*)fp
->f_fglob
->fg_data
; 
 339                 error 
= vnode_getwithref(vp
); 
 343                 if (vp
->v_type 
!= VREG 
&& vp
->v_type 
!= VCHR
) { 
 349                 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
); 
 352                  * POSIX: mmap needs to update access time for mapped files 
 354                 if ((vnode_vfsvisflags(vp
) & MNT_NOATIME
) == 0) { 
 356                         nanotime(&va
.va_access_time
); 
 357                         VATTR_SET_ACTIVE(&va
, va_access_time
); 
 358                         vnode_setattr(vp
, &va
, ctx
); 
 362                  * XXX hack to handle use of /dev/zero to map anon memory (ala 
 365                 if (vp
->v_type 
== VCHR 
|| vp
->v_type 
== VSTR
) { 
 371                          * Ensure that file and memory protections are 
 372                          * compatible.  Note that we only worry about 
 373                          * writability if mapping is shared; in this case, 
 374                          * current and max prot are dictated by the open file. 
 375                          * XXX use the vnode instead?  Problem is: what 
 376                          * credentials do we use for determination? What if 
 377                          * proc does a setuid? 
 379                         maxprot 
= VM_PROT_EXECUTE
;      /* ??? */ 
 380                         if (fp
->f_fglob
->fg_flag 
& FREAD
) 
 381                                 maxprot 
|= VM_PROT_READ
; 
 382                         else if (prot 
& PROT_READ
) { 
 388                          * If we are sharing potential changes (either via 
 389                          * MAP_SHARED or via the implicit sharing of character 
 390                          * device mappings), and we are trying to get write 
 391                          * permission although we opened it without asking 
 395                         if ((flags 
& MAP_SHARED
) != 0) { 
 396                                 if ((fp
->f_fglob
->fg_flag 
& FWRITE
) != 0) { 
 398                                          * check for write access 
 400                                          * Note that we already made this check when granting FWRITE 
 401                                          * against the file, so it seems redundant here. 
 403                                         error 
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_CHECKIMMUTABLE
, ctx
); 
 405                                         /* if not granted for any reason, but we wanted it, bad */ 
 406                                         if ((prot 
& PROT_WRITE
) && (error 
!= 0)) { 
 411                                         /* if writable, remember */ 
 413                                                 maxprot 
|= VM_PROT_WRITE
; 
 415                                 } else if ((prot 
& PROT_WRITE
) != 0) { 
 421                                 maxprot 
|= VM_PROT_WRITE
; 
 425                         error 
= mac_file_check_mmap(vfs_context_ucred(ctx
), 
 426                             fp
->f_fglob
, prot
, flags
, &maxprot
); 
 435         if (user_size 
== 0)  { 
 443          *      We bend a little - round the start and end addresses 
 444          *      to the nearest page boundary. 
 446         user_size 
= mach_vm_round_page(user_size
); 
 448         if (file_pos 
& PAGE_MASK_64
) { 
 455         user_map 
= current_map(); 
 457         if ((flags 
& MAP_FIXED
) == 0) { 
 458                 alloc_flags 
|= VM_FLAGS_ANYWHERE
; 
 459                 user_addr 
= mach_vm_round_page(user_addr
); 
 461                 if (user_addr 
!= mach_vm_trunc_page(user_addr
)) { 
 468                  * mmap(MAP_FIXED) will replace any existing mappings in the 
 469                  * specified range, if the new mapping is successful. 
 470                  * If we just deallocate the specified address range here, 
 471                  * another thread might jump in and allocate memory in that 
 472                  * range before we get a chance to establish the new mapping, 
 473                  * and we won't have a chance to restore the old mappings. 
 474                  * So we use VM_FLAGS_OVERWRITE to let Mach VM know that it 
 475                  * has to deallocate the existing mappings and establish the 
 476                  * new ones atomically. 
 478                 alloc_flags 
|= VM_FLAGS_FIXED 
| VM_FLAGS_OVERWRITE
; 
 481         if (flags 
& MAP_NOCACHE
) 
 482                 alloc_flags 
|= VM_FLAGS_NO_CACHE
; 
 485          * Lookup/allocate object. 
 487         if (handle 
== NULL
) { 
 491 #if defined(VM_PROT_READ_IS_EXEC) 
 492                 if (prot 
& VM_PROT_READ
) 
 493                         prot 
|= VM_PROT_EXECUTE
; 
 494                 if (maxprot 
& VM_PROT_READ
) 
 495                         maxprot 
|= VM_PROT_EXECUTE
; 
 500                 if (prot 
& (VM_PROT_EXECUTE 
| VM_PROT_WRITE
)) 
 501                         prot 
|= VM_PROT_READ
; 
 502                 if (maxprot 
& (VM_PROT_EXECUTE 
| VM_PROT_WRITE
)) 
 503                         maxprot 
|= VM_PROT_READ
; 
 504 #endif  /* radar 3777787 */ 
 506                 result 
= vm_map_enter_mem_object(user_map
, 
 507                                                  &user_addr
, user_size
, 
 509                                                  IPC_PORT_NULL
, 0, FALSE
, 
 511                                                  (flags 
& MAP_SHARED
) ? 
 514                 if (result 
!= KERN_SUCCESS
)  
 517                 pager 
= (vm_pager_t
)ubc_getpager(vp
); 
 527                  *      FIXME: if we're writing the file we need a way to 
 528                  *      ensure that someone doesn't replace our R/W creds 
 529                  *      with ones that only work for read. 
 532                 ubc_setthreadcred(vp
, p
, current_thread()); 
 534                 if ((flags 
& (MAP_ANON
|MAP_SHARED
)) == 0) { 
 540 #if defined(VM_PROT_READ_IS_EXEC) 
 541                 if (prot 
& VM_PROT_READ
) 
 542                         prot 
|= VM_PROT_EXECUTE
; 
 543                 if (maxprot 
& VM_PROT_READ
) 
 544                         maxprot 
|= VM_PROT_EXECUTE
; 
 549                 if (prot 
& (VM_PROT_EXECUTE 
| VM_PROT_WRITE
)) 
 550                         prot 
|= VM_PROT_READ
; 
 551                 if (maxprot 
& (VM_PROT_EXECUTE 
| VM_PROT_WRITE
)) 
 552                         maxprot 
|= VM_PROT_READ
; 
 553 #endif  /* radar 3777787 */ 
 555                 result 
= vm_map_enter_mem_object(user_map
, 
 556                                                  &user_addr
, user_size
, 
 558                                                  (ipc_port_t
)pager
, file_pos
, 
 559                                                  docow
, prot
, maxprot
,  
 560                                                  (flags 
& MAP_SHARED
) ? 
 564                 if (result 
!= KERN_SUCCESS
)  { 
 569                 file_prot 
= prot 
& (PROT_READ 
| PROT_WRITE 
| PROT_EXEC
); 
 571                         /* private mapping: won't write to the file */ 
 572                         file_prot 
&= ~PROT_WRITE
; 
 574                 (void) ubc_map(vp
, file_prot
); 
 583                 *retval 
= user_addr 
+ pageoff
; 
 586         case KERN_INVALID_ADDRESS
: 
 590         case KERN_PROTECTION_FAILURE
: 
 599                 fp_drop(p
, fd
, fp
, 0); 
 601         KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_SC_EXTENDED_INFO
, SYS_mmap
) | DBG_FUNC_NONE
), fd
, (uint32_t)(*retval
), (uint32_t)user_size
, error
, 0); 
 602         KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_SC_EXTENDED_INFO2
, SYS_mmap
) | DBG_FUNC_NONE
), (uint32_t)(*retval 
>> 32), (uint32_t)(user_size 
>> 32), 
 603                               (uint32_t)(file_pos 
>> 32), (uint32_t)file_pos
, 0); 
 609 msync(__unused proc_t p
, struct msync_args 
*uap
, register_t 
*retval
) 
 611         __pthread_testcancel(1); 
 612         return(msync_nocancel(p
, (struct msync_nocancel_args 
*)uap
, retval
)); 
 616 msync_nocancel(__unused proc_t p
, struct msync_nocancel_args 
*uap
, __unused register_t 
*retval
) 
 618         mach_vm_offset_t addr
; 
 623         vm_sync_t sync_flags
=0; 
 625         addr 
= (mach_vm_offset_t
) uap
->addr
; 
 626         size 
= (mach_vm_size_t
)uap
->len
; 
 628         KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_SC_EXTENDED_INFO
, SYS_msync
) | DBG_FUNC_NONE
), (uint32_t)(addr 
>> 32), (uint32_t)(size 
>> 32), 0, 0, 0); 
 630         if (addr 
& PAGE_MASK_64
) { 
 631                 /* UNIX SPEC: user address is not page-aligned, return EINVAL */ 
 636                  * We cannot support this properly without maintaining 
 637                  * list all mmaps done. Cannot use vm_map_entry as they could be 
 638                  * split or coalesced by indepenedant actions. So instead of  
 639                  * inaccurate results, lets just return error as invalid size 
 642                 return (EINVAL
); /* XXX breaks posix apps */ 
 646         /* disallow contradictory flags */ 
 647         if ((flags 
& (MS_SYNC
|MS_ASYNC
)) == (MS_SYNC
|MS_ASYNC
)) 
 650         if (flags 
& MS_KILLPAGES
) 
 651                 sync_flags 
|= VM_SYNC_KILLPAGES
; 
 652         if (flags 
& MS_DEACTIVATE
) 
 653                 sync_flags 
|= VM_SYNC_DEACTIVATE
; 
 654         if (flags 
& MS_INVALIDATE
) 
 655                 sync_flags 
|= VM_SYNC_INVALIDATE
; 
 657         if ( !(flags 
& (MS_KILLPAGES 
| MS_DEACTIVATE
))) { 
 658                 if (flags 
& MS_ASYNC
)  
 659                         sync_flags 
|= VM_SYNC_ASYNCHRONOUS
; 
 661                         sync_flags 
|= VM_SYNC_SYNCHRONOUS
; 
 664         sync_flags 
|= VM_SYNC_CONTIGUOUS
;       /* complain if holes */ 
 666         user_map 
= current_map(); 
 667         rv 
= mach_vm_msync(user_map
, addr
, size
, sync_flags
); 
 672         case KERN_INVALID_ADDRESS
:      /* hole in region being sync'ed */ 
 686         /* Not yet implemented */ 
 691 munmap(__unused proc_t p
, struct munmap_args 
*uap
, __unused register_t 
*retval
) 
 693         mach_vm_offset_t        user_addr
; 
 694         mach_vm_size_t  user_size
; 
 695         kern_return_t   result
; 
 697         user_addr 
= (mach_vm_offset_t
) uap
->addr
; 
 698         user_size 
= (mach_vm_size_t
) uap
->len
; 
 700         AUDIT_ARG(addr
, user_addr
); 
 701         AUDIT_ARG(len
, user_size
); 
 703         if (user_addr 
& PAGE_MASK_64
) { 
 704                 /* UNIX SPEC: user address is not page-aligned, return EINVAL */ 
 708         if (user_addr 
+ user_size 
< user_addr
) 
 711         if (user_size 
== 0) { 
 712                 /* UNIX SPEC: size is 0, return EINVAL */ 
 716         result 
= mach_vm_deallocate(current_map(), user_addr
, user_size
); 
 717         if (result 
!= KERN_SUCCESS
) { 
 724 mprotect(__unused proc_t p
, struct mprotect_args 
*uap
, __unused register_t 
*retval
) 
 726         register vm_prot_t prot
; 
 727         mach_vm_offset_t        user_addr
; 
 728         mach_vm_size_t  user_size
; 
 729         kern_return_t   result
; 
 735         AUDIT_ARG(addr
, uap
->addr
); 
 736         AUDIT_ARG(len
, uap
->len
); 
 737         AUDIT_ARG(value
, uap
->prot
); 
 739         user_addr 
= (mach_vm_offset_t
) uap
->addr
; 
 740         user_size 
= (mach_vm_size_t
) uap
->len
; 
 741         prot 
= (vm_prot_t
)(uap
->prot 
& VM_PROT_ALL
); 
 743         if (user_addr 
& PAGE_MASK_64
) { 
 744                 /* UNIX SPEC: user address is not page-aligned, return EINVAL */ 
 750 #if defined(VM_PROT_READ_IS_EXEC) 
 751         if (prot 
& VM_PROT_READ
) 
 752                 prot 
|= VM_PROT_EXECUTE
; 
 757         if (prot 
& (VM_PROT_EXECUTE 
| VM_PROT_WRITE
)) 
 758                 prot 
|= VM_PROT_READ
; 
 761         user_map 
= current_map(); 
 765          * The MAC check for mprotect is of limited use for 2 reasons: 
 766          * Without mmap revocation, the caller could have asked for the max 
 767          * protections initially instead of a reduced set, so a mprotect 
 768          * check would offer no new security. 
 769          * It is not possible to extract the vnode from the pager object(s) 
 770          * of the target memory range. 
 771          * However, the MAC check may be used to prevent a process from, 
 772          * e.g., making the stack executable. 
 774         error 
= mac_proc_check_mprotect(p
, user_addr
, 
 779         result 
= mach_vm_protect(user_map
, user_addr
, user_size
, 
 784         case KERN_PROTECTION_FAILURE
: 
 786         case KERN_INVALID_ADDRESS
: 
 787                 /* UNIX SPEC: for an invalid address range, return ENOMEM */ 
 795 minherit(__unused proc_t p
, struct minherit_args 
*uap
, __unused register_t 
*retval
) 
 797         mach_vm_offset_t addr
; 
 799         register vm_inherit_t inherit
; 
 801         kern_return_t   result
; 
 803         AUDIT_ARG(addr
, uap
->addr
); 
 804         AUDIT_ARG(len
, uap
->len
); 
 805         AUDIT_ARG(value
, uap
->inherit
); 
 807         addr 
= (mach_vm_offset_t
)uap
->addr
; 
 808         size 
= (mach_vm_size_t
)uap
->len
; 
 809         inherit 
= uap
->inherit
; 
 811         user_map 
= current_map(); 
 812         result 
= mach_vm_inherit(user_map
, addr
, size
, 
 817         case KERN_PROTECTION_FAILURE
: 
 824 madvise(__unused proc_t p
, struct madvise_args 
*uap
, __unused register_t 
*retval
) 
 827         mach_vm_offset_t start
; 
 829         vm_behavior_t new_behavior
; 
 830         kern_return_t   result
; 
 833          * Since this routine is only advisory, we default to conservative 
 836         switch (uap
->behav
) { 
 838                         new_behavior 
= VM_BEHAVIOR_RANDOM
; 
 840                 case MADV_SEQUENTIAL
:  
 841                         new_behavior 
= VM_BEHAVIOR_SEQUENTIAL
; 
 844                         new_behavior 
= VM_BEHAVIOR_DEFAULT
; 
 847                         new_behavior 
= VM_BEHAVIOR_WILLNEED
; 
 850                         new_behavior 
= VM_BEHAVIOR_DONTNEED
; 
 856         start 
= (mach_vm_offset_t
) uap
->addr
; 
 857         size 
= (mach_vm_size_t
) uap
->len
; 
 859         user_map 
= current_map(); 
 861         result 
= mach_vm_behavior_set(user_map
, start
, size
, new_behavior
); 
 865                 case KERN_INVALID_ADDRESS
: 
 873 mincore(__unused proc_t p
, struct mincore_args 
*uap
, __unused register_t 
*retval
) 
 875         mach_vm_offset_t addr
, first_addr
, end
; 
 879         int vecindex
, lastvecindex
; 
 890          * Make sure that the addresses presented are valid for user 
 893         first_addr 
= addr 
= mach_vm_trunc_page(uap
->addr
); 
 894         end 
= addr 
+ mach_vm_round_page(uap
->len
); 
 900          * Address of byte vector 
 907          * Do this on a map entry basis so that if the pages are not 
 908          * in the current processes address space, we can easily look 
 909          * up the pages elsewhere. 
 912         for( ; addr 
< end
; addr 
+= PAGE_SIZE 
) { 
 914                 ret 
= mach_vm_page_query(map
, addr
, &pqueryinfo
, &numref
); 
 915                 if (ret 
!= KERN_SUCCESS
)  
 918                 if (pqueryinfo 
& VM_PAGE_QUERY_PAGE_PRESENT
) 
 919                         mincoreinfo 
|= MINCORE_INCORE
; 
 920                 if (pqueryinfo 
& VM_PAGE_QUERY_PAGE_REF
) 
 921                         mincoreinfo 
|= MINCORE_REFERENCED
; 
 922                 if (pqueryinfo 
& VM_PAGE_QUERY_PAGE_DIRTY
) 
 923                         mincoreinfo 
|= MINCORE_MODIFIED
; 
 927                  * calculate index into user supplied byte vector 
 929                 vecindex 
= (addr 
- first_addr
)>> PAGE_SHIFT
; 
 932                  * If we have skipped map entries, we need to make sure that 
 933                  * the byte vector is zeroed for those skipped entries. 
 935                 while((lastvecindex 
+ 1) < vecindex
) { 
 937                         error 
= copyout(&c
, vec 
+ lastvecindex
, 1); 
 945                  * Pass the page information to the user 
 947                 c 
= (char)mincoreinfo
; 
 948                 error 
= copyout(&c
, vec 
+ vecindex
, 1); 
 952                 lastvecindex 
= vecindex
; 
 957          * Zero the last entries in the byte vector. 
 959         vecindex 
= (end 
- first_addr
) >> PAGE_SHIFT
; 
 960         while((lastvecindex 
+ 1) < vecindex
) { 
 962                 error 
= copyout(&c
, vec 
+ lastvecindex
, 1); 
 973 mlock(__unused proc_t p
, struct mlock_args 
*uap
, __unused register_t 
*retvalval
) 
 976         vm_map_offset_t addr
; 
 977         vm_map_size_t size
, pageoff
; 
 978         kern_return_t   result
; 
 980         AUDIT_ARG(addr
, uap
->addr
); 
 981         AUDIT_ARG(len
, uap
->len
); 
 983         addr 
= (vm_map_offset_t
) uap
->addr
; 
 984         size 
= (vm_map_size_t
)uap
->len
; 
 986         /* disable wrap around */ 
 987         if (addr 
+ size 
< addr
) 
 993         pageoff 
= (addr 
& PAGE_MASK
); 
 995         size 
= vm_map_round_page(size
+pageoff
); 
 996         user_map 
= current_map(); 
 998         /* have to call vm_map_wire directly to pass "I don't know" protections */ 
 999         result 
= vm_map_wire(user_map
, addr
, addr
+size
, VM_PROT_NONE
, TRUE
); 
1001         if (result 
== KERN_RESOURCE_SHORTAGE
) 
1003         else if (result 
!= KERN_SUCCESS
) 
1006         return 0;       /* KERN_SUCCESS */ 
1010 munlock(__unused proc_t p
, struct munlock_args 
*uap
, __unused register_t 
*retval
) 
1012         mach_vm_offset_t addr
; 
1013         mach_vm_size_t size
; 
1015         kern_return_t   result
; 
1017         AUDIT_ARG(addr
, uap
->addr
); 
1018         AUDIT_ARG(addr
, uap
->len
); 
1020         addr 
= (mach_vm_offset_t
) uap
->addr
; 
1021         size 
= (mach_vm_size_t
)uap
->len
; 
1022         user_map 
= current_map(); 
1024         /* JMM - need to remove all wirings by spec - this just removes one */ 
1025         result 
= mach_vm_wire(host_priv_self(), user_map
, addr
, size
, VM_PROT_NONE
); 
1026         return (result 
== KERN_SUCCESS 
? 0 : ENOMEM
); 
1031 mlockall(__unused proc_t p
, __unused 
struct mlockall_args 
*uap
, __unused register_t 
*retval
) 
1037 munlockall(__unused proc_t p
, __unused 
struct munlockall_args 
*uap
, __unused register_t 
*retval
) 
1045 obreak(__unused proc_t p
, __unused 
struct obreak_args 
*uap
, __unused register_t 
*retval
) 
1047         /* Not implemented, obsolete */ 
1054 ovadvise(__unused proc_t p
, __unused 
struct ovadvise_args 
*uap
, __unused register_t 
*retval
) 
1064 /* USV: No! need to obsolete map_fd()! mmap() already supports 64 bits */ 
1066 map_fd(struct map_fd_args 
*args
) 
1069         vm_offset_t     offset 
= args
->offset
; 
1070         vm_offset_t     
*va 
= args
->va
; 
1071         boolean_t       findspace 
= args
->findspace
; 
1072         vm_size_t       size 
= args
->size
; 
1075         AUDIT_MACH_SYSCALL_ENTER(AUE_MAPFD
); 
1076         AUDIT_ARG(addr
, CAST_DOWN(user_addr_t
, va
)); 
1079         ret 
= map_fd_funneled( fd
, (vm_object_offset_t
)offset
, va
, findspace
, size
); 
1081         AUDIT_MACH_SYSCALL_EXIT(ret
); 
1088         vm_object_offset_t      offset
, 
1090         boolean_t               findspace
, 
1093         kern_return_t   result
; 
1094         struct fileproc 
*fp
; 
1097         vm_offset_t     map_addr
=0; 
1101         proc_t          p 
= current_proc(); 
1102         struct vnode_attr vattr
; 
1105          *      Find the inode; verify that it's a regular file. 
1108         err 
= fp_lookup(p
, fd
, &fp
, 0); 
1112         if (fp
->f_fglob
->fg_type 
!= DTYPE_VNODE
){ 
1113                 err 
= KERN_INVALID_ARGUMENT
; 
1117         if (!(fp
->f_fglob
->fg_flag 
& FREAD
)) { 
1118                 err 
= KERN_PROTECTION_FAILURE
; 
1122         vp 
= (struct vnode 
*)fp
->f_fglob
->fg_data
; 
1123         err 
= vnode_getwithref(vp
); 
1127         if (vp
->v_type 
!= VREG
) { 
1128                 (void)vnode_put(vp
); 
1129                 err 
= KERN_INVALID_ARGUMENT
; 
1133         AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
); 
1136          * POSIX: mmap needs to update access time for mapped files 
1138         if ((vnode_vfsvisflags(vp
) & MNT_NOATIME
) == 0) { 
1140                 nanotime(&vattr
.va_access_time
); 
1141                 VATTR_SET_ACTIVE(&vattr
, va_access_time
); 
1142                 vnode_setattr(vp
, &vattr
, vfs_context_current()); 
1145         if (offset 
& PAGE_MASK_64
) { 
1146                 printf("map_fd: file offset not page aligned(%d : %s)\n",p
->p_pid
, p
->p_comm
); 
1147                 (void)vnode_put(vp
); 
1148                 err 
= KERN_INVALID_ARGUMENT
; 
1151         map_size 
= round_page(size
); 
1154          * Allow user to map in a zero length file. 
1157                 (void)vnode_put(vp
); 
1164         pager 
= (void *)ubc_getpager(vp
); 
1165         if (pager 
== NULL
) { 
1166                 (void)vnode_put(vp
); 
1172         my_map 
= current_map(); 
1176                         &map_addr
, map_size
, (vm_offset_t
)0,  
1177                         VM_FLAGS_ANYWHERE
, pager
, offset
, TRUE
, 
1178                         VM_PROT_DEFAULT
, VM_PROT_ALL
, 
1179                         VM_INHERIT_DEFAULT
); 
1180         if (result 
!= KERN_SUCCESS
) { 
1181                 (void)vnode_put(vp
); 
1188                 vm_offset_t     dst_addr
; 
1191                 if (copyin(CAST_USER_ADDR_T(va
), &dst_addr
, sizeof (dst_addr
))  || 
1192                                         trunc_page_32(dst_addr
) != dst_addr
) { 
1193                         (void) vm_map_remove( 
1195                                         map_addr
, map_addr 
+ map_size
, 
1197                         (void)vnode_put(vp
); 
1198                         err 
= KERN_INVALID_ADDRESS
; 
1202                 result 
= vm_map_copyin(my_map
, (vm_map_address_t
)map_addr
, 
1203                                        (vm_map_size_t
)map_size
, TRUE
, &tmp
); 
1204                 if (result 
!= KERN_SUCCESS
) { 
1206                         (void) vm_map_remove(my_map
, vm_map_trunc_page(map_addr
), 
1207                                         vm_map_round_page(map_addr 
+ map_size
), 
1209                         (void)vnode_put(vp
); 
1214                 result 
= vm_map_copy_overwrite(my_map
, 
1215                                         (vm_map_address_t
)dst_addr
, tmp
, FALSE
); 
1216                 if (result 
!= KERN_SUCCESS
) { 
1217                         vm_map_copy_discard(tmp
); 
1218                         (void)vnode_put(vp
); 
1223                 if (copyout(&map_addr
, CAST_USER_ADDR_T(va
), sizeof (map_addr
))) { 
1224                         (void) vm_map_remove(my_map
, vm_map_trunc_page(map_addr
), 
1225                                         vm_map_round_page(map_addr 
+ map_size
), 
1227                         (void)vnode_put(vp
); 
1228                         err 
= KERN_INVALID_ADDRESS
; 
1233         ubc_setthreadcred(vp
, current_proc(), current_thread()); 
1234         (void)ubc_map(vp
, (PROT_READ 
| PROT_EXEC
)); 
1235         (void)vnode_put(vp
); 
1238         fp_drop(p
, fd
, fp
, 0);