]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_asl.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / kern_asl.c
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
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 /* Print the key-value pairs in ASL format */
130 vaddlog(fmt, vargs);
131
132 /*
133 * Note: can't use os_log_with_args() here because 'fmt' is
134 * constructed on the stack i.e. doesn't come from a text
135 * section. More importantly, the newer logging system
136 * doesn't grok ASL either.
137 */
138
139 return err;
140 }
141
142 int
143 kern_asl_msg(int level, const char *facility, size_t num_pairs, ...)
144 {
145 int err;
146 va_list ap;
147
148 va_start(ap, num_pairs);
149 err = kern_asl_msg_va(level, facility,
150 num_pairs, ap);
151 va_end(ap);
152
153 return err;
154 }
155
156 /* Search if given string contains '[' and ']'. If any, escape it by
157 * prefixing with a '\'. If the length of the string is not big enough,
158 * no changes are done and error is returned.
159 *
160 * Parameters -
161 * str - string that can contain '[' or ']', should be NULL terminated
162 * len - length, in bytes, of valid data, including NULL character.
163 * buflen - size of buffer that contains the string
164 */
165 int
166 escape_str(char *str, size_t len, size_t buflen)
167 {
168 size_t count;
169 char *src, *dst;
170
171 /* Count number of characters to escape */
172 src = str;
173 count = 0;
174 do {
175 if ((*src == '[') || (*src == ']')) {
176 count++;
177 }
178 } while (*src++);
179
180 if (count) {
181 /*
182 * Check if the buffer has enough space to escape all
183 * characters
184 */
185 if ((buflen - len) < count) {
186 return ENOSPC;
187 }
188
189 src = str + len;
190 dst = src + count;
191 while (count) {
192 *dst-- = *src;
193 if ((*src == '[') || (*src == ']')) {
194 /* Last char copied needs to be escaped */
195 *dst-- = '\\';
196 count--;
197 }
198 src--;
199 }
200 }
201
202 return 0;
203 }