• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws System Fault Injection
3  *
4  * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 #include <assert.h>
28 
29 static lws_fi_priv_t *
lws_fi_lookup(const lws_fi_ctx_t * fic,const char * name)30 lws_fi_lookup(const lws_fi_ctx_t *fic, const char *name)
31 {
32 	lws_start_foreach_dll(struct lws_dll2 *, p, fic->fi_owner.head) {
33 		lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
34 
35 		if (!strcmp(pv->fi.name, name))
36 			return pv;
37 
38 	} lws_end_foreach_dll(p);
39 
40 	return NULL;
41 }
42 
43 int
lws_fi(const lws_fi_ctx_t * fic,const char * name)44 lws_fi(const lws_fi_ctx_t *fic, const char *name)
45 {
46 	lws_fi_priv_t *pv;
47 	int n;
48 
49 	pv = lws_fi_lookup(fic, name);
50 
51 	if (!pv)
52 		return 0;
53 
54 	switch (pv->fi.type) {
55 	case LWSFI_ALWAYS:
56 		goto inject;
57 
58 	case LWSFI_DETERMINISTIC:
59 		pv->fi.times++;
60 		if (pv->fi.times >= pv->fi.pre)
61 			if (pv->fi.times < pv->fi.pre + pv->fi.count)
62 				goto inject;
63 		return 0;
64 
65 	case LWSFI_PROBABILISTIC:
66 		if (lws_xos_percent((lws_xos_t *)&fic->xos, (int)pv->fi.pre))
67 			goto inject;
68 		return 0;
69 
70 	case LWSFI_PATTERN:
71 	case LWSFI_PATTERN_ALLOC:
72 		n = (int)((pv->fi.times++) % pv->fi.count);
73 		if (pv->fi.pattern[n >> 3] & (1 << (n & 7)))
74 			goto inject;
75 
76 		return 0;
77 
78 	default:
79 		return 0;
80 	}
81 
82 	return 0;
83 
84 inject:
85 	lwsl_warn("%s: Injecting fault %s->%s\n", __func__,
86 			fic->name ? fic->name : "unk", pv->fi.name);
87 
88 	return 1;
89 }
90 
91 int
lws_fi_range(const lws_fi_ctx_t * fic,const char * name,uint64_t * result)92 lws_fi_range(const lws_fi_ctx_t *fic, const char *name, uint64_t *result)
93 {
94 	lws_fi_priv_t *pv;
95 	uint64_t d;
96 
97 	pv = lws_fi_lookup(fic, name);
98 
99 	if (!pv)
100 		return 1;
101 
102 	if (pv->fi.type != LWSFI_RANGE) {
103 		lwsl_err("%s: fault %s is not a 123..456 range\n",
104 			 __func__, name);
105 		return 1;
106 	}
107 
108 	d = pv->fi.count - pv->fi.pre;
109 
110 	*result = pv->fi.pre + (lws_xos((lws_xos_t *)&fic->xos) % d);
111 
112 	return 0;
113 }
114 
115 int
_lws_fi_user_wsi_fi(struct lws * wsi,const char * name)116 _lws_fi_user_wsi_fi(struct lws *wsi, const char *name)
117 {
118 	return lws_fi(&wsi->fic, name);
119 }
120 
121 int
_lws_fi_user_context_fi(struct lws_context * ctx,const char * name)122 _lws_fi_user_context_fi(struct lws_context *ctx, const char *name)
123 {
124 	return lws_fi(&ctx->fic, name);
125 }
126 
127 #if defined(LWS_WITH_SECURE_STREAMS)
128 int
_lws_fi_user_ss_fi(struct lws_ss_handle * h,const char * name)129 _lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *name)
130 {
131 	return lws_fi(&h->fic, name);
132 }
133 
134 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
135 int
_lws_fi_user_sspc_fi(struct lws_sspc_handle * h,const char * name)136 _lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *name)
137 {
138 	return lws_fi(&h->fic, name);
139 }
140 #endif
141 #endif
142 
143 int
lws_fi_add(lws_fi_ctx_t * fic,const lws_fi_t * fi)144 lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi)
145 {
146 	lws_fi_priv_t *pv;
147 	size_t n = strlen(fi->name);
148 
149 	pv = lws_malloc(sizeof(*pv) + n + 1, __func__);
150 	if (!pv)
151 		return 1;
152 
153 	lws_dll2_clear(&pv->list);
154 
155 	memcpy(&pv->fi, fi, sizeof(*fi));
156 	pv->fi.name = (const char *)&pv[1];
157 	memcpy(&pv[1], fi->name, n + 1);
158 
159 	lws_dll2_add_tail(&pv->list, &fic->fi_owner);
160 
161 	return 0;
162 }
163 
164 void
lws_fi_remove(lws_fi_ctx_t * fic,const char * name)165 lws_fi_remove(lws_fi_ctx_t *fic, const char *name)
166 {
167 	lws_fi_priv_t *pv = lws_fi_lookup(fic, name);
168 
169 	if (!pv)
170 		return;
171 
172 	lws_dll2_remove(&pv->list);
173 	lws_free(pv);
174 }
175 
176 void
lws_fi_import(lws_fi_ctx_t * fic_dest,const lws_fi_ctx_t * fic_src)177 lws_fi_import(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src)
178 {
179 
180 	/* inherit the PRNG seed for our context from source guy too */
181 	lws_xos_init(&fic_dest->xos, lws_xos((lws_xos_t *)&fic_src->xos));
182 
183 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
184 				   fic_src->fi_owner.head) {
185 		lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
186 
187 		lws_dll2_remove(&pv->list);
188 		lws_dll2_add_tail(&pv->list, &fic_dest->fi_owner);
189 
190 	} lws_end_foreach_dll_safe(p, p1);
191 }
192 
193 static void
do_inherit(lws_fi_ctx_t * fic_dest,lws_fi_t * pfi,size_t trim)194 do_inherit(lws_fi_ctx_t *fic_dest, lws_fi_t *pfi, size_t trim)
195 {
196 	lws_fi_t fi = *pfi;
197 
198 	fi.name += trim;
199 
200 	lwsl_info("%s: %s: %s inherited as %s\n", __func__, fic_dest->name,
201 		  pfi->name, fi.name);
202 
203 	if (fi.type == LWSFI_PATTERN_ALLOC) {
204 		fi.pattern = lws_malloc((size_t)((fi.count >> 3) + 1), __func__);
205 		if (!fi.pattern)
206 			return;
207 		memcpy((uint8_t *)fi.pattern, pfi->pattern,
208 		       (size_t)((fi.count >> 3) + 1));
209 	}
210 
211 	lws_fi_add(fic_dest, &fi);
212 }
213 
214 void
lws_fi_inherit_copy(lws_fi_ctx_t * fic_dest,const lws_fi_ctx_t * fic_src,const char * scope,const char * value)215 lws_fi_inherit_copy(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src,
216 		    const char *scope, const char *value)
217 {
218 	size_t sl = 0, vl = 0;
219 
220 	if (scope)
221 		sl = strlen(scope);
222 
223 	if (value)
224 		vl = strlen(value);
225 
226 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
227 				   fic_src->fi_owner.head) {
228 		lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
229 		size_t nl = strlen(pv->fi.name);
230 
231 		if (!scope)
232 			do_inherit(fic_dest, &pv->fi, 0);
233 		else
234 			if (nl > sl + 2 &&
235 			    !strncmp(pv->fi.name, scope, sl) &&
236 			    pv->fi.name[sl] == '/')
237 				do_inherit(fic_dest, &pv->fi, sl + 1);
238 			else {
239 				if (value && nl > sl + vl + 2 &&
240 				    pv->fi.name[sl] == '=' &&
241 				    !strncmp(pv->fi.name + sl + 1, value, vl) &&
242 				    pv->fi.name[sl + 1 + vl] == '/')
243 					do_inherit(fic_dest, &pv->fi, sl + vl + 2);
244 			}
245 
246 	} lws_end_foreach_dll_safe(p, p1);
247 }
248 
249 void
lws_fi_destroy(const lws_fi_ctx_t * fic)250 lws_fi_destroy(const lws_fi_ctx_t *fic)
251 {
252 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
253 				   fic->fi_owner.head) {
254 		lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
255 
256 		if (pv->fi.type == LWSFI_PATTERN_ALLOC && pv->fi.pattern) {
257 			lws_free((void *)pv->fi.pattern);
258 			pv->fi.pattern = NULL;
259 		}
260 
261 		lws_dll2_remove(&pv->list);
262 		lws_free(pv);
263 
264 	} lws_end_foreach_dll_safe(p, p1);
265 }
266 
267 /*
268  * We want to support these kinds of qualifier
269  *
270  * myfault            true always
271  * myfault(10%)       true 10% of the time
272  * myfault(....X X)   true when X
273  * myfault2(20..3000)  pick a number between 20 and 3000
274  */
275 
276 enum {
277 	PARSE_NAME,
278 	PARSE_WHEN,
279 	PARSE_PC,
280 	PARSE_ENDBR,
281 	PARSE_COMMA
282 };
283 
284 void
lws_fi_deserialize(lws_fi_ctx_t * fic,const char * sers)285 lws_fi_deserialize(lws_fi_ctx_t *fic, const char *sers)
286 {
287 	int state = PARSE_NAME, m;
288 	struct lws_tokenize ts;
289 	lws_fi_t fi;
290 	char nm[64];
291 
292 	/*
293 	 * Go through the comma-separated list of faults
294 	 * creating them and adding to the lws_context info
295 	 */
296 
297 	lws_tokenize_init(&ts, sers, LWS_TOKENIZE_F_DOT_NONTERM |
298 				     LWS_TOKENIZE_F_NO_INTEGERS |
299 				     LWS_TOKENIZE_F_NO_FLOATS |
300 				     LWS_TOKENIZE_F_EQUALS_NONTERM |
301 				     LWS_TOKENIZE_F_SLASH_NONTERM |
302 				     LWS_TOKENIZE_F_MINUS_NONTERM);
303 	ts.len = (unsigned int)strlen(sers);
304 	if (ts.len < 1 || ts.len > 10240)
305 		return;
306 
307 	do {
308 		ts.e = (int8_t)lws_tokenize(&ts);
309 		switch (ts.e) {
310 		case LWS_TOKZE_TOKEN:
311 
312 			if (state == PARSE_NAME) {
313 				/*
314 				 * One fault to inject looks like, eg,
315 				 *
316 				 *   vh=xxx/listenskt
317 				 */
318 
319 				memset(&fi, 0, sizeof(fi));
320 
321 				lws_strnncpy(nm, ts.token, ts.token_len,
322 					     sizeof(nm));
323 				fi.name = nm;
324 				fi.type = LWSFI_ALWAYS;
325 
326 				lwsl_notice("%s: name %.*s\n", __func__,
327 					    (int)ts.token_len, ts.token);
328 
329 				/* added later, potentially after (when) */
330 				break;
331 			}
332 			if (state == PARSE_WHEN) {
333 				/* it's either numeric (then % or ..num2), or
334 				 * .X pattern */
335 
336 				lwsl_notice("%s: when\n", __func__);
337 
338 				if (*ts.token == '.' || *ts.token == 'X') {
339 					uint8_t *pat;
340 					size_t n;
341 
342 					/*
343 					 * pattern... we need to allocate it
344 					 */
345 					fi.type = LWSFI_PATTERN_ALLOC;
346 					pat = lws_zalloc((ts.token_len >> 3) + 1,
347 							 __func__);
348 					if (!pat)
349 						return;
350 					fi.pattern = pat;
351 					fi.count = (uint64_t)ts.token_len;
352 
353 					for (n = 0; n < ts.token_len; n++)
354 						if (ts.token[n] == 'X')
355 							pat[n >> 3] = (uint8_t)(
356 								pat[n >> 3] |
357 								(1 << (n & 7)));
358 
359 					lwsl_hexdump_notice(pat,
360 						       (ts.token_len >> 3) + 1);
361 
362 					state = PARSE_ENDBR;
363 					break;
364 				}
365 
366 				fi.pre = (uint64_t)atoll(ts.token);
367 
368 				for (m = 0; m < (int)ts.token_len - 1; m++)
369 					if (ts.token[m] < '0' ||
370 					    ts.token[m] > '9')
371 						break;
372 
373 				/*
374 				 * We can understand num% or num..num
375 				 */
376 
377 				if (m != (int)ts.token_len &&
378 				    ts.token[m] == '.' &&
379 				    ts.token[m + 1] == '.') {
380 					fi.count = (uint64_t)atoll(
381 						&ts.token[m + 2]);
382 					fi.type = LWSFI_RANGE;
383 					state = PARSE_ENDBR;
384 
385 					if (fi.pre >= fi.count) {
386 						lwsl_err("%s: range must have "
387 							 "smaller first!\n",
388 							 __func__);
389 					}
390 
391 					lwsl_notice("%s: range %llx .."
392 						    "%llx\n", __func__,
393 						    (unsigned long long)fi.pre,
394 						    (unsigned long long)fi.count);
395 					break;
396 				}
397 
398 				lwsl_notice("%s: prob %d%%\n", __func__,
399 					    (int)fi.pre);
400 				fi.type = LWSFI_PROBABILISTIC;
401 				state = PARSE_PC;
402 				break;
403 			}
404 			break;
405 
406 		case LWS_TOKZE_DELIMITER:
407 			if (*ts.token == ',') {
408 				lws_fi_add(fic, &fi);
409 				state = PARSE_NAME;
410 				break;
411 			}
412 			if (*ts.token == '(') {
413 				lwsl_notice("%s: (\n", __func__);
414 				if (state != PARSE_NAME) {
415 					lwsl_err("%s: misplaced (\n", __func__);
416 					return;
417 				}
418 				state = PARSE_WHEN;
419 				break;
420 			}
421 			if (*ts.token == ')') {
422 				if (state != PARSE_ENDBR) {
423 					lwsl_err("%s: misplaced )\n", __func__);
424 					return;
425 				}
426 				state = PARSE_NAME;
427 				break;
428 			}
429 			if (*ts.token == '%') {
430 				if (state != PARSE_PC) {
431 					lwsl_err("%s: misplaced %%\n", __func__);
432 					return;
433 				}
434 				state = PARSE_ENDBR;
435 				break;
436 			}
437 			break;
438 
439 		case LWS_TOKZE_ENDED:
440 			lws_fi_add(fic, &fi);
441 			return;
442 
443 		default:
444 			return;
445 		}
446 	} while (ts.e > 0);
447 }
448