/*
 * 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;
}
Beispiel #2
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);
}