LCOV - code coverage report
Current view: directory - src/trusted/validator_ragel - dfa_validate_64.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 107 94 87.9 %
Date: 2014-06-18 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 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                 : /* Implement the Validator API for the x86-64 architecture. */
       8                 : #include <errno.h>
       9                 : #include <string.h>
      10                 : 
      11                 : #include "native_client/src/shared/platform/nacl_check.h"
      12                 : #include "native_client/src/trusted/validator/validation_cache.h"
      13                 : #include "native_client/src/trusted/validator_ragel/dfa_validate_common.h"
      14                 : #include "native_client/src/trusted/validator_ragel/validator.h"
      15                 : 
      16                 : /*
      17                 :  * Be sure the correct compile flags are defined for this.
      18                 :  * TODO(khim): Try to figure out if these checks actually make any sense.
      19                 :  *             I don't foresee any use in cross-environment, but it should work
      20                 :  *             and may be useful in some case so why not?
      21                 :  */
      22                 : #if NACL_ARCH(NACL_TARGET_ARCH) != NACL_x86 || NACL_TARGET_SUBARCH != 64
      23                 : # error "Can't compile, target is for x86-64"
      24                 : #endif
      25                 : 
      26                 : 
      27                 : static NaClValidationStatus ApplyDfaValidator_x86_64(
      28            1414 :     uintptr_t guest_addr,
      29            1414 :     uint8_t *data,
      30            1414 :     size_t size,
      31            1414 :     int stubout_mode,
      32            1414 :     int readonly_text,
      33            1414 :     const NaClCPUFeatures *f,
      34            1414 :     const struct NaClValidationMetadata *metadata,
      35            1414 :     struct NaClValidationCache *cache) {
      36                 :   /* TODO(jfb) Use a safe cast here. */
      37            1414 :   NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f;
      38            1414 :   enum NaClValidationStatus status = NaClValidationFailed;
      39            1414 :   int did_stubout = 0;
      40            1414 :   void *query = NULL;
      41            2828 :   UNREFERENCED_PARAMETER(guest_addr);
      42                 : 
      43            1414 :   if (stubout_mode)
      44               0 :     return NaClValidationFailedNotImplemented;
      45            1414 :   if (!NaClArchSupportedX86(cpu_features))
      46               0 :     return NaClValidationFailedCpuNotSupported;
      47            1414 :   if (size & kBundleMask)
      48               0 :     return NaClValidationFailed;
      49                 : 
      50                 :   /*
      51                 :    * If the validation caching interface is available and it would be
      52                 :    * inexpensive to do so, perform a query.
      53                 :    */
      54            1425 :   if (cache != NULL && NaClCachingIsInexpensive(cache, metadata))
      55              11 :     query = cache->CreateQuery(cache->handle);
      56            1414 :   if (query != NULL) {
      57                 :     const char validator_id[] = "x86-64 dfa";
      58              11 :     cache->AddData(query, (uint8_t *) validator_id, sizeof(validator_id));
      59              11 :     cache->AddData(query, (uint8_t *) cpu_features, sizeof(*cpu_features));
      60              11 :     NaClAddCodeIdentity(data, size, metadata, cache, query);
      61              11 :     if (cache->QueryKnownToValidate(query)) {
      62               3 :       cache->DestroyQuery(query);
      63               3 :       return NaClValidationSucceeded;
      64                 :     }
      65               8 :   }
      66                 : 
      67            1411 :   if (readonly_text) {
      68               7 :     if (ValidateChunkAMD64(data, size, 0 /*options*/, cpu_features,
      69                 :                            NaClDfaProcessValidationError,
      70                 :                            NULL))
      71               7 :       status = NaClValidationSucceeded;
      72               7 :   } else {
      73            1404 :     if (ValidateChunkAMD64(data, size, 0 /*options*/, cpu_features,
      74                 :                            NaClDfaStubOutCPUUnsupportedInstruction,
      75                 :                            &did_stubout))
      76            1366 :       status = NaClValidationSucceeded;
      77                 :   }
      78                 : 
      79            1449 :   if (status != NaClValidationSucceeded && errno == ENOMEM)
      80               0 :     status = NaClValidationFailedOutOfMemory;
      81                 : 
      82                 :   /* Cache the result if validation succeeded and the code was not modified. */
      83            1411 :   if (query != NULL) {
      84              15 :     if (status == NaClValidationSucceeded && did_stubout == 0)
      85               6 :       cache->SetKnownToValidate(query);
      86               8 :     cache->DestroyQuery(query);
      87               8 :   }
      88                 : 
      89            1411 :   return status;
      90            1414 : }
      91                 : 
      92                 : 
      93                 : static NaClValidationStatus ValidatorCodeCopy_x86_64(
      94               7 :     uintptr_t guest_addr,
      95               7 :     uint8_t *data_existing,
      96               7 :     uint8_t *data_new,
      97               7 :     size_t size,
      98               7 :     const NaClCPUFeatures *f,
      99               7 :     NaClCopyInstructionFunc copy_func) {
     100                 :   /* TODO(jfb) Use a safe cast here. */
     101               7 :   NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f;
     102               7 :   struct CodeCopyCallbackData callback_data;
     103              14 :   UNREFERENCED_PARAMETER(guest_addr);
     104                 : 
     105               7 :   if (size & kBundleMask)
     106               0 :     return NaClValidationFailed;
     107               7 :   callback_data.copy_func = copy_func;
     108               7 :   callback_data.existing_minus_new = data_existing - data_new;
     109               7 :   if (ValidateChunkAMD64(data_new, size, CALL_USER_CALLBACK_ON_EACH_INSTRUCTION,
     110                 :                          cpu_features, NaClDfaProcessCodeCopyInstruction,
     111                 :                          &callback_data))
     112               7 :     return NaClValidationSucceeded;
     113               0 :   if (errno == ENOMEM)
     114               0 :     return NaClValidationFailedOutOfMemory;
     115               0 :   return NaClValidationFailed;
     116               7 : }
     117                 : 
     118                 : 
     119             339 : static Bool ProcessCodeReplacementInstruction(const uint8_t *begin_new,
     120             339 :                                               const uint8_t *end_new,
     121             339 :                                               uint32_t info_new,
     122             339 :                                               void *callback_data) {
     123             339 :   ptrdiff_t existing_minus_new = (ptrdiff_t)callback_data;
     124             339 :   size_t instruction_length = end_new - begin_new;
     125             339 :   const uint8_t *begin_existing = begin_new + existing_minus_new;
     126             339 :   const uint8_t *end_existing = end_new + existing_minus_new;
     127                 : 
     128                 :   /* Sanity check: instruction must be no longer than 17 bytes.  */
     129            1017 :   CHECK(instruction_length <= MAX_INSTRUCTION_LENGTH);
     130                 : 
     131                 :   /* Unsupported instruction must have been replaced with HLTs.  */
     132             339 :   if ((info_new & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION)
     133               0 :     return NaClDfaCodeReplacementIsStubouted(begin_existing,
     134                 :                                              instruction_length);
     135                 : 
     136                 :   /* If we have jump which jumps out of it's range...  */
     137             339 :   if (info_new & DIRECT_JUMP_OUT_OF_RANGE) {
     138                 :     /* then everything is fine if it's the only error and jump is unchanged!  */
     139               2 :     if ((info_new & VALIDATION_ERRORS_MASK) == DIRECT_JUMP_OUT_OF_RANGE &&
     140               2 :         memcmp(begin_new, begin_existing, instruction_length) == 0)
     141               1 :       return TRUE;
     142               1 :     return FALSE;
     143                 :   }
     144                 : 
     145                 :   /* If instruction is not accepted then we have nothing to do here.  */
     146             337 :   if (info_new & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET))
     147               2 :     return FALSE;
     148                 : 
     149                 :   /* Instruction is untouched: we are done.  */
     150             335 :   if (memcmp(begin_new, begin_existing, instruction_length) == 0)
     151             313 :     return TRUE;
     152                 : 
     153                 :   /* Only some instructions can be modified.  */
     154              22 :   if (!(info_new & MODIFIABLE_INSTRUCTION))
     155               9 :     return FALSE;
     156                 : 
     157                 :   /*
     158                 :    * In order to understand where the following three cases came from you need
     159                 :    * to understand that there are three kinds of instructions:
     160                 :    *  - "normal" x86 instructions
     161                 :    *  - x86 instructions which [ab]use "immediate" field in the instructions
     162                 :    *     - 3DNow! x86 instructions use it as an opcode extentions
     163                 :    *     - four-operand instructions encode fourth register in it
     164                 :    *  - five-operands instructions encode 2bit immediate and fourth register
     165                 :    *
     166                 :    * For the last two cases we need to keep either the whole last byte or at
     167                 :    * least non-immediate part of it intact.
     168                 :    *
     169                 :    * See Figure 1-1 "Instruction Encoding Syntax" in AMDs third volume
     170                 :    * "General-Purpose and System Instructions" for the information about
     171                 :    * "normal" x86 instructions and 3DNow! instructions.
     172                 :    *
     173                 :    * See Figure 1-1 "Typical Descriptive Synopsis - Extended SSE Instructions"
     174                 :    * in AMDs fourth volume "128-Bit and 256-Bit Media Instructions" and the
     175                 :    * "Immediate Byte Usage Unique to the SSE instructions" for the information
     176                 :    * about four-operand and five-operand instructions.
     177                 :    */
     178                 : 
     179                 :   /*
     180                 :    * Instruction with two-bit immediate can only change these two bits and
     181                 :    * immediate/displacement.
     182                 :    */
     183              13 :   if ((info_new & IMMEDIATE_2BIT) == IMMEDIATE_2BIT)
     184               0 :     return memcmp(begin_new, begin_existing,
     185                 :                   instruction_length -
     186                 :                   INFO_ANYFIELDS_SIZE(info_new) - 1) == 0 &&
     187                 :            (end_new[-1] & 0xfc) == (end_existing[-1] & 0xfc);
     188                 : 
     189                 :   /* Instruction's last byte is not immediate, thus it must be unchanged.  */
     190              13 :   if (info_new & LAST_BYTE_IS_NOT_IMMEDIATE)
     191               0 :     return memcmp(begin_new, begin_existing,
     192                 :                   instruction_length -
     193                 :                   INFO_ANYFIELDS_SIZE(info_new) - 1) == 0 &&
     194                 :            end_new[-1] == end_existing[-1];
     195                 : 
     196                 :   /*
     197                 :    * Normal instruction can only change an anyfied: immediate, displacement or
     198                 :    * relative offset.
     199                 :    */
     200              13 :   return memcmp(begin_new, begin_existing,
     201                 :                 instruction_length - INFO_ANYFIELDS_SIZE(info_new)) == 0;
     202             339 : }
     203                 : 
     204                 : static NaClValidationStatus ValidatorCodeReplacement_x86_64(
     205              13 :     uintptr_t guest_addr,
     206              13 :     uint8_t *data_existing,
     207              13 :     uint8_t *data_new,
     208              13 :     size_t size,
     209              13 :     const NaClCPUFeatures *f) {
     210                 :   /* TODO(jfb) Use a safe cast here. */
     211              13 :   NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f;
     212              26 :   UNREFERENCED_PARAMETER(guest_addr);
     213                 : 
     214              13 :   if (size & kBundleMask)
     215               0 :     return NaClValidationFailed;
     216              13 :   if (ValidateChunkAMD64(data_new, size, CALL_USER_CALLBACK_ON_EACH_INSTRUCTION,
     217                 :                          cpu_features, ProcessCodeReplacementInstruction,
     218                 :                          (void *)(data_existing - data_new)))
     219               7 :     return NaClValidationSucceeded;
     220               6 :   if (errno == ENOMEM)
     221               0 :     return NaClValidationFailedOutOfMemory;
     222               6 :   return NaClValidationFailed;
     223              13 : }
     224                 : 
     225                 : static const struct NaClValidatorInterface validator = {
     226                 :   FALSE, /* Optional stubout_mode is not implemented.            */
     227                 :   TRUE,  /* Optional readonly_text mode is implemented.          */
     228                 :   TRUE,  /* Optional code replacement functions are implemented. */
     229                 :   ApplyDfaValidator_x86_64,
     230                 :   ValidatorCodeCopy_x86_64,
     231                 :   ValidatorCodeReplacement_x86_64,
     232                 :   sizeof(NaClCPUFeaturesX86),
     233                 :   NaClSetAllCPUFeaturesX86,
     234                 :   NaClGetCurrentCPUFeaturesX86,
     235                 :   NaClFixCPUFeaturesX86,
     236                 : };
     237                 : 
     238                 : const struct NaClValidatorInterface *NaClDfaValidatorCreate_x86_64(void) {
     239             304 :   return &validator;
     240                 : }

Generated by: LCOV version 1.7