Annotation of kernel/kern/mach_loader.c, revision 1.1

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

unix.superglobalmegacorp.com

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