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