1 #include "log.h"
2 
3 #include <execinfo.h>
4 #include <openssl/bio.h>
5 #include <openssl/err.h>
6 #include <pthread.h>
7 #include <signal.h>
8 #include <syslog.h>
9 #include <time.h>
10 #include <unistd.h>
11 
12 #include "config.h"
13 #include "thread_var.h"
14 
15 struct level {
16 	char const *label;
17 	char const *color;
18 	FILE *stream;
19 };
20 
21 static struct level DBG = { "DBG", "\x1B[36m" }; /* Cyan */
22 static struct level INF = { "INF", "\x1B[37m" }; /* White */
23 static struct level WRN = { "WRN", "\x1B[33m" }; /* Yellow */
24 static struct level ERR = { "ERR", "\x1B[31m" }; /* Red */
25 static struct level CRT = { "CRT", "\x1B[35m" }; /* Purple */
26 static struct level UNK = { "UNK", "" };
27 #define COLOR_RESET "\x1B[0m"
28 
29 struct log_config {
30 	bool fprintf_enabled; /* Print on the standard streams? */
31 	bool syslog_enabled; /* Print on syslog? */
32 
33 	uint8_t level;
34 	char const *prefix;
35 	bool color;
36 	int facility;
37 };
38 
39 /* Configuration for the operation logs. */
40 static struct log_config op_config;
41 /* Configuration for the validation logs. */
42 static struct log_config val_config;
43 
44 /*
45  * Note: Normally, fprintf and syslog would have separate locks.
46  *
47  * However, fprintf and syslog are rarely enabled at the same time, so I don't
48  * think it's worth it. So I'm reusing the lock.
49  *
50  * "log" + "lock" = "logck"
51  */
52 static pthread_mutex_t logck;
53 
54 /**
55  * Important: -rdynamic needs to be enabled, otherwise this does not print
56  * function names. See LDFLAGS_DEBUG in Makefile.am.
57  * Also: Only non-static functions will be labeled.
58  *
59  * The first printed entry is probably not meaningful. (But I'm printing
60  * everything anyway due to paranoia.)
61  *
62  * @title is allowed to be NULL. If you need locking, do it outside. (And be
63  * aware that pthread_mutex_lock() can return error codes, which shouldn't
64  * prevent critical stack traces from printing.)
65  */
66 void
print_stack_trace(char const * title)67 print_stack_trace(char const *title)
68 {
69 #define STACK_SIZE 64
70 
71 	void *array[STACK_SIZE];
72 	size_t size;
73 	char **strings;
74 	size_t i;
75 	int fp;
76 
77 	size = backtrace(array, STACK_SIZE);
78 	strings = backtrace_symbols(array, size);
79 
80 	if (op_config.fprintf_enabled) {
81 		if (title != NULL)
82 			fprintf(ERR.stream, "%s\n", title);
83 		fprintf(ERR.stream, "Stack trace:\n");
84 		for (i = 0; i < size; i++)
85 			fprintf(ERR.stream, "  %s\n", strings[i]);
86 		fprintf(ERR.stream, "(End of stack trace)\n");
87 	}
88 
89 	if (op_config.syslog_enabled) {
90 		fp = LOG_ERR | op_config.facility;
91 		if (title != NULL)
92 			syslog(fp, "%s", title);
93 		syslog(fp, "Stack trace:");
94 		for (i = 0; i < size; i++)
95 			syslog(fp, "  %s", strings[i]);
96 		syslog(fp, "(End of stack trace)");
97 	}
98 
99 	free(strings);
100 }
101 
init_config(struct log_config * cfg,bool unit_tests)102 static void init_config(struct log_config *cfg, bool unit_tests)
103 {
104 	cfg->fprintf_enabled = true;
105 	cfg->syslog_enabled = !unit_tests;
106 	cfg->level = LOG_DEBUG;
107 	cfg->prefix = NULL;
108 	cfg->color = false;
109 	cfg->facility = LOG_DAEMON;
110 }
111 
112 static void
sigsegv_handler(int signum)113 sigsegv_handler(int signum)
114 {
115 	/*
116 	 * IMPORTANT: See https://stackoverflow.com/questions/29982643
117 	 * I went with rationalcoder's answer, because I think not printing
118 	 * stack traces on segfaults is a nice way of ending up committing
119 	 * suicide.
120 	 *
121 	 * Here's a list of legal functions:
122 	 * https://stackoverflow.com/a/16891799/1735458
123 	 * (Man, I wish POSIX standards were easier to link to.)
124 	 */
125 
126 #define STACK_SIZE 64
127 	void *array[STACK_SIZE];
128 	size_t size;
129 
130 	size = backtrace(array, STACK_SIZE);
131 	backtrace_symbols_fd(array, size, STDERR_FILENO);
132 
133 	/* Trigger default handler. */
134 	signal(signum, SIG_DFL);
135 	kill(getpid(), signum);
136 }
137 
138 /*
139  * Register better handlers for some signals.
140  *
141  * Remember to enable -rdynamic (See print_stack_trace()).
142  */
143 static void
register_signal_handlers(void)144 register_signal_handlers(void)
145 {
146 	struct sigaction action;
147 	void* dummy;
148 
149 	/*
150 	 * Make sure libgcc is loaded; otherwise backtrace() might allocate
151 	 * during a signal handler. (Which is illegal.)
152 	 */
153 	dummy = NULL;
154 	backtrace(&dummy, 1);
155 
156 	/* Register the segmentation fault handler */
157 	memset(&action, 0, sizeof(action));
158 	action.sa_handler = sigsegv_handler;
159 	sigemptyset(&action.sa_mask);
160 	action.sa_flags = 0;
161 	if (sigaction(SIGSEGV, &action, NULL) == -1) {
162 		/*
163 		 * Not fatal; it just means we will not print stack traces on
164 		 * Segmentation Faults.
165 		 */
166 		pr_op_errno(errno, "SIGSEGV handler registration failure");
167 	}
168 
169 	/*
170 	 * SIGPIPE can be triggered by any I/O function. libcurl is particularly
171 	 * tricky:
172 	 *
173 	 * > libcurl makes an effort to never cause such SIGPIPEs to trigger,
174 	 * > but some operating systems have no way to avoid them and even on
175 	 * > those that have there are some corner cases when they may still
176 	 * > happen
177 	 * (Documentation of CURLOPT_NOSIGNAL)
178 	 *
179 	 * All SIGPIPE means is "the peer closed the connection for some reason,
180 	 * fuck you."
181 	 * Which is a normal I/O error, and should be handled by the normal
182 	 * error propagation logic, not by a signal handler.
183 	 * So, ignore SIGPIPE.
184 	 *
185 	 * https://github.com/NICMx/FORT-validator/issues/49
186 	 */
187 	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
188 		/*
189 		 * Not fatal. It just means that, if a broken pipe happens, we
190 		 * will die silently.
191 		 * But they're somewhat rare, so whatever.
192 		 */
193 		pr_op_errno(errno, "SIGPIPE handler registration failure");
194 	}
195 }
196 
197 int
log_setup(bool unit_tests)198 log_setup(bool unit_tests)
199 {
200 	/*
201 	 * Remember not to use any actual logging functions until logging has
202 	 * been properly initialized.
203 	 */
204 
205 	int error;
206 
207 	DBG.stream = stdout;
208 	INF.stream = stdout;
209 	WRN.stream = stderr;
210 	ERR.stream = stderr;
211 	CRT.stream = stderr;
212 	UNK.stream = stdout;
213 
214 	if (unit_tests)
215 		openlog("fort", LOG_CONS | LOG_PID, LOG_DAEMON);
216 
217 	init_config(&op_config, unit_tests);
218 	init_config(&val_config, unit_tests);
219 
220 	error = pthread_mutex_init(&logck, NULL);
221 	if (error) {
222 		fprintf(ERR.stream, "pthread_mutex_init() returned %d: %s\n",
223 		    error, strerror(abs(error)));
224 		if (!unit_tests)
225 			syslog(LOG_ERR | op_config.facility,
226 			    "pthread_mutex_init() returned %d: %s",
227 			    error, strerror(abs(error)));
228 		return error;
229 	}
230 
231 	if (!unit_tests)
232 		register_signal_handlers();
233 
234 	return 0;
235 }
236 
237 static void
log_disable_syslog(void)238 log_disable_syslog(void)
239 {
240 	if (op_config.syslog_enabled || val_config.syslog_enabled) {
241 		closelog();
242 		op_config.syslog_enabled = false;
243 		val_config.syslog_enabled = false;
244 	}
245 }
246 
247 void
log_start(void)248 log_start(void)
249 {
250 	if (config_get_val_log_enabled()) {
251 		switch (config_get_val_log_output()) {
252 		case SYSLOG:
253 			pr_op_info("Syslog log output configured; disabling validation logging on standard streams.");
254 			pr_op_info("(Validation Logs will be sent to syslog only.)");
255 			val_config.fprintf_enabled = false;
256 			break;
257 		case CONSOLE:
258 			pr_op_info("Console log output configured; disabling validation logging on syslog.");
259 			pr_op_info("(Validation Logs will be sent to the standard streams only.)");
260 			val_config.syslog_enabled = false;
261 			break;
262 		}
263 	} else {
264 		pr_op_info("Disabling validation logging on syslog.");
265 		pr_op_info("Disabling validation logging on standard streams.");
266 		val_config.fprintf_enabled = false;
267 		val_config.syslog_enabled = false;
268 	}
269 
270 	if (config_get_op_log_enabled()) {
271 		switch (config_get_op_log_output()) {
272 		case SYSLOG:
273 			pr_op_info("Syslog log output configured; disabling operation logging on standard streams.");
274 			pr_op_info("(Operation Logs will be sent to syslog only.)");
275 			op_config.fprintf_enabled = false;
276 			break;
277 		case CONSOLE:
278 			pr_op_info("Console log output configured; disabling operation logging on syslog.");
279 			pr_op_info("(Operation Logs will be sent to the standard streams only.)");
280 			if (val_config.syslog_enabled)
281 				op_config.syslog_enabled = false;
282 			else
283 				log_disable_syslog();
284 			break;
285 		}
286 	} else {
287 		pr_op_info("Disabling operation logging on syslog.");
288 		pr_op_info("Disabling operation logging on standard streams.");
289 		op_config.fprintf_enabled = false;
290 		if (val_config.syslog_enabled)
291 			op_config.syslog_enabled = false;
292 		else
293 			log_disable_syslog();
294 	}
295 
296 	op_config.level = config_get_op_log_level();
297 	op_config.prefix = config_get_op_log_tag();
298 	op_config.color = config_get_op_log_color_output();
299 	op_config.facility = config_get_op_log_facility();
300 	val_config.level = config_get_val_log_level();
301 	val_config.prefix = config_get_val_log_tag();
302 	val_config.color = config_get_val_log_color_output();
303 	val_config.facility = config_get_val_log_facility();
304 }
305 
306 void
log_teardown(void)307 log_teardown(void)
308 {
309 	log_disable_syslog();
310 	pthread_mutex_destroy(&logck);
311 }
312 
313 void
log_flush(void)314 log_flush(void)
315 {
316 	if (op_config.fprintf_enabled || val_config.fprintf_enabled) {
317 		fflush(stdout);
318 		fflush(stderr);
319 	}
320 }
321 
322 bool
log_val_enabled(unsigned int level)323 log_val_enabled(unsigned int level)
324 {
325 	return val_config.level >= level;
326 }
327 
328 bool
log_op_enabled(unsigned int level)329 log_op_enabled(unsigned int level)
330 {
331 	return op_config.level >= level;
332 }
333 
334 static struct level const *
level2struct(int level)335 level2struct(int level)
336 {
337 	switch (level) {
338 	case LOG_CRIT:
339 		return &CRT;
340 	case LOG_ERR:
341 		return &ERR;
342 	case LOG_WARNING:
343 		return &WRN;
344 	case LOG_INFO:
345 		return &INF;
346 	case LOG_DEBUG:
347 		return &DBG;
348 	}
349 
350 	return &UNK;
351 }
352 
353 static void
lock_mutex(void)354 lock_mutex(void)
355 {
356 	int error;
357 
358 	error = pthread_mutex_lock(&logck);
359 	if (error) {
360 		/*
361 		 * Despite being supposed to be impossible, failing to lock the
362 		 * mutex is not fatal; it just means we might log some mixed
363 		 * messages, which is better than dying.
364 		 *
365 		 * Furthermore, this might have been called while logging
366 		 * another critical. We must absolutely not get in the way of
367 		 * that critical's print.
368 		 */
369 		print_stack_trace(strerror(error));
370 	}
371 }
372 
373 static void
unlock_mutex(void)374 unlock_mutex(void)
375 {
376 	int error;
377 
378 	error = pthread_mutex_unlock(&logck);
379 	if (error)
380 		print_stack_trace(strerror(error)); /* Same as above. */
381 }
382 
383 static void
__vfprintf(int level,struct log_config * cfg,char const * format,va_list args)384 __vfprintf(int level, struct log_config *cfg, char const *format, va_list args)
385 {
386 	char time_buff[20];
387 	struct level const *lvl;
388 	time_t now;
389 	struct tm stm_buff;
390 	char const *file_name;
391 
392 	lvl = level2struct(level);
393 
394 	lock_mutex();
395 
396 	if (cfg->color)
397 		fprintf(lvl->stream, "%s", lvl->color);
398 
399 	now = time(0);
400 	if (now != ((time_t) -1)) {
401 		localtime_r(&now, &stm_buff);
402 		strftime(time_buff, sizeof(time_buff), "%b %e %T", &stm_buff);
403 		fprintf(lvl->stream, "%s ", time_buff);
404 	}
405 
406 	fprintf(lvl->stream, "%s", lvl->label);
407 	if (cfg->prefix)
408 		fprintf(lvl->stream, " [%s]", cfg->prefix);
409 	fprintf(lvl->stream, ": ");
410 
411 	file_name = fnstack_peek();
412 	if (file_name != NULL)
413 		fprintf(lvl->stream, "%s: ", file_name);
414 
415 	vfprintf(lvl->stream, format, args);
416 
417 	if (cfg->color)
418 		fprintf(lvl->stream, COLOR_RESET);
419 	fprintf(lvl->stream, "\n");
420 
421 	/* Force flush */
422 	if (lvl->stream == stdout)
423 		fflush(lvl->stream);
424 
425 	unlock_mutex();
426 }
427 
428 #define MSG_LEN 1024
429 
430 static void
__syslog(int level,struct log_config * cfg,const char * format,va_list args)431 __syslog(int level, struct log_config *cfg, const char *format, va_list args)
432 {
433 	static char msg[MSG_LEN];
434 	char const *file_name;
435 	struct level const *lvl;
436 
437 	file_name = fnstack_peek();
438 	lvl = level2struct(level);
439 
440 	lock_mutex();
441 
442 	/* Can't use vsyslog(); it's not portable. */
443 	vsnprintf(msg, MSG_LEN, format, args);
444 	if (file_name != NULL) {
445 		if (cfg->prefix != NULL)
446 			syslog(level | cfg->facility, "%s [%s]: %s: %s",
447 			    lvl->label, cfg->prefix, file_name, msg);
448 		else
449 			syslog(level | cfg->facility, "%s: %s: %s",
450 			    lvl->label, file_name, msg);
451 	} else {
452 		if (cfg->prefix != NULL)
453 			syslog(level | cfg->facility, "%s [%s]: %s",
454 			    lvl->label, cfg->prefix, msg);
455 		else
456 			syslog(level | cfg->facility, "%s: %s",
457 			    lvl->label, msg);
458 	}
459 
460 	unlock_mutex();
461 }
462 
463 #define PR_SIMPLE(lvl, config)						\
464 	do {								\
465 		va_list args;						\
466 									\
467 		if (lvl > config.level)					\
468 			break;						\
469 									\
470 		if (config.syslog_enabled) {				\
471 			va_start(args, format);				\
472 			__syslog(lvl, &config, format, args);		\
473 			va_end(args);					\
474 		}							\
475 									\
476 		if (config.fprintf_enabled) {				\
477 			va_start(args, format);				\
478 			__vfprintf(lvl, &config, format, args);		\
479 			va_end(args);					\
480 		}							\
481 	} while (0)
482 
483 void
pr_op_debug(const char * format,...)484 pr_op_debug(const char *format, ...)
485 {
486 	PR_SIMPLE(LOG_DEBUG, op_config);
487 }
488 
489 void
pr_op_info(const char * format,...)490 pr_op_info(const char *format, ...)
491 {
492 	PR_SIMPLE(LOG_INFO, op_config);
493 }
494 
495 /**
496  * Always returs 0. (So you can interrupt whatever you're doing without failing
497  * validation.)
498  */
499 int
pr_op_warn(const char * format,...)500 pr_op_warn(const char *format, ...)
501 {
502 	PR_SIMPLE(LOG_WARNING, op_config);
503 	return 0;
504 }
505 
506 int
__pr_op_err(int error,const char * format,...)507 __pr_op_err(int error, const char *format, ...)
508 {
509 	PR_SIMPLE(LOG_ERR, op_config);
510 	lock_mutex();
511 	print_stack_trace(NULL);
512 	unlock_mutex();
513 	return error;
514 }
515 
516 void
pr_val_debug(const char * format,...)517 pr_val_debug(const char *format, ...)
518 {
519 	PR_SIMPLE(LOG_DEBUG, val_config);
520 }
521 
522 void
pr_val_info(const char * format,...)523 pr_val_info(const char *format, ...)
524 {
525 	PR_SIMPLE(LOG_INFO, val_config);
526 }
527 
528 /**
529  * Always returs 0. (So you can interrupt whatever you're doing without failing
530  * validation.)
531  */
532 int
pr_val_warn(const char * format,...)533 pr_val_warn(const char *format, ...)
534 {
535 	PR_SIMPLE(LOG_WARNING, val_config);
536 	return 0;
537 }
538 
539 int
__pr_val_err(int error,const char * format,...)540 __pr_val_err(int error, const char *format, ...)
541 {
542 	PR_SIMPLE(LOG_ERR, val_config);
543 	return error;
544 }
545 
546 struct crypto_cb_arg {
547 	unsigned int stack_size;
548 	int (*error_fn)(int, const char *, ...);
549 };
550 
551 static int
log_crypto_error(const char * str,size_t len,void * _arg)552 log_crypto_error(const char *str, size_t len, void *_arg)
553 {
554 	struct crypto_cb_arg *arg = _arg;
555 	arg->error_fn(0, "-> %s", str);
556 	arg->stack_size++;
557 	return 1;
558 }
559 
560 static int
crypto_err(struct log_config * cfg,int (* error_fn)(int,const char *,...))561 crypto_err(struct log_config *cfg, int (*error_fn)(int, const char *, ...))
562 {
563 	struct crypto_cb_arg arg;
564 
565 	error_fn(0, "libcrypto error stack:");
566 
567 	arg.stack_size = 0;
568 	arg.error_fn = error_fn;
569 	ERR_print_errors_cb(log_crypto_error, &arg);
570 	if (arg.stack_size == 0)
571 		error_fn(0, "   <Empty>");
572 	else
573 		error_fn(0, "End of libcrypto stack.");
574 
575 	return -EINVAL;
576 }
577 
578 /**
579  * This is like pr_err() and pr_errno(), except meant to log an error made
580  * during a libcrypto routine.
581  *
582  * This differs from usual printf-like functions:
583  *
584  * - It returns -EINVAL, not bytes written.
585  * - It prints a newline.
586  * - Also prints the cryptolib's error message stack.
587  *
588  * Always appends a newline at the end.
589  */
590 int
op_crypto_err(const char * format,...)591 op_crypto_err(const char *format, ...)
592 {
593 	PR_SIMPLE(LOG_ERR, op_config);
594 	return crypto_err(&op_config, __pr_op_err);
595 }
596 
597 /**
598  * This is like pr_err() and pr_errno(), except meant to log an error made
599  * during a libcrypto routine.
600  *
601  * This differs from usual printf-like functions:
602  *
603  * - It returns -EINVAL, not bytes written.
604  * - It prints a newline.
605  * - Also prints the cryptolib's error message stack.
606  *
607  * Always appends a newline at the end.
608  */
609 int
val_crypto_err(const char * format,...)610 val_crypto_err(const char *format, ...)
611 {
612 	PR_SIMPLE(LOG_ERR, val_config);
613 	return crypto_err(&val_config, __pr_val_err);
614 }
615 
616 int
pr_enomem(void)617 pr_enomem(void)
618 {
619 	static char const *ENOMEM_MSG = "Out of memory.\n";
620 	ssize_t garbage;
621 
622 	/*
623 	 * I'm not using PR_SIMPLE and friends, because those allocate.
624 	 * We want to minimize allocations after a memory allocation failure.
625 	 */
626 
627 	if (LOG_ERR > op_config.level)
628 		return -ENOMEM;
629 
630 	if (op_config.fprintf_enabled) {
631 		lock_mutex();
632 		/*
633 		 * write() is AS-Safe, which implies it doesn't allocate,
634 		 * unlike printf().
635 		 */
636 		garbage = write(STDERR_FILENO, ENOMEM_MSG, strlen(ENOMEM_MSG));
637 		unlock_mutex();
638 		garbage++;
639 	}
640 
641 	if (op_config.syslog_enabled) {
642 		lock_mutex();
643 		/* This allocates, but I don't think I have more options. */
644 		syslog(LOG_ERR | op_config.facility, "Out of memory.");
645 		unlock_mutex();
646 	}
647 
648 	return -ENOMEM;
649 }
650 
651 __dead void
pr_crit(const char * format,...)652 pr_crit(const char *format, ...)
653 {
654 	PR_SIMPLE(LOG_ERR, op_config);
655 	print_stack_trace(NULL);
656 	exit(-1);
657 }
658 
659 /**
660  * Prints the [format, ...] error message using the configured logging severity
661  * of the @id incidence.
662  */
663 int
incidence(enum incidence_id id,const char * format,...)664 incidence(enum incidence_id id, const char *format, ...)
665 {
666 	enum incidence_action action;
667 
668 	action = incidence_get_action(id);
669 	switch (action) {
670 	case INAC_IGNORE:
671 		return 0;
672 	case INAC_WARN:
673 		PR_SIMPLE(LOG_WARNING, val_config);
674 		return 0;
675 	case INAC_ERROR:
676 		PR_SIMPLE(LOG_ERR, val_config);
677 		return -EINVAL;
678 	}
679 
680 	pr_crit("Unknown incidence action: %u", action);
681 }
682