/* * Find and allocate an available selector, inserting an LDT entry with the * appropriate permissions. */ uint16_t NaClLdtAllocateSelector(int32_t entry_number, int size_is_in_pages, NaClLdtDescriptorType type, int read_exec_only, void* base_addr, uint32_t size_minus_one) { struct user_desc ud; int retval; NaClXMutexLock(&nacl_ldt_mutex); if (-1 == entry_number) { /* -1 means caller did not specify -- allocate */ entry_number = NaClFindUnusedEntryNumber(); if (-1 == entry_number) { /* * No free entries were available. */ goto alloc_error; } } ud.entry_number = entry_number; switch (type) { case NACL_LDT_DESCRIPTOR_DATA: ud.contents = MODIFY_LDT_CONTENTS_DATA; break; case NACL_LDT_DESCRIPTOR_CODE: ud.contents = MODIFY_LDT_CONTENTS_CODE; break; default: goto alloc_error; } ud.read_exec_only = read_exec_only; ud.seg_32bit = 1; ud.seg_not_present = 0; ud.useable = 1; if (size_is_in_pages && ((unsigned long) base_addr & 0xfff)) { /* * The base address needs to be page aligned. */ goto alloc_error; }; ud.base_addr = (unsigned long) base_addr; if (size_minus_one > 0xfffff) { /* * If size is in pages, no more than 2**20 pages can be protected. * If size is in bytes, no more than 2**20 bytes can be protected. */ goto alloc_error; } ud.limit = size_minus_one; ud.limit_in_pages = size_is_in_pages; /* * Install the LDT entry. */ retval = modify_ldt(1, &ud, sizeof ud); if (-1 == retval) { goto alloc_error; } /* * Return an LDT selector with a requested privilege level of 3. */ NaClXMutexUnlock(&nacl_ldt_mutex); return (ud.entry_number << 3) | 0x7; /* * All error returns go through this epilog. */ alloc_error: NaClXMutexUnlock(&nacl_ldt_mutex); return 0; }
/* * Find and allocate an available selector, inserting an LDT entry with the * appropriate permissions. */ uint16_t NaClLdtAllocateSelector(int entry_number, int size_is_in_pages, NaClLdtDescriptorType type, int read_exec_only, void* base_addr, uint32_t size_minus_one) { int retval; struct LdtEntry ldt; retval = 0; NaClXMutexLock(&nacl_ldt_mutex); if (-1 == entry_number) { entry_number = NaClFindUnusedEntryNumber(); if (-1 == entry_number) { /* * No free entries were available. */ NaClXMutexUnlock(&nacl_ldt_mutex); return 0; } } switch (type) { case NACL_LDT_DESCRIPTOR_DATA: if (read_exec_only) { ldt.type = 0x10; /* Data read only */ } else { ldt.type = 0x12; /* Data read/write */ } break; case NACL_LDT_DESCRIPTOR_CODE: if (read_exec_only) { ldt.type = 0x18; /* Code execute */ } else { ldt.type = 0x1a; /* Code execute/read */ } break; default: NaClXMutexUnlock(&nacl_ldt_mutex); return 0; } ldt.descriptor_privilege = 3; ldt.present = 1; ldt.available = 1; /* TODO(dcs) */ ldt.code_64_bit = 0; ldt.op_size_32 = 1; if (size_is_in_pages && ((unsigned long) base_addr & 0xfff)) { /* * The base address needs to be page aligned. */ NaClXMutexUnlock(&nacl_ldt_mutex); return 0; }; ldt.base_00to15 = ((unsigned long) base_addr) & 0xffff; ldt.base_16to23 = (((unsigned long) base_addr) >> 16) & 0xff; ldt.base_24to31 = (((unsigned long) base_addr) >> 24) & 0xff; if (size_minus_one > 0xfffff) { /* * If the size is in pages, no more than 2**20 pages can be protected. * If the size is in bytes, no more than 2**20 bytes can be protected. */ NaClXMutexUnlock(&nacl_ldt_mutex); return 0; } ldt.limit_00to15 = size_minus_one & 0xffff; ldt.limit_16to19 = (size_minus_one >> 16) & 0xf; ldt.granularity = size_is_in_pages; /* * Install the LDT entry. */ if (NULL != set_ldt_entries) { union { struct LdtEntry ldt; DWORD dwords[2]; } u; u.ldt = ldt; retval = (*set_ldt_entries)((entry_number << 3) | 0x7, u.dwords[0], u.dwords[1], 0, 0, 0); } if ((NULL == set_ldt_entries) || (0 != retval)) { LdtInfo info; info.byte_offset = entry_number << 3; info.size = sizeof(struct LdtEntry); info.entries[0] = ldt; retval = (*set_information_process)((HANDLE)-1, 10, (void*)&info, 16); } if (0 != retval) { NaClXMutexUnlock(&nacl_ldt_mutex); return 0; } /* * Return an LDT selector with a requested privilege level of 3. */ NaClXMutexUnlock(&nacl_ldt_mutex); return (uint16_t)((entry_number << 3) | 0x7); }