Annotation of XNU/osfmk/i386/user_ldt.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_COPYRIGHT@
        !            24:  */
        !            25: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1991 Carnegie Mellon University
        !            28:  * All Rights Reserved.
        !            29:  * 
        !            30:  * Permission to use, copy, modify and distribute this software and its
        !            31:  * documentation is hereby granted, provided that both the copyright
        !            32:  * notice and this permission notice appear in all copies of the
        !            33:  * software, derivative works or modified versions, and any portions
        !            34:  * thereof, and that both notices appear in supporting documentation.
        !            35:  * 
        !            36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            39:  * 
        !            40:  * Carnegie Mellon requests users of this software to return to
        !            41:  * 
        !            42:  *  Software Distribution Coordinator  or  [email protected]
        !            43:  *  School of Computer Science
        !            44:  *  Carnegie Mellon University
        !            45:  *  Pittsburgh PA 15213-3890
        !            46:  * 
        !            47:  * any improvements or extensions that they make and grant Carnegie Mellon 
        !            48:  * the rights to redistribute these changes.
        !            49:  */
        !            50: 
        !            51: /*
        !            52:  */
        !            53: 
        !            54: /*
        !            55:  * User LDT management.
        !            56:  * Each thread in a task may have its own LDT.
        !            57:  */
        !            58: 
        !            59: #include <kern/kalloc.h>
        !            60: #include <kern/thread.h>
        !            61: #include <kern/misc_protos.h>
        !            62: 
        !            63: #include <vm/vm_kern.h>
        !            64: 
        !            65: #include <i386/seg.h>
        !            66: #include <i386/thread.h>
        !            67: #include <i386/user_ldt.h>
        !            68: 
        !            69: char   acc_type[8][3] = {
        !            70:     /* code    stack   data */
        !            71:     {  0,      0,      1       },      /* data */
        !            72:     {  0,      1,      1       },      /* data, writable */
        !            73:     {  0,      0,      1       },      /* data, expand-down */
        !            74:     {  0,      1,      1       },      /* data, writable, expand-down */
        !            75:     {  1,      0,      0       },      /* code */
        !            76:     {  1,      0,      1       },      /* code, readable */
        !            77:     {  1,      0,      0       },      /* code, conforming */
        !            78:     {  1,      0,      1       },      /* code, readable, conforming */
        !            79: };
        !            80: 
        !            81: extern struct fake_descriptor ldt[];   /* for system call gate */
        !            82: 
        !            83: #if 0
        !            84: /* Forward */
        !            85: 
        !            86: extern boolean_t       selector_check(
        !            87:                                thread_t                thread,
        !            88:                                int                     sel,
        !            89:                                int                     type);
        !            90: 
        !            91: boolean_t
        !            92: selector_check(
        !            93:        thread_t                thread,
        !            94:        int                     sel,
        !            95:        int                     type)
        !            96: {
        !            97:        struct user_ldt *ldt;
        !            98:        int     access;
        !            99: 
        !           100:        ldt = thread->top_act->mact.pcb->ims.ldt;
        !           101:        if (ldt == 0) {
        !           102:            switch (type) {
        !           103:                case S_CODE:
        !           104:                    return sel == USER_CS;
        !           105:                case S_STACK:
        !           106:                    return sel == USER_DS;
        !           107:                case S_DATA:
        !           108:                    return sel == 0 ||
        !           109:                           sel == USER_CS ||
        !           110:                           sel == USER_DS;
        !           111:            }
        !           112:        }
        !           113: 
        !           114:        if (type != S_DATA && sel == 0)
        !           115:            return FALSE;
        !           116:        if ((sel & (SEL_LDTS|SEL_PL)) != (SEL_LDTS|SEL_PL_U)
        !           117:          || sel > ldt->desc.limit_low)
        !           118:                return FALSE;
        !           119: 
        !           120:        access = ldt->ldt[sel_idx(sel)].access;
        !           121:        
        !           122:        if ((access & (ACC_P|ACC_PL|ACC_TYPE_USER))
        !           123:                != (ACC_P|ACC_PL_U|ACC_TYPE_USER))
        !           124:            return FALSE;
        !           125:                /* present, pl == pl.user, not system */
        !           126: 
        !           127:        return acc_type[(access & 0xe)>>1][type];
        !           128: }
        !           129: 
        !           130: /*
        !           131:  * Add the descriptors to the LDT, starting with
        !           132:  * the descriptor for 'first_selector'.
        !           133:  */
        !           134: 
        !           135: kern_return_t
        !           136: i386_set_ldt(
        !           137:        thread_act_t            thr_act,
        !           138:        int                     first_selector,
        !           139:        descriptor_list_t       desc_list,
        !           140:        mach_msg_type_number_t  count)
        !           141: {
        !           142:        user_ldt_t      new_ldt, old_ldt, temp;
        !           143:        struct real_descriptor *dp;
        !           144:        int             i;
        !           145:        int             min_selector = 0;
        !           146:        pcb_t           pcb;
        !           147:        vm_size_t       ldt_size_needed;
        !           148:        int             first_desc = sel_idx(first_selector);
        !           149:        vm_map_copy_t   old_copy_object;
        !           150:        thread_t                thread;
        !           151: 
        !           152:        if (first_desc < min_selector || first_desc > 8191)
        !           153:            return KERN_INVALID_ARGUMENT;
        !           154:        if (first_desc + count >= 8192)
        !           155:            return KERN_INVALID_ARGUMENT;
        !           156:        if (thr_act == THR_ACT_NULL)
        !           157:            return KERN_INVALID_ARGUMENT;
        !           158:        if ((thread = act_lock_thread(thr_act)) == THREAD_NULL) {
        !           159:                act_unlock_thread(thr_act);
        !           160:            return KERN_INVALID_ARGUMENT;
        !           161:        }
        !           162:        if (thread == current_thread())
        !           163:                min_selector = LDTSZ;
        !           164:        act_unlock_thread(thr_act);
        !           165: 
        !           166:        /*
        !           167:         * We must copy out desc_list to the kernel map, and wire
        !           168:         * it down (we touch it while the PCB is locked).
        !           169:         *
        !           170:         * We make a copy of the copyin object, and clear
        !           171:         * out the old one, so that the MIG stub will have a
        !           172:         * a empty (but valid) copyin object to discard.
        !           173:         */
        !           174:        {
        !           175:            kern_return_t       kr;
        !           176:            vm_offset_t         dst_addr;
        !           177: 
        !           178:            old_copy_object = (vm_map_copy_t) desc_list;
        !           179: 
        !           180:            kr = vm_map_copyout(ipc_kernel_map, &dst_addr,
        !           181:                                vm_map_copy_copy(old_copy_object));
        !           182:            if (kr != KERN_SUCCESS)
        !           183:                return kr;
        !           184: 
        !           185:            (void) vm_map_wire(ipc_kernel_map,
        !           186:                        trunc_page(dst_addr),
        !           187:                        round_page(dst_addr + 
        !           188:                                count * sizeof(struct real_descriptor)),
        !           189:                        VM_PROT_READ|VM_PROT_WRITE, FALSE);
        !           190:            desc_list = (descriptor_list_t) dst_addr;
        !           191:        }
        !           192: 
        !           193:        for (i = 0, dp = (struct real_descriptor *) desc_list;
        !           194:             i < count;
        !           195:             i++, dp++)
        !           196:        {
        !           197:            switch (dp->access & ~ACC_A) {
        !           198:                case 0:
        !           199:                case ACC_P:
        !           200:                    /* valid empty descriptor */
        !           201:                    break;
        !           202:                case ACC_P | ACC_CALL_GATE:
        !           203:                    /* Mach kernel call */
        !           204:                    *dp = *(struct real_descriptor *)
        !           205:                                &ldt[sel_idx(USER_SCALL)];
        !           206:                    break;
        !           207:                case ACC_P | ACC_PL_U | ACC_DATA:
        !           208:                case ACC_P | ACC_PL_U | ACC_DATA_W:
        !           209:                case ACC_P | ACC_PL_U | ACC_DATA_E:
        !           210:                case ACC_P | ACC_PL_U | ACC_DATA_EW:
        !           211:                case ACC_P | ACC_PL_U | ACC_CODE:
        !           212:                case ACC_P | ACC_PL_U | ACC_CODE_R:
        !           213:                case ACC_P | ACC_PL_U | ACC_CODE_C:
        !           214:                case ACC_P | ACC_PL_U | ACC_CODE_CR:
        !           215:                case ACC_P | ACC_PL_U | ACC_CALL_GATE_16:
        !           216:                case ACC_P | ACC_PL_U | ACC_CALL_GATE:
        !           217:                    break;
        !           218:                default:
        !           219:                    (void) vm_map_remove(ipc_kernel_map, 
        !           220:                                         (vm_offset_t) desc_list,
        !           221:                                         count * sizeof(struct real_descriptor),
        !           222:                                         VM_MAP_REMOVE_KUNWIRE);
        !           223:                    return KERN_INVALID_ARGUMENT;
        !           224:            }
        !           225:        }
        !           226:        ldt_size_needed = sizeof(struct real_descriptor)
        !           227:                        * (first_desc + count);
        !           228: 
        !           229:        pcb = thr_act->mact.pcb;
        !           230:        new_ldt = 0;
        !           231:     Retry:
        !           232:        simple_lock(&pcb->lock);
        !           233:        old_ldt = pcb->ims.ldt;
        !           234:        if (old_ldt == 0 ||
        !           235:            old_ldt->desc.limit_low + 1 < ldt_size_needed)
        !           236:        {
        !           237:            /*
        !           238:             * No old LDT, or not big enough
        !           239:             */
        !           240:            if (new_ldt == 0) {
        !           241:                simple_unlock(&pcb->lock);
        !           242: 
        !           243:                new_ldt = (user_ldt_t) kalloc(ldt_size_needed
        !           244:                                              + sizeof(struct real_descriptor));
        !           245:                new_ldt->desc.limit_low   = ldt_size_needed - 1;
        !           246:                new_ldt->desc.limit_high  = 0;
        !           247:                new_ldt->desc.base_low    = 
        !           248:                                ((vm_offset_t)&new_ldt->ldt[0]) & 0xffff;
        !           249:                new_ldt->desc.base_med    = 
        !           250:                                (((vm_offset_t)&new_ldt->ldt[0]) >> 16)
        !           251:                                                 & 0xff;
        !           252:                new_ldt->desc.base_high   = 
        !           253:                                ((vm_offset_t)&new_ldt->ldt[0]) >> 24;
        !           254:                new_ldt->desc.access      = ACC_P | ACC_LDT;
        !           255:                new_ldt->desc.granularity = 0;
        !           256: 
        !           257:                goto Retry;
        !           258:            }
        !           259: 
        !           260:            /*
        !           261:             * Have new LDT.  If there was a an old ldt, copy descriptors
        !           262:             * from old to new.  Otherwise copy the default ldt.
        !           263:             */
        !           264:            if (old_ldt) {
        !           265:                bcopy((char *)&old_ldt->ldt[0],
        !           266:                      (char *)&new_ldt->ldt[0],
        !           267:                      old_ldt->desc.limit_low + 1);
        !           268:            }
        !           269:            else if (thr_act == current_act()) {
        !           270:                struct real_descriptor template = {0, 0, 0, ACC_P, 0, 0 ,0};
        !           271: 
        !           272:                for (dp = &new_ldt->ldt[0], i = 0; i < first_desc; i++, dp++) {
        !           273:                    if (i < LDTSZ)
        !           274:                        *dp = *(struct real_descriptor *) &ldt[i];
        !           275:                    else
        !           276:                        *dp = template;
        !           277:                }
        !           278:            }
        !           279: 
        !           280:            temp = old_ldt;
        !           281:            old_ldt = new_ldt;  /* use new LDT from now on */
        !           282:            new_ldt = temp;     /* discard old LDT */
        !           283: 
        !           284:            pcb->ims.ldt = old_ldt;     /* new LDT for thread */
        !           285:        }
        !           286: 
        !           287:        /*
        !           288:         * Install new descriptors.
        !           289:         */
        !           290:        bcopy((char *)desc_list,
        !           291:              (char *)&old_ldt->ldt[first_desc],
        !           292:              count * sizeof(struct real_descriptor));
        !           293: 
        !           294:        simple_unlock(&pcb->lock);
        !           295: 
        !           296:        if (new_ldt)
        !           297:            kfree((vm_offset_t)new_ldt,
        !           298:                  new_ldt->desc.limit_low+1+sizeof(struct real_descriptor));
        !           299: 
        !           300:        /*
        !           301:         * Free the descriptor list.
        !           302:         */
        !           303:        (void) vm_map_remove(ipc_kernel_map, (vm_offset_t) desc_list,
        !           304:                        count * sizeof(struct real_descriptor),
        !           305:                        VM_MAP_REMOVE_KUNWIRE);
        !           306:        return KERN_SUCCESS;
        !           307: }
        !           308: 
        !           309: kern_return_t
        !           310: i386_get_ldt(
        !           311:        thread_act_t            thr_act,
        !           312:        int                     first_selector,
        !           313:        int                     selector_count, /* number wanted */
        !           314:        descriptor_list_t       *desc_list,     /* in/out */
        !           315:        mach_msg_type_number_t  *count)         /* in/out */
        !           316: {
        !           317:        struct user_ldt *user_ldt;
        !           318:        pcb_t           pcb = thr_act->mact.pcb;
        !           319:        int             first_desc = sel_idx(first_selector);
        !           320:        unsigned int    ldt_count;
        !           321:        vm_size_t       ldt_size;
        !           322:        vm_size_t       size, size_needed;
        !           323:        vm_offset_t     addr;
        !           324:        thread_t                thread;
        !           325: 
        !           326:        if (thr_act == THR_ACT_NULL || (thread = thr_act->thread)==THREAD_NULL)
        !           327:            return KERN_INVALID_ARGUMENT;
        !           328: 
        !           329:        if (first_desc < 0 || first_desc > 8191)
        !           330:            return KERN_INVALID_ARGUMENT;
        !           331:        if (first_desc + selector_count >= 8192)
        !           332:            return KERN_INVALID_ARGUMENT;
        !           333: 
        !           334:        addr = 0;
        !           335:        size = 0;
        !           336: 
        !           337:        for (;;) {
        !           338:            simple_lock(&pcb->lock);
        !           339:            user_ldt = pcb->ims.ldt;
        !           340:            if (user_ldt == 0) {
        !           341:                simple_unlock(&pcb->lock);
        !           342:                if (addr)
        !           343:                    kmem_free(ipc_kernel_map, addr, size);
        !           344:                *count = 0;
        !           345:                return KERN_SUCCESS;
        !           346:            }
        !           347: 
        !           348:            /*
        !           349:             * Find how many descriptors we should return.
        !           350:             */
        !           351:            ldt_count = (user_ldt->desc.limit_low + 1) /
        !           352:                        sizeof (struct real_descriptor);
        !           353:            ldt_count -= first_desc;
        !           354:            if (ldt_count > selector_count)
        !           355:                ldt_count = selector_count;
        !           356: 
        !           357:            ldt_size = ldt_count * sizeof(struct real_descriptor);
        !           358: 
        !           359:            /*
        !           360:             * Do we have the memory we need?
        !           361:             */
        !           362:            if (ldt_count <= *count)
        !           363:                break;          /* fits in-line */
        !           364: 
        !           365:            size_needed = round_page(ldt_size);
        !           366:            if (size_needed <= size)
        !           367:                break;
        !           368: 
        !           369:            /*
        !           370:             * Unlock the pcb and allocate more memory
        !           371:             */
        !           372:            simple_unlock(&pcb->lock);
        !           373: 
        !           374:            if (size != 0)
        !           375:                kmem_free(ipc_kernel_map, addr, size);
        !           376: 
        !           377:            size = size_needed;
        !           378: 
        !           379:            if (kmem_alloc(ipc_kernel_map, &addr, size)
        !           380:                        != KERN_SUCCESS)
        !           381:                return KERN_RESOURCE_SHORTAGE;
        !           382:        }
        !           383: 
        !           384:        /*
        !           385:         * copy out the descriptors
        !           386:         */
        !           387:        bcopy((char *)&user_ldt->ldt[first_desc],
        !           388:              (char *)addr,
        !           389:              ldt_size);
        !           390:        *count = ldt_count;
        !           391:        simple_unlock(&pcb->lock);
        !           392: 
        !           393:        if (addr) {
        !           394:            vm_size_t           size_used, size_left;
        !           395:            vm_map_copy_t       memory;
        !           396: 
        !           397:            /*
        !           398:             * Free any unused memory beyond the end of the last page used
        !           399:             */
        !           400:            size_used = round_page(ldt_size);
        !           401:            if (size_used != size)
        !           402:                kmem_free(ipc_kernel_map,
        !           403:                        addr + size_used, size - size_used);
        !           404: 
        !           405:            /*
        !           406:             * Zero the remainder of the page being returned.
        !           407:             */
        !           408:            size_left = size_used - ldt_size;
        !           409:            if (size_left > 0)
        !           410:                bzero((char *)addr + ldt_size, size_left);
        !           411: 
        !           412:            /*
        !           413:             * Unwire the memory and make it into copyin form.
        !           414:             */
        !           415:            (void) vm_map_unwire(ipc_kernel_map, trunc_page(addr),
        !           416:                                 round_page(addr + size_used), FALSE);
        !           417:            (void) vm_map_copyin(ipc_kernel_map, addr, size_used,
        !           418:                                TRUE, &memory);
        !           419:            *desc_list = (descriptor_list_t) memory;
        !           420:        }
        !           421: 
        !           422:        return KERN_SUCCESS;
        !           423: }
        !           424: 
        !           425: #endif 
        !           426: void
        !           427: user_ldt_free(
        !           428:        user_ldt_t      user_ldt)
        !           429: {
        !           430:        kfree((vm_offset_t)user_ldt,
        !           431:                user_ldt->desc.limit_low+1+sizeof(struct real_descriptor));
        !           432: }

unix.superglobalmegacorp.com

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