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 * Simple Fault Injection library. (No, SFI is already taken!) 9 * 10 * For testing, inject faults under the control of environment 11 * variables. At call sites where faults may occur, e.g., memory 12 * allocation, wrap the call to the function so that rather than 13 * calling the function, a dummy bad return value can be provided 14 * instead. 15 * 16 * When fault injection occurs is controlled by the 17 * NACL_FAULT_INJECTION environment variable. Its value is a colon or 18 * comma separated list of <site_name>=<fault_control_expression> 19 * pairs. The <site_name> portion is just the call site string name 20 * specified in the NACL_FI, NACL_FI_VAL, or NACL_FI_SYSCALL macros 21 * below. The <fault_control_expression> is an expression that 22 * controls when to inject the fault and what value(s) to use (in the 23 * case of NACL_FI, the value is only under the control of the macro 24 * and not the environment variable). Often it is desirable that the 25 * fault does not occur on the first time that the call site is 26 * reached. This is where the <fault_control_expression> comes in. 27 * It grammar in BNF is 28 * 29 * <fault_control_expression> ::= T <pass_or_fail_seq> | G <pass_or_fail_seq> 30 * <pass_or_fail_seq> ::= <pass_or_fail_seq> <pass_or_fail> | <pass_or_fail> 31 * | <pass_or_fail_seq> + <pass_or_fail> 32 * <pass_or_fail> ::= P<count> | F[<value>][/<count>]] 33 * <count> := <digits>|@ 34 * <value> := <digits> 35 * 36 * If a leading literal 'T' occurs, the fault control expression is 37 * thread specific -- every thread is started with its own private 38 * counters for how many times it has reached the call site, etc; 39 * otherwise there must be a leading literal 'G', and the fault 40 * control counter for the call site is global, and accessed after 41 * acquiring a lock. 42 * 43 * <pass_or_fail> specifies at what "time" a call to that call site 44 * fails. The <count> value after the literal 'P' specifies how many 45 * times the fault injection passes the call through to the real 46 * function (note that the real function can also return an error or 47 * faulting value), and the optional <value> and optional <count> 48 * after the 'F' literal specifies the injected fault value, and how 49 * many times the fault occurs (if the call-site is reached again) 50 * [defaulting to 1]. If <value> is omitted, it defaults to 0; 51 * <count> may be '@', in which case "infinite" or ~(size_t) 0 is 52 * used. 53 * 54 * Once the <fault_control_sequence> is exhausted, the call site will 55 * revert to passing through (i.e., the real function will always be 56 * called). The fault injection library does not implicitly add F/@ 57 * to the <fault_control_sequence>. 58 * 59 * <pass_or_fail_seq> has an option '+' separator between the 60 * <pass_or_fail> entries so that <digits> can include hexadecimal, 61 * and since 'F' is a valid hexadecimal digit, we would otherwise 62 * consume the failure prefix. 63 * 64 * TODO: <fault_control_sequence> should really be extended to be more 65 * like regular expressions, so that e.g. (P1F/2){3}F-1/2P2 could be 66 * used to specify 67 * 68 * P F(0) F(0) P F(0) F(0) P F(0) F(0) F(-1) F(-1) P P 69 * 70 * in which case instead of '@' for infinity we should use '*'. NB: 71 * unlike regular expressions which are used for matching a regular 72 * set, we want generating expressions which generates exactly one 73 * (possibly infinite length) sequence of P or F(fault_value) symbols. 74 */ 75 76 #ifndef NATIVE_CLIENT_SRC_TRUSTED_FAULT_INJECTION_FAULT_INJECTION_H_ 77 #define NATIVE_CLIENT_SRC_TRUSTED_FAULT_INJECTION_FAULT_INJECTION_H_ 78 79 #include "native_client/src/include/nacl_base.h" 80 #include "native_client/src/include/portability.h" 81 82 EXTERN_C_BEGIN 83 84 /* 85 * Module initializer. Requires log module to have been initialized. 86 * 87 * Must be called before going multithreaded. Idempotent: repeated 88 * calls ignored. 89 */ 90 void NaClFaultInjectionModuleInit(void); 91 92 /* 93 * Private functions, to be used only by the macros below. Not stable 94 * ABI; may change. 95 */ 96 int NaClFaultInjectionFaultP(char const *site_name); 97 uintptr_t NaClFaultInjectionValue(void); 98 99 /* 100 * Function to free per-thread counters. 101 * 102 * We use pthread_cleanup_push on systems with pthread, but the API 103 * cannot rely on this, since Windows has no equivalent cleanup 104 * function, so sans deeper integration with threading libraries 105 * (e.g. platform), we cannot do the cleanup automatically. 106 */ 107 void NaClFaultInjectionPreThreadExitCleanup(void); 108 109 /* 110 * Private test functions. 111 */ 112 void NaClFaultInjectionModuleInternalInit(void); 113 void NaClFaultInjectionModuleInternalFini(void); 114 115 116 /* 117 * NB: macros below may evaluate the site_name (call site name) 118 * argument multiply, so beware. In typical uses this will be a C 119 * NUL-terminated string immediate, so it shouldn't be a problem. 120 */ 121 122 /* 123 * char *buffer = NACL_FI("io_buffer", malloc(buffer_size), NULL); 124 * 125 * NACL_FAULT_INJECTION=io_buffer=GP2F ./path/to/sel_ldr -args -- some.nexe 126 * 127 * The malloc function is called normally twice, then on the third 128 * call, rather than actually invoking malloc, NULL is returned to 129 * simulate an out-of-memory condition. If the program continues to 130 * run and that call site is reached again, malloc will be invoked 131 * normally. 132 */ 133 134 #define NACL_FI(site_name, funcall, error_value) \ 135 (NaClFaultInjectionFaultP(site_name) ? (error_value) : (funcall)) 136 /* 137 * Note that the |error_value| parameter can be more complex, e.g., it 138 * can be an expression that invokes a factory function to obtain a 139 * special error value. Similarly, |funcall| can be an arbitrary 140 * expression, e.g., the guard to a conditional that leads to a 141 * LOG_FATAL. 142 */ 143 144 /* 145 * if (NACL_FI_ERROR_COND("test", !NaClSecureServiceCtor(...))) { 146 * error_handling_code(); 147 * } 148 * 149 * This is a common case -- the error check guard to error handling 150 * code is wrapped with NACL_FI_ERROR_COND to pretend that the guard 151 * fired and force the error handling code to execute. 152 * 153 * NB: does NOT evaluate |expr| when the fault injection machinery 154 * triggers. 155 */ 156 #define NACL_FI_ERROR_COND(site_name, expr) \ 157 (NACL_FI(site_name, expr, 1)) 158 159 #define NACL_FI_FATAL(site_name) \ 160 do { \ 161 if (NACL_FI(site_name, 0, 1)) { \ 162 NaClLog(LOG_FATAL, "NaCl Fault Injection: at %s\n", site_name); \ 163 } \ 164 } while (0) 165 166 /* 167 * NaClErrorCode = NACL_FI_VAL("load_module", NaClErrorCode, 168 * NaClAppLoadFile(load_src, nap)); 169 * 170 * NACL_FAULT_INJECTION=load_module=GF2 ./path/to/sel_ldr -args -- some.nexe 171 * # error 2 is LOAD_UNSUPPORTED_OS_PLATFORM 172 * 173 * Since the type is a macro argument, we could inject in any integral 174 * values that is the size of uintptr_t or smaller (e.g., pointers are 175 * possible), but we cannot construct objects etc. 176 * 177 * WARNING: if you use NACL_FI_VAL with functions such as malloc, then 178 * the fault injection harness, if enabled, could be used to subvert 179 * security by, e.g., making an apparent call to malloc return a 180 * pointer to user-controlled data regions rather than new memory. 181 */ 182 183 #define NACL_FI_VAL(site_name, type, funcall) \ 184 (NaClFaultInjectionFaultP(site_name) \ 185 ? (type) NaClFaultInjectionValue() \ 186 : (funcall)) 187 188 /* 189 * int syscall_ret = NACL_FI_SYSCALL("PlatformLinuxRead3", 190 * read(d, ...)) 191 * 192 * NACL_FAULT_INJECTION=PlatformLinuxRead3=GF9 ./path/to/sel_ldr -args \ 193 * -- some.nexe 194 * # errno 9 on linux is EBADF. 195 * 196 * This case causes the call to return -1 and sets errno to 9. 197 */ 198 #define NACL_FI_SYSCALL(site_name, funcall) \ 199 (NaClFaultInjectionFaultP(site_name) \ 200 ? ((errno = (int) NaClFaultInjectionValue()), -1) \ 201 : (funcall)) 202 203 /* 204 * int syscall_ret = NACL_FI_TYPED_SYSCALL("PlatformLinuxMmap5", 205 * void *, mmap(d, ...)) 206 * 207 * NACL_FAULT_INJECTION=PlatformLinuxMmap5=GF9 ./path/to/sel_ldr -args \ 208 * -- some.nexe 209 * # errno 9 on linux is EBADF. 210 * 211 * This case causes the call to return -1 and sets errno to 9. 212 */ 213 #define NACL_FI_TYPED_SYSCALL(site_name, type, funcall) \ 214 (NaClFaultInjectionFaultP(site_name) \ 215 ? ((errno = (int) NaClFaultInjectionValue()), (type) -1) \ 216 : (funcall)) 217 218 EXTERN_C_END 219 220 #endif 221