1    	/*
2    	 * Copyright (C) 2011,2016 Red Hat, Inc.
3    	 *
4    	 * All rights reserved.
5    	 *
6    	 * Author: Angus Salkeld <asalkeld@redhat.com>
7    	 *
8    	 * libqb is free software: you can redistribute it and/or modify
9    	 * it under the terms of the GNU Lesser General Public License as published by
10   	 * the Free Software Foundation, either version 2.1 of the License, or
11   	 * (at your option) any later version.
12   	 *
13   	 * libqb is distributed in the hope that it will be useful,
14   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   	 * GNU Lesser General Public License for more details.
17   	 *
18   	 * You should have received a copy of the GNU Lesser General Public License
19   	 * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
20   	 */
21   	#include "os_base.h"
22   	#include <ctype.h>
23   	
24   	#include <qb/qbdefs.h>
25   	#include "log_int.h"
26   	
27   	static qb_log_tags_stringify_fn _user_tags_stringify_fn;
28   	
29   	/*
30   	 * syslog prioritynames, facility names to value mapping
31   	 * Some C libraries build this in to their headers, but it is non-portable
32   	 * so logsys supplies its own version.
33   	 */
34   	struct syslog_names {
35   		const char *c_name;
36   		int32_t c_val;
37   	};
38   	
39   	static struct syslog_names prioritynames[] = {
40   		{"emerg", LOG_EMERG},
41   		{"alert", LOG_ALERT},
42   		{"crit", LOG_CRIT},
43   		{"error", LOG_ERR},
44   		{"warning", LOG_WARNING},
45   		{"notice", LOG_NOTICE},
46   		{"info", LOG_INFO},
47   		{"debug", LOG_DEBUG},
48   		{"trace", LOG_TRACE},
49   		{NULL, -1}
50   	};
51   	
52   	static struct syslog_names facilitynames[] = {
53   		{"auth", LOG_AUTH},
54   	#if defined(LOG_AUTHPRIV)
55   		{"authpriv", LOG_AUTHPRIV},
56   	#endif
57   		{"cron", LOG_CRON},
58   		{"daemon", LOG_DAEMON},
59   	#if defined(LOG_FTP)
60   		{"ftp", LOG_FTP},
61   	#endif
62   		{"kern", LOG_KERN},
63   		{"lpr", LOG_LPR},
64   		{"mail", LOG_MAIL},
65   		{"news", LOG_NEWS},
66   		{"syslog", LOG_SYSLOG},
67   		{"user", LOG_USER},
68   		{"uucp", LOG_UUCP},
69   		{"local0", LOG_LOCAL0},
70   		{"local1", LOG_LOCAL1},
71   		{"local2", LOG_LOCAL2},
72   		{"local3", LOG_LOCAL3},
73   		{"local4", LOG_LOCAL4},
74   		{"local5", LOG_LOCAL5},
75   		{"local6", LOG_LOCAL6},
76   		{"local7", LOG_LOCAL7},
77   		{NULL, -1}
78   	};
79   	
80   	static const char log_month_name[][4] = {
81   		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
82   		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
83   	};
84   	
85   	static pthread_rwlock_t _formatlock;
86   	
87   	void
88   	qb_log_format_init(void)
89   	{
90   		int32_t l;
91   		struct qb_log_target *t;
92   		enum qb_log_target_slot i;
93   	
94   		l = pthread_rwlock_init(&_formatlock, NULL);
95   		assert(l == 0);
96   	
97   		for (i = QB_LOG_TARGET_START; i < QB_LOG_TARGET_MAX; i++) {
98   			t = qb_log_target_get(i);
99   			t->format = strdup("[%p] %b");
100  		}
101  	}
102  	
103  	void
104  	qb_log_format_fini(void)
105  	{
106  		struct qb_log_target *t;
107  		enum qb_log_target_slot i;
108  	
109  		pthread_rwlock_destroy(&_formatlock);
110  	
111  		for (i = QB_LOG_TARGET_START; i < QB_LOG_TARGET_MAX; i++) {
112  			t = qb_log_target_get(i);
113  			free(t->format);
114  		}
115  	}
116  	
117  	void
118  	qb_log_format_set(int32_t target, const char *format)
119  	{
120  		char modified_format[256];
121  		struct qb_log_target *t = qb_log_target_get(target);
122  	
123  		pthread_rwlock_wrlock(&_formatlock);
124  	
125  		free(t->format);
126  	
127  		if (format) {
128  			qb_log_target_format_static(target, format, modified_format);
129  			t->format = strdup(modified_format);
130  		} else {
131  			t->format = strdup("[%p] %b");
132  		}
133  		assert(t->format != NULL);
134  	
135  		pthread_rwlock_unlock(&_formatlock);
136  	}
137  	
138  	/* Convert string "auth" to equivalent number "LOG_AUTH" etc. */
139  	int32_t
140  	qb_log_facility2int(const char *fname)
141  	{
142  		int32_t i;
143  	
144  		if (fname == NULL) {
145  			return -EINVAL;
146  		}
147  	
148  		for (i = 0; facilitynames[i].c_name != NULL; i++) {
149  			if (strcmp(fname, facilitynames[i].c_name) == 0) {
150  				return facilitynames[i].c_val;
151  			}
152  		}
153  		return -EINVAL;
154  	}
155  	
156  	/* Convert number "LOG_AUTH" to equivalent string "auth" etc. */
157  	const char *
158  	qb_log_facility2str(int32_t fnum)
159  	{
160  		int32_t i;
161  	
162  		for (i = 0; facilitynames[i].c_name != NULL; i++) {
163  			if (facilitynames[i].c_val == fnum) {
164  				return facilitynames[i].c_name;
165  			}
166  		}
167  		return NULL;
168  	}
169  	
170  	const char *
171  	qb_log_priority2str(uint8_t priority)
172  	{
173  		if (priority > LOG_TRACE) {
174  			return prioritynames[LOG_TRACE].c_name;
175  		}
176  		return prioritynames[priority].c_name;
177  	}
178  	
179  	void
180  	qb_log_tags_stringify_fn_set(qb_log_tags_stringify_fn fn)
181  	{
182  		_user_tags_stringify_fn = fn;
183  	}
184  	
185  	static int
186  	_strcpy_cutoff(char *dest, const char *src, size_t cutoff, int ralign,
187  		       size_t buf_len)
188  	{
189  		size_t len = strlen(src);
190  		if (buf_len <= 1) {
191  			if (buf_len == 0)
192  				dest[0] = 0;
193  			return 0;
194  		}
195  	
196  		if (cutoff == 0) {
197  			cutoff = len;
198  		}
199  	
200  		cutoff = QB_MIN(cutoff, buf_len - 1);
201  		len = QB_MIN(len, cutoff);
202  		if (ralign) {
203  			memset(dest, ' ', cutoff - len);
204  			memcpy(dest + cutoff - len, src, len);
205  		} else {
206  			memcpy(dest, src, len);
207  			memset(dest + len, ' ', cutoff - len);
208  		}
209  	
210  		dest[cutoff] = '\0';
211  	
212  		return cutoff;
213  	}
214  	
215  	/*
216  	 * This function will do static formatting (for things that don't
217  	 * change on each log message).
218  	 *
219  	 * %P PID
220  	 * %N name passed into qb_log_init
221  	 * %H hostname
222  	 *
223  	 * any number between % and character specify field length to pad or chop
224  	 */
225  	void
226  	qb_log_target_format_static(int32_t target, const char * format,
227  				    char *output_buffer)
228  	{
229  		char tmp_buf[255];
230  		unsigned int format_buffer_idx = 0;
231  		unsigned int output_buffer_idx = 0;
232  		size_t cutoff;
233  		uint32_t len;
234  		int ralign;
235  		int c;
236  		struct qb_log_target *t = qb_log_target_get(target);
237  	
238  		if (format == NULL) {
239  			return;
240  		}
241  	
242  		while ((c = format[format_buffer_idx])) {
243  			cutoff = 0;
244  			ralign = QB_FALSE;
245  			if (c != '%') {
246  				output_buffer[output_buffer_idx++] = c;
247  				format_buffer_idx++;
248  			} else {
249  				const char *p;
250  				unsigned int percent_buffer_idx = format_buffer_idx;
251  	
252  				format_buffer_idx += 1;
253  				if (format[format_buffer_idx] == '-') {
254  					ralign = QB_TRUE;
255  					format_buffer_idx += 1;
256  				}
257  	
258  				if (isdigit(format[format_buffer_idx])) {
259  					cutoff = atoi(&format[format_buffer_idx]);
260  				}
261  				while (isdigit(format[format_buffer_idx])) {
262  					format_buffer_idx += 1;
263  				}
264  	
265  				switch (format[format_buffer_idx]) {
266  				case 'P':
267  					snprintf(tmp_buf, 30, "%d", getpid());
268  					p = tmp_buf;
269  					break;
270  	
271  				case 'N':
272  					p = t->name;
273  					break;
274  	
275  				case 'H':
276  					if (gethostname(tmp_buf, sizeof(tmp_buf)) == 0) {
277  						tmp_buf[sizeof(tmp_buf) - 1] = '\0';
278  					} else {
279  						(void)strlcpy(tmp_buf, "localhost",
280  							      sizeof(tmp_buf));
281  					}
282  					p = tmp_buf;
283  					break;
284  	
285  				default:
286  					p = &format[percent_buffer_idx];
287  					cutoff = (format_buffer_idx - percent_buffer_idx + 1);
288  					ralign = QB_FALSE;
289  					break;
290  				}
291  				len = _strcpy_cutoff(output_buffer + output_buffer_idx,
292  						     p, cutoff, ralign,
293  						     (t->max_line_length -
294  						      output_buffer_idx));
295  				output_buffer_idx += len;
296  				format_buffer_idx += 1;
297  			}
298  			if (output_buffer_idx >= t->max_line_length - 1) {
299  				break;
300  			}
301  		}
302  	
303  		output_buffer[output_buffer_idx] = '\0';
304  	}
305  	
306  	/*
307  	 * %n FUNCTION NAME
308  	 * %f FILENAME
309  	 * %l FILELINE
310  	 * %p PRIORITY
311  	 * %t TIMESTAMP
312  	 * %T TIMESTAMP with milliseconds
313  	 * %b BUFFER
314  	 * %g SUBSYSTEM
315  	 *
316  	 * any number between % and character specify field length to pad or chop
317  	 */
318  	void
319  	qb_log_target_format(int32_t target,
320  			     struct qb_log_callsite *cs,
321  			     struct timespec *the_ts,
322  			     const char *formatted_message, char *output_buffer)
323  	{
324  		char tmp_buf[128];
325  		struct tm tm_res;
326  		time_t time_sec;
327  		unsigned int format_buffer_idx = 0;
328  		unsigned int output_buffer_idx = 0;
329  		size_t cutoff;
330  		uint32_t len;
331  		int ralign;
332  		int c;
333  		struct qb_log_target *t = qb_log_target_get(target);
334  	
335  		pthread_rwlock_rdlock(&_formatlock);
336  		if (t->format == NULL) {
337  			pthread_rwlock_unlock(&_formatlock);
338  			return;
339  		}
340  	
341  		while ((c = t->format[format_buffer_idx])) {
342  			cutoff = 0;
343  			ralign = QB_FALSE;
344  			if (c != '%') {
345  				output_buffer[output_buffer_idx++] = c;
346  				format_buffer_idx++;
347  			} else {
348  				const char *p;
349  	
350  				format_buffer_idx += 1;
351  				if (t->format[format_buffer_idx] == '-') {
352  					ralign = QB_TRUE;
353  					format_buffer_idx += 1;
354  				}
355  	
356  				if (isdigit(t->format[format_buffer_idx])) {
357  					cutoff = atoi(&t->format[format_buffer_idx]);
358  				}
359  				while (isdigit(t->format[format_buffer_idx])) {
360  					format_buffer_idx += 1;
361  				}
362  	
363  				switch (t->format[format_buffer_idx]) {
364  				case 'g':
365  					if (_user_tags_stringify_fn) {
366  						p = _user_tags_stringify_fn(cs->tags);
367  					} else {
368  						p = "";
369  					}
370  					break;
371  	
372  				case 'n':
373  					p = cs->function;
374  					break;
375  	
376  				case 'f':
377  	#ifdef BUILDING_IN_PLACE
378  					p = cs->filename;
379  	#else
380  					p = strrchr(cs->filename, '/');
381  					if (p == NULL) {
382  						p = cs->filename;
383  					} else {
384  						p++; /* move past the "/" */
385  					}
386  	#endif /* BUILDING_IN_PLACE */
387  					break;
388  	
389  				case 'l':
390  	#ifndef S_SPLINT_S
391  					snprintf(tmp_buf, 30, "%" PRIu32, cs->lineno);
392  	#endif /* S_SPLINT_S */
393  					p = tmp_buf;
394  					break;
395  	
396  				case 't':
397  					time_sec = the_ts->tv_sec;
398  					(void)localtime_r(&time_sec, &tm_res);
399  					snprintf(tmp_buf, TIME_STRING_SIZE,
400  						 "%s %02d %02d:%02d:%02d",
401  						 log_month_name[tm_res.tm_mon],
402  						 tm_res.tm_mday, tm_res.tm_hour,
403  						 tm_res.tm_min, tm_res.tm_sec);
404  					p = tmp_buf;
405  					break;
406  	
407  				case 'T':
408  					time_sec = the_ts->tv_sec;
409  					(void)localtime_r(&time_sec, &tm_res);
410  					snprintf(tmp_buf, TIME_STRING_SIZE,
411  						 "%s %02d %02d:%02d:%02d.%03llu",
412  						 log_month_name[tm_res.tm_mon],
413  						 tm_res.tm_mday, tm_res.tm_hour,
414  						 tm_res.tm_min, tm_res.tm_sec,
415  						 the_ts->tv_nsec/QB_TIME_NS_IN_MSEC);
416  					p = tmp_buf;
417  					break;
418  	
419  				case 'b':
420  					p = formatted_message;
421  					break;
422  	
423  				case 'p':
424  					if (cs->priority > LOG_TRACE) {
425  						p = prioritynames[LOG_TRACE].c_name;
426  					} else {
427  						p = prioritynames[cs->priority].c_name;
428  					}
429  					break;
430  	
431  				default:
432  					p = "";
433  					break;
434  				}
435  				len = _strcpy_cutoff(output_buffer + output_buffer_idx,
436  						     p, cutoff, ralign,
437  						     (t->max_line_length -
438  						      output_buffer_idx));
439  				output_buffer_idx += len;
440  				format_buffer_idx += 1;
441  			}
442  			if (output_buffer_idx >= t->max_line_length - 1) {
443  				break;
444  			}
445  		}
446  		pthread_rwlock_unlock(&_formatlock);
447  	
448  		if (output_buffer[output_buffer_idx - 1] == '\n') {
449  			output_buffer[output_buffer_idx - 1] = '\0';
450  		} else {
451  			output_buffer[output_buffer_idx] = '\0';
452  		}
453  	
454  		/* Indicate truncation */
455  		if (t->ellipsis && output_buffer_idx >= t->max_line_length-1) {
456  			output_buffer[output_buffer_idx-3] = '.';
457  			output_buffer[output_buffer_idx-2] = '.';
458  			output_buffer[output_buffer_idx-1] = '.';
459  		}
460  	}
461  	
462  	
463  	/*
464  	 * These wrappers around strl* functions just return the
465  	 * number of characters written, not the number of characters
466  	 * requested to be written.
467  	 */
468  	static size_t
469  	my_strlcpy(char *dest, const char * src, size_t maxlen)
470  	{
(1) Event taint_sink_lv_call: Passing tainted expression "maxlen" to taint sink "strlcpy".
471  		size_t rc = strlcpy(dest, src, maxlen);
472  		/* maxlen includes NUL, so -1 */
473  		return QB_MIN(rc, maxlen-1);
474  	}
475  	
476  	static size_t
477  	my_strlcat(char *dest, const char * src, size_t maxlen)
478  	{
479  		size_t rc = strlcat(dest, src, maxlen);
480  		return QB_MIN(rc, maxlen-1);
481  	}
482  	
483  	size_t
484  	qb_vsnprintf_serialize(char *serialize, size_t max_len,
485  			       const char *fmt, va_list ap)
486  	{
487  		char *format;
488  		char *p;
489  		char *qb_xc;
490  		int type_long = QB_FALSE;
491  		int type_longlong = QB_FALSE;
492  		size_t sformat_length = 0;
493  		int sformat_precision = QB_FALSE;
494  		uint32_t location = my_strlcpy(serialize, fmt, max_len) + 1;
495  	
496  		/* Assume serialized output always wants extended information
497  		 * (@todo: add variant of this function that takes argument for whether
498  		 * to print extended information, and make this a macro with that
499  		 * argument set to QB_TRUE, so callers can honor extended setting)
500  		 */
(1) Event cond_true: Condition "(qb_xc = strchr(serialize, 7)) != NULL", taking true branch.
501  		if ((qb_xc = strchr(serialize, QB_XC)) != NULL) {
(2) Event cond_true: Condition "qb_xc[1]", taking true branch.
502  			*qb_xc = *(qb_xc + 1)? '|' : '\0';
503  		}
504  	
505  		format = (char *)fmt;
(39) Event loop_begin: Jumped back to beginning of loop.
(53) Event loop_begin: Jumped back to beginning of loop.
(73) Event loop_begin: Jumped back to beginning of loop.
(88) Event loop_begin: Jumped back to beginning of loop.
(103) Event loop_begin: Jumped back to beginning of loop.
(113) Event loop_begin: Jumped back to beginning of loop.
(133) Event loop_begin: Jumped back to beginning of loop.
(147) Event loop_begin: Jumped back to beginning of loop.
506  		for (;;) {
507  			type_long = QB_FALSE;
508  			type_longlong = QB_FALSE;
509  			p = strchrnul((const char *)format, '%');
(3) Event cond_false: Condition "*p == 0", taking false branch.
(40) Event cond_false: Condition "*p == 0", taking false branch.
(54) Event cond_false: Condition "*p == 0", taking false branch.
(74) Event cond_false: Condition "*p == 0", taking false branch.
(89) Event cond_false: Condition "*p == 0", taking false branch.
(104) Event cond_false: Condition "*p == 0", taking false branch.
(114) Event cond_false: Condition "*p == 0", taking false branch.
(134) Event cond_false: Condition "*p == 0", taking false branch.
(148) Event cond_false: Condition "*p == 0", taking false branch.
510  			if (*p == '\0') {
511  				break;
(4) Event if_end: End of if statement.
(41) Event if_end: End of if statement.
(55) Event if_end: End of if statement.
(75) Event if_end: End of if statement.
(90) Event if_end: End of if statement.
(105) Event if_end: End of if statement.
(115) Event if_end: End of if statement.
(135) Event if_end: End of if statement.
(149) Event if_end: End of if statement.
512  			}
513  			format = p + 1;
(8) Event label: Reached label "reprocess".
(13) Event label: Reached label "reprocess".
(19) Event label: Reached label "reprocess".
(24) Event label: Reached label "reprocess".
(30) Event label: Reached label "reprocess".
(62) Event label: Reached label "reprocess".
(121) Event label: Reached label "reprocess".
514  	reprocess:
(5) Event switch: Switch case value "'.'".
(9) Event switch: Switch case value "'0'".
(14) Event switch: Switch case value "'*'".
(20) Event switch: Switch case value "'l'".
(25) Event switch: Switch case value "'l'".
(31) Event switch: Switch case value "'d'".
(42) Event switch: Switch case value "'s'".
(56) Event switch: Switch case value "'*'".
(63) Event switch: Switch case value "'s'".
(76) Event switch: Switch case value "'s'".
(91) Event switch: Switch case value "'s'".
(106) Event switch: Switch case value "'%'".
(116) Event switch: Switch case value "'0'".
(122) Event switch: Switch case value "'s'".
(136) Event switch: Switch case value "'s'".
(150) Event switch: Switch case value "'s'".
515  			switch (format[0]) {
516  			case '#': /* alternate form conversion, ignore */
517  			case '-': /* left adjust, ignore */
518  			case ' ': /* a space, ignore */
519  			case '+': /* a sign should be used, ignore */
520  			case '\'': /* group in thousands, ignore */
521  			case 'I': /* glibc-ism locale alternative, ignore */
522  	                    format++;
523  	                    goto reprocess;
(6) Event switch_case: Reached case "'.'".
524  			case '.': /* precision, ignore */
525  	                    format++;
526  	                    sformat_precision = QB_TRUE;
(7) Event goto: Jumping to label "reprocess".
527  	                    goto reprocess;
(10) Event switch_case: Reached case "'0'".
(117) Event switch_case: Reached case "'0'".
528  			case '0': /* field width, ignore */
529  			case '1': /* field width, ignore */
530  			case '2': /* field width, ignore */
531  			case '3': /* field width, ignore */
532  			case '4': /* field width, ignore */
533  			case '5': /* field width, ignore */
534  			case '6': /* field width, ignore */
535  			case '7': /* field width, ignore */
536  			case '8': /* field width, ignore */
537  			case '9': /* field width, ignore */
(11) Event cond_true: Condition "sformat_precision", taking true branch.
(118) Event cond_false: Condition "sformat_precision", taking false branch.
538  	                        if (sformat_precision) {
539  	                            sformat_length *= 10;
540  	                            sformat_length += (format[0] - '0');
(119) Event if_end: End of if statement.
541  	                        }
542  				format++;
(12) Event goto: Jumping to label "reprocess".
(120) Event goto: Jumping to label "reprocess".
543  				goto reprocess;
(15) Event switch_case: Reached case "'*'".
(57) Event switch_case: Reached case "'*'".
544  			case '*': /* variable field width, save */ {
545  				int arg_int = va_arg(ap, int);
(16) Event cond_false: Condition "location + 4UL /* sizeof (int) */ > max_len", taking false branch.
(58) Event cond_false: Condition "location + 4UL /* sizeof (int) */ > max_len", taking false branch.
546  				if (location + sizeof (int) > max_len) {
547  					return max_len;
(17) Event if_end: End of if statement.
(59) Event if_end: End of if statement.
548  				}
549  				memcpy(&serialize[location], &arg_int, sizeof (int));
(60) Event overflow: The expression "location += 4UL" is deemed overflowed because at least one of its arguments has overflowed.
Also see events: [tainted_data_return][overflow][overflow][overflow][overflow][overflow][overflow][overflow][overflow_sink]
550  				location += sizeof(int);
551  				format++;
(18) Event goto: Jumping to label "reprocess".
(61) Event goto: Jumping to label "reprocess".
552  				goto reprocess;
553  			}
(21) Event switch_case: Reached case "'l'".
(26) Event switch_case: Reached case "'l'".
554  			case 'l':
555  				format++;
556  				type_long = QB_TRUE;
(22) Event cond_true: Condition "*format == 'l'", taking true branch.
(27) Event cond_false: Condition "*format == 'l'", taking false branch.
557  				if (*format == 'l') {
558  					type_long = QB_FALSE;
559  					type_longlong = QB_TRUE;
560  					format++;
(28) Event if_end: End of if statement.
561  				}
(23) Event goto: Jumping to label "reprocess".
(29) Event goto: Jumping to label "reprocess".
562  				goto reprocess;
563  			case 'z':
564  				format++;
565  				if (sizeof(size_t) == sizeof(long long)) {
566  					type_longlong = QB_TRUE;
567  				} else {
568  					type_long = QB_TRUE;
569  				}
570  				goto reprocess;
571  			case 't':
572  				format++;
573  				if (sizeof(ptrdiff_t) == sizeof(long long)) {
574  					type_longlong = QB_TRUE;
575  				} else {
576  					type_long = QB_TRUE;
577  				}
578  				goto reprocess;
579  			case 'j':
580  				format++;
581  				if (sizeof(intmax_t) == sizeof(long long)) {
582  					type_longlong = QB_TRUE;
583  				} else {
584  					type_long = QB_TRUE;
585  				}
586  				goto reprocess;
(32) Event switch_case: Reached case "'d'".
587  			case 'd': /* int argument */
588  			case 'i': /* int argument */
589  			case 'o': /* unsigned int argument */
590  			case 'u':
591  			case 'x':
592  			case 'X':
(33) Event cond_true: Condition "type_long", taking true branch.
593  				if (type_long) {
594  					long int arg_int;
595  	
(34) Event cond_false: Condition "location + 8UL /* sizeof (long) */ > max_len", taking false branch.
596  					if (location + sizeof (long int) > max_len) {
597  						return max_len;
(35) Event if_end: End of if statement.
598  					}
599  					arg_int = va_arg(ap, long int);
600  					memcpy(&serialize[location], &arg_int,
601  					       sizeof(long int));
602  					location += sizeof(long int);
603  					format++;
(36) Event break: Breaking from switch.
604  					break;
605  				} else if (type_longlong) {
606  					long long int arg_int;
607  	
608  					if (location + sizeof (long long int) > max_len) {
609  						return max_len;
610  					}
611  					arg_int = va_arg(ap, long long int);
612  					memcpy(&serialize[location], &arg_int,
613  					       sizeof(long long int));
614  					location += sizeof(long long int);
615  					format++;
616  					break;
617  				} else {
618  					int arg_int;
619  	
620  					if (location + sizeof (int) > max_len) {
621  						return max_len;
622  					}
623  					arg_int = va_arg(ap, int);
624  					memcpy(&serialize[location], &arg_int,
625  					       sizeof(int));
626  					location += sizeof(int);
627  					format++;
628  					break;
629  				}
630  			case 'e':
631  			case 'E':
632  			case 'f':
633  			case 'F':
634  			case 'g':
635  			case 'G':
636  			case 'a':
637  			case 'A':
638  				{
639  				double arg_double;
640  	
641  				if (location + sizeof (double) > max_len) {
642  					return max_len;
643  				}
644  				arg_double = va_arg(ap, double);
645  				memcpy (&serialize[location], &arg_double, sizeof (double));
646  				location += sizeof(double);
647  				format++;
648  				break;
649  				}
650  			case 'c':
651  				{
652  				int arg_int;
653  				unsigned char arg_char;
654  	
655  				if (location + sizeof (unsigned char) > max_len) {
656  					return max_len;
657  				}
658  				/* va_arg only takes fully promoted types */
659  				arg_int = va_arg(ap, unsigned int);
660  				arg_char = (unsigned char)arg_int;
661  				memcpy (&serialize[location], &arg_char, sizeof (unsigned char));
662  				location += sizeof(unsigned char);
663  				break;
664  				}
(43) Event switch_case: Reached case "'s'".
(64) Event switch_case: Reached case "'s'".
(77) Event switch_case: Reached case "'s'".
(92) Event switch_case: Reached case "'s'".
(123) Event switch_case: Reached case "'s'".
(137) Event switch_case: Reached case "'s'".
(151) Event switch_case: Reached case "'s'".
665  			case 's':
666  				{
667  				char *arg_string;
668  				arg_string = va_arg(ap, char *);
(44) Event cond_true: Condition "arg_string == NULL", taking true branch.
(65) Event cond_true: Condition "arg_string == NULL", taking true branch.
(78) Event cond_false: Condition "arg_string == NULL", taking false branch.
(93) Event cond_false: Condition "arg_string == NULL", taking false branch.
(124) Event cond_false: Condition "arg_string == NULL", taking false branch.
(138) Event cond_false: Condition "arg_string == NULL", taking false branch.
(152) Event cond_false: Condition "arg_string == NULL", taking false branch.
669  				if (arg_string == NULL) {
(45) Event cond_true: Condition "strlen("(null)") + 1 < max_len - location", taking true branch.
(46) Event tainted_data_return: Called function "my_strlcpy(&serialize[location], "(null)", ((strlen("(null)") + 1UL < max_len - location) ? strlen("(null)") + 1UL : (max_len - location)))", and a possible return value is known to be less than zero.
(47) Event overflow: The expression "location" is considered to have possibly overflowed.
(66) Event cond_true: Condition "strlen("(null)") + 1 < max_len - location", taking true branch.
(67) Event overflow: The expression "location += my_strlcpy(&serialize[location], "(null)", ((strlen("(null)") + 1UL < max_len - location) ? strlen("(null)") + 1UL : (max_len - location)))" is deemed underflowed because at least one of its arguments has underflowed.
Also see events: [overflow][overflow][overflow][overflow][overflow][overflow][overflow_sink]
670  					location += my_strlcpy(&serialize[location],
671  							   "(null)",
672  							   QB_MIN(strlen("(null)") + 1,
673  								  max_len - location));
(48) Event if_fallthrough: Falling through to end of if statement.
(68) Event if_fallthrough: Falling through to end of if statement.
(79) Event else_branch: Reached else branch.
(80) Event cond_true: Condition "sformat_length", taking true branch.
(94) Event else_branch: Reached else branch.
(95) Event cond_true: Condition "sformat_length", taking true branch.
(125) Event else_branch: Reached else branch.
(126) Event cond_false: Condition "sformat_length", taking false branch.
(139) Event else_branch: Reached else branch.
(140) Event cond_false: Condition "sformat_length", taking false branch.
(153) Event else_branch: Reached else branch.
(154) Event cond_false: Condition "sformat_length", taking false branch.
674  				} else if (sformat_length) {
(81) Event cond_true: Condition "sformat_length + 1 < max_len - location", taking true branch.
(82) Event overflow: The expression "location += my_strlcpy(&serialize[location], arg_string, ((sformat_length + 1UL < max_len - location) ? sformat_length + 1UL : (max_len - location)))" is deemed underflowed because at least one of its arguments has underflowed.
(96) Event cond_false: Condition "sformat_length + 1 < max_len - location", taking false branch.
(97) Event overflow: The expression "location += my_strlcpy(&serialize[location], arg_string, ((sformat_length + 1UL < max_len - location) ? sformat_length + 1UL : (max_len - location)))" is deemed underflowed because at least one of its arguments has underflowed.
Also see events: [tainted_data_return][overflow][overflow][overflow][overflow][overflow][overflow][overflow_sink]
675  					location += my_strlcpy(&serialize[location],
676  							   arg_string,
677  							   QB_MIN(sformat_length + 1,
678  							   (max_len - location)));
(83) Event if_fallthrough: Falling through to end of if statement.
(98) Event if_fallthrough: Falling through to end of if statement.
(127) Event else_branch: Reached else branch.
(141) Event else_branch: Reached else branch.
(155) Event else_branch: Reached else branch.
679  				} else {
(128) Event cond_true: Condition "strlen(arg_string) + 1 < max_len - location", taking true branch.
(129) Event overflow: The expression "location += my_strlcpy(&serialize[location], arg_string, ((strlen(arg_string) + 1UL < max_len - location) ? strlen(arg_string) + 1UL : (max_len - location)))" is deemed underflowed because at least one of its arguments has underflowed.
(142) Event cond_true: Condition "strlen(arg_string) + 1 < max_len - location", taking true branch.
(143) Event overflow: The expression "location += my_strlcpy(&serialize[location], arg_string, ((strlen(arg_string) + 1UL < max_len - location) ? strlen(arg_string) + 1UL : (max_len - location)))" is deemed underflowed because at least one of its arguments has underflowed.
(156) Event cond_false: Condition "strlen(arg_string) + 1 < max_len - location", taking false branch.
(157) Event overflow: The expression "max_len - location" is deemed underflowed because at least one of its arguments has underflowed.
(158) Event overflow_sink: "(strlen(arg_string) + 1UL < max_len - location) ? strlen(arg_string) + 1UL : (max_len - location)", which might have underflowed, is passed to "my_strlcpy(&serialize[location], arg_string, ((strlen(arg_string) + 1UL < max_len - location) ? strlen(arg_string) + 1UL : (max_len - location)))". [details]
Also see events: [tainted_data_return][overflow][overflow][overflow][overflow][overflow]
680  					location += my_strlcpy(&serialize[location],
681  							   arg_string,
682  							   QB_MIN(strlen(arg_string) + 1,
683  								  max_len - location));
(49) Event if_end: End of if statement.
(69) Event if_end: End of if statement.
(84) Event if_end: End of if statement.
(99) Event if_end: End of if statement.
684  				}
685  				location++;
(50) Event break: Breaking from switch.
(70) Event break: Breaking from switch.
(85) Event break: Breaking from switch.
(100) Event break: Breaking from switch.
(130) Event break: Breaking from switch.
(144) Event break: Breaking from switch.
686  				break;
687  				}
688  			case 'p':
689  				{
690  				ptrdiff_t arg_pointer = va_arg(ap, ptrdiff_t);
691  				if (location + sizeof (ptrdiff_t) > max_len) {
692  					return max_len;
693  				}
694  				memcpy(&serialize[location], &arg_pointer, sizeof(ptrdiff_t));
695  				location += sizeof(ptrdiff_t);
696  				break;
697  				}
(107) Event switch_case: Reached case "'%'".
698  			case '%':
(108) Event cond_false: Condition "location + 1 > max_len", taking false branch.
699  				if (location + 1 > max_len) {
700  					return max_len;
(109) Event if_end: End of if statement.
701  				}
702  				serialize[location++] = '%';
703  	                        sformat_length = 0;
704  	                        sformat_precision = QB_FALSE;
(110) Event break: Breaking from switch.
705  				break;
706  	
(37) Event switch_end: Reached end of switch.
(51) Event switch_end: Reached end of switch.
(71) Event switch_end: Reached end of switch.
(86) Event switch_end: Reached end of switch.
(101) Event switch_end: Reached end of switch.
(111) Event switch_end: Reached end of switch.
(131) Event switch_end: Reached end of switch.
(145) Event switch_end: Reached end of switch.
707  			}
(38) Event loop: Jumping back to the beginning of the loop.
(52) Event loop: Jumping back to the beginning of the loop.
(72) Event loop: Jumping back to the beginning of the loop.
(87) Event loop: Jumping back to the beginning of the loop.
(102) Event loop: Jumping back to the beginning of the loop.
(112) Event loop: Jumping back to the beginning of the loop.
(132) Event loop: Jumping back to the beginning of the loop.
(146) Event loop: Jumping back to the beginning of the loop.
708  		}
709  		return (location);
710  	}
711  	
712  	#define MINI_FORMAT_STR_LEN 20
713  	
714  	size_t
715  	qb_vsnprintf_deserialize(char *string, size_t str_len, const char *buf)
716  	{
717  		char *p;
718  		char *format;
719  		char fmt[MINI_FORMAT_STR_LEN];
720  		int fmt_pos;
721  	
722  		uint32_t location = 0;
723  		uint32_t data_pos = strlen(buf) + 1;
724  		int type_long = QB_FALSE;
725  		int type_longlong = QB_FALSE;
726  		int len;
727  	
728  		string[0] = '\0';
729  		format = (char *)buf;
730  		for (;;) {
731  			type_long = QB_FALSE;
732  			type_longlong = QB_FALSE;
733  			p = strchrnul((const char *)format, '%');
734  			if (*p == '\0') {
735  				return my_strlcat(string, format, str_len) + 1;
736  			}
737  			/* copy from current to the next % */
738  			len = p - format;
739  			memcpy(&string[location], format, len);
740  			location += len;
741  			format = p;
742  	
743  			/* start building up the format for snprintf */
744  			fmt_pos = 0;
745  			fmt[fmt_pos++] = *format;
746  			format++;
747  	reprocess:
748  			switch (format[0]) {
749  			case '#': /* alternate form conversion, ignore */
750  			case '-': /* left adjust, ignore */
751  			case ' ': /* a space, ignore */
752  			case '+': /* a sign should be used, ignore */
753  			case '\'': /* group in thousands, ignore */
754  			case 'I': /* glibc-ism locale alternative, ignore */
755  			case '.': /* precision, ignore */
756  			case '0': /* field width, ignore */
757  			case '1': /* field width, ignore */
758  			case '2': /* field width, ignore */
759  			case '3': /* field width, ignore */
760  			case '4': /* field width, ignore */
761  			case '5': /* field width, ignore */
762  			case '6': /* field width, ignore */
763  			case '7': /* field width, ignore */
764  			case '8': /* field width, ignore */
765  			case '9': /* field width, ignore */
766  				fmt[fmt_pos++] = *format;
767  				format++;
768  				goto reprocess;
769  	
770  			case '*': {
771  				int arg_int;
772  				memcpy(&arg_int, &buf[data_pos], sizeof(int));
773  				data_pos += sizeof(int);
774  				fmt_pos += snprintf(&fmt[fmt_pos],
775  						   MINI_FORMAT_STR_LEN - fmt_pos,
776  						   "%d", arg_int);
777  				format++;
778  				goto reprocess;
779  			}
780  			case 'l':
781  				fmt[fmt_pos++] = *format;
782  				format++;
783  				type_long = QB_TRUE;
784  				if (*format == 'l') {
785  					type_long = QB_FALSE;
786  					type_longlong = QB_TRUE;
787  				}
788  				goto reprocess;
789  			case 'z':
790  				fmt[fmt_pos++] = *format;
791  				format++;
792  				if (sizeof(size_t) == sizeof(long long)) {
793  					type_long = QB_FALSE;
794  					type_longlong = QB_TRUE;
795  				} else {
796  					type_longlong = QB_FALSE;
797  					type_long = QB_TRUE;
798  				}
799  				goto reprocess;
800  			case 't':
801  				fmt[fmt_pos++] = *format;
802  				format++;
803  				if (sizeof(ptrdiff_t) == sizeof(long long)) {
804  					type_longlong = QB_TRUE;
805  				} else {
806  					type_long = QB_TRUE;
807  				}
808  				goto reprocess;
809  			case 'j':
810  				fmt[fmt_pos++] = *format;
811  				format++;
812  				if (sizeof(intmax_t) == sizeof(long long)) {
813  					type_longlong = QB_TRUE;
814  				} else {
815  					type_long = QB_TRUE;
816  				}
817  				goto reprocess;
818  			case 'd': /* int argument */
819  			case 'i': /* int argument */
820  			case 'o': /* unsigned int argument */
821  			case 'u':
822  			case 'x':
823  			case 'X':
824  				if (type_long) {
825  					long int arg_int;
826  	
827  					fmt[fmt_pos++] = *format;
828  					fmt[fmt_pos++] = '\0';
829  					memcpy(&arg_int, &buf[data_pos], sizeof(long int));
830  					location += snprintf(&string[location],
831  							     str_len - location,
832  							     fmt, arg_int);
833  					data_pos += sizeof(long int);
834  					format++;
835  					break;
836  				} else if (type_longlong) {
837  					long long int arg_int;
838  	
839  					fmt[fmt_pos++] = *format;
840  					fmt[fmt_pos++] = '\0';
841  					memcpy(&arg_int, &buf[data_pos], sizeof(long long int));
842  					location += snprintf(&string[location],
843  							     str_len - location,
844  							     fmt, arg_int);
845  					data_pos += sizeof(long long int);
846  					format++;
847  					break;
848  				} else {
849  					int arg_int;
850  	
851  					fmt[fmt_pos++] = *format;
852  					fmt[fmt_pos++] = '\0';
853  					memcpy(&arg_int, &buf[data_pos], sizeof(int));
854  					location += snprintf(&string[location],
855  							     str_len - location,
856  							     fmt, arg_int);
857  					data_pos += sizeof(int);
858  					format++;
859  					break;
860  				}
861  			case 'e':
862  			case 'E':
863  			case 'f':
864  			case 'F':
865  			case 'g':
866  			case 'G':
867  			case 'a':
868  			case 'A':
869  				{
870  				double arg_double;
871  	
872  				fmt[fmt_pos++] = *format;
873  				fmt[fmt_pos++] = '\0';
874  				memcpy(&arg_double, &buf[data_pos], sizeof(double));
875  				location += snprintf(&string[location],
876  						     str_len - location,
877  						     fmt, arg_double);
878  				data_pos += sizeof(double);
879  				format++;
880  				break;
881  				}
882  			case 'c':
883  				{
884  				unsigned char *arg_char;
885  	
886  				fmt[fmt_pos++] = *format;
887  				fmt[fmt_pos++] = '\0';
888  				arg_char = (unsigned char*)&buf[data_pos];
889  				location += snprintf(&string[location],
890  						     str_len - location,
891  						     fmt, *arg_char);
892  				data_pos += sizeof(unsigned char);
893  				format++;
894  				break;
895  				}
896  			case 's':
897  				{
898  				fmt[fmt_pos++] = *format;
899  				fmt[fmt_pos++] = '\0';
900  				len = snprintf(&string[location],
901  					       str_len - location,
902  					       fmt, &buf[data_pos]);
903  				location += len;
904  				/* don't use len as there might be a len modifier */
905  				data_pos += strlen(&buf[data_pos]) + 1;
906  				format++;
907  				break;
908  				}
909  			case 'p':
910  				{
911  				ptrdiff_t pt;
912  				memcpy(&pt, &buf[data_pos],
913  				       sizeof(ptrdiff_t));
914  				fmt[fmt_pos++] = *format;
915  				fmt[fmt_pos++] = '\0';
916  				location += snprintf(&string[location],
917  						     str_len - location,
918  						     fmt, pt);
919  				data_pos += sizeof(void*);
920  				format++;
921  				break;
922  				}
923  			case '%':
924  				string[location++] = '%';
925  				format++;
926  				break;
927  	
928  			}
929  		}
930  		return location;
931  	}
932  	
933