LCOV - code coverage report
Current view: directory - src/trusted/platform_qualify/posix - nacl_dep_qualify.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 44 40 90.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                 : /*
       8                 :  * POSIX-specific routines for verifying that Data Execution Prevention is
       9                 :  * functional.
      10                 :  */
      11                 : 
      12                 : #include <setjmp.h>
      13                 : #include <stdlib.h>
      14                 : #include <signal.h>
      15                 : 
      16                 : #include "native_client/src/include/nacl_compiler_annotations.h"
      17                 : #include "native_client/src/shared/platform/nacl_check.h"
      18                 : #include "native_client/src/trusted/platform_qualify/nacl_dep_qualify.h"
      19                 : 
      20                 : #if NACL_OSX
      21                 : #include <mach/mach.h>
      22                 : #endif
      23                 : 
      24                 : #if (NACL_OSX && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \
      25                 :      NACL_BUILD_SUBARCH == 64)
      26                 : # define EXPECTED_SIGNAL SIGBUS
      27                 : #else
      28                 : # define EXPECTED_SIGNAL SIGSEGV
      29                 : #endif
      30                 : 
      31                 : static struct sigaction previous_sigaction;
      32                 : static struct sigaction try_sigaction;
      33                 : static sigjmp_buf try_state;
      34                 : 
      35               0 : static void signal_catch(int sig) {
      36               0 :   siglongjmp(try_state, sig);
      37               0 : }
      38                 : 
      39                 : static void setup_signals(void) {
      40             267 :   try_sigaction.sa_handler = signal_catch;
      41             267 :   sigemptyset(&try_sigaction.sa_mask);
      42             267 :   try_sigaction.sa_flags = SA_RESETHAND;
      43                 : 
      44             267 :   (void) sigaction(EXPECTED_SIGNAL, &try_sigaction, &previous_sigaction);
      45             267 : }
      46                 : 
      47                 : static void restore_signals(void) {
      48             267 :   (void) sigaction(EXPECTED_SIGNAL, &previous_sigaction, 0);
      49             267 : }
      50                 : 
      51                 : #if NACL_OSX
      52                 : 
      53                 : /*
      54                 :  * If present, Breakpad's handler will swallow the hardware exception that
      55                 :  * the test triggers before its signal handler can respond to it. Temporarily
      56                 :  * disable Breakpad's handler to allow the system's in-kernel handler to
      57                 :  * transform the exception into the signal that's expected here.
      58                 :  */
      59                 : 
      60                 : /*
      61                 :  * <mach/mach_types.defs> says that these arrays have room for 32 elements,
      62                 :  * not EXC_TYPES_COUNT. task_swap_exception_ports expects there to be room for
      63                 :  * 32.
      64                 :  */
      65                 : #define MAX_EXCEPTION_PORTS 32
      66                 : 
      67                 : typedef struct {
      68                 :   exception_mask_t masks[MAX_EXCEPTION_PORTS];
      69                 :   exception_handler_t ports[MAX_EXCEPTION_PORTS];
      70                 :   exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
      71                 :   thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
      72                 :   mach_msg_type_number_t count;
      73                 : } MachExceptionHandlerData;
      74                 : 
      75                 : static void DisableMachExceptionHandler(
      76             267 :     MachExceptionHandlerData *saved_handlers) {
      77             267 :   kern_return_t kr = task_swap_exception_ports(
      78                 :       mach_task_self(),
      79                 :       EXC_MASK_BAD_ACCESS,
      80                 :       MACH_PORT_NULL,
      81                 :       EXCEPTION_DEFAULT,
      82                 :       THREAD_STATE_NONE,
      83                 :       (exception_mask_array_t) &saved_handlers->masks,
      84                 :       &saved_handlers->count,
      85                 :       (exception_handler_array_t) &saved_handlers->ports,
      86                 :       (exception_behavior_array_t) &saved_handlers->behaviors,
      87                 :       (exception_flavor_array_t) &saved_handlers->flavors);
      88             801 :   CHECK(kr == KERN_SUCCESS);
      89             267 : }
      90                 : 
      91                 : static void EnableMachExceptionHandler(
      92             267 :     MachExceptionHandlerData *saved_handlers) {
      93            1068 :   for (size_t index = 0; index < saved_handlers->count; ++index) {
      94             267 :     if (saved_handlers->ports[index] != MACH_PORT_NULL) {
      95              28 :       kern_return_t kr = task_set_exception_ports(
      96                 :           mach_task_self(),
      97                 :           saved_handlers->masks[index],
      98                 :           saved_handlers->ports[index],
      99                 :           saved_handlers->behaviors[index],
     100                 :           saved_handlers->flavors[index]);
     101              84 :       CHECK(kr == KERN_SUCCESS);
     102              28 :     }
     103             267 :   }
     104             267 : }
     105                 : 
     106                 : #else
     107                 : 
     108                 : typedef int MachExceptionHandlerData;
     109                 : 
     110                 : static void DisableMachExceptionHandler(
     111                 :     MachExceptionHandlerData *saved_handlers) {
     112                 :   UNREFERENCED_PARAMETER(saved_handlers);
     113                 : }
     114                 : 
     115                 : static void EnableMachExceptionHandler(
     116                 :     MachExceptionHandlerData *saved_handlers) {
     117                 :   UNREFERENCED_PARAMETER(saved_handlers);
     118                 : }
     119                 : 
     120                 : #endif
     121                 : 
     122             533 : int NaClAttemptToExecuteDataAtAddr(char *thunk_buffer, size_t size) {
     123             533 :   int result;
     124             533 :   MachExceptionHandlerData saved_handlers;
     125             533 :   nacl_void_thunk thunk = NaClGenerateThunk(thunk_buffer, size);
     126                 : 
     127             533 :   setup_signals();
     128             533 :   DisableMachExceptionHandler(&saved_handlers);
     129                 : 
     130             533 :   if (0 == sigsetjmp(try_state, 1)) {
     131             267 :     thunk();
     132             267 :     result = 0;
     133             267 :   } else {
     134             266 :     result = 1;
     135                 :   }
     136                 : 
     137             267 :   EnableMachExceptionHandler(&saved_handlers);
     138             267 :   restore_signals();
     139                 : 
     140             267 :   return result;
     141                 : }
     142                 : 
     143                 : /*
     144                 :  * Returns 1 if Data Execution Prevention is present and working.
     145                 :  */
     146                 : int NaClAttemptToExecuteData(void) {
     147             265 :   int result;
     148             530 :   char *thunk_buffer = malloc(64);
     149             265 :   if (NULL == thunk_buffer) {
     150               0 :     return 0;
     151                 :   }
     152             265 :   result = NaClAttemptToExecuteDataAtAddr(thunk_buffer, 64);
     153             265 :   free(thunk_buffer);
     154             265 :   return result;
     155             265 : }

Generated by: LCOV version 1.7