]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_fslog.c
dfc64b7a2ca2e61552b6e29391844dd3c18cbf24
[apple/xnu.git] / bsd / vfs / vfs_fslog.c
1 /*
2 * Copyright (c) 2006 Apple Computer, 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 /* Log information about external modification of a process,
50 * using MessageTracer formatting. Assumes that both the caller
51 * and target are appropriately locked.
52 * Currently prints following information -
53 * 1. Caller process name (truncated to 16 characters)
54 * 2. Caller process Mach-O UUID
55 * 3. Target process name (truncated to 16 characters)
56 * 4. Target process Mach-O UUID
57 */
58 void
59 fslog_extmod_msgtracer(proc_t caller, proc_t target)
60 {
61 if ((caller != PROC_NULL) && (target != PROC_NULL)) {
62
63 /*
64 * Print into buffer large enough for "ThisIsAnApplicat(BC223DD7-B314-42E0-B6B0-C5D2E6638337)",
65 * including space for escaping, and NUL byte included in sizeof(uuid_string_t).
66 */
67
68 uuid_string_t uuidstr;
69 char c_name[2*MAXCOMLEN + 2 /* () */ + sizeof(uuid_string_t)];
70 char t_name[2*MAXCOMLEN + 2 /* () */ + sizeof(uuid_string_t)];
71
72 strlcpy(c_name, caller->p_comm, sizeof(c_name));
73 uuid_unparse_upper(caller->p_uuid, uuidstr);
74 strlcat(c_name, "(", sizeof(c_name));
75 strlcat(c_name, uuidstr, sizeof(c_name));
76 strlcat(c_name, ")", sizeof(c_name));
77 if (0 != escape_str(c_name, strlen(c_name), sizeof(c_name))) {
78 return;
79 }
80
81 strlcpy(t_name, target->p_comm, sizeof(t_name));
82 uuid_unparse_upper(target->p_uuid, uuidstr);
83 strlcat(t_name, "(", sizeof(t_name));
84 strlcat(t_name, uuidstr, sizeof(t_name));
85 strlcat(t_name, ")", sizeof(t_name));
86 if (0 != escape_str(t_name, strlen(t_name), sizeof(t_name))) {
87 return;
88 }
89 #if DEBUG
90 printf("EXTMOD: %s(%d) -> %s(%d)\n",
91 c_name,
92 proc_pid(caller),
93 t_name,
94 proc_pid(target));
95 #endif
96
97 kern_asl_msg(LOG_DEBUG, "messagetracer",
98 5,
99 "com.apple.message.domain", "com.apple.kernel.external_modification", /* 0 */
100 "com.apple.message.signature", c_name, /* 1 */
101 "com.apple.message.signature2", t_name, /* 2 */
102 "com.apple.message.result", "noop", /* 3 */
103 "com.apple.message.summarize", "YES", /* 4 */
104 NULL);
105 }
106 }
107
108 /* Log file system related error in key-value format identified by Apple
109 * system log (ASL) facility. The key-value pairs are string pointers
110 * (char *) and are provided as variable arguments list. A NULL value
111 * indicates end of the list.
112 *
113 * Keys can not contain '[', ']', space, and newline. Values can not
114 * contain '[', ']', and newline. If any key-value contains any of the
115 * reserved characters, the behavior is undefined. The caller of the
116 * function should escape any occurrences of '[' and ']' by prefixing
117 * it with '\'.
118 *
119 * The function takes a message ID which can be used to logically group
120 * different ASL messages. Messages in same logical group have same message
121 * ID and have information to describe order of the message --- first,
122 * middle, or last.
123 *
124 * The following message IDs have special meaning -
125 * FSLOG_MSG_FIRST - This message is the first message in its logical
126 * group. This generates a unique message ID, creates two key-value
127 * pairs with message ID and order of the message as "First".
128 * FSLOG_MSG_LAST - This is really a MASK which should be logically OR'ed
129 * with message ID to indicate the last message for a logical group.
130 * This also creates two key-value pairs with message ID and order of
131 * message as "Last".
132 * FSLOG_MSG_SINGLE - This signifies that the message is the only message
133 * in its logical group. Therefore no extra key-values are generated
134 * for this option.
135 * For all other values of message IDs, it regards them as intermediate
136 * message and generates two key-value pairs with message ID and order of
137 * message as "Middle".
138 *
139 * Returns -
140 * Message ID of the ASL message printed. The caller should use
141 * this value to print intermediate messages or end the logical message
142 * group.
143 * For FSLOG_MSG_SINGLE option, it returns FSLOG_MSG_SINGLE.
144 */
145 unsigned long fslog_err(unsigned long msg_id, ... )
146 {
147 va_list ap;
148 int num_pairs;
149 char msg_id_str[21]; /* To convert 64-bit number to string with NULL char */
150 char *arg;
151 const char *msg_order_ptr;
152
153 /* Count number of arguments and key-value pairs provided by user */
154 num_pairs = 0;
155 va_start(ap, msg_id);
156 arg = va_arg(ap, char *);
157 while (arg) {
158 num_pairs++;
159 arg = va_arg(ap, char *);
160 }
161 num_pairs /= 2;
162 va_end(ap);
163
164 va_start(ap, msg_id);
165 if (msg_id == FSLOG_MSG_SINGLE) {
166 /* Single message, do not print message ID and message order */
167 (void) kern_asl_msg_va(FSLOG_VAL_LEVEL, FSLOG_VAL_FACILITY,
168 num_pairs, ap,
169 FSLOG_KEY_READ_UID, FSLOG_VAL_READ_UID,
170 NULL);
171 } else {
172 if (msg_id == FSLOG_MSG_FIRST) {
173 /* First message, generate random message ID */
174 while ((msg_id == FSLOG_MSG_FIRST) ||
175 (msg_id == FSLOG_MSG_LAST) ||
176 (msg_id == FSLOG_MSG_SINGLE)) {
177 msg_id = RandomULong();
178 /* MSB is reserved for indicating last message
179 * in sequence. Clear the MSB while generating
180 * new message ID.
181 */
182 msg_id = msg_id >> 1;
183 }
184 msg_order_ptr = FSLOG_VAL_ORDER_FIRST;
185 } else if (msg_id & FSLOG_MSG_LAST) {
186 /* MSB set to indicate last message for this ID */
187 msg_order_ptr = FSLOG_VAL_ORDER_LAST;
188 /* MSB of message ID is set to indicate last message
189 * in sequence. Clear the bit to get real message ID.
190 */
191 msg_id = msg_id & ~FSLOG_MSG_LAST;
192 } else {
193 /* Intermediate message for this ID */
194 msg_order_ptr = FSLOG_VAL_ORDER_MIDDLE;
195 }
196
197 snprintf(msg_id_str, sizeof(msg_id_str), "%lu", msg_id);
198 (void) kern_asl_msg_va(FSLOG_VAL_LEVEL, FSLOG_VAL_FACILITY,
199 num_pairs, ap,
200 FSLOG_KEY_READ_UID, FSLOG_VAL_READ_UID,
201 FSLOG_KEY_MSG_ID, msg_id_str,
202 FSLOG_KEY_MSG_ORDER, msg_order_ptr, NULL);
203 }
204 va_end(ap);
205 return msg_id;
206 }
207
208 /* Log information about runtime file system corruption detected by
209 * the file system. It takes the VFS mount structure as
210 * parameter which is used to access the mount point of the
211 * corrupt volume. If no mount structure or mount point string
212 * string exists, nothing is logged to ASL database.
213 *
214 * Currently prints following information -
215 * 1. Mount Point
216 */
217 void fslog_fs_corrupt(struct mount *mnt)
218 {
219 if (mnt != NULL) {
220 fslog_err(FSLOG_MSG_SINGLE,
221 FSLOG_KEY_ERR_TYPE, FSLOG_VAL_ERR_TYPE_FS,
222 FSLOG_KEY_MNTPT, mnt->mnt_vfsstat.f_mntonname,
223 NULL);
224 }
225
226 return;
227 }
228
229 /* Log information about IO error detected in buf_biodone()
230 * Currently prints following information -
231 * 1. Physical block number
232 * 2. Logical block number
233 * 3. Device node
234 * 4. Mount point
235 * 5. Path for file, if any
236 * 6. Error number
237 * 7. Type of IO (read/write)
238 */
239 void fslog_io_error(const buf_t bp)
240 {
241 int err;
242 unsigned long msg_id;
243 char blknum_str[21];
244 char lblknum_str[21];
245 char errno_str[6];
246 const char *iotype;
247 unsigned char print_last = 0;
248 vnode_t vp;
249
250 if (buf_error(bp) == 0) {
251 return;
252 }
253
254 /* Convert error number to string */
255 snprintf (errno_str, sizeof(errno_str), "%d", buf_error(bp));
256
257 /* Determine type of IO operation */
258 if (buf_flags(bp) & B_READ) {
259 iotype = FSLOG_VAL_IOTYPE_READ;
260 } else {
261 iotype = FSLOG_VAL_IOTYPE_WRITE;
262 }
263
264 /* Convert physical block number to string */
265 snprintf (blknum_str, sizeof(blknum_str), "%lld", buf_blkno(bp));
266
267 /* Convert logical block number to string */
268 snprintf (lblknum_str, sizeof(lblknum_str), "%lld", buf_lblkno(bp));
269
270 msg_id = fslog_err(FSLOG_MSG_FIRST,
271 FSLOG_KEY_ERR_TYPE, FSLOG_VAL_ERR_TYPE_IO,
272 FSLOG_KEY_ERRNO, errno_str,
273 FSLOG_KEY_IOTYPE, iotype,
274 FSLOG_KEY_PHYS_BLKNUM, blknum_str,
275 FSLOG_KEY_LOG_BLKNUM, lblknum_str,
276 NULL);
277
278 /* Access the vnode for this buffer */
279 vp = buf_vnode(bp);
280 if (vp) {
281 struct vfsstatfs *sp;
282 mount_t mp;
283 char *path;
284 int len;
285 struct vfs_context context;
286
287 mp = vnode_mount(vp);
288 /* mp should be NULL only for bdevvp during boot */
289 if (mp == NULL) {
290 goto out;
291 }
292 sp = vfs_statfs(mp);
293
294 /* Access the file path */
295 MALLOC(path, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
296 if (path) {
297 len = MAXPATHLEN;
298 context.vc_thread = current_thread();
299 context.vc_ucred = kauth_cred_get();
300 /* Find path without entering file system */
301 err = build_path(vp, path, len, &len, BUILDPATH_NO_FS_ENTER,
302 &context);
303 if (!err) {
304 err = escape_str(path, len, MAXPATHLEN);
305 if (!err) {
306 /* Print device node, mount point, path */
307 msg_id = fslog_err(msg_id | FSLOG_MSG_LAST,
308 FSLOG_KEY_DEVNODE, sp->f_mntfromname,
309 FSLOG_KEY_MNTPT, sp->f_mntonname,
310 FSLOG_KEY_PATH, path,
311 NULL);
312 print_last = 1;
313 }
314 }
315 FREE(path, M_TEMP);
316 }
317
318 if (print_last == 0) {
319 /* Print device node and mount point */
320 msg_id = fslog_err(msg_id | FSLOG_MSG_LAST,
321 FSLOG_KEY_DEVNODE, sp->f_mntfromname,
322 FSLOG_KEY_MNTPT, sp->f_mntonname,
323 NULL);
324 print_last = 1;
325 }
326 }
327
328 out:
329 if (print_last == 0) {
330 msg_id = fslog_err(msg_id | FSLOG_MSG_LAST, NULL);
331 }
332
333 return;
334 }
335