xref: /xnu-8792.41.9/bsd/kern/kern_asl.c (revision 5c2921b07a2480ab43ec66f5b9e41cb872bc554f)
1 /*
2  * Copyright (c) 2020 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <sys/errno.h>
30 #include <sys/types.h>
31 #include <sys/malloc.h>
32 #include <sys/buf.h>
33 #include <sys/time.h>
34 #include <sys/kauth.h>
35 #include <sys/mount.h>
36 #include <sys/vnode.h>
37 #include <sys/syslog.h>
38 #include <sys/vnode_internal.h>
39 #include <sys/fslog.h>
40 #include <sys/mount_internal.h>
41 #include <sys/kasl.h>
42 
43 #include <dev/random/randomdev.h>
44 
45 #include <uuid/uuid.h>
46 
47 #include <stdarg.h>
48 
49 /* String to append as format modifier for each key-value pair */
50 #define KASL_KEYVAL_FMT "[%s %s] "
51 #define KASL_KEYVAL_FMT_LEN     (sizeof(KASL_KEYVAL_FMT) - 1)
52 
53 #define KASL_NEWLINE_CHAR       "\n"
54 #define KASL_NEWLINE_CHAR_LEN   (sizeof(KASL_NEWLINE_CHAR) - 1)
55 
56 /* Length of entire ASL message in 10 characters.  Kernel defaults to zero */
57 #define KASL_ASL_MSG_LEN        "         0"
58 
59 /* Length of default format string to be used by printf */
60 #define MAX_FMT_LEN             256
61 
62 
63 /* Function to print input values as key-value pairs in format
64  * identifiable by Apple system log (ASL) facility. All key-value pairs
65  * are assumed to be pointer to strings and are provided using va_list
66  * argument which is a list of varying number of arguments created by the
67  * caller of this function.
68  *
69  * Parameters -
70  *      level     - Priority level for this ASL message
71  *	facility  - Facility for this ASL message.
72  *	num_pairs - Number of key-value pairs provided by vargs argument.
73  *	vargs     - List of key-value pairs.
74  *
75  * Returns -
76  *	zero	- On success, when it prints all key-values pairs provided.
77  *	E2BIG	- When it cannot print all key-value pairs provided and had
78  *		  to truncate the output.
79  */
80 static int
kern_asl_msg_va(int level,const char * facility,size_t num_pairs,va_list vargs)81 kern_asl_msg_va(int level, const char *facility, size_t num_pairs, va_list vargs)
82 {
83 	int err = 0;
84 	char fmt[MAX_FMT_LEN];  /* Format string to use with vaddlog */
85 	size_t calc_pairs = 0;
86 	size_t len;
87 
88 	/* Mask extra bits, if any, from priority level */
89 	level = LOG_PRI(level);
90 
91 	/* Create the first part of format string consisting of ASL
92 	 * message length, level, and facility.
93 	 */
94 	if (facility) {
95 		snprintf(fmt, MAX_FMT_LEN, "%s [%s %d] [%s %s] ",
96 		    KASL_ASL_MSG_LEN,
97 		    KASL_KEY_LEVEL, level,
98 		    KASL_KEY_FACILITY, facility);
99 	} else {
100 		snprintf(fmt, MAX_FMT_LEN, "%s [%s %d] ",
101 		    KASL_ASL_MSG_LEN,
102 		    KASL_KEY_LEVEL, level);
103 	}
104 
105 	/* Determine the number of key-value format string [%s %s] that
106 	 * should be added in format string for every key-value pair provided
107 	 * in va_list.  Calculate maximum number of format string that can be
108 	 * accommodated in the remaining format buffer (after saving space
109 	 * for newline character).  If the caller provided pairs in va_list
110 	 * is more than calculated pairs, truncate extra pairs.
111 	 */
112 	len = MAX_FMT_LEN - strlen(fmt) - KASL_NEWLINE_CHAR_LEN - 1;
113 	calc_pairs = len / KASL_KEYVAL_FMT_LEN;
114 	if (num_pairs <= calc_pairs) {
115 		calc_pairs = num_pairs;
116 	} else {
117 		err = E2BIG;
118 	}
119 
120 	/* Append format strings [%s %s] for the key-value pairs in vargs */
121 	len = MAX_FMT_LEN - KASL_NEWLINE_CHAR_LEN;
122 	for (size_t i = 0; i < calc_pairs; i++) {
123 		(void) strlcat(fmt, KASL_KEYVAL_FMT, len);
124 	}
125 
126 	/* Append newline */
127 	(void) strlcat(fmt, KASL_NEWLINE_CHAR, MAX_FMT_LEN);
128 
129 #pragma clang diagnostic push
130 #pragma clang diagnostic ignored "-Wformat-nonliteral"
131 	/* Print the key-value pairs in ASL format */
132 	vaddlog(fmt, vargs);
133 #pragma clang diagnostic pop
134 
135 	/*
136 	 * Note: can't use os_log_with_args() here because 'fmt' is
137 	 * constructed on the stack i.e. doesn't come from a text
138 	 * section. More importantly, the newer logging system
139 	 * doesn't grok ASL either.
140 	 */
141 
142 	return err;
143 }
144 
145 int
kern_asl_msg(int level,const char * facility,size_t num_pairs,...)146 kern_asl_msg(int level, const char *facility, size_t num_pairs, ...)
147 {
148 	int err;
149 	va_list ap;
150 
151 	va_start(ap, num_pairs);
152 	err = kern_asl_msg_va(level, facility,
153 	    num_pairs, ap);
154 	va_end(ap);
155 
156 	return err;
157 }
158 
159 /* Search if given string contains '[' and ']'.  If any, escape it by
160  * prefixing with a '\'.  If the length of the string is not big enough,
161  * no changes are done and error is returned.
162  *
163  * Parameters -
164  *      str - string that can contain '[' or ']', should be NULL terminated
165  *	len - length, in bytes, of valid data, including NULL character.
166  *	buflen - size of buffer that contains the string
167  */
168 int
escape_str(char * str,size_t len,size_t buflen)169 escape_str(char *str, size_t len, size_t buflen)
170 {
171 	size_t count;
172 	char *src, *dst;
173 
174 	/* Count number of characters to escape */
175 	src = str;
176 	count = 0;
177 	do {
178 		if ((*src == '[') || (*src == ']')) {
179 			count++;
180 		}
181 	} while (*src++);
182 
183 	if (count) {
184 		/*
185 		 * Check if the buffer has enough space to escape all
186 		 * characters
187 		 */
188 		if ((buflen - len) < count) {
189 			return ENOSPC;
190 		}
191 
192 		src = str + len;
193 		dst = src + count;
194 		while (count) {
195 			*dst-- = *src;
196 			if ((*src == '[') || (*src == ']')) {
197 				/* Last char copied needs to be escaped */
198 				*dst-- = '\\';
199 				count--;
200 			}
201 			src--;
202 		}
203 	}
204 
205 	return 0;
206 }
207