Annotation of XNU/bsd/kern/mach_loader.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 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: #include <mach_nbc.h>
                     34: #include <sys/param.h>
                     35: #include <sys/vnode.h>
                     36: #include <sys/uio.h>
                     37: #include <sys/namei.h>
                     38: #include <sys/proc.h>
                     39: #include <sys/stat.h>
                     40: #include <sys/malloc.h>
                     41: #include <sys/mount.h>
                     42: #include <sys/fcntl.h>
                     43: 
                     44: #include <ufs/ufs/lockf.h>
                     45: #include <ufs/ufs/quota.h>
                     46: #include <ufs/ufs/inode.h>
                     47: 
                     48: #include <mach/mach_types.h>
                     49: 
                     50: #include <kern/mach_loader.h>
                     51: #include <kern/mapfs.h>
                     52: 
                     53: #include <mach-o/fat.h>
                     54: #include <mach-o/loader.h>
                     55: 
                     56: #include <kern/cpu_number.h>
                     57: 
                     58: #include <vm/vm_map.h>
                     59: #include <vm/vm_kern.h>
                     60: #include <vm/vm_pager.h>
                     61: #include <vm/vnode_pager.h>
                     62: #include <mach/shared_memory_server.h>
                     63: 
                     64: /*
                     65:  * Prototypes of static functions.
                     66:  */
                     67: static
                     68: load_return_t
                     69: parse_machfile(
                     70:        struct vnode            *vp,
                     71:        vm_map_t                map,
                     72:        struct mach_header      *header,
                     73:        unsigned long           file_offset,
                     74:        unsigned long           macho_size,
                     75:        int                     depth,
                     76:        unsigned long           *lib_version,
                     77:        load_result_t           *result
                     78: ),
                     79: load_segment(
                     80:        struct segment_command  *scp,
                     81:        void *                  pager,
                     82:        unsigned long           pager_offset,
                     83:        unsigned long           macho_size,
                     84:        unsigned long           end_of_file,
                     85:        vm_map_t                map,
                     86:        load_result_t           *result
                     87: ),
                     88: load_unixthread(
                     89:        struct thread_command   *tcp,
                     90:        load_result_t           *result
                     91: ),
                     92: load_thread(
                     93:        struct thread_command   *tcp,
                     94:        load_result_t           *result
                     95: ),
                     96: load_threadstate(
                     97:        thread_t        thread,
                     98:        unsigned long   *ts,
                     99:        unsigned long   total_size
                    100: ),
                    101: load_threadstack(
                    102:        thread_t        thread,
                    103:        unsigned long   *ts,
                    104:        unsigned long   total_size,
                    105:        vm_offset_t     *user_stack
                    106: ),
                    107: load_threadentry(
                    108:        thread_t        thread,
                    109:        unsigned long   *ts,
                    110:        unsigned long   total_size,
                    111:        vm_offset_t     *entry_point
                    112: ),
                    113: load_fvmlib(
                    114:        struct fvmlib_command   *lcp,
                    115:        vm_map_t                map,
                    116:        int                     depth
                    117: ),
                    118: load_idfvmlib(
                    119:        struct fvmlib_command   *lcp,
                    120:        unsigned long           *version
                    121: ),
                    122: load_dylinker(
                    123:        struct dylinker_command *lcp,
                    124:        vm_map_t                map,
                    125:        int                     depth,
                    126:        load_result_t           *result
                    127: ),
                    128: get_macho_vnode(
                    129:        char                    *path,
                    130:        struct mach_header      *mach_header,
                    131:        unsigned long           *file_offset,
                    132:        unsigned long           *macho_size,
                    133:        struct vnode            **vpp
                    134: );
                    135: 
                    136: load_return_t
                    137: load_machfile(
                    138:        struct vnode            *vp,
                    139:        struct mach_header      *header,
                    140:        unsigned long           file_offset,
                    141:        unsigned long           macho_size,
                    142:        load_result_t           *result
                    143: )
                    144: {
                    145:        pmap_t                  pmap;
                    146:        vm_map_t                map;
                    147:        vm_map_t                old_map;
                    148:        load_result_t           myresult;
                    149:        kern_return_t           kret;
                    150:        load_return_t           lret;
                    151:        extern void map_ref_fixup(vm_map_t,vm_map_t);
                    152: 
                    153:        old_map = current_map();
                    154:        pmap = get_task_pmap(current_task());
                    155:        pmap_reference(pmap);
                    156:        map = vm_map_create(pmap,
                    157:                        get_map_min(old_map),
                    158:                        get_map_max(old_map),
                    159:                        TRUE); /**** FIXME ****/
                    160: 
                    161:        if (!result)
                    162:                result = &myresult;
                    163: 
                    164:        *result = (load_result_t) { 0 };
                    165: 
                    166:        lret = parse_machfile(vp, map, header, file_offset, macho_size,
                    167:                             0, (unsigned long *)0, result);
                    168: 
                    169:        if (lret != LOAD_SUCCESS) {
                    170:                vm_map_deallocate(map); /* will lose pmap reference too */
                    171:                return(lret);
                    172:        }
                    173:        /*
                    174:         *      Commit to new map, destroy old map.  (Destruction
                    175:         *      of old map cleans up pmap data structures too).
                    176:         */
                    177:        /* current_task()->map = map; */
                    178:        set_task_map(current_task(),map);
                    179:        set_act_map(current_act(),map);
                    180:        /****** FIX ME ***/
                    181:        map_ref_fixup(old_map, map);
                    182:        vm_map_deallocate(old_map);
                    183: 
                    184:        return(LOAD_SUCCESS);
                    185: }
                    186: 
                    187: int    dylink_test = 0;
                    188: 
                    189: static
                    190: load_return_t
                    191: parse_machfile(
                    192:        struct vnode            *vp,
                    193:        vm_map_t                map,
                    194:        struct mach_header      *header,
                    195:        unsigned long           file_offset,
                    196:        unsigned long           macho_size,
                    197:        int                     depth,
                    198:        unsigned long           *lib_version,
                    199:        load_result_t           *result
                    200: )
                    201: {
                    202:        struct machine_slot     *ms;
                    203:        int                     ncmds;
                    204:        struct load_command     *lcp, *next;
                    205:        struct dylinker_command *dlp = 0;
                    206:        void *                  pager;
                    207:        load_return_t           ret;
                    208:        vm_offset_t             addr, kl_addr;
                    209:        vm_size_t               size,kl_size;
                    210:        int                     offset;
                    211:        int                     pass;
                    212:        struct proc *p = current_proc();                /* XXXX */
                    213:        int                     error;
                    214:        int resid=0;
                    215: 
                    216:        /*
                    217:         *      Break infinite recursion
                    218:         */
                    219:        if (depth > 6)
                    220:                return(LOAD_FAILURE);
                    221:        depth++;
                    222: 
                    223:        /*
                    224:         *      Check to see if right machine type.
                    225:         */
                    226:        ms = &machine_slot[cpu_number()];
                    227:        if ((header->cputype != ms->cpu_type) ||
                    228:            !check_cpu_subtype(header->cpusubtype))
                    229:                return(LOAD_BADARCH);
                    230:                
                    231:        switch (header->filetype) {
                    232:        
                    233:        case MH_OBJECT:
                    234:        case MH_EXECUTE:
                    235:        case MH_PRELOAD:
                    236:                if (depth != 1)
                    237:                        return (LOAD_FAILURE);
                    238:                break;
                    239:                
                    240:        case MH_FVMLIB:
                    241:        case MH_DYLIB:
                    242:                if (depth == 1)
                    243:                        return (LOAD_FAILURE);
                    244:                break;
                    245: 
                    246:        case MH_DYLINKER:
                    247:                if (depth != 2)
                    248:                        return (LOAD_FAILURE);
                    249:                break;
                    250:                
                    251:        default:
                    252:                return (LOAD_FAILURE);
                    253:        }
                    254: 
                    255:        /*
                    256:         *      Get the pager for the file.
                    257:         */
                    258:        if (!vp->v_vm_info) {
                    259:                vm_info_init(vp);
                    260:        }
                    261:        pager = (void *) vnode_pager_setup(vp, vp->v_vm_info->pager, FALSE, TRUE);
                    262: 
                    263: 
                    264:        /*
                    265:         *      Map portion that must be accessible directly into
                    266:         *      kernel's map.
                    267:         */
                    268:        if ((sizeof (struct mach_header) + header->sizeofcmds) > macho_size)
                    269:                return(LOAD_BADMACHO);
                    270: 
                    271:        /*
                    272:         *      Round size of Mach-O commands up to page boundry.
                    273:         */
                    274:        size = round_page(sizeof (struct mach_header) + header->sizeofcmds);
                    275:        if (size <= 0)
                    276:                return(LOAD_BADMACHO);
                    277: 
                    278:        /*
                    279:         * Map the load commands into kernel memory.
                    280:         */
                    281:        addr = 0;
                    282: #if 0 /* [
                    283: #if FIXME
                    284:        ret = vm_allocate_with_pager(kernel_map, &addr, size, TRUE, pager,
                    285:                                     file_offset);
                    286: #else
                    287:        ret = vm_map(kernel_map,&addr,size,0,TRUE, pager, file_offset, FALSE,
                    288:                        VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
                    289: #endif /* FIXME */
                    290:        if (ret != KERN_SUCCESS) {
                    291:                return(LOAD_NOSPACE);
                    292:        }
                    293: #else /* 0 ][ */
                    294:        kl_size = size;
                    295:        kl_addr = kalloc(size);
                    296:        addr = kl_addr;
                    297:        if (addr == NULL)  {
                    298:                printf("No space to readin load commands\n");
                    299:                return(LOAD_NOSPACE);
                    300:        }
                    301:        if(error = vn_rdwr(UIO_READ, vp, addr, size, file_offset,
                    302:            UIO_SYSSPACE, 0, p->p_ucred, &resid, p)) {
                    303:                printf("Load command read over nfs failed\n");
                    304:                if (kl_addr ) kfree(kl_addr,kl_size);
                    305:                return(EIO);
                    306:        }
                    307:        
                    308: #endif /* 0 ] */
                    309:        /*
                    310:         *      Scan through the commands, processing each one as necessary.
                    311:         */
                    312:        for (pass = 1; pass <= 2; pass++) {
                    313:                offset = sizeof(struct mach_header);
                    314:                ncmds = header->ncmds;
                    315:                while (ncmds--) {
                    316:                        /*
                    317:                         *      Get a pointer to the command.
                    318:                         */
                    319:                        lcp = (struct load_command *)(addr + offset);
                    320:                        offset += lcp->cmdsize;
                    321: 
                    322:                        /*
                    323:                         *      Check for valid lcp pointer by checking
                    324:                         *      next offset.
                    325:                         */
                    326:                        if (offset > header->sizeofcmds
                    327:                                        + sizeof(struct mach_header)) {
                    328: #if 0
                    329:                                vm_map_remove(kernel_map, addr, addr + size);
                    330: #endif
                    331:                                if (kl_addr ) kfree(kl_addr,kl_size);
                    332:                                return(LOAD_BADMACHO);
                    333:                        }
                    334: 
                    335:                        /*
                    336:                         *      Check for valid command.
                    337:                         */
                    338:                        switch(lcp->cmd) {
                    339:                        case LC_SEGMENT:
                    340:                                if (pass != 1)
                    341:                                        break;
                    342:                                ret = load_segment(
                    343:                                               (struct segment_command *) lcp,
                    344:                                                   pager, file_offset,
                    345:                                                   macho_size,
                    346:                                                   vp->v_vm_info->vnode_size,
                    347:                                                   map,
                    348:                                                   result);
                    349:                                break;
                    350:                        case LC_THREAD:
                    351:                                if (pass != 2)
                    352:                                        break;
                    353:                                ret = load_thread((struct thread_command *)lcp,
                    354:                                                  result);
                    355:                                break;
                    356:                        case LC_UNIXTHREAD:
                    357:                                if (pass != 2)
                    358:                                        break;
                    359:                                ret = load_unixthread(
                    360:                                                 (struct thread_command *) lcp,
                    361:                                                 result);
                    362:                                break;
                    363:                        case LC_LOADFVMLIB:
                    364:                                if (pass != 1)
                    365:                                        break;
                    366:                                ret = load_fvmlib((struct fvmlib_command *)lcp,
                    367:                                                  map, depth);
                    368:                                break;
                    369:                        case LC_IDFVMLIB:
                    370:                                if (pass != 1)
                    371:                                        break;
                    372:                                if (lib_version) {
                    373:                                        ret = load_idfvmlib(
                    374:                                                (struct fvmlib_command *)lcp,
                    375:                                                lib_version);
                    376:                                }
                    377:                                break;
                    378:                        case LC_LOAD_DYLINKER:
                    379:                                if (pass != 2)
                    380:                                        break;
                    381:                                if (depth == 1 || dlp == 0)
                    382:                                        dlp = (struct dylinker_command *)lcp;
                    383:                                else
                    384:                                        ret = LOAD_FAILURE;
                    385:                                break;
                    386:                        default:
                    387:                                ret = KERN_SUCCESS;/* ignore other stuff */
                    388:                        }
                    389:                        if (ret != LOAD_SUCCESS)
                    390:                                break;
                    391:                }
                    392:                if (ret != LOAD_SUCCESS)
                    393:                        break;
                    394:        }
                    395:        if (ret == LOAD_SUCCESS && dlp != 0) {
                    396:                vm_offset_t addr;
                    397: 
                    398:                if (dylink_test) {
                    399:                        addr = 0x20000000;
                    400:                        vm_map(map, &addr, 0x10000000, 0, SHARED_LIB_ALIAS,
                    401:                                shared_text_region_handle, 0, FALSE,
                    402:                                VM_PROT_READ, VM_PROT_READ, VM_INHERIT_SHARE);
                    403:                        addr = 0x30000000;
                    404:                        vm_map(map, &addr, 0x10000000, 0, SHARED_LIB_ALIAS,
                    405:                                shared_data_region_handle, 0, TRUE,
                    406:                                VM_PROT_READ, VM_PROT_READ, VM_INHERIT_SHARE);
                    407:                }
                    408:                ret = load_dylinker(dlp, map, depth, result);
                    409:        }
                    410: 
                    411:        if (kl_addr ) kfree(kl_addr,kl_size);
                    412: #if 0
                    413:        vm_map_remove(kernel_map, addr, addr + size);
                    414: #endif
                    415:        if ((ret == LOAD_SUCCESS) && (depth == 1) &&
                    416:                                (result->thread_count == 0))
                    417:                ret = LOAD_FAILURE;
                    418:        return(ret);
                    419: }
                    420: 
                    421: static
                    422: load_return_t load_segment(
                    423:        struct segment_command  *scp,
                    424:        void *                  pager,
                    425:        unsigned long           pager_offset,
                    426:        unsigned long           macho_size,
                    427:        unsigned long           end_of_file,
                    428:        vm_map_t                map,
                    429:        load_result_t           *result
                    430: )
                    431: {
                    432:        kern_return_t           ret;
                    433:        vm_offset_t             map_addr, map_offset;
                    434:        vm_size_t               map_size, seg_size, delta_size;
                    435:        caddr_t                 tmp;
                    436:        vm_prot_t               initprot;
                    437:        vm_prot_t               maxprot;
                    438: #if 1
                    439:        extern int print_map_addr;
                    440: #endif /* 1 */
                    441: 
                    442:        /*
                    443:         * Make sure what we get from the file is really ours (as specified
                    444:         * by macho_size).
                    445:         */
                    446:        if (scp->fileoff + scp->filesize > macho_size)
                    447:                return (LOAD_BADMACHO);
                    448: 
                    449:        seg_size = round_page(scp->vmsize);
                    450:        if (seg_size == 0)
                    451:                return(KERN_SUCCESS);
                    452: 
                    453:        /*
                    454:         *      Round sizes to page size.
                    455:         */
                    456:        map_size = round_page(scp->filesize);
                    457:        map_addr = trunc_page(scp->vmaddr);
                    458: 
                    459:        map_offset = pager_offset + scp->fileoff;
                    460: 
                    461:        if (map_size > 0) {
                    462:                initprot = (scp->initprot) & VM_PROT_ALL;
                    463:                maxprot = (scp->maxprot) & VM_PROT_ALL;
                    464:                /*
                    465:                 *      Map a copy of the file into the address space.
                    466:                 */
                    467:                ret = vm_map(map,
                    468:                                &map_addr, map_size, (vm_offset_t)0, FALSE,
                    469:                                pager, map_offset, TRUE,
                    470:                                initprot, maxprot,
                    471:                                VM_INHERIT_DEFAULT);
                    472:                if (ret != KERN_SUCCESS)
                    473:                        return(LOAD_NOSPACE);
                    474:        
                    475: #if 1
                    476:                if (print_map_addr)
                    477:                        printf("LSegment: Mapped addr= %x; size = %x\n", map_addr, map_size);
                    478: #endif /* 1 */
                    479:                /*
                    480:                 *      If the file didn't end on a page boundary,
                    481:                 *      we need to zero the leftover.
                    482:                 */
                    483:                delta_size = map_size - scp->filesize;
                    484: #if FIXME
                    485:                if (delta_size > 0) {
                    486:                        vm_offset_t     tmp;
                    487:        
                    488:                        ret = vm_allocate(kernel_map, &tmp, delta_size, TRUE);
                    489:                        if (ret != KERN_SUCCESS)
                    490:                                return(LOAD_RESOURCE);
                    491:        
                    492:                        if (copyout(tmp, map_addr + scp->filesize,
                    493:                                                                delta_size)) {
                    494:                                (void) vm_deallocate(
                    495:                                                kernel_map, tmp, delta_size);
                    496:                                return(LOAD_FAILURE);
                    497:                        }
                    498:                        
                    499:                        (void) vm_deallocate(kernel_map, tmp, delta_size);
                    500:                }
                    501: #endif /* FIXME */
                    502:        }
                    503: 
                    504:        /*
                    505:         *      If the virtual size of the segment is greater
                    506:         *      than the size from the file, we need to allocate
                    507:         *      zero fill memory for the rest.
                    508:         */
                    509:        delta_size = seg_size - map_size;
                    510:        if (delta_size > 0) {
                    511:                vm_offset_t     tmp = map_addr + map_size;
                    512: 
                    513:                ret = vm_allocate(map, &tmp, delta_size, FALSE);
                    514:                if (ret != KERN_SUCCESS)
                    515:                        return(LOAD_NOSPACE);
                    516:        }
                    517: 
                    518:        /*
                    519:         *      Set protection values. (Note: ignore errors!)
                    520:         */
                    521: 
                    522:        if (scp->maxprot != VM_PROT_DEFAULT) {
                    523:                (void) vm_protect(map,
                    524:                                        map_addr, seg_size,
                    525:                                        TRUE, scp->maxprot);
                    526:        }
                    527:        if (scp->initprot != VM_PROT_DEFAULT) {
                    528:                (void) vm_protect(map,
                    529:                                      map_addr, seg_size,
                    530:                                      FALSE, scp->initprot);
                    531:        }
                    532:        if ( (scp->fileoff == 0) && (scp->filesize != 0) )
                    533:                result->mach_header = map_addr;
                    534:        return(LOAD_SUCCESS);
                    535: }
                    536: 
                    537: static
                    538: load_return_t
                    539: load_unixthread(
                    540:        struct thread_command   *tcp,
                    541:        load_result_t           *result
                    542: )
                    543: {
                    544:        thread_t        thread = current_thread();
                    545:        load_return_t   ret;
                    546:        
                    547:        if (result->thread_count != 0)
                    548:                return (LOAD_FAILURE);
                    549:        
                    550:        ret = load_threadstack(thread,
                    551:                       (unsigned long *)(((vm_offset_t)tcp) + 
                    552:                                sizeof(struct thread_command)),
                    553:                       tcp->cmdsize - sizeof(struct thread_command),
                    554:                       &result->user_stack);
                    555:        if (ret != LOAD_SUCCESS)
                    556:                return(ret);
                    557: 
                    558:        ret = load_threadentry(thread,
                    559:                       (unsigned long *)(((vm_offset_t)tcp) + 
                    560:                                sizeof(struct thread_command)),
                    561:                       tcp->cmdsize - sizeof(struct thread_command),
                    562:                       &result->entry_point);
                    563:        if (ret != LOAD_SUCCESS)
                    564:                return(ret);
                    565: 
                    566:        ret = load_threadstate(thread,
                    567:                       (unsigned long *)(((vm_offset_t)tcp) + 
                    568:                                sizeof(struct thread_command)),
                    569:                       tcp->cmdsize - sizeof(struct thread_command));
                    570:        if (ret != LOAD_SUCCESS)
                    571:                return (ret);
                    572: 
                    573:        result->unixproc = TRUE;
                    574:        result->thread_count++;
                    575: 
                    576:        return(LOAD_SUCCESS);
                    577: }
                    578: 
                    579: static
                    580: load_return_t
                    581: load_thread(
                    582:        struct thread_command   *tcp,
                    583:        load_result_t           *result
                    584: )
                    585: {
                    586:        thread_t        thread;
                    587:        kern_return_t   kret;
                    588:        load_return_t   lret;
                    589: 
                    590:        if (result->thread_count == 0)
                    591:                thread = current_thread();
                    592:        else {
                    593:                kret = thread_create(current_task(), &thread);
                    594:                if (kret != KERN_SUCCESS)
                    595:                        return(LOAD_RESOURCE);
                    596:                thread_deallocate(thread);
                    597:        }
                    598: 
                    599:        lret = load_threadstate(thread,
                    600:                       (unsigned long *)(((vm_offset_t)tcp) + 
                    601:                                sizeof(struct thread_command)),
                    602:                       tcp->cmdsize - sizeof(struct thread_command));
                    603:        if (lret != LOAD_SUCCESS)
                    604:                return (lret);
                    605: 
                    606:        if (result->thread_count == 0) {
                    607:                lret = load_threadstack(current_thread(),
                    608:                                (unsigned long *)(((vm_offset_t)tcp) + 
                    609:                                        sizeof(struct thread_command)),
                    610:                                tcp->cmdsize - sizeof(struct thread_command),
                    611:                                &result->user_stack);
                    612:                if (lret != LOAD_SUCCESS)
                    613:                        return(lret);
                    614: 
                    615:                lret = load_threadentry(current_thread(),
                    616:                                (unsigned long *)(((vm_offset_t)tcp) + 
                    617:                                        sizeof(struct thread_command)),
                    618:                                tcp->cmdsize - sizeof(struct thread_command),
                    619:                                &result->entry_point);
                    620:                if (lret != LOAD_SUCCESS)
                    621:                        return(lret);
                    622:        }
                    623:        /*
                    624:         *      Resume thread now, note that this means that the thread
                    625:         *      commands should appear after all the load commands to
                    626:         *      be sure they don't reference anything not yet mapped.
                    627:         */
                    628:        else
                    629:                thread_resume(thread);
                    630:                
                    631:        result->thread_count++;
                    632: 
                    633:        return(LOAD_SUCCESS);
                    634: }
                    635: 
                    636: static
                    637: load_return_t
                    638: load_threadstate(
                    639:        thread_t        thread,
                    640:        unsigned long   *ts,
                    641:        unsigned long   total_size
                    642: )
                    643: {
                    644:        kern_return_t   ret;
                    645:        unsigned long   size;
                    646:        int             flavor;
                    647: 
                    648:        /*
                    649:         *      Set the thread state.
                    650:         */
                    651: 
                    652:        while (total_size > 0) {
                    653:                flavor = *ts++;
                    654:                size = *ts++;
                    655:                total_size -= (size+2)*sizeof(unsigned long);
                    656:                if (total_size < 0)
                    657:                        return(LOAD_BADMACHO);
                    658:                ret = thread_setstatus(getact_thread(thread), flavor, ts, size);
                    659:                if (ret != KERN_SUCCESS)
                    660:                        return(LOAD_FAILURE);
                    661:                ts += size;     /* ts is a (unsigned long *) */
                    662:        }
                    663:        return(LOAD_SUCCESS);
                    664: }
                    665: 
                    666: static
                    667: load_return_t
                    668: load_threadstack(
                    669:        thread_t        thread,
                    670:        unsigned long   *ts,
                    671:        unsigned long   total_size,
                    672:        vm_offset_t     *user_stack
                    673: )
                    674: {
                    675:        kern_return_t   ret;
                    676:        unsigned long   size;
                    677:        int             flavor;
                    678: 
                    679:        /*
                    680:         *      Set the thread state.
                    681:         */
                    682:        *user_stack = 0;
                    683:        while (total_size > 0) {
                    684:                flavor = *ts++;
                    685:                size = *ts++;
                    686:                total_size -= (size+2)*sizeof(unsigned long);
                    687:                if (total_size < 0)
                    688:                        return(LOAD_BADMACHO);
                    689:                ret = thread_userstack(thread, flavor, ts, size, user_stack);
                    690:                if (ret != KERN_SUCCESS)
                    691:                        return(LOAD_FAILURE);
                    692:                ts += size;     /* ts is a (unsigned long *) */
                    693:        }
                    694:        return(LOAD_SUCCESS);
                    695: }
                    696: 
                    697: static
                    698: load_return_t
                    699: load_threadentry(
                    700:        thread_t        thread,
                    701:        unsigned long   *ts,
                    702:        unsigned long   total_size,
                    703:        vm_offset_t     *entry_point
                    704: )
                    705: {
                    706:        kern_return_t   ret;
                    707:        unsigned long   size;
                    708:        int             flavor;
                    709: 
                    710:        /*
                    711:         *      Set the thread state.
                    712:         */
                    713:        *entry_point = 0;
                    714:        while (total_size > 0) {
                    715:                flavor = *ts++;
                    716:                size = *ts++;
                    717:                total_size -= (size+2)*sizeof(unsigned long);
                    718:                if (total_size < 0)
                    719:                        return(LOAD_BADMACHO);
                    720:                ret = thread_entrypoint(thread, flavor, ts, size, entry_point);
                    721:                if (ret != KERN_SUCCESS)
                    722:                        return(LOAD_FAILURE);
                    723:                ts += size;     /* ts is a (unsigned long *) */
                    724:        }
                    725:        return(LOAD_SUCCESS);
                    726: }
                    727: 
                    728: static
                    729: load_return_t
                    730: load_fvmlib(
                    731:        struct fvmlib_command   *lcp,
                    732:        vm_map_t                map,
                    733:        int                     depth
                    734: )
                    735: {
                    736:        char                    *name;
                    737:        char                    *p;
                    738:        struct vnode            *vp;
                    739:        struct mach_header      header;
                    740:        unsigned long           file_offset;
                    741:        unsigned long           macho_size;
                    742:        unsigned long           lib_version;
                    743:        load_result_t           myresult;
                    744:        kern_return_t           ret;
                    745: 
                    746:        name = (char *)lcp + lcp->fvmlib.name.offset;
                    747:        /*
                    748:         *      Check for a proper null terminated string.
                    749:         */
                    750:        p = name;
                    751:        do {
                    752:                if (p >= (char *)lcp + lcp->cmdsize)
                    753:                        return(LOAD_BADMACHO);
                    754:        } while (*p++);
                    755: 
                    756:        ret = get_macho_vnode(name, &header, &file_offset, &macho_size, &vp);
                    757:        if (ret)
                    758:                return (ret);
                    759:                
                    760:        myresult = (load_result_t) { 0 };
                    761: 
                    762:        /*
                    763:         *      Load the Mach-O.
                    764:         */
                    765:        ret = parse_machfile(vp, map, &header,
                    766:                                file_offset, macho_size,
                    767:                                depth, &lib_version, &myresult);
                    768: 
                    769:        if ((ret == LOAD_SUCCESS) &&
                    770:            (lib_version < lcp->fvmlib.minor_version))
                    771:                ret = LOAD_SHLIB;
                    772: 
                    773:        vrele(vp);
                    774:        return(ret);
                    775: }
                    776: 
                    777: static
                    778: load_return_t
                    779: load_idfvmlib(
                    780:        struct fvmlib_command   *lcp,
                    781:        unsigned long           *version
                    782: )
                    783: {
                    784:        *version = lcp->fvmlib.minor_version;
                    785:        return(LOAD_SUCCESS);
                    786: }
                    787: 
                    788: 
                    789: static
                    790: load_return_t
                    791: load_dylinker(
                    792:        struct dylinker_command *lcp,
                    793:        vm_map_t                map,
                    794:        int                     depth,
                    795:        load_result_t           *result
                    796: )
                    797: {
                    798:        char                    *name;
                    799:        char                    *p;
                    800:        struct vnode            *vp;
                    801:        struct mach_header      header;
                    802:        unsigned long           file_offset;
                    803:        unsigned long           macho_size;
                    804:        vm_map_t                copy_map;
                    805:        load_result_t           myresult;
                    806:        kern_return_t           ret;
                    807:        vm_map_copy_t   tmp;
                    808:        vm_offset_t     dyl_start, map_addr;
                    809:        vm_size_t       dyl_length;
                    810: 
                    811:        name = (char *)lcp + lcp->name.offset;
                    812:        /*
                    813:         *      Check for a proper null terminated string.
                    814:         */
                    815:        p = name;
                    816:        do {
                    817:                if (p >= (char *)lcp + lcp->cmdsize)
                    818:                        return(LOAD_BADMACHO);
                    819:        } while (*p++);
                    820: 
                    821:        ret = get_macho_vnode(name, &header, &file_offset, &macho_size, &vp);
                    822:        if (ret)
                    823:                return (ret);
                    824:                        
                    825:        myresult = (load_result_t) { 0 };
                    826: 
                    827:        /*
                    828:         *      Load the Mach-O.
                    829:         */
                    830:                
                    831:        copy_map = vm_map_create(pmap_create(macho_size),
                    832:                        get_map_min(map), get_map_max( map), TRUE);
                    833: 
                    834:        ret = parse_machfile(vp, copy_map, &header,
                    835:                                file_offset, macho_size,
                    836:                                depth, 0, &myresult);
                    837: 
                    838:        if (ret)
                    839:                goto out;
                    840: 
                    841:        if (get_map_nentries(copy_map) > 0) {
                    842: 
                    843:                dyl_start = get_map_start(copy_map);
                    844:                dyl_length = get_map_end(copy_map) - dyl_start;
                    845: 
                    846:                map_addr = dyl_start;
                    847:                ret = vm_allocate(map, &map_addr, dyl_length, FALSE);
                    848:                if (ret != KERN_SUCCESS)  {
                    849:                        ret = vm_allocate(map, &map_addr, dyl_length, TRUE);
                    850:                }
                    851: 
                    852:                if (ret != KERN_SUCCESS) {
                    853:                        ret = LOAD_NOSPACE;
                    854:                        goto out;
                    855:                
                    856:                }
                    857:                ret = vm_map_copyin(copy_map, dyl_start, dyl_length, TRUE,
                    858:                                &tmp);
                    859:                if (ret != KERN_SUCCESS) {
                    860:                        (void) vm_map_remove(map,
                    861:                                             map_addr,
                    862:                                             map_addr + dyl_length,
                    863:                                             VM_MAP_NO_FLAGS);
                    864:                        goto out;
                    865:                }
                    866: 
                    867:                ret = vm_map_copy_overwrite(map, map_addr, tmp, FALSE);
                    868:                if (ret != KERN_SUCCESS) {
                    869:                                vm_map_copy_discard(tmp);
                    870:                                (void) vm_map_remove(map,
                    871:                                                     map_addr,
                    872:                                                     map_addr + dyl_length,
                    873:                                                     VM_MAP_NO_FLAGS);
                    874:                                goto out;               }
                    875: 
                    876:                if (map_addr != dyl_start)
                    877:                        myresult.entry_point += (map_addr - dyl_start);
                    878:        } else
                    879:                ret = LOAD_FAILURE;
                    880:        
                    881:        if (ret == LOAD_SUCCESS) {              
                    882:                result->dynlinker = TRUE;
                    883:                result->entry_point = myresult.entry_point;
                    884:        }
                    885: out:
                    886:        vm_map_deallocate(copy_map);
                    887:        
                    888:        vrele(vp);
                    889:        return (ret);
                    890: 
                    891: }
                    892: 
                    893: static
                    894: load_return_t
                    895: get_macho_vnode(
                    896:        char                    *path,
                    897:        struct mach_header      *mach_header,
                    898:        unsigned long           *file_offset,
                    899:        unsigned long           *macho_size,
                    900:        struct vnode            **vpp
                    901: )
                    902: {
                    903:        struct vnode            *vp;
                    904:        struct vattr attr, *atp;
                    905:        struct nameidata nid, *ndp;
                    906:        struct proc *p = current_proc();                /* XXXX */
                    907:        boolean_t               is_fat;
                    908:        struct fat_arch         fat_arch;
                    909:        int                     error;
                    910:        int resid;
                    911:        union {
                    912:                struct mach_header      mach_header;
                    913:                struct fat_header       fat_header;
                    914:                char    pad[512];
                    915:        } header;
                    916:        error = KERN_SUCCESS;
                    917:        
                    918:        ndp = &nid;
                    919:        atp = &attr;
                    920:        
                    921:        /* init the namei data to point the file user's program name */
                    922:        NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME, UIO_SYSSPACE, path, p);
                    923: 
                    924:        if (error = namei(ndp))
                    925:                return(error);
                    926:        
                    927:        vp = ndp->ni_vp;
                    928:        
                    929:        /* check for regular file */
                    930:        if (vp->v_type != VREG) {
                    931:                error = EACCES;
                    932:                goto bad1;
                    933:        }
                    934: 
                    935:        /* get attributes */
                    936:        if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p))
                    937:                goto bad1;
                    938: 
                    939:        /* Check mount point */
                    940:        if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
                    941:                error = EACCES;
                    942:                goto bad1;
                    943:        }
                    944: 
                    945:        if ((vp->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & P_TRACED))
                    946:                atp->va_mode &= ~(VSUID | VSGID);
                    947: 
                    948:                /* check access.  for root we have to see if any exec bit on */
                    949:        if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p))
                    950:                goto bad1;
                    951:        if ((atp->va_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) {
                    952:                error = EACCES;
                    953:                goto bad1;
                    954:        }
                    955: 
                    956:        /* try to open it */
                    957:        if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p))
                    958:                goto bad1;
                    959: #if MACH_NBC
                    960:        VOP_UNLOCK(vp, 0, p);
                    961: #endif /* MACH_NBC */
                    962:        if(error = vn_rdwr(UIO_READ, vp, (caddr_t)&header, sizeof(header), 0,
                    963:            UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p))
                    964:                goto bad2;
                    965: 
                    966: 
                    967: /* XXXX WMG - we should check for a short read of the header here */
                    968:        
                    969:        if (header.mach_header.magic == MH_MAGIC)
                    970:            is_fat = FALSE;
                    971:        else if (header.fat_header.magic == FAT_MAGIC ||
                    972:                 header.fat_header.magic == FAT_CIGAM)
                    973:            is_fat = TRUE;
                    974:        else {
                    975:            error = LOAD_BADMACHO;
                    976:            goto bad2;
                    977:        }
                    978: 
                    979:        if (is_fat) {
                    980:                /*
                    981:                 * Look up our architecture in the fat file.
                    982:                 */
                    983:                error = fatfile_getarch(vp, (vm_offset_t)(&header.fat_header), &fat_arch);
                    984:                if (error != LOAD_SUCCESS) {
                    985:                        goto bad2;
                    986:                }
                    987:                /*
                    988:                 *      Read the Mach-O header out of it
                    989:                 */
                    990:                error = vn_rdwr(UIO_READ, vp, &header.mach_header,
                    991:                                sizeof(header.mach_header), fat_arch.offset,
                    992:                                UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
                    993:                if (error) {
                    994:                        error = LOAD_FAILURE;
                    995:                        goto bad2;
                    996:                }
                    997: 
                    998:                /*
                    999:                 *      Is this really a Mach-O?
                   1000:                 */
                   1001:                if (header.mach_header.magic != MH_MAGIC) {
                   1002:                        error = LOAD_BADMACHO;
                   1003:                        goto bad2;
                   1004:                }
                   1005:                
                   1006:                *mach_header = header.mach_header;
                   1007:                *file_offset = fat_arch.offset;
                   1008:                *macho_size = fat_arch.size;
                   1009:                *vpp = vp;
                   1010:                // leaks otherwise - A.R
                   1011:                FREE_ZONE(ndp->ni_cnd.cn_pnbuf, ndp->ni_cnd.cn_pnlen, M_NAMEI);
                   1012:                
                   1013:                // i_lock exclusive panics, otherwise during pageins
                   1014: #if !MACH_NBC
                   1015:                VOP_UNLOCK(vp, 0, p);
                   1016: #endif /* !MACH_NBC */
                   1017:                return (error);
                   1018:        } else {
                   1019:        
                   1020:                *mach_header = header.mach_header;
                   1021:                *file_offset = 0;
                   1022:                if (vp->v_vm_info) {
                   1023:                        vp->v_vm_info->vnode_size = attr.va_size;
                   1024:                }
                   1025:                *macho_size =  attr.va_size;
                   1026:                *vpp = vp;
                   1027:                // leaks otherwise - A.R
                   1028:                FREE_ZONE(ndp->ni_cnd.cn_pnbuf, ndp->ni_cnd.cn_pnlen, M_NAMEI);
                   1029: 
                   1030:                // i_lock exclusive panics, otherwise during pageins
                   1031: #if !MACH_NBC
                   1032:         VOP_UNLOCK(vp, 0, p);
                   1033: #endif /* !MACH_NBC */
                   1034:                return (error);
                   1035:        }
                   1036: 
                   1037: bad2:
                   1038:        /*
                   1039:         * unlock and close the vnode, restore the old one, free the
                   1040:         * pathname buf, and punt.
                   1041:         */
                   1042: #if !MACH_NBC
                   1043:        VOP_UNLOCK(vp, 0, p);
                   1044: #endif /* !MACH_NBC */
                   1045:        vn_close(vp, FREAD, p->p_ucred, p);
                   1046:        FREE_ZONE(ndp->ni_cnd.cn_pnbuf, ndp->ni_cnd.cn_pnlen, M_NAMEI);
                   1047:        return (error);
                   1048: bad1:
                   1049:        /*
                   1050:         * free the namei pathname buffer, and put the vnode
                   1051:         * (which we don't yet have open).
                   1052:         */
                   1053:        FREE_ZONE(ndp->ni_cnd.cn_pnbuf, ndp->ni_cnd.cn_pnlen, M_NAMEI);
                   1054:        vput(vp);
                   1055:        return(error);
                   1056: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.