LCOV - code coverage report
Current view: directory - src/trusted/service_runtime/osx - nacl_ldt.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 75 62 82.7 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2011 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * Derived from Linux and Windows versions.
       9                 :  * TODO(jrg): locking is nooped.  PrintSelector() #if 0'd.
      10                 :  */
      11                 : 
      12                 : #include <errno.h>
      13                 : #include <stdio.h>
      14                 : #include <string.h>
      15                 : #include "native_client/src/include/portability.h"
      16                 : #include "native_client/src/shared/platform/nacl_sync.h"
      17                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      18                 : #include "native_client/src/trusted/service_runtime/arch/x86/nacl_ldt_x86.h"
      19                 : /* for LDT_ENTRIES */
      20                 : #include "native_client/src/trusted/service_runtime/arch/x86/sel_ldr_x86.h"
      21                 : 
      22                 : /* OSX specific */
      23                 : #include <architecture/i386/desc.h>  /* ldt_desc, etc */
      24                 : #include <architecture/i386/table.h> /* ldt_entry_t */
      25                 : #include <architecture/i386/sel.h>   /* sel_t */
      26                 : #include <i386/user_ldt.h>           /* i386_set_ldt() */
      27                 : 
      28                 : /* Buffer used to store the current state of the LDT. */
      29                 : static ldt_entry_t entries[LDT_ENTRIES];
      30                 : 
      31                 : /*
      32                 :  * The module initializer and finalizer set up a mutex used to guard LDT
      33                 :  * manipulation.
      34                 :  */
      35                 : static struct NaClMutex nacl_ldt_mutex;
      36                 : 
      37                 : 
      38              14 : int NaClLdtInitPlatformSpecific() {
      39              14 :   return NaClMutexCtor(&nacl_ldt_mutex);
      40                 : }
      41                 : 
      42               9 : void NaClLdtFiniPlatformSpecific() {
      43               9 :   NaClMutexDtor(&nacl_ldt_mutex);
      44               9 : }
      45                 : 
      46                 : /*
      47                 :  * Find a free selector.  Always invoked while holding nacl_ldt_mutex.
      48                 :  */
      49              18 : static int NaClFindUnusedEntryNumber(int start, int refresh_state) {
      50              18 :   int i, retval = 0;
      51                 : 
      52              18 :   if (refresh_state) {
      53               9 :     retval = i386_get_ldt(0, entries, LDT_ENTRIES);
      54                 :   }
      55                 : 
      56              18 :   if (-1 != retval) {
      57              18 :     retval = -1;  /* In case we don't find any free entry */
      58              81 :     for (i = start; i < LDT_ENTRIES; ++i) {
      59              81 :       if (!entries[i].code.present) {
      60              18 :         retval = i;
      61              18 :         break;
      62                 :       }
      63                 :     }
      64                 :   }
      65              18 :   return retval;
      66                 : }
      67                 : 
      68              26 : static uint16_t BuildSelector(int sel_index) {
      69                 :   union {
      70                 :     sel_t sel;
      71                 :     uint16_t uintsel;
      72                 :   } u;
      73                 : 
      74                 :   /*
      75                 :    * Return an LDT selector.
      76                 :    */
      77              26 :   u.sel.rpl = USER_PRIV;
      78              26 :   u.sel.ti = SEL_LDT;
      79              26 :   u.sel.index = sel_index;
      80                 : 
      81              26 :   return u.uintsel;
      82                 : }
      83                 : 
      84                 : /*
      85                 :  * Find and allocate an available selector, inserting an LDT entry with the
      86                 :  * appropriate permissions.
      87                 :  */
      88                 : uint16_t NaClLdtAllocateSelector(int32_t entry_number,
      89                 :                                  int size_is_in_pages,
      90                 :                                  NaClLdtDescriptorType type,
      91                 :                                  int read_exec_only,
      92                 :                                  void* base_addr,
      93              26 :                                  uint32_t size_minus_one) {
      94                 :   ldt_entry_t ldt;
      95              26 :   int sel_index = -1;
      96                 : 
      97              26 :   memset(&ldt, 0, sizeof(ldt));
      98                 : 
      99              26 :   NaClXMutexLock(&nacl_ldt_mutex);
     100                 : 
     101              26 :   switch (type) {
     102                 :     case NACL_LDT_DESCRIPTOR_DATA:
     103              23 :       ldt.data.type = (read_exec_only ? DESC_DATA_RONLY : DESC_DATA_WRITE);
     104              23 :       break;
     105                 :     case NACL_LDT_DESCRIPTOR_CODE:
     106               3 :       ldt.code.type = (read_exec_only ? DESC_CODE_EXEC : DESC_CODE_READ);
     107               3 :       break;
     108                 :     default:
     109               0 :       goto alloc_error;
     110                 :   }
     111                 : 
     112                 :   /* Ideas from win/nacl_ldt.c */
     113              26 :   ldt.code.dpl = 3;
     114              26 :   ldt.code.present = 1;
     115              26 :   ldt.code.opsz = 1;
     116                 : 
     117              26 :   if ((size_is_in_pages && ((unsigned long) base_addr & 0xfff)) ||
     118                 :       (size_minus_one > 0xfffff)) {
     119                 :     /*
     120                 :      * The base address needs to be page aligned if page granularity.
     121                 :      * If size is in pages no more than 2**20 pages can be protected.
     122                 :      * If size is in bytes no more than 2**20 bytes can be protected.
     123                 :      */
     124                 :     goto alloc_error;
     125                 :   }
     126              26 :   ldt.code.base00 = ((unsigned long) base_addr) & 0xffff;
     127              26 :   ldt.code.base16 = (((unsigned long) base_addr) >> 16) & 0xff;
     128              26 :   ldt.code.base24 = (((unsigned long) base_addr) >> 24) & 0xff;
     129                 : 
     130              26 :   ldt.code.limit00 = size_minus_one & 0xffff;
     131              26 :   ldt.code.limit16 = (size_minus_one >> 16) & 0xf;
     132              26 :   ldt.code.granular = (size_is_in_pages ? DESC_GRAN_PAGE : DESC_GRAN_BYTE);
     133                 : 
     134                 :   /*
     135                 :    * Install the LDT entry.
     136                 :    */
     137              26 :   if (-1 == entry_number) {
     138                 :     /* -1 means caller did not specify -- allocate the first available. */
     139               9 :     entry_number = NaClFindUnusedEntryNumber(0, 1);
     140              36 :     while ((-1 == sel_index) && (-1 != entry_number)) {
     141              18 :       sel_index = i386_set_ldt(entry_number, &ldt, 1);
     142              18 :       if (-1 == sel_index) {
     143                 :         /*
     144                 :          * For some reason we failed to allocate the LDT entry - try the next
     145                 :          * available one.
     146                 :          */
     147               9 :         entry_number = NaClFindUnusedEntryNumber(entry_number + 1, 0);
     148                 :       }
     149                 :     }
     150                 :   } else {
     151                 :     /* The caller specified an entry number - try only this one. */
     152              17 :     sel_index = i386_set_ldt(entry_number, &ldt, 1);
     153                 :   }
     154                 : 
     155              26 :   if (-1 == sel_index) {
     156               0 :     goto alloc_error;
     157                 :   }
     158                 : 
     159              26 :   NaClXMutexUnlock(&nacl_ldt_mutex);
     160                 : 
     161              26 :   return BuildSelector(sel_index);
     162                 : 
     163                 :   /*
     164                 :    * All error returns go through this epilog.
     165                 :    */
     166               0 :  alloc_error:
     167               0 :   NaClXMutexUnlock(&nacl_ldt_mutex);
     168               0 :   return 0;
     169                 : }
     170                 : 
     171                 : /*
     172                 :  * Allocates a selector whose size is specified in pages.
     173                 :  * Page granular protection requires that the start address be page-aligned.
     174                 :  */
     175                 : uint16_t NaClLdtAllocatePageSelector(NaClLdtDescriptorType type,
     176                 :                                      int read_exec_only,
     177                 :                                      void* base_addr,
     178               6 :                                      uint32_t size_in_pages) {
     179               6 :   return NaClLdtAllocateSelector(-1, 1, type, read_exec_only, base_addr,
     180                 :                                  size_in_pages - 1);
     181                 : }
     182                 : 
     183                 : /*
     184                 :  * Allocates a selector whose size is specified in bytes.
     185                 :  */
     186                 : uint16_t NaClLdtAllocateByteSelector(NaClLdtDescriptorType type,
     187                 :                                      int read_exec_only,
     188                 :                                      void* base_addr,
     189               3 :                                      uint32_t size_in_bytes) {
     190               3 :   return NaClLdtAllocateSelector(-1, 0, type, read_exec_only, base_addr,
     191                 :                                  size_in_bytes - 1);
     192                 : }
     193                 : 
     194                 : /*
     195                 :  * Changes a selector whose size is specified in pages.
     196                 :  * Page granular protection requires that the start address be page-aligned.
     197                 :  */
     198                 : uint16_t NaClLdtChangePageSelector(int32_t entry_number,
     199                 :                                    NaClLdtDescriptorType type,
     200                 :                                    int read_exec_only,
     201                 :                                    void* base_addr,
     202               0 :                                    uint32_t size_in_pages) {
     203               0 :   if ((uint32_t) entry_number >= LDT_ENTRIES) {
     204               0 :     return 0;
     205                 :   }
     206               0 :   return NaClLdtAllocateSelector(entry_number, 1, type, read_exec_only,
     207                 :                                  base_addr, size_in_pages - 1);
     208                 : }
     209                 : 
     210                 : /*
     211                 :  * Changes a selector whose size is specified in bytes.
     212                 :  */
     213                 : uint16_t NaClLdtChangeByteSelector(int32_t entry_number,
     214                 :                                    NaClLdtDescriptorType type,
     215                 :                                    int read_exec_only,
     216                 :                                    void* base_addr,
     217               3 :                                    uint32_t size_in_bytes) {
     218               3 :   if ((uint32_t) entry_number >= LDT_ENTRIES) {
     219               0 :     return 0;
     220                 :   }
     221               3 :   return NaClLdtAllocateSelector(entry_number, 0, type, read_exec_only,
     222                 :                                  base_addr, size_in_bytes - 1);
     223                 : }
     224                 : 
     225                 : 
     226               0 : void NaClLdtPrintSelector(uint16_t selector) {
     227                 :   /* TODO(jrg) */
     228                 : #if 0
     229                 :   /* type_name converts the segment type into print name */
     230                 :   static const char* type_name[] = {
     231                 :     "data read only",
     232                 :     "data read_only accessed",
     233                 :     "data read write",
     234                 :     "data read write accessed",
     235                 :     "data read expand",
     236                 :     "data read expand accessed",
     237                 :     "data read write expand",
     238                 :     "data read write expand accessed",
     239                 :     "code execute",
     240                 :     "code execute accessed",
     241                 :     "code execute read",
     242                 :     "code execute read accessed",
     243                 :     "code execute conforming",
     244                 :     "code execute conforming accessed",
     245                 :     "code execute read conforming",
     246                 :     "code execute read conforming accessed"
     247                 :   };
     248                 : 
     249                 :   struct LdtEntry entries[LDT_ENTRIES];
     250                 :   struct LdtEntry entry;
     251                 :   int retval = modify_ldt(0, entries, sizeof(entries));
     252                 :   if (-1 == retval) {
     253                 :     return;
     254                 :   }
     255                 :   entry = entries[selector >> 3];
     256                 :   printf("DESCRIPTOR for selector %04x\n", selector);
     257                 :   /* create functions to do base, limit, and type */
     258                 :   printf("  base        %08x\n", (entry.base_24to31 << 24)
     259                 :          | (entry.base_16to23 << 16) | entry.base_00to15);
     260                 :   printf("  limit       %08x%s\n",
     261                 :          (((entry.limit_16to19 << 16) | entry.limit_00to15)
     262                 :           << (entry.granularity ? 12 : 0)),
     263                 :          (entry.granularity ? " (page granularity)" : ""));
     264                 :   printf("  type        %s, %s\n", ((entry.type & 0x10) ? "user" : "system"),
     265                 :          type_name[entry.type & 0xf]);
     266                 :   printf("  privilege   %d\n", entry.descriptor_privilege);
     267                 :   printf("  present %s\n", (entry.present ? "yes" : "no"));
     268                 :   printf("  available %s\n", (entry.available ? "yes" : "no"));
     269                 :   printf("  64-bit code %s\n", (entry.code_64_bit ? "yes" : "no"));
     270                 :   printf("  op size %s\n", (entry.op_size_32 ? "32" : "16"));
     271                 : #else
     272                 :   UNREFERENCED_PARAMETER(selector);
     273                 : #endif
     274               0 : }
     275                 : 
     276                 : /*
     277                 :  * Mark a selector as available for future reuse.
     278                 :  */
     279               3 : void NaClLdtDeleteSelector(uint16_t selector) {
     280                 : 
     281               3 :   NaClXMutexLock(&nacl_ldt_mutex);
     282               3 :   if (-1 == i386_set_ldt(selector >> 3, NULL, 1)) {
     283               0 :     perror("NaClLdtDeleteSelector: i386_set_ldt()");
     284                 :   }
     285               3 :   NaClXMutexUnlock(&nacl_ldt_mutex);
     286               3 : }

Generated by: LCOV version 1.7