darwin-xnu/bsd/kern/kern_mman.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22/*
  23 * Copyright (c) 1988 University of Utah.
  24 * Copyright (c) 1991, 1993
  25 *      The Regents of the University of California.  All rights reserved.
  26 *
  27 * This code is derived from software contributed to Berkeley by
  28 * the Systems Programming Group of the University of Utah Computer
  29 * Science Department.
  30 *
  31 * Redistribution and use in source and binary forms, with or without
  32 * modification, are permitted provided that the following conditions
  33 * are met:
  34 * 1. Redistributions of source code must retain the above copyright
  35 *    notice, this list of conditions and the following disclaimer.
  36 * 2. Redistributions in binary form must reproduce the above copyright
  37 *    notice, this list of conditions and the following disclaimer in the
  38 *    documentation and/or other materials provided with the distribution.
  39 * 3. All advertising materials mentioning features or use of this software
  40 *    must display the following acknowledgement:
  41 *      This product includes software developed by the University of
  42 *      California, Berkeley and its contributors.
  43 * 4. Neither the name of the University nor the names of its contributors
  44 *    may be used to endorse or promote products derived from this software
  45 *    without specific prior written permission.
  46 *
  47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  50 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  57 * SUCH DAMAGE.
  58 *
  59 * from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$
  60 *
  61 *      @(#)vm_mmap.c   8.10 (Berkeley) 2/19/95
  62 */
  63
  64/*
  65 * Mapped file (mmap) interface to VM
  66 */
  67
  68#include <sys/param.h>
  69#include <sys/systm.h>
  70#include <sys/filedesc.h>
  71#include <sys/proc_internal.h>
  72#include <sys/kauth.h>
  73#include <sys/resourcevar.h>
  74#include <sys/vnode_internal.h>
  75#include <sys/acct.h>
  76#include <sys/wait.h>
  77#include <sys/file_internal.h>
  78#include <sys/vadvise.h>
  79#include <sys/trace.h>
  80#include <sys/mman.h>
  81#include <sys/conf.h>
  82#include <sys/stat.h>
  83#include <sys/ubc.h>
  84#include <sys/sysproto.h>
  85
  86#include <bsm/audit_kernel.h>
  87#include <bsm/audit_kevents.h>
  88
  89#include <mach/mach_types.h>
  90#include <mach/mach_traps.h>
  91#include <mach/vm_sync.h>
  92#include <mach/vm_behavior.h>
  93#include <mach/vm_inherit.h>
  94#include <mach/vm_statistics.h>
  95#include <mach/mach_vm.h>
  96#include <mach/vm_map.h>
  97#include <mach/host_priv.h>
  98
  99#include <kern/cpu_number.h>
 100#include <kern/host.h>
 101
 102#include <vm/vm_map.h>
 103#include <vm/vm_kern.h>
 104#include <vm/vm_pager.h>
 105
 106int
 107sbrk(__unused struct proc *p, __unused struct sbrk_args *uap, __unused register_t *retval)
 108{
 109        /* Not yet implemented */
 110        return (ENOTSUP);
 111}
 112
 113int
 114sstk(__unused struct proc *p, __unused struct sstk_args *uap, __unused register_t *retval)
 115{
 116        /* Not yet implemented */
 117        return (ENOTSUP);
 118}
 119
 120
 121struct osmmap_args {
 122                caddr_t addr;
 123                int     len;
 124                int     prot;
 125                int     share;
 126                int     fd;
 127                long    pos;
 128};
 129
 130int
 131osmmap(
 132        struct proc *curp,
 133        register struct osmmap_args *uap,
 134        register_t *retval)
 135{
 136        struct mmap_args newargs;
 137        user_addr_t addr;
 138        int ret;
 139
 140        if ((uap->share ==  MAP_SHARED )|| (uap->share ==  MAP_PRIVATE )) {
 141                newargs.addr = CAST_USER_ADDR_T(uap->addr);
 142                newargs.len = CAST_USER_ADDR_T(uap->len);
 143                newargs.prot = uap->prot;
 144                newargs.flags = uap->share;
 145                newargs.fd = uap->fd;
 146                newargs.pos = (off_t)uap->pos;
 147                ret = mmap(curp, &newargs, &addr);
 148                if (ret == 0)
 149                        *retval = CAST_DOWN(register_t, addr);
 150        } else
 151                ret = EINVAL;
 152        return ret;
 153}
 154
 155
 156int
 157mmap(struct proc *p, struct mmap_args *uap, user_addr_t *retval)
 158{
 159        /*
 160         *      Map in special device (must be SHARED) or file
 161         */
 162        struct fileproc *fp;
 163        register struct         vnode *vp;
 164        int                     flags;
 165        int                     prot;
 166        int                     err=0;
 167        vm_map_t                user_map;
 168        kern_return_t           result;
 169        mach_vm_offset_t        user_addr;
 170        mach_vm_size_t          user_size;
 171        vm_object_offset_t      pageoff;
 172        vm_object_offset_t      file_pos;
 173        int                     alloc_flags;
 174        boolean_t               docow;
 175        vm_prot_t               maxprot;
 176        void                    *handle;
 177        vm_pager_t              pager;
 178        int                     mapanon=0;
 179        int                     fpref=0;
 180        int error =0;
 181        int fd = uap->fd;
 182
 183        user_addr = (mach_vm_offset_t)uap->addr;
 184        user_size = (mach_vm_size_t) uap->len;
 185
 186        AUDIT_ARG(addr, user_addr);
 187        AUDIT_ARG(len, user_size);
 188        AUDIT_ARG(fd, uap->fd);
 189
 190        prot = (uap->prot & VM_PROT_ALL);
 191        flags = uap->flags;
 192        vp = NULLVP;
 193
 194        /*
 195         * The vm code does not have prototypes & compiler doesn't do the'
 196         * the right thing when you cast 64bit value and pass it in function 
 197         * call. So here it is.
 198         */
 199        file_pos = (vm_object_offset_t)uap->pos;
 200
 201
 202        /* make sure mapping fits into numeric range etc */
 203        if ((file_pos + user_size > (vm_object_offset_t)-PAGE_SIZE_64) ||
 204            ((flags & MAP_ANON) && fd != -1))
 205                return (EINVAL);
 206
 207        /*
 208         * Align the file position to a page boundary,
 209         * and save its page offset component.
 210         */
 211        pageoff = (file_pos & PAGE_MASK);
 212        file_pos -= (vm_object_offset_t)pageoff;
 213
 214
 215        /* Adjust size for rounding (on both ends). */
 216        user_size += pageoff;                   /* low end... */
 217        user_size = mach_vm_round_page(user_size);      /* hi end */
 218
 219
 220        /*
 221         * Check for illegal addresses.  Watch out for address wrap... Note
 222         * that VM_*_ADDRESS are not constants due to casts (argh).
 223         */
 224        if (flags & MAP_FIXED) {
 225                /*
 226                 * The specified address must have the same remainder
 227                 * as the file offset taken modulo PAGE_SIZE, so it
 228                 * should be aligned after adjustment by pageoff.
 229                 */
 230                user_addr -= pageoff;
 231                if (user_addr & PAGE_MASK)
 232                        return (EINVAL);
 233        }
 234#ifdef notyet
 235        /* DO not have apis to get this info, need to wait till then*/
 236        /*
 237         * XXX for non-fixed mappings where no hint is provided or
 238         * the hint would fall in the potential heap space,
 239         * place it after the end of the largest possible heap.
 240         *
 241         * There should really be a pmap call to determine a reasonable
 242         * location.
 243         */
 244        else if (addr < mach_vm_round_page(p->p_vmspace->vm_daddr + MAXDSIZ))
 245                addr = mach_vm_round_page(p->p_vmspace->vm_daddr + MAXDSIZ);
 246
 247#endif
 248
 249
 250        if (flags & MAP_ANON) {
 251                /*
 252                 * Mapping blank space is trivial.
 253                 */
 254                handle = NULL;
 255                maxprot = VM_PROT_ALL;
 256                file_pos = 0;
 257                mapanon = 1;
 258        } else {
 259                struct vnode_attr va;
 260                struct vfs_context context;
 261                /*
 262                 * Mapping file, get fp for validation. Obtain vnode and make
 263                 * sure it is of appropriate type.
 264                 */
 265                err = fp_lookup(p, fd, &fp, 0);
 266                if (err)
 267                        return(err);
 268                fpref = 1;
 269                if(fp->f_fglob->fg_type == DTYPE_PSXSHM) {
 270                        uap->addr = (user_addr_t)user_addr;
 271                        uap->len = (user_size_t)user_size;
 272                        uap->prot = prot;
 273                        uap->flags = flags;
 274                        uap->pos = file_pos;
 275                        error = pshm_mmap(p, uap, retval, fp, (off_t)pageoff);
 276                        goto bad;
 277                }
 278
 279                if (fp->f_fglob->fg_type != DTYPE_VNODE) {
 280                        error = EINVAL;
 281                        goto bad;
 282                }
 283                vp = (struct vnode *)fp->f_fglob->fg_data;
 284                error = vnode_getwithref(vp);
 285                if(error != 0)
 286                        goto bad;
 287
 288                if (vp->v_type != VREG && vp->v_type != VCHR) {
 289                        (void)vnode_put(vp);
 290                        error = EINVAL;
 291                        goto bad;
 292                }
 293
 294                AUDIT_ARG(vnpath, vp, ARG_VNODE1);
 295                
 296                /* conformance change - mmap needs to update access time for mapped
 297                 * files
 298                 */
 299                VATTR_INIT(&va);
 300                nanotime(&va.va_access_time);
 301                VATTR_SET_ACTIVE(&va, va_access_time);
 302                context.vc_proc = p;
 303                context.vc_ucred = kauth_cred_get();
 304                vnode_setattr(vp, &va, &context);
 305
 306                /*
 307                 * XXX hack to handle use of /dev/zero to map anon memory (ala
 308                 * SunOS).
 309                 */
 310                if (vp->v_type == VCHR || vp->v_type == VSTR) {
 311                        (void)vnode_put(vp);
 312                        error = ENODEV;
 313                        goto bad;
 314                } else {
 315                        /*
 316                         * Ensure that file and memory protections are
 317                         * compatible.  Note that we only worry about
 318                         * writability if mapping is shared; in this case,
 319                         * current and max prot are dictated by the open file.
 320                         * XXX use the vnode instead?  Problem is: what
 321                         * credentials do we use for determination? What if
 322                         * proc does a setuid?
 323                         */
 324                        maxprot = VM_PROT_EXECUTE;      /* ??? */
 325                        if (fp->f_fglob->fg_flag & FREAD)
 326                                maxprot |= VM_PROT_READ;
 327                        else if (prot & PROT_READ) {
 328                                (void)vnode_put(vp);
 329                                error = EACCES;
 330                                goto bad;
 331                        }
 332                        /*
 333                         * If we are sharing potential changes (either via
 334                         * MAP_SHARED or via the implicit sharing of character
 335                         * device mappings), and we are trying to get write
 336                         * permission although we opened it without asking
 337                         * for it, bail out. 
 338                         */
 339
 340                        if ((flags & MAP_SHARED) != 0) {
 341                                if ((fp->f_fglob->fg_flag & FWRITE) != 0) {
 342                                        /*
 343                                         * check for write access
 344                                         *
 345                                         * Note that we already made this check when granting FWRITE
 346                                         * against the file, so it seems redundant here.
 347                                         */
 348                                        error = vnode_authorize(vp, NULL, KAUTH_VNODE_CHECKIMMUTABLE, &context);
 349 
 350                                        /* if not granted for any reason, but we wanted it, bad */
 351                                        if ((prot & PROT_WRITE) && (error != 0)) {
 352                                                vnode_put(vp);
 353                                                goto bad;
 354                                        }
 355 
 356                                        /* if writable, remember */
 357                                        if (error == 0)
 358                                                maxprot |= VM_PROT_WRITE;
 359
 360                                } else if ((prot & PROT_WRITE) != 0) {
 361                                        (void)vnode_put(vp);
 362                                        error = EACCES;
 363                                        goto bad;
 364                                }
 365                        } else
 366                                maxprot |= VM_PROT_WRITE;
 367
 368                        handle = (void *)vp;
 369                }
 370        }
 371
 372        if (user_size == 0)  {
 373                if (!mapanon)
 374                        (void)vnode_put(vp);
 375                error = 0;
 376                goto bad;
 377        }
 378
 379        /*
 380         *      We bend a little - round the start and end addresses
 381         *      to the nearest page boundary.
 382         */
 383        user_size = mach_vm_round_page(user_size);
 384
 385        if (file_pos & PAGE_MASK_64) {
 386                if (!mapanon)
 387                        (void)vnode_put(vp);
 388                error = EINVAL;
 389                goto bad;
 390        }
 391
 392        user_map = current_map();
 393
 394        if ((flags & MAP_FIXED) == 0) {
 395                alloc_flags = VM_FLAGS_ANYWHERE;
 396                user_addr = mach_vm_round_page(user_addr);
 397        } else {
 398                if (user_addr != mach_vm_trunc_page(user_addr)) {
 399                        if (!mapanon)
 400                                (void)vnode_put(vp);
 401                        error = EINVAL;
 402                        goto bad;
 403                }
 404                /*
 405                 * mmap(MAP_FIXED) will replace any existing mappings in the
 406                 * specified range, if the new mapping is successful.
 407                 * If we just deallocate the specified address range here,
 408                 * another thread might jump in and allocate memory in that
 409                 * range before we get a chance to establish the new mapping,
 410                 * and we won't have a chance to restore the old mappings.
 411                 * So we use VM_FLAGS_OVERWRITE to let Mach VM know that it
 412                 * has to deallocate the existing mappings and establish the
 413                 * new ones atomically.
 414                 */
 415                alloc_flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
 416        }
 417
 418
 419        /*
 420         * Lookup/allocate object.
 421         */
 422        if (handle == NULL) {
 423                pager = NULL;
 424#ifdef notyet
 425/* Hmm .. */
 426#if defined(VM_PROT_READ_IS_EXEC)
 427                if (prot & VM_PROT_READ)
 428                        prot |= VM_PROT_EXECUTE;
 429
 430                if (maxprot & VM_PROT_READ)
 431                        maxprot |= VM_PROT_EXECUTE;
 432#endif
 433#endif
 434                result = mach_vm_map(user_map, &user_addr, user_size, 0,
 435                                alloc_flags, IPC_PORT_NULL, 0,
 436                                FALSE, prot, maxprot,
 437                                (flags & MAP_SHARED) ? VM_INHERIT_SHARE : 
 438                                                       VM_INHERIT_DEFAULT);
 439                if (result != KERN_SUCCESS) 
 440                                goto out;
 441        } else {
 442                UBCINFOCHECK("mmap", vp);
 443                pager = (vm_pager_t)ubc_getpager(vp);
 444                
 445                if (pager == NULL) {
 446                        (void)vnode_put(vp);
 447                        error = ENOMEM;
 448                        goto bad;
 449                }
 450
 451                /*
 452                 *  Set credentials:
 453                 *      FIXME: if we're writing the file we need a way to
 454                 *      ensure that someone doesn't replace our R/W creds
 455                 *      with ones that only work for read.
 456                 */
 457
 458                ubc_setthreadcred(vp, p, current_thread());
 459                docow = FALSE;
 460                if ((flags & (MAP_ANON|MAP_SHARED)) == 0) {
 461                        docow = TRUE;
 462                }
 463
 464#ifdef notyet
 465/* Hmm .. */
 466#if defined(VM_PROT_READ_IS_EXEC)
 467                if (prot & VM_PROT_READ)
 468                        prot |= VM_PROT_EXECUTE;
 469
 470                if (maxprot & VM_PROT_READ)
 471                        maxprot |= VM_PROT_EXECUTE;
 472#endif
 473#endif /* notyet */
 474
 475                result = mach_vm_map(user_map, &user_addr, user_size,
 476                                0, alloc_flags, (ipc_port_t)pager, file_pos,
 477                                docow, prot, maxprot, 
 478                                (flags & MAP_SHARED) ? VM_INHERIT_SHARE : 
 479                                                       VM_INHERIT_DEFAULT);
 480
 481                if (result != KERN_SUCCESS)  {
 482                                (void)vnode_put(vp);
 483                                goto out;
 484                }
 485
 486                (void)ubc_map(vp,(prot & ( PROT_EXEC | PROT_READ | PROT_WRITE | PROT_EXEC)));
 487        }
 488
 489        if (!mapanon)
 490                (void)vnode_put(vp);
 491
 492out:
 493        switch (result) {
 494        case KERN_SUCCESS:
 495                *retval = user_addr + pageoff;
 496                error = 0;
 497                break;
 498        case KERN_INVALID_ADDRESS:
 499        case KERN_NO_SPACE:
 500                error =  ENOMEM;
 501                break;
 502        case KERN_PROTECTION_FAILURE:
 503                error =  EACCES;
 504                break;
 505        default:
 506                error =  EINVAL;
 507                break;
 508        }
 509bad:
 510        if (fpref)
 511                fp_drop(p, fd, fp, 0);
 512        return(error);
 513}
 514
 515int
 516msync(__unused struct proc *p, struct msync_args *uap, __unused register_t *retval)
 517{
 518        mach_vm_offset_t addr;
 519        mach_vm_size_t size;
 520        int flags;
 521        vm_map_t user_map;
 522        int rv;
 523        vm_sync_t sync_flags=0;
 524
 525        addr = (mach_vm_offset_t) uap->addr;
 526        size = (mach_vm_size_t)uap->len;
 527
 528        if (addr & PAGE_MASK_64) {
 529                /* UNIX SPEC: user address is not page-aligned, return EINVAL */
 530                return EINVAL;
 531        }
 532        if (size == 0) {
 533                /*
 534                 * We cannot support this properly without maintaining
 535                 * list all mmaps done. Cannot use vm_map_entry as they could be
 536                 * split or coalesced by indepenedant actions. So instead of 
 537                 * inaccurate results, lets just return error as invalid size
 538                 * specified
 539                 */
 540                return (EINVAL); /* XXX breaks posix apps */
 541        }
 542
 543        flags = uap->flags;
 544        /* disallow contradictory flags */
 545        if ((flags & (MS_SYNC|MS_ASYNC)) == (MS_SYNC|MS_ASYNC) ||
 546            (flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE))
 547                return (EINVAL);
 548
 549        if (flags & MS_KILLPAGES)
 550                sync_flags |= VM_SYNC_KILLPAGES;
 551        if (flags & MS_DEACTIVATE)
 552                sync_flags |= VM_SYNC_DEACTIVATE;
 553        if (flags & MS_INVALIDATE)
 554                sync_flags |= VM_SYNC_INVALIDATE;
 555
 556        if ( !(flags & (MS_KILLPAGES | MS_DEACTIVATE))) {
 557                if (flags & MS_ASYNC) 
 558                        sync_flags |= VM_SYNC_ASYNCHRONOUS;
 559                else 
 560                        sync_flags |= VM_SYNC_SYNCHRONOUS;
 561        }
 562
 563        sync_flags |= VM_SYNC_CONTIGUOUS;       /* complain if holes */
 564
 565        user_map = current_map();
 566        rv = mach_vm_msync(user_map, addr, size, sync_flags);
 567
 568        switch (rv) {
 569        case KERN_SUCCESS:
 570                break;
 571        case KERN_INVALID_ADDRESS:      /* hole in region being sync'ed */
 572                return (ENOMEM);
 573        case KERN_FAILURE:
 574                return (EIO);
 575        default:
 576                return (EINVAL);
 577        }
 578        return (0);
 579}
 580
 581
 582int
 583mremap(void)
 584{
 585        /* Not yet implemented */
 586        return (ENOTSUP);
 587}
 588
 589int
 590munmap(__unused struct proc *p, struct munmap_args *uap, __unused register_t *retval)
 591{
 592        mach_vm_offset_t        user_addr;
 593        mach_vm_size_t  user_size;
 594        kern_return_t   result;
 595
 596        user_addr = (mach_vm_offset_t) uap->addr;
 597        user_size = (mach_vm_size_t) uap->len;
 598
 599        AUDIT_ARG(addr, user_addr);
 600        AUDIT_ARG(len, user_size);
 601
 602        if (user_addr & PAGE_MASK_64) {
 603                /* UNIX SPEC: user address is not page-aligned, return EINVAL */
 604                return EINVAL;
 605        }
 606
 607        if (user_addr + user_size < user_addr)
 608                return(EINVAL);
 609
 610        if (user_size == 0) {
 611                /* UNIX SPEC: size is 0, return EINVAL */
 612                return EINVAL;
 613        }
 614
 615        result = mach_vm_deallocate(current_map(), user_addr, user_size);
 616        if (result != KERN_SUCCESS) {
 617                return(EINVAL);
 618        }
 619        return(0);
 620}
 621
 622int
 623mprotect(__unused struct proc *p, struct mprotect_args *uap, __unused register_t *retval)
 624{
 625        register vm_prot_t prot;
 626        mach_vm_offset_t        user_addr;
 627        mach_vm_size_t  user_size;
 628        kern_return_t   result;
 629        vm_map_t        user_map;
 630
 631        AUDIT_ARG(addr, uap->addr);
 632        AUDIT_ARG(len, uap->len);
 633        AUDIT_ARG(value, uap->prot);
 634
 635        user_addr = (mach_vm_offset_t) uap->addr;
 636        user_size = (mach_vm_size_t) uap->len;
 637        prot = (vm_prot_t)(uap->prot & VM_PROT_ALL);
 638
 639        if (user_addr & PAGE_MASK_64) {
 640                /* UNIX SPEC: user address is not page-aligned, return EINVAL */
 641                return EINVAL;
 642        }
 643                
 644#ifdef notyet
 645/* Hmm .. */
 646#if defined(VM_PROT_READ_IS_EXEC)
 647        if (prot & VM_PROT_READ)
 648                prot |= VM_PROT_EXECUTE;
 649#endif
 650#endif /* notyet */
 651
 652        user_map = current_map();
 653
 654        result = mach_vm_protect(user_map, user_addr, user_size,
 655                                 FALSE, prot);
 656        switch (result) {
 657        case KERN_SUCCESS:
 658                return (0);
 659        case KERN_PROTECTION_FAILURE:
 660                return (EACCES);
 661        case KERN_INVALID_ADDRESS:
 662                /* UNIX SPEC: for an invalid address range, return ENOMEM */
 663                return ENOMEM;
 664        }
 665        return (EINVAL);
 666}
 667
 668
 669int
 670minherit(__unused struct proc *p, struct minherit_args *uap, __unused register_t *retval)
 671{
 672        mach_vm_offset_t addr;
 673        mach_vm_size_t size;
 674        register vm_inherit_t inherit;
 675        vm_map_t        user_map;
 676        kern_return_t   result;
 677
 678        AUDIT_ARG(addr, uap->addr);
 679        AUDIT_ARG(len, uap->len);
 680        AUDIT_ARG(value, uap->inherit);
 681
 682        addr = (mach_vm_offset_t)uap->addr;
 683        size = (mach_vm_size_t)uap->len;
 684        inherit = uap->inherit;
 685
 686        user_map = current_map();
 687        result = mach_vm_inherit(user_map, addr, size,
 688                                inherit);
 689        switch (result) {
 690        case KERN_SUCCESS:
 691                return (0);
 692        case KERN_PROTECTION_FAILURE:
 693                return (EACCES);
 694        }
 695        return (EINVAL);
 696}
 697
 698int
 699madvise(__unused struct proc *p, struct madvise_args *uap, __unused register_t *retval)
 700{
 701        vm_map_t user_map;
 702        mach_vm_offset_t start;
 703        mach_vm_size_t size;
 704        vm_behavior_t new_behavior;
 705        kern_return_t   result;
 706
 707        /*
 708         * Since this routine is only advisory, we default to conservative
 709         * behavior.
 710         */
 711        switch (uap->behav) {
 712                case MADV_RANDOM:
 713                        new_behavior = VM_BEHAVIOR_RANDOM;
 714                        break;
 715                case MADV_SEQUENTIAL: 
 716                        new_behavior = VM_BEHAVIOR_SEQUENTIAL;
 717                        break;
 718                case MADV_NORMAL:
 719                        new_behavior = VM_BEHAVIOR_DEFAULT;
 720                        break;
 721                case MADV_WILLNEED:
 722                        new_behavior = VM_BEHAVIOR_WILLNEED;
 723                        break;
 724                case MADV_DONTNEED:
 725                        new_behavior = VM_BEHAVIOR_DONTNEED;
 726                        break;
 727                default:
 728                        return(EINVAL);
 729        }
 730
 731        start = (mach_vm_offset_t) uap->addr;
 732        size = (mach_vm_size_t) uap->len;
 733        
 734        user_map = current_map();
 735
 736        result = mach_vm_behavior_set(user_map, start, size, new_behavior);
 737        switch (result) {
 738                case KERN_SUCCESS:
 739                        return (0);
 740                case KERN_INVALID_ADDRESS:
 741                        return (ENOMEM);
 742        }
 743
 744        return (EINVAL);
 745}
 746
 747int
 748mincore(__unused struct proc *p, struct mincore_args *uap, __unused register_t *retval)
 749{
 750        mach_vm_offset_t addr, first_addr, end;
 751        vm_map_t map;
 752        user_addr_t vec;
 753        int error;
 754        int vecindex, lastvecindex;
 755        int mincoreinfo=0;
 756        int pqueryinfo;
 757        kern_return_t   ret;
 758        int numref;
 759
 760        char c;
 761
 762        map = current_map();
 763
 764        /*
 765         * Make sure that the addresses presented are valid for user
 766         * mode.
 767         */
 768        first_addr = addr = mach_vm_trunc_page(uap->addr);
 769        end = addr + mach_vm_round_page(uap->len);
 770
 771        if (end < addr)
 772                return (EINVAL);
 773
 774        /*
 775         * Address of byte vector
 776         */
 777        vec = uap->vec;
 778
 779        map = current_map();
 780
 781        /*
 782         * Do this on a map entry basis so that if the pages are not
 783         * in the current processes address space, we can easily look
 784         * up the pages elsewhere.
 785         */
 786        lastvecindex = -1;
 787        for( ; addr < end; addr += PAGE_SIZE ) {
 788                pqueryinfo = 0;
 789                ret = vm_map_page_query(map, addr, &pqueryinfo, &numref);
 790                if (ret != KERN_SUCCESS) 
 791                        pqueryinfo = 0;
 792                mincoreinfo = 0;
 793                if (pqueryinfo & VM_PAGE_QUERY_PAGE_PRESENT)
 794                        mincoreinfo |= MINCORE_INCORE;
 795                if (pqueryinfo & VM_PAGE_QUERY_PAGE_REF)
 796                        mincoreinfo |= MINCORE_REFERENCED;
 797                if (pqueryinfo & VM_PAGE_QUERY_PAGE_DIRTY)
 798                        mincoreinfo |= MINCORE_MODIFIED;
 799                
 800                
 801                /*
 802                 * calculate index into user supplied byte vector
 803                 */
 804                vecindex = (addr - first_addr)>> PAGE_SHIFT;
 805
 806                /*
 807                 * If we have skipped map entries, we need to make sure that
 808                 * the byte vector is zeroed for those skipped entries.
 809                 */
 810                while((lastvecindex + 1) < vecindex) {
 811                        c = 0;
 812                        error = copyout(&c, vec + lastvecindex, 1);
 813                        if (error) {
 814                                return (EFAULT);
 815                        }
 816                        ++lastvecindex;
 817                }
 818
 819                /*
 820                 * Pass the page information to the user
 821                 */
 822                c = (char)mincoreinfo;
 823                error = copyout(&c, vec + vecindex, 1);
 824                if (error) {
 825                        return (EFAULT);
 826                }
 827                lastvecindex = vecindex;
 828        }
 829
 830
 831        /*
 832         * Zero the last entries in the byte vector.
 833         */
 834        vecindex = (end - first_addr) >> PAGE_SHIFT;
 835        while((lastvecindex + 1) < vecindex) {
 836                c = 0;
 837                error = copyout(&c, vec + lastvecindex, 1);
 838                if (error) {
 839                        return (EFAULT);
 840                }
 841                ++lastvecindex;
 842        }
 843        
 844        return (0);
 845}
 846
 847int
 848mlock(__unused struct proc *p, struct mlock_args *uap, __unused register_t *retvalval)
 849{
 850        vm_map_t user_map;
 851        vm_map_offset_t addr;
 852        vm_map_size_t size, pageoff;
 853        kern_return_t   result;
 854
 855        AUDIT_ARG(addr, uap->addr);
 856        AUDIT_ARG(len, uap->len);
 857
 858        addr = (vm_map_offset_t) uap->addr;
 859        size = (vm_map_size_t)uap->len;
 860
 861        /* disable wrap around */
 862        if (addr + size < addr)
 863                return (EINVAL);
 864
 865        if (size == 0)
 866                return (0);
 867
 868        pageoff = (addr & PAGE_MASK);
 869        addr -= pageoff;
 870        size = vm_map_round_page(size+pageoff);
 871
 872#ifdef notyet 
 873/* Hmm.. What am I going to do with this? */
 874        if (atop(size) + cnt.v_wire_count > vm_page_max_wired)
 875                return (EAGAIN);
 876#ifdef pmap_wired_count
 877        if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) >
 878            p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur)
 879                return (ENOMEM);
 880#else
 881        error = suser(kauth_cred_get(), &p->p_acflag);
 882        if (error)
 883                return (error);
 884#endif
 885#endif /* notyet */
 886
 887        user_map = current_map();
 888
 889        /* have to call vm_map_wire directly to pass "I don't know" protections */
 890        result = vm_map_wire(user_map, addr, addr+size, VM_PROT_NONE, TRUE);
 891        return (result == KERN_SUCCESS ? 0 : ENOMEM);
 892}
 893
 894int
 895munlock(__unused struct proc *p, struct munlock_args *uap, __unused register_t *retval)
 896{
 897        mach_vm_offset_t addr;
 898        mach_vm_size_t size;
 899        vm_map_t user_map;
 900        kern_return_t   result;
 901
 902        AUDIT_ARG(addr, uap->addr);
 903        AUDIT_ARG(addr, uap->len);
 904
 905        addr = (mach_vm_offset_t) uap->addr;
 906        size = (mach_vm_size_t)uap->len;
 907
 908
 909#ifdef notyet 
 910/* Hmm.. What am I going to do with this? */
 911#ifndef pmap_wired_count
 912        error = suser(kauth_cred_get(), &p->p_acflag);
 913        if (error)
 914                return (error);
 915#endif
 916#endif /* notyet */
 917
 918        user_map = current_map();
 919
 920        /* JMM - need to remove all wirings by spec - this just removes one */
 921        result = mach_vm_wire(host_priv_self(), user_map, addr, size, VM_PROT_NONE);
 922        return (result == KERN_SUCCESS ? 0 : ENOMEM);
 923}
 924
 925
 926int
 927mlockall(__unused struct proc *p, __unused struct mlockall_args *uap, __unused register_t *retval)
 928{
 929        return (ENOSYS);
 930}
 931
 932int
 933munlockall(__unused struct proc *p, __unused struct munlockall_args *uap, __unused register_t *retval)
 934{
 935        return(ENOSYS);
 936}
 937
 938
 939/* BEGIN DEFUNCT */
 940int
 941obreak(__unused struct proc *p, __unused struct obreak_args *uap, __unused register_t *retval)
 942{
 943        /* Not implemented, obsolete */
 944        return (ENOMEM);
 945}
 946
 947int     both;
 948
 949int
 950ovadvise(__unused struct proc *p, __unused struct ovadvise_args *uap, __unused register_t *retval)
 951{
 952
 953#ifdef lint
 954        both = 0;
 955#endif
 956        return( 0 );
 957}
 958/* END DEFUNCT */
 959
 960/* USV: No! need to obsolete map_fd()! mmap() already supports 64 bits */
 961kern_return_t
 962map_fd(struct map_fd_args *args)
 963{
 964        int             fd = args->fd;
 965        vm_offset_t     offset = args->offset;
 966        vm_offset_t     *va = args->va;
 967        boolean_t       findspace = args->findspace;
 968        vm_size_t       size = args->size;
 969        kern_return_t ret;
 970
 971        AUDIT_MACH_SYSCALL_ENTER(AUE_MAPFD);
 972        AUDIT_ARG(addr, CAST_DOWN(user_addr_t, va));
 973        AUDIT_ARG(fd, fd);
 974
 975        ret = map_fd_funneled( fd, (vm_object_offset_t)offset, va, findspace, size);
 976
 977        AUDIT_MACH_SYSCALL_EXIT(ret);
 978        return ret;
 979}
 980
 981kern_return_t
 982map_fd_funneled(
 983        int                     fd,
 984        vm_object_offset_t      offset,
 985        vm_offset_t             *va,
 986        boolean_t               findspace,
 987        vm_size_t               size)
 988{
 989        kern_return_t   result;
 990        struct fileproc *fp;
 991        struct vnode    *vp;
 992        void *  pager;
 993        vm_offset_t     map_addr=0;
 994        vm_size_t       map_size;
 995        int             err=0;
 996        vm_map_t        my_map;
 997        struct proc     *p =(struct proc *)current_proc();
 998        struct vnode_attr vattr;
 999        struct vfs_context context;
1000
1001        /*
1002         *      Find the inode; verify that it's a regular file.
1003         */
1004
1005        err = fp_lookup(p, fd, &fp, 0);
1006        if (err)
1007                return(err);
1008        
1009        if (fp->f_fglob->fg_type != DTYPE_VNODE){
1010                err = KERN_INVALID_ARGUMENT;
1011                goto bad;
1012        }
1013
1014        if (!(fp->f_fglob->fg_flag & FREAD)) {
1015                err = KERN_PROTECTION_FAILURE;
1016                goto bad;
1017        }
1018
1019        vp = (struct vnode *)fp->f_fglob->fg_data;
1020        err = vnode_getwithref(vp);
1021        if(err != 0) 
1022                goto bad;
1023
1024        if (vp->v_type != VREG) {
1025                (void)vnode_put(vp);
1026                err = KERN_INVALID_ARGUMENT;
1027                goto bad;
1028        }
1029
1030        AUDIT_ARG(vnpath, vp, ARG_VNODE1);
1031
1032        /* conformance change - mmap needs to update access time for mapped
1033         * files
1034         */
1035        VATTR_INIT(&vattr);
1036        nanotime(&vattr.va_access_time);
1037        VATTR_SET_ACTIVE(&vattr, va_access_time);
1038        context.vc_proc = p;
1039        context.vc_ucred = kauth_cred_get();
1040        vnode_setattr(vp, &vattr, &context);
1041
1042        if (offset & PAGE_MASK_64) {
1043                printf("map_fd: file offset not page aligned(%d : %s)\n",p->p_pid, p->p_comm);
1044                (void)vnode_put(vp);
1045                err = KERN_INVALID_ARGUMENT;
1046                goto bad;
1047        }
1048        map_size = round_page(size);
1049
1050        /*
1051         * Allow user to map in a zero length file.
1052         */
1053        if (size == 0) {
1054                (void)vnode_put(vp);
1055                err = KERN_SUCCESS;
1056                goto bad;
1057        }
1058        /*
1059         *      Map in the file.
1060         */
1061        UBCINFOCHECK("map_fd_funneled", vp);
1062        pager = (void *) ubc_getpager(vp);
1063        if (pager == NULL) {
1064                (void)vnode_put(vp);
1065                err = KERN_FAILURE;
1066                goto bad;
1067        }
1068
1069
1070        my_map = current_map();
1071
1072        result = vm_map_64(
1073                        my_map,
1074                        &map_addr, map_size, (vm_offset_t)0, 
1075                        VM_FLAGS_ANYWHERE, pager, offset, TRUE,
1076                        VM_PROT_DEFAULT, VM_PROT_ALL,
1077                        VM_INHERIT_DEFAULT);
1078        if (result != KERN_SUCCESS) {
1079                (void)vnode_put(vp);
1080                err = result;
1081                goto bad;
1082        }
1083
1084
1085        if (!findspace) {
1086                vm_offset_t     dst_addr;
1087                vm_map_copy_t   tmp;
1088
1089                if (copyin(CAST_USER_ADDR_T(va), &dst_addr, sizeof (dst_addr))  ||
1090                                        trunc_page_32(dst_addr) != dst_addr) {
1091                        (void) vm_map_remove(
1092                                        my_map,
1093                                        map_addr, map_addr + map_size,
1094                                        VM_MAP_NO_FLAGS);
1095                        (void)vnode_put(vp);
1096                        err = KERN_INVALID_ADDRESS;
1097                        goto bad;
1098                }
1099
1100                result = vm_map_copyin(my_map, (vm_map_address_t)map_addr,
1101                                       (vm_map_size_t)map_size, TRUE, &tmp);
1102                if (result != KERN_SUCCESS) {
1103                        
1104                        (void) vm_map_remove(my_map, vm_map_trunc_page(map_addr),
1105                                        vm_map_round_page(map_addr + map_size),
1106                                        VM_MAP_NO_FLAGS);
1107                        (void)vnode_put(vp);
1108                        err = result;
1109                        goto bad;
1110                }
1111
1112                result = vm_map_copy_overwrite(my_map,
1113                                        (vm_map_address_t)dst_addr, tmp, FALSE);
1114                if (result != KERN_SUCCESS) {
1115                        vm_map_copy_discard(tmp);
1116                        (void)vnode_put(vp);
1117                        err = result;
1118                        goto bad;
1119                }
1120        } else {
1121                if (copyout(&map_addr, CAST_USER_ADDR_T(va), sizeof (map_addr))) {
1122                        (void) vm_map_remove(my_map, vm_map_trunc_page(map_addr),
1123                                        vm_map_round_page(map_addr + map_size),
1124                                        VM_MAP_NO_FLAGS);
1125                        (void)vnode_put(vp);
1126                        err = KERN_INVALID_ADDRESS;
1127                        goto bad;
1128                }
1129        }
1130
1131        ubc_setthreadcred(vp, current_proc(), current_thread());
1132        (void)ubc_map(vp, (PROT_READ | PROT_WRITE | PROT_EXEC));
1133        (void)vnode_put(vp);
1134        err = 0;
1135bad:
1136        fp_drop(p, fd, fp, 0);
1137        return (err);
1138}
1139
1140
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.