Annotation of XNU/bsd/kern/mach_loader.c, revision 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.