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

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @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.