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