darwin-xnu/bsd/kern/mach_loader.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, 1989,  NeXT, Inc.
  24 *
  25 *      File:   kern/mach_loader.c
  26 *      Author: Avadis Tevanian, Jr.
  27 *
  28 *      Mach object file loader (kernel version, for now).
  29 *
  30 * 21-Jul-88  Avadis Tevanian, Jr. (avie) at NeXT
  31 *      Started.
  32 */
  33
  34#include <sys/param.h>
  35#include <sys/vnode_internal.h>
  36#include <sys/uio.h>
  37#include <sys/namei.h>
  38#include <sys/proc_internal.h>
  39#include <sys/kauth.h>
  40#include <sys/stat.h>
  41#include <sys/malloc.h>
  42#include <sys/mount_internal.h>
  43#include <sys/fcntl.h>
  44#include <sys/ubc_internal.h>
  45#include <sys/imgact.h>
  46
  47#include <mach/mach_types.h>
  48#include <mach/vm_map.h>        /* vm_allocate() */
  49#include <mach/mach_vm.h>       /* mach_vm_allocate() */
  50#include <mach/vm_statistics.h>
  51#include <mach/shared_memory_server.h>
  52#include <mach/task.h>
  53#include <mach/thread_act.h>
  54
  55#include <machine/vmparam.h>
  56
  57#include <kern/kern_types.h>
  58#include <kern/cpu_number.h>
  59#include <kern/mach_loader.h>
  60#include <kern/kalloc.h>
  61#include <kern/task.h>
  62#include <kern/thread.h>
  63
  64#include <mach-o/fat.h>
  65#include <mach-o/loader.h>
  66
  67#include <vm/pmap.h>
  68#include <vm/vm_map.h>
  69#include <vm/vm_kern.h>
  70#include <vm/vm_pager.h>
  71#include <vm/vnode_pager.h>
  72#include <vm/vm_shared_memory_server.h>
  73#include <vm/vm_protos.h> 
  74
  75/*
  76 * XXX vm/pmap.h should not treat these prototypes as MACH_KERNEL_PRIVATE
  77 * when KERNEL is defined.
  78 */
  79extern pmap_t   pmap_create(vm_map_size_t size);
  80extern void     pmap_switch(pmap_t);
  81extern void     pmap_map_sharedpage(task_t task, pmap_t pmap);
  82
  83/*
  84 * XXX kern/thread.h should not treat these prototypes as MACH_KERNEL_PRIVATE
  85 * when KERNEL is defined.
  86 */
  87extern kern_return_t    thread_setstatus(thread_t thread, int flavor,
  88                                thread_state_t tstate,
  89                                mach_msg_type_number_t count);
  90
  91extern kern_return_t    thread_state_initialize(thread_t thread);
  92
  93
  94/* XXX should have prototypes in a shared header file */
  95extern int grade_binary(cpu_type_t exectype, cpu_subtype_t execsubtype);
  96extern int      get_map_nentries(vm_map_t);
  97extern kern_return_t    thread_userstack(thread_t, int, thread_state_t,
  98                                unsigned int, mach_vm_offset_t *, int *);
  99extern kern_return_t    thread_entrypoint(thread_t, int, thread_state_t,
 100                                unsigned int, mach_vm_offset_t *);
 101
 102
 103/* An empty load_result_t */
 104static load_result_t load_result_null = {
 105        MACH_VM_MIN_ADDRESS,
 106        MACH_VM_MIN_ADDRESS,
 107        MACH_VM_MIN_ADDRESS,
 108        0,
 109        0,
 110        0,
 111        0
 112};
 113
 114/*
 115 * Prototypes of static functions.
 116 */
 117static load_return_t
 118parse_machfile(
 119        struct vnode            *vp,
 120        vm_map_t                map,
 121        thread_t                thr_act,
 122        struct mach_header      *header,
 123        off_t                   file_offset,
 124        off_t                   macho_size,
 125        boolean_t               shared_regions,
 126        boolean_t               clean_regions,
 127        int                     depth,
 128        load_result_t           *result
 129);
 130
 131static load_return_t
 132load_segment(
 133        struct segment_command  *scp,
 134        void *                                  pager,
 135        off_t                           pager_offset,
 136        off_t                           macho_size,
 137        off_t                           end_of_file,
 138        vm_map_t                                map,
 139        load_result_t                   *result
 140);
 141
 142static load_return_t
 143load_segment_64(
 144        struct segment_command_64       *scp64,
 145        void                            *pager,
 146        off_t                           pager_offset,
 147        off_t                           macho_size,
 148        off_t                           end_of_file,
 149        vm_map_t                        map,
 150        load_result_t                   *result
 151);
 152
 153static load_return_t
 154load_unixthread(
 155        struct thread_command   *tcp,
 156        thread_t                        thr_act,
 157        load_result_t                   *result
 158);
 159
 160static load_return_t
 161load_thread(
 162        struct thread_command   *tcp,
 163        thread_t                        thr_act,
 164        load_result_t                   *result
 165);
 166
 167static load_return_t
 168load_threadstate(
 169        thread_t                thread,
 170        unsigned long   *ts,
 171        unsigned long   total_size
 172);
 173
 174static load_return_t
 175load_threadstack(
 176        thread_t                thread,
 177        unsigned long   *ts,
 178        unsigned long   total_size,
 179        mach_vm_offset_t        *user_stack,
 180        int                             *customstack
 181);
 182
 183static load_return_t
 184load_threadentry(
 185        thread_t                thread,
 186        unsigned long   *ts,
 187        unsigned long   total_size,
 188        mach_vm_offset_t        *entry_point
 189);
 190
 191static load_return_t
 192load_dylinker(
 193        struct dylinker_command *lcp,
 194        integer_t               archbits,
 195        vm_map_t                                map,
 196        thread_t                        thr_act,
 197        int                                             depth,
 198        load_result_t                   *result,
 199        boolean_t                       clean_regions
 200);
 201
 202static load_return_t
 203get_macho_vnode(
 204        char                            *path,
 205        integer_t               archbits,
 206        struct mach_header      *mach_header,
 207        off_t                   *file_offset,
 208        off_t                   *macho_size,
 209        struct vnode            **vpp
 210);
 211
 212load_return_t
 213load_machfile(
 214        struct image_params     *imgp,
 215        struct mach_header      *header,
 216        thread_t                thr_act,
 217        vm_map_t                new_map,
 218        boolean_t               clean_regions,
 219        load_result_t           *result
 220)
 221{
 222        struct vnode            *vp = imgp->ip_vp;
 223        off_t                   file_offset = imgp->ip_arch_offset;
 224        off_t                   macho_size = imgp->ip_arch_size;
 225        
 226        pmap_t                  pmap = 0;       /* protected by create_map */
 227        vm_map_t                map;
 228        vm_map_t                old_map;
 229        load_result_t           myresult;
 230        load_return_t           lret;
 231        boolean_t create_map = TRUE;
 232
 233        if (new_map != VM_MAP_NULL) {
 234                create_map = FALSE;
 235        }
 236
 237        if (create_map) {
 238                old_map = current_map();
 239#ifdef i386
 240                pmap = get_task_pmap(current_task());
 241                pmap_reference(pmap);
 242#else
 243                pmap = pmap_create((vm_map_size_t) 0);
 244#endif
 245                map = vm_map_create(pmap,
 246                                get_map_min(old_map),
 247                                get_map_max(old_map),
 248                                TRUE); /**** FIXME ****/
 249        } else
 250                map = new_map;
 251                
 252        if (!result)
 253                result = &myresult;
 254
 255        *result = load_result_null;
 256
 257        lret = parse_machfile(vp, map, thr_act, header, file_offset, macho_size,
 258                              ((imgp->ip_flags & IMGPF_IS_64BIT) == 0), /* shared regions? */
 259                              clean_regions, 0, result);
 260
 261        if (lret != LOAD_SUCCESS) {
 262                if (create_map) {
 263                        vm_map_deallocate(map); /* will lose pmap reference too */
 264                }
 265                return(lret);
 266        }
 267
 268        /*
 269         *      Commit to new map.  First make sure that the current
 270         *      users of the task get done with it, and that we clean
 271         *      up the old contents of IPC and memory.  The task is
 272         *      guaranteed to be single threaded upon return (us).
 273         *
 274         *      Swap the new map for the old, which  consumes our new map
 275         *      reference but each leaves us responsible for the old_map reference.
 276         *      That lets us get off the pmap associated with it, and
 277         *      then we can release it.
 278         */
 279         if (create_map) {
 280                task_halt(current_task());
 281
 282                old_map = swap_task_map(current_task(), map);
 283#ifndef i386
 284                pmap_switch(pmap);      /* Make sure we are using the new pmap */
 285#endif
 286                vm_map_deallocate(old_map);
 287        }
 288        return(LOAD_SUCCESS);
 289}
 290
 291int     dylink_test = 1;
 292
 293/*
 294 * The file size of a mach-o file is limited to 32 bits; this is because
 295 * this is the limit on the kalloc() of enough bytes for a mach_header and
 296 * the contents of its sizeofcmds, which is currently constrained to 32
 297 * bits in the file format itself.  We read into the kernel buffer the
 298 * commands section, and then parse it in order to parse the mach-o file
 299 * format load_command segment(s).  We are only interested in a subset of
 300 * the total set of possible commands.
 301 */
 302static
 303load_return_t
 304parse_machfile(
 305        struct vnode            *vp,       
 306        vm_map_t                map,
 307        thread_t                thr_act,
 308        struct mach_header      *header,
 309        off_t                   file_offset,
 310        off_t                   macho_size,
 311        boolean_t               shared_regions,
 312        boolean_t               clean_regions,
 313        int                     depth,
 314        load_result_t           *result
 315)
 316{
 317        uint32_t                ncmds;
 318        struct load_command     *lcp;
 319        struct dylinker_command *dlp = 0;
 320        integer_t               dlarchbits = 0;
 321        void *                  pager;
 322        load_return_t           ret = LOAD_SUCCESS;
 323        caddr_t                 addr;
 324        void *                  kl_addr;
 325        vm_size_t               size,kl_size;
 326        size_t                  offset;
 327        size_t                  oldoffset;      /* for overflow check */
 328        int                     pass;
 329        struct proc *p = current_proc();                /* XXXX */
 330        int                     error;
 331        int resid=0;
 332        task_t task;
 333        size_t                  mach_header_sz = sizeof(struct mach_header);
 334        boolean_t               abi64;
 335
 336        if (header->magic == MH_MAGIC_64 ||
 337            header->magic == MH_CIGAM_64) {
 338                mach_header_sz = sizeof(struct mach_header_64);
 339        }
 340
 341        /*
 342         *      Break infinite recursion
 343         */
 344        if (depth > 6)
 345                return(LOAD_FAILURE);
 346
 347        task = (task_t)get_threadtask(thr_act);
 348
 349        depth++;
 350
 351        /*
 352         *      Check to see if right machine type.
 353         */
 354        if (((cpu_type_t)(header->cputype & ~CPU_ARCH_MASK) != cpu_type()) ||
 355            !grade_binary(header->cputype, header->cpusubtype))
 356                return(LOAD_BADARCH);
 357                
 358        abi64 = ((header->cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64);
 359                
 360        switch (header->filetype) {
 361        
 362        case MH_OBJECT:
 363        case MH_EXECUTE:
 364        case MH_PRELOAD:
 365                if (depth != 1)
 366                        return (LOAD_FAILURE);
 367                break;
 368                
 369        case MH_FVMLIB:
 370        case MH_DYLIB:
 371                if (depth == 1)
 372                        return (LOAD_FAILURE);
 373                break;
 374
 375        case MH_DYLINKER:
 376                if (depth != 2)
 377                        return (LOAD_FAILURE);
 378                break;
 379                
 380        default:
 381                return (LOAD_FAILURE);
 382        }
 383
 384        /*
 385         *      Get the pager for the file.
 386         */
 387        UBCINFOCHECK("parse_machfile", vp);
 388        pager = (void *) ubc_getpager(vp);
 389
 390        /*
 391         *      Map portion that must be accessible directly into
 392         *      kernel's map.
 393         */
 394        if ((mach_header_sz + header->sizeofcmds) > macho_size)
 395                return(LOAD_BADMACHO);
 396
 397        /*
 398         *      Round size of Mach-O commands up to page boundry.
 399         */
 400        size = round_page(mach_header_sz + header->sizeofcmds);
 401        if (size <= 0)
 402                return(LOAD_BADMACHO);
 403
 404        /*
 405         * Map the load commands into kernel memory.
 406         */
 407        addr = 0;
 408        kl_size = size;
 409        kl_addr = kalloc(size);
 410        addr = (caddr_t)kl_addr;
 411        if (addr == NULL)
 412                return(LOAD_NOSPACE);
 413
 414        error = vn_rdwr(UIO_READ, vp, addr, size, file_offset,
 415            UIO_SYSSPACE32, 0, kauth_cred_get(), &resid, p);
 416        if (error) {
 417                if (kl_addr )
 418                        kfree(kl_addr, kl_size);
 419                return(LOAD_IOERROR);
 420        }
 421        /* (void)ubc_map(vp, PROT_EXEC); */ /* NOT HERE */
 422        
 423        /*
 424         *      Scan through the commands, processing each one as necessary.
 425         */
 426        for (pass = 1; pass <= 2; pass++) {
 427                /*
 428                 * Loop through each of the load_commands indicated by the
 429                 * Mach-O header; if an absurd value is provided, we just
 430                 * run off the end of the reserved section by incrementing
 431                 * the offset too far, so we are implicitly fail-safe.
 432                 */
 433                offset = mach_header_sz;
 434                ncmds = header->ncmds;
 435                while (ncmds--) {
 436                        /*
 437                         *      Get a pointer to the command.
 438                         */
 439                        lcp = (struct load_command *)(addr + offset);
 440                        oldoffset = offset;
 441                        offset += lcp->cmdsize;
 442
 443                        /*
 444                         * Perform prevalidation of the struct load_command
 445                         * before we attempt to use its contents.  Invalid
 446                         * values are ones which result in an overflow, or
 447                         * which can not possibly be valid commands, or which
 448                         * straddle or exist past the reserved section at the
 449                         * start of the image.
 450                         */
 451                        if (oldoffset > offset ||
 452                            lcp->cmdsize < sizeof(struct load_command) ||
 453                            offset > header->sizeofcmds + mach_header_sz) {
 454                                ret = LOAD_BADMACHO;
 455                                break;
 456                        }
 457
 458                        /*
 459                         * Act on struct load_command's for which kernel
 460                         * intervention is required.
 461                         */
 462                        switch(lcp->cmd) {
 463                        case LC_SEGMENT_64:
 464                                if (pass != 1)
 465                                        break;
 466                                ret = load_segment_64(
 467                                               (struct segment_command_64 *)lcp,
 468                                                   pager,
 469                                                   file_offset,
 470                                                   macho_size,
 471                                                   ubc_getsize(vp),
 472                                                   map,
 473                                                   result);
 474                                break;
 475                        case LC_SEGMENT:
 476                                if (pass != 1)
 477                                        break;
 478                                ret = load_segment(
 479                                               (struct segment_command *) lcp,
 480                                                   pager,
 481                                                   file_offset,
 482                                                   macho_size,
 483                                                   ubc_getsize(vp),
 484                                                   map,
 485                                                   result);
 486                                break;
 487                        case LC_THREAD:
 488                                if (pass != 2)
 489                                        break;
 490                                ret = load_thread((struct thread_command *)lcp,
 491                                                   thr_act,
 492                                                  result);
 493                                break;
 494                        case LC_UNIXTHREAD:
 495                                if (pass != 2)
 496                                        break;
 497                                ret = load_unixthread(
 498                                                 (struct thread_command *) lcp,
 499                                                   thr_act,
 500                                                 result);
 501                                break;
 502                        case LC_LOAD_DYLINKER:
 503                                if (pass != 2)
 504                                        break;
 505                                if ((depth == 1) && (dlp == 0)) {
 506                                        dlp = (struct dylinker_command *)lcp;
 507                                        dlarchbits = (header->cputype & CPU_ARCH_MASK);
 508                                } else {
 509                                        ret = LOAD_FAILURE;
 510                                }
 511                                break;
 512                        default:
 513                                /* Other commands are ignored by the kernel */
 514                                ret = LOAD_SUCCESS;
 515                                break;
 516                        }
 517                        if (ret != LOAD_SUCCESS)
 518                                break;
 519                }
 520                if (ret != LOAD_SUCCESS)
 521                        break;
 522        }
 523        if (ret == LOAD_SUCCESS) { 
 524
 525            if (shared_regions) {
 526                vm_offset_t vmaddr;
 527                shared_region_mapping_t shared_region;
 528                struct shared_region_task_mappings      map_info;
 529                shared_region_mapping_t next;
 530
 531RedoLookup:
 532                vm_get_shared_region(task, &shared_region);
 533                map_info.self = (vm_offset_t)shared_region;
 534                shared_region_mapping_info(shared_region,
 535                        &(map_info.text_region),   
 536                        &(map_info.text_size),
 537                        &(map_info.data_region),
 538                        &(map_info.data_size),
 539                        &(map_info.region_mappings),
 540                        &(map_info.client_base),
 541                        &(map_info.alternate_base),
 542                        &(map_info.alternate_next), 
 543                        &(map_info.fs_base),
 544                        &(map_info.system),
 545                        &(map_info.flags), &next);
 546
 547                if((map_info.flags & SHARED_REGION_FULL) ||
 548                        (map_info.flags & SHARED_REGION_STALE)) {
 549                        shared_region_mapping_t system_region;
 550                        system_region = lookup_default_shared_region(
 551                                map_info.fs_base, map_info.system);
 552                        if((map_info.self != (vm_offset_t)system_region) &&
 553                                (map_info.flags & SHARED_REGION_SYSTEM)) {
 554                           if(system_region == NULL) {
 555                                shared_file_boot_time_init(
 556                                        map_info.fs_base, map_info.system);
 557                           } else {
 558                                vm_set_shared_region(task, system_region);
 559                           }
 560                           shared_region_mapping_dealloc(
 561                                        (shared_region_mapping_t)map_info.self);
 562                           goto RedoLookup;
 563                        } else if (map_info.flags & SHARED_REGION_SYSTEM) {
 564                              shared_region_mapping_dealloc(system_region);
 565                              shared_file_boot_time_init(
 566                                        map_info.fs_base, map_info.system);
 567                              shared_region_mapping_dealloc(
 568                                     (shared_region_mapping_t)map_info.self);
 569                        } else {
 570                              shared_region_mapping_dealloc(system_region);
 571                        }
 572                }
 573
 574                if (dylink_test) {
 575                        p->p_flag |=  P_NOSHLIB; /* no shlibs in use */
 576                        vmaddr = map_info.client_base;
 577                        if(clean_regions) {
 578                           vm_map(map, &vmaddr, map_info.text_size, 
 579                                0, SHARED_LIB_ALIAS|VM_FLAGS_FIXED,
 580                                map_info.text_region, 0, FALSE,
 581                                VM_PROT_READ, VM_PROT_READ, VM_INHERIT_SHARE);
 582                        } else {
 583                           vm_map(map, &vmaddr, map_info.text_size, 0, 
 584                                (VM_MEMORY_SHARED_PMAP << 24) 
 585                                  | SHARED_LIB_ALIAS | VM_FLAGS_FIXED,
 586                                map_info.text_region, 0, FALSE,
 587                                VM_PROT_READ, VM_PROT_READ, VM_INHERIT_SHARE);
 588                        }
 589                        vmaddr = map_info.client_base + map_info.text_size;
 590                        vm_map(map, &vmaddr, map_info.data_size, 
 591                                0, SHARED_LIB_ALIAS | VM_FLAGS_FIXED,
 592                                map_info.data_region, 0, TRUE,
 593                                VM_PROT_READ, VM_PROT_READ, VM_INHERIT_SHARE);
 594        
 595                        while (next) {
 596                           /* this should be fleshed out for the general case */
 597                           /* but this is not necessary for now.  Indeed we   */
 598                           /* are handling the com page inside of the         */
 599                           /* shared_region mapping create calls for now for  */
 600                           /* simplicities sake.  If more general support is  */
 601                           /* needed the code to manipulate the shared range  */
 602                           /* chain can be pulled out and moved to the callers*/
 603                           shared_region_mapping_info(next,
 604                                &(map_info.text_region),   
 605                                &(map_info.text_size),
 606                                &(map_info.data_region),
 607                                &(map_info.data_size),
 608                                &(map_info.region_mappings),
 609                                &(map_info.client_base),
 610                                &(map_info.alternate_base),
 611                                &(map_info.alternate_next), 
 612                                &(map_info.fs_base),
 613                                &(map_info.system),
 614                                &(map_info.flags), &next);
 615
 616                           vmaddr = map_info.client_base;
 617                           vm_map(map, &vmaddr, map_info.text_size, 
 618                                0, SHARED_LIB_ALIAS | VM_FLAGS_FIXED,
 619                                map_info.text_region, 0, FALSE,
 620                                VM_PROT_READ, VM_PROT_READ, VM_INHERIT_SHARE);
 621                        }
 622                }
 623            }
 624            if (dlp != 0)
 625                        ret = load_dylinker(dlp, dlarchbits, map, thr_act, depth, result, clean_regions);
 626
 627            if(depth == 1) {
 628                if (result->thread_count == 0)
 629                        ret = LOAD_FAILURE;
 630#ifdef __ppc__
 631                else if ( abi64 ) {
 632                        /* Map in 64-bit commpage */
 633                        /* LP64todo - make this clean */
 634                        pmap_map_sharedpage(current_task(), get_map_pmap(map));
 635                        vm_map_commpage64(map);
 636                }
 637#endif
 638            }
 639        }
 640
 641        if (kl_addr )
 642                kfree(kl_addr, kl_size);
 643
 644        if (ret == LOAD_SUCCESS)
 645                (void)ubc_map(vp, PROT_EXEC);
 646                
 647        return(ret);
 648}
 649
 650static
 651load_return_t
 652load_segment(
 653        struct segment_command  *scp,
 654        void *                  pager,
 655        off_t                   pager_offset,
 656        off_t                   macho_size,
 657        __unused off_t          end_of_file,
 658        vm_map_t                map,
 659        load_result_t           *result
 660)
 661{
 662        kern_return_t           ret;
 663        vm_offset_t             map_addr, map_offset;
 664        vm_size_t               map_size, seg_size, delta_size;
 665        vm_prot_t               initprot;
 666        vm_prot_t               maxprot;
 667
 668        /*
 669         * Make sure what we get from the file is really ours (as specified
 670         * by macho_size).
 671         */
 672        if (scp->fileoff + scp->filesize > macho_size)
 673                return (LOAD_BADMACHO);
 674
 675        seg_size = round_page(scp->vmsize);
 676        if (seg_size == 0)
 677                return(KERN_SUCCESS);
 678
 679        /*
 680         *      Round sizes to page size.
 681         */
 682        map_size = round_page(scp->filesize);
 683        map_addr = trunc_page(scp->vmaddr);
 684
 685        map_offset = pager_offset + scp->fileoff;
 686
 687        if (map_size > 0) {
 688                initprot = (scp->initprot) & VM_PROT_ALL;
 689                maxprot = (scp->maxprot) & VM_PROT_ALL;
 690                /*
 691                 *      Map a copy of the file into the address space.
 692                 */
 693                ret = vm_map(map,
 694                                &map_addr, map_size, (vm_offset_t)0,
 695                                VM_FLAGS_FIXED, pager, map_offset, TRUE,
 696                                initprot, maxprot,
 697                                VM_INHERIT_DEFAULT);
 698                if (ret != KERN_SUCCESS)
 699                        return(LOAD_NOSPACE);
 700        
 701                /*
 702                 *      If the file didn't end on a page boundary,
 703                 *      we need to zero the leftover.
 704                 */
 705                delta_size = map_size - scp->filesize;
 706#if FIXME
 707                if (delta_size > 0) {
 708                        vm_offset_t     tmp;
 709        
 710                        ret = vm_allocate(kernel_map, &tmp, delta_size, VM_FLAGS_ANYWHERE);
 711                        if (ret != KERN_SUCCESS)
 712                                return(LOAD_RESOURCE);
 713        
 714                        if (copyout(tmp, map_addr + scp->filesize,
 715                                                                delta_size)) {
 716                                (void) vm_deallocate(
 717                                                kernel_map, tmp, delta_size);
 718                                return(LOAD_FAILURE);
 719                        }
 720                        
 721                        (void) vm_deallocate(kernel_map, tmp, delta_size);
 722                }
 723#endif /* FIXME */
 724        }
 725
 726        /*
 727         *      If the virtual size of the segment is greater
 728         *      than the size from the file, we need to allocate
 729         *      zero fill memory for the rest.
 730         */
 731        delta_size = seg_size - map_size;
 732        if (delta_size > 0) {
 733                vm_offset_t     tmp = map_addr + map_size;
 734
 735                ret = vm_allocate(map, &tmp, delta_size, VM_FLAGS_FIXED);
 736                if (ret != KERN_SUCCESS)
 737                        return(LOAD_NOSPACE);
 738        }
 739
 740        /*
 741         *      Set protection values. (Note: ignore errors!)
 742         */
 743
 744        if (scp->maxprot != VM_PROT_DEFAULT) {
 745                (void) vm_protect(map,
 746                                        map_addr, seg_size,
 747                                        TRUE, scp->maxprot);
 748        }
 749        if (scp->initprot != VM_PROT_DEFAULT) {
 750                (void) vm_protect(map,
 751                                      map_addr, seg_size,
 752                                      FALSE, scp->initprot);
 753        }
 754        if ( (scp->fileoff == 0) && (scp->filesize != 0) )
 755                result->mach_header = map_addr;
 756        return(LOAD_SUCCESS);
 757}
 758
 759static
 760load_return_t
 761load_segment_64(
 762        struct segment_command_64       *scp64,
 763        void *                          pager,
 764        off_t                           pager_offset,
 765        off_t                           macho_size,
 766        __unused off_t                  end_of_file,
 767        vm_map_t                        map,
 768        load_result_t           *result
 769)
 770{
 771        kern_return_t           ret;
 772        mach_vm_offset_t        map_addr, map_offset;
 773        mach_vm_size_t          map_size, seg_size, delta_size;
 774        vm_prot_t               initprot;
 775        vm_prot_t               maxprot;
 776        
 777        /*
 778         * Make sure what we get from the file is really ours (as specified
 779         * by macho_size).
 780         */
 781        if (scp64->fileoff + scp64->filesize > (uint64_t)macho_size)
 782                return (LOAD_BADMACHO);
 783
 784        seg_size = round_page_64(scp64->vmsize);
 785        if (seg_size == 0)
 786                return(KERN_SUCCESS);
 787
 788        /*
 789         *      Round sizes to page size.
 790         */
 791        map_size = round_page_64(scp64->filesize);      /* limited to 32 bits */
 792        map_addr = round_page_64(scp64->vmaddr);
 793
 794        map_offset = pager_offset + scp64->fileoff;     /* limited to 32 bits */
 795
 796        if (map_size > 0) {
 797                initprot = (scp64->initprot) & VM_PROT_ALL;
 798                maxprot = (scp64->maxprot) & VM_PROT_ALL;
 799                /*
 800                 *      Map a copy of the file into the address space.
 801                 */
 802                ret = mach_vm_map(map,
 803                                &map_addr, map_size, (mach_vm_offset_t)0,
 804                                VM_FLAGS_FIXED, pager, map_offset, TRUE,
 805                                initprot, maxprot,
 806                                VM_INHERIT_DEFAULT);
 807                if (ret != KERN_SUCCESS)
 808                        return(LOAD_NOSPACE);
 809        
 810                /*
 811                 *      If the file didn't end on a page boundary,
 812                 *      we need to zero the leftover.
 813                 */
 814                delta_size = map_size - scp64->filesize;
 815#if FIXME
 816                if (delta_size > 0) {
 817                        mach_vm_offset_t        tmp;
 818        
 819                        ret = vm_allocate(kernel_map, &tmp, delta_size, VM_FLAGS_ANYWHERE);
 820                        if (ret != KERN_SUCCESS)
 821                                return(LOAD_RESOURCE);
 822        
 823                        if (copyout(tmp, map_addr + scp64->filesize,
 824                                                                delta_size)) {
 825                                (void) vm_deallocate(
 826                                                kernel_map, tmp, delta_size);
 827                return (LOAD_FAILURE);
 828                        }
 829        
 830                        (void) vm_deallocate(kernel_map, tmp, delta_size);
 831                }
 832#endif /* FIXME */
 833        }
 834
 835        /*
 836         *      If the virtual size of the segment is greater
 837         *      than the size from the file, we need to allocate
 838         *      zero fill memory for the rest.
 839         */
 840        delta_size = seg_size - map_size;
 841        if (delta_size > 0) {
 842                mach_vm_offset_t tmp = map_addr + map_size;
 843
 844                ret = mach_vm_allocate(map, &tmp, delta_size, VM_FLAGS_FIXED);
 845                if (ret != KERN_SUCCESS)
 846                        return(LOAD_NOSPACE);
 847        }
 848
 849        /*
 850         *      Set protection values. (Note: ignore errors!)
 851         */
 852
 853        if (scp64->maxprot != VM_PROT_DEFAULT) {
 854                (void) mach_vm_protect(map,
 855                                        map_addr, seg_size,
 856                                        TRUE, scp64->maxprot);
 857        }
 858        if (scp64->initprot != VM_PROT_DEFAULT) {
 859                (void) mach_vm_protect(map,
 860                                      map_addr, seg_size,
 861                                      FALSE, scp64->initprot);
 862        }
 863        if ( (scp64->fileoff == 0) && (scp64->filesize != 0) )
 864                result->mach_header = map_addr;
 865        return(LOAD_SUCCESS);
 866}
 867
 868static
 869load_return_t
 870load_thread(
 871        struct thread_command   *tcp,
 872        thread_t                        thread,
 873        load_result_t           *result
 874)
 875{
 876        kern_return_t   kret;
 877        load_return_t   lret;
 878        task_t                  task;
 879        int customstack=0;
 880
 881        task = get_threadtask(thread);
 882
 883        /* if count is 0; same as thr_act */
 884        if (result->thread_count != 0) {
 885                kret = thread_create(task, &thread);
 886                if (kret != KERN_SUCCESS)
 887                        return(LOAD_RESOURCE);
 888                thread_deallocate(thread);
 889        }
 890
 891        lret = load_threadstate(thread,
 892                       (unsigned long *)(((vm_offset_t)tcp) + 
 893                                sizeof(struct thread_command)),
 894                       tcp->cmdsize - sizeof(struct thread_command));
 895        if (lret != LOAD_SUCCESS)
 896                return (lret);
 897
 898        if (result->thread_count == 0) {
 899                lret = load_threadstack(thread,
 900                                (unsigned long *)(((vm_offset_t)tcp) + 
 901                                        sizeof(struct thread_command)),
 902                                tcp->cmdsize - sizeof(struct thread_command),
 903                                &result->user_stack,
 904                                &customstack);
 905                if (customstack)
 906                                result->customstack = 1;
 907                else
 908                                result->customstack = 0;
 909                        
 910                if (lret != LOAD_SUCCESS)
 911                        return(lret);
 912
 913                lret = load_threadentry(thread,
 914                                (unsigned long *)(((vm_offset_t)tcp) + 
 915                                        sizeof(struct thread_command)),
 916                                tcp->cmdsize - sizeof(struct thread_command),
 917                                &result->entry_point);
 918                if (lret != LOAD_SUCCESS)
 919                        return(lret);
 920        }
 921        /*
 922         *      Resume thread now, note that this means that the thread
 923         *      commands should appear after all the load commands to
 924         *      be sure they don't reference anything not yet mapped.
 925         */
 926        else
 927                thread_resume(thread);
 928                
 929        result->thread_count++;
 930
 931        return(LOAD_SUCCESS);
 932}
 933
 934static
 935load_return_t
 936load_unixthread(
 937        struct thread_command   *tcp,
 938        thread_t                thread,
 939        load_result_t           *result
 940)
 941{
 942        load_return_t   ret;
 943        int customstack =0;
 944        
 945        if (result->thread_count != 0)
 946                return (LOAD_FAILURE);
 947        
 948        ret = load_threadstack(thread,
 949                       (unsigned long *)(((vm_offset_t)tcp) + 
 950                                sizeof(struct thread_command)),
 951                       tcp->cmdsize - sizeof(struct thread_command),
 952                       &result->user_stack,
 953                           &customstack);
 954        if (ret != LOAD_SUCCESS)
 955                return(ret);
 956
 957        if (customstack)
 958                        result->customstack = 1;
 959        else
 960                        result->customstack = 0;
 961        ret = load_threadentry(thread,
 962                       (unsigned long *)(((vm_offset_t)tcp) + 
 963                                sizeof(struct thread_command)),
 964                       tcp->cmdsize - sizeof(struct thread_command),
 965                       &result->entry_point);
 966        if (ret != LOAD_SUCCESS)
 967                return(ret);
 968
 969        ret = load_threadstate(thread,
 970                       (unsigned long *)(((vm_offset_t)tcp) + 
 971                                sizeof(struct thread_command)),
 972                       tcp->cmdsize - sizeof(struct thread_command));
 973        if (ret != LOAD_SUCCESS)
 974                return (ret);
 975
 976        result->unixproc = TRUE;
 977        result->thread_count++;
 978
 979        return(LOAD_SUCCESS);
 980}
 981
 982static
 983load_return_t
 984load_threadstate(
 985        thread_t        thread,
 986        unsigned long   *ts,
 987        unsigned long   total_size
 988)
 989{
 990        kern_return_t   ret;
 991        unsigned long   size;
 992        int             flavor;
 993        unsigned long   thread_size;
 994
 995    ret = thread_state_initialize( thread );
 996    if (ret != KERN_SUCCESS)
 997        return(LOAD_FAILURE);
 998    
 999        /*
1000         *      Set the new thread state; iterate through the state flavors in
1001     *  the mach-o file.
1002         */
1003        while (total_size > 0) {
1004                flavor = *ts++;
1005                size = *ts++;
1006                thread_size = (size+2)*sizeof(unsigned long);
1007                if (thread_size > total_size)
1008                        return(LOAD_BADMACHO);
1009                total_size -= thread_size;
1010                /*
1011                 * Third argument is a kernel space pointer; it gets cast
1012                 * to the appropriate type in machine_thread_set_state()
1013                 * based on the value of flavor.
1014                 */
1015                ret = thread_setstatus(thread, flavor, (thread_state_t)ts, size);
1016                if (ret != KERN_SUCCESS)
1017                        return(LOAD_FAILURE);
1018                ts += size;     /* ts is a (unsigned long *) */
1019        }
1020        return(LOAD_SUCCESS);
1021}
1022
1023static
1024load_return_t
1025load_threadstack(
1026        thread_t        thread,
1027        unsigned long   *ts,
1028        unsigned long   total_size,
1029        user_addr_t     *user_stack,
1030        int *customstack
1031)
1032{
1033        kern_return_t   ret;
1034        unsigned long   size;
1035        int             flavor;
1036        unsigned long   stack_size;
1037
1038        while (total_size > 0) {
1039                flavor = *ts++;
1040                size = *ts++;
1041                stack_size = (size+2)*sizeof(unsigned long);
1042                if (stack_size > total_size)
1043                        return(LOAD_BADMACHO);
1044                total_size -= stack_size;
1045
1046                /*
1047                 * Third argument is a kernel space pointer; it gets cast
1048                 * to the appropriate type in thread_userstack() based on
1049                 * the value of flavor.
1050                 */
1051                ret = thread_userstack(thread, flavor, (thread_state_t)ts, size, user_stack, customstack);
1052                if (ret != KERN_SUCCESS)
1053                        return(LOAD_FAILURE);
1054                ts += size;     /* ts is a (unsigned long *) */
1055        }
1056        return(LOAD_SUCCESS);
1057}
1058
1059static
1060load_return_t
1061load_threadentry(
1062        thread_t        thread,
1063        unsigned long   *ts,
1064        unsigned long   total_size,
1065        mach_vm_offset_t        *entry_point
1066)
1067{
1068        kern_return_t   ret;
1069        unsigned long   size;
1070        int             flavor;
1071        unsigned long   entry_size;
1072
1073        /*
1074         *      Set the thread state.
1075         */
1076        *entry_point = MACH_VM_MIN_ADDRESS;
1077        while (total_size > 0) {
1078                flavor = *ts++;
1079                size = *ts++;
1080                entry_size = (size+2)*sizeof(unsigned long);
1081                if (entry_size > total_size)
1082                        return(LOAD_BADMACHO);
1083                total_size -= entry_size;
1084                /*
1085                 * Third argument is a kernel space pointer; it gets cast
1086                 * to the appropriate type in thread_entrypoint() based on
1087                 * the value of flavor.
1088                 */
1089                ret = thread_entrypoint(thread, flavor, (thread_state_t)ts, size, entry_point);
1090                if (ret != KERN_SUCCESS)
1091                        return(LOAD_FAILURE);
1092                ts += size;     /* ts is a (unsigned long *) */
1093        }
1094        return(LOAD_SUCCESS);
1095}
1096
1097
1098static
1099load_return_t
1100load_dylinker(
1101        struct dylinker_command *lcp,
1102        integer_t               archbits,
1103        vm_map_t                map,
1104        thread_t        thr_act,
1105        int                     depth,
1106        load_result_t           *result,
1107        boolean_t               clean_regions
1108)
1109{
1110        char                    *name;
1111        char                    *p;
1112        struct vnode            *vp;
1113        struct mach_header      header;
1114        off_t                   file_offset;
1115        off_t                   macho_size;
1116        vm_map_t                copy_map;
1117        load_result_t           myresult;
1118        kern_return_t           ret;
1119        vm_map_copy_t   tmp;
1120        mach_vm_offset_t        dyl_start, map_addr;
1121        mach_vm_size_t          dyl_length;
1122
1123        name = (char *)lcp + lcp->name.offset;
1124        /*
1125         *      Check for a proper null terminated string.
1126         */
1127        p = name;
1128        do {
1129                if (p >= (char *)lcp + lcp->cmdsize)
1130                        return(LOAD_BADMACHO);
1131        } while (*p++);
1132
1133        ret = get_macho_vnode(name, archbits, &header, &file_offset, &macho_size, &vp);
1134        if (ret)
1135                return (ret);
1136                        
1137        /*
1138         *      Load the Mach-O.
1139         *      Use a temporary map to do the work.
1140         */
1141        copy_map = vm_map_create(pmap_create(vm_map_round_page(macho_size)),
1142                                 get_map_min(map), get_map_max(map), TRUE);
1143        if (VM_MAP_NULL == copy_map) {
1144                ret = LOAD_RESOURCE;
1145                goto out;
1146        }
1147
1148        myresult = load_result_null;
1149
1150        ret = parse_machfile(vp, copy_map, thr_act, &header,
1151                                file_offset, macho_size,
1152                                FALSE, clean_regions, depth, &myresult);
1153
1154        if (ret)
1155                goto out;
1156
1157        if (get_map_nentries(copy_map) > 0) {
1158
1159                dyl_start = mach_get_vm_start(copy_map);
1160                dyl_length = mach_get_vm_end(copy_map) - dyl_start;
1161
1162                map_addr = dyl_start;
1163                ret = mach_vm_allocate(map, &map_addr, dyl_length, VM_FLAGS_FIXED);
1164                if (ret != KERN_SUCCESS)  {
1165                        ret = mach_vm_allocate(map, &map_addr, dyl_length, VM_FLAGS_ANYWHERE);
1166                }
1167
1168                if (ret != KERN_SUCCESS) {
1169                        ret = LOAD_NOSPACE;
1170                        goto out;
1171                
1172                }
1173                ret = vm_map_copyin(copy_map,
1174                                    (vm_map_address_t)dyl_start,
1175                                    (vm_map_size_t)dyl_length,
1176                                    TRUE, &tmp);
1177                if (ret != KERN_SUCCESS) {
1178                        (void) vm_map_remove(map,
1179                                     vm_map_trunc_page(map_addr),
1180                                     vm_map_round_page(map_addr + dyl_length),
1181                                     VM_MAP_NO_FLAGS);
1182                        goto out;
1183                }
1184
1185                ret = vm_map_copy_overwrite(map,
1186                                     (vm_map_address_t)map_addr,
1187                                     tmp, FALSE);
1188                if (ret != KERN_SUCCESS) {
1189                        vm_map_copy_discard(tmp);
1190                        (void) vm_map_remove(map,
1191                                     vm_map_trunc_page(map_addr),
1192                                     vm_map_round_page(map_addr + dyl_length),
1193                                     VM_MAP_NO_FLAGS);
1194                        goto out;
1195                }
1196
1197                if (map_addr != dyl_start)
1198                        myresult.entry_point += (map_addr - dyl_start);
1199        } else
1200                ret = LOAD_FAILURE;
1201        
1202        if (ret == LOAD_SUCCESS) {              
1203                result->dynlinker = TRUE;
1204                result->entry_point = myresult.entry_point;
1205                (void)ubc_map(vp, PROT_EXEC);
1206        }
1207out:
1208        vm_map_deallocate(copy_map);
1209        
1210        vnode_put(vp);
1211        return (ret);
1212
1213}
1214
1215/*
1216 * This routine exists to support the load_dylinker().
1217 *
1218 * This routine has its own, separate, understanding of the FAT file format,
1219 * which is terrifically unfortunate.
1220 */
1221static
1222load_return_t
1223get_macho_vnode(
1224        char                    *path,
1225        integer_t               archbits,
1226        struct mach_header      *mach_header,
1227        off_t                   *file_offset,
1228        off_t                   *macho_size,
1229        struct vnode            **vpp
1230)
1231{
1232        struct vnode            *vp;
1233        struct vfs_context context;
1234        struct nameidata nid, *ndp;
1235        struct proc *p = current_proc();                /* XXXX */
1236        boolean_t               is_fat;
1237        struct fat_arch         fat_arch;
1238        int                     error = LOAD_SUCCESS;
1239        int resid;
1240        union {
1241                struct mach_header      mach_header;
1242                struct fat_header       fat_header;
1243                char    pad[512];
1244        } header;
1245        off_t fsize = (off_t)0;
1246        struct  ucred *cred = kauth_cred_get();
1247        int err2;
1248        
1249        context.vc_proc = p;
1250        context.vc_ucred = cred;
1251
1252        ndp = &nid;
1253        
1254        /* init the namei data to point the file user's program name */
1255        NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE32, CAST_USER_ADDR_T(path), &context);
1256
1257        if ((error = namei(ndp)) != 0) {
1258                if (error == ENOENT)
1259                        error = LOAD_ENOENT;
1260                else
1261                        error = LOAD_FAILURE;
1262                return(error);
1263        }
1264        nameidone(ndp);
1265        vp = ndp->ni_vp;
1266        
1267        /* check for regular file */
1268        if (vp->v_type != VREG) {
1269                error = LOAD_PROTECT;
1270                goto bad1;
1271        }
1272
1273        /* get size */
1274        if ((error = vnode_size(vp, &fsize, &context)) != 0) {
1275                error = LOAD_FAILURE;
1276                goto bad1;
1277        }
1278
1279        /* Check mount point */
1280        if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
1281                error = LOAD_PROTECT;
1282                goto bad1;
1283        }
1284
1285        /* check access */
1286        if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_EXECUTE, &context)) != 0) {
1287                error = LOAD_PROTECT;
1288                goto bad1;
1289        }
1290
1291        /* try to open it */
1292        if ((error = VNOP_OPEN(vp, FREAD, &context)) != 0) {
1293                error = LOAD_PROTECT;
1294                goto bad1;
1295        }
1296
1297        if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)&header, sizeof(header), 0,
1298            UIO_SYSSPACE32, IO_NODELOCKED, cred, &resid, p)) != 0) {
1299                error = LOAD_IOERROR;
1300                goto bad2;
1301        }
1302        
1303        if (header.mach_header.magic == MH_MAGIC ||
1304            header.mach_header.magic == MH_MAGIC_64)
1305            is_fat = FALSE;
1306        else if (header.fat_header.magic == FAT_MAGIC ||
1307                 header.fat_header.magic == FAT_CIGAM)
1308            is_fat = TRUE;
1309        else {
1310            error = LOAD_BADMACHO;
1311            goto bad2;
1312        }
1313
1314        if (is_fat) {
1315                /* Look up our architecture in the fat file. */
1316                error = fatfile_getarch_with_bits(vp, archbits, (vm_offset_t)(&header.fat_header), &fat_arch);
1317                if (error != LOAD_SUCCESS)
1318                        goto bad2;
1319
1320                /* Read the Mach-O header out of it */
1321                error = vn_rdwr(UIO_READ, vp, (caddr_t)&header.mach_header,
1322                                sizeof(header.mach_header), fat_arch.offset,
1323                                UIO_SYSSPACE32, IO_NODELOCKED, cred, &resid, p);
1324                if (error) {
1325                        error = LOAD_IOERROR;
1326                        goto bad2;
1327                }
1328
1329                /* Is this really a Mach-O? */
1330                if (header.mach_header.magic != MH_MAGIC &&
1331                    header.mach_header.magic != MH_MAGIC_64) {
1332                        error = LOAD_BADMACHO;
1333                        goto bad2;
1334                }
1335
1336                *file_offset = fat_arch.offset;
1337                *macho_size = fsize = fat_arch.size;
1338        } else {
1339                /*
1340                 * Force get_macho_vnode() to fail if the architecture bits
1341                 * do not match the expected architecture bits.  This in
1342                 * turn causes load_dylinker() to fail for the same reason,
1343                 * so it ensures the dynamic linker and the binary are in
1344                 * lock-step.  This is potentially bad, if we ever add to
1345                 * the CPU_ARCH_* bits any bits that are desirable but not
1346                 * required, since the dynamic linker might work, but we will
1347                 * refuse to load it because of this check.
1348                 */
1349                if ((cpu_type_t)(header.mach_header.cputype & CPU_ARCH_MASK) != archbits)
1350                        return(LOAD_BADARCH);
1351
1352                *file_offset = 0;
1353                *macho_size = fsize;
1354        }
1355
1356        *mach_header = header.mach_header;
1357        *vpp = vp;
1358
1359        ubc_setsize(vp, fsize);
1360        
1361        return (error);
1362
1363bad2:
1364        err2 = VNOP_CLOSE(vp, FREAD, &context);
1365        vnode_put(vp);
1366        return (error);
1367
1368bad1:
1369        vnode_put(vp);
1370        return(error);
1371}
1372
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.