]>
Commit | Line | Data |
---|---|---|
2d21ac55 A |
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 | ||
2d21ac55 A |
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> | |
39236c6e | 37 | #include <sys/syslog.h> |
2d21ac55 | 38 | #include <sys/vnode_internal.h> |
2d21ac55 A |
39 | #include <sys/fslog.h> |
40 | #include <sys/mount_internal.h> | |
39236c6e | 41 | #include <sys/kasl.h> |
2d21ac55 | 42 | |
39236c6e | 43 | #include <dev/random/randomdev.h> |
2d21ac55 | 44 | |
39236c6e | 45 | #include <uuid/uuid.h> |
2d21ac55 | 46 | |
39236c6e | 47 | #include <stdarg.h> |
2d21ac55 | 48 | |
39236c6e A |
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 | |
2d21ac55 | 57 | */ |
39236c6e A |
58 | void |
59 | fslog_extmod_msgtracer(proc_t caller, proc_t target) | |
2d21ac55 | 60 | { |
39236c6e | 61 | if ((caller != PROC_NULL) && (target != PROC_NULL)) { |
2d21ac55 | 62 | |
39236c6e A |
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). | |
2d21ac55 | 66 | */ |
2d21ac55 | 67 | |
39236c6e A |
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)]; | |
2d21ac55 | 71 | |
39236c6e A |
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; | |
2d21ac55 | 79 | } |
2d21ac55 | 80 | |
39236c6e A |
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 | |
2d21ac55 | 96 | |
39236c6e A |
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 | } | |
2d21ac55 A |
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 */ | |
39236c6e A |
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); | |
2d21ac55 A |
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); | |
39236c6e A |
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); | |
2d21ac55 A |
203 | } |
204 | va_end(ap); | |
205 | return msg_id; | |
206 | } | |
207 | ||
2d21ac55 A |
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) { | |
6d2010ae A |
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); | |
2d21ac55 A |
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) { | |
39236c6e | 259 | iotype = FSLOG_VAL_IOTYPE_READ; |
2d21ac55 | 260 | } else { |
39236c6e | 261 | iotype = FSLOG_VAL_IOTYPE_WRITE; |
2d21ac55 A |
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 | } | |
6d2010ae | 335 |