]>
Commit | Line | Data |
---|---|---|
55e303ae | 1 | /* |
91447636 | 2 | * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. |
55e303ae | 3 | * |
8f6c56a5 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
8ad349bb | 5 | * |
8f6c56a5 A |
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 | |
8ad349bb | 24 | * limitations under the License. |
8f6c56a5 A |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
55e303ae A |
27 | */ |
28 | #include <sys/param.h> | |
29 | #include <sys/fcntl.h> | |
30 | #include <sys/kernel.h> | |
31 | #include <sys/lock.h> | |
32 | #include <sys/namei.h> | |
91447636 A |
33 | #include <sys/proc_internal.h> |
34 | #include <sys/kauth.h> | |
55e303ae A |
35 | #include <sys/queue.h> |
36 | #include <sys/systm.h> | |
37 | #include <sys/time.h> | |
38 | #include <sys/ucred.h> | |
39 | #include <sys/uio.h> | |
40 | #include <sys/unistd.h> | |
91447636 A |
41 | #include <sys/file_internal.h> |
42 | #include <sys/vnode_internal.h> | |
55e303ae | 43 | #include <sys/user.h> |
55e303ae A |
44 | #include <sys/syscall.h> |
45 | #include <sys/malloc.h> | |
46 | #include <sys/un.h> | |
91447636 A |
47 | #include <sys/sysent.h> |
48 | #include <sys/sysproto.h> | |
49 | #include <sys/vfs_context.h> | |
e5568f75 | 50 | #include <sys/domain.h> |
91447636 A |
51 | #include <sys/protosw.h> |
52 | #include <sys/socketvar.h> | |
e5568f75 A |
53 | |
54 | #include <bsm/audit.h> | |
55 | #include <bsm/audit_kevents.h> | |
56 | #include <bsm/audit_klib.h> | |
57 | #include <bsm/audit_kernel.h> | |
58 | ||
91447636 | 59 | #include <mach/host_priv.h> |
e5568f75 | 60 | #include <mach/host_special_ports.h> |
91447636 | 61 | #include <mach/audit_triggers_server.h> |
55e303ae | 62 | |
91447636 A |
63 | #include <kern/host.h> |
64 | #include <kern/kalloc.h> | |
65 | #include <kern/zalloc.h> | |
55e303ae A |
66 | #include <kern/lock.h> |
67 | #include <kern/wait_queue.h> | |
91447636 A |
68 | #include <kern/sched_prim.h> |
69 | ||
70 | #include <net/route.h> | |
e5568f75 | 71 | |
91447636 A |
72 | #include <netinet/in.h> |
73 | #include <netinet/in_pcb.h> | |
55e303ae A |
74 | |
75 | #ifdef AUDIT | |
76 | ||
77 | /* | |
78 | * The AUDIT_EXCESSIVELY_VERBOSE define enables a number of | |
79 | * gratuitously noisy printf's to the console. Due to the | |
80 | * volume, it should be left off unless you want your system | |
81 | * to churn a lot whenever the audit record flow gets high. | |
82 | */ | |
83 | /* #define AUDIT_EXCESSIVELY_VERBOSE */ | |
84 | #ifdef AUDIT_EXCESSIVELY_VERBOSE | |
91447636 | 85 | #define AUDIT_PRINTF_ONLY |
55e303ae A |
86 | #define AUDIT_PRINTF(x) printf x |
87 | #else | |
91447636 | 88 | #define AUDIT_PRINTF_ONLY __unused |
55e303ae A |
89 | #define AUDIT_PRINTF(X) |
90 | #endif | |
91 | ||
92 | #if DIAGNOSTIC | |
93 | #if defined(assert) | |
94 | #undef assert() | |
95 | #endif | |
96 | #define assert(cond) \ | |
97 | ((void) ((cond) ? 0 : panic("%s:%d (%s)", __FILE__, __LINE__, # cond))) | |
98 | #else | |
99 | #include <kern/assert.h> | |
100 | #endif /* DIAGNOSTIC */ | |
101 | ||
102 | /* | |
103 | * Define the audit control flags. | |
104 | */ | |
105 | int audit_enabled; | |
106 | int audit_suspended; | |
107 | ||
108 | /* | |
109 | * Mutex to protect global variables shared between various threads and | |
110 | * processes. | |
111 | */ | |
112 | static mutex_t *audit_mtx; | |
113 | ||
114 | /* | |
115 | * Queue of audit records ready for delivery to disk. We insert new | |
e5568f75 A |
116 | * records at the tail, and remove records from the head. Also, |
117 | * a count of the number of records used for checking queue depth. | |
118 | * In addition, a counter of records that we have allocated but are | |
119 | * not yet in the queue, which is needed to estimate the total | |
120 | * size of the combined set of records outstanding in the system. | |
55e303ae | 121 | */ |
91447636 A |
122 | static TAILQ_HEAD(, kaudit_record) audit_q; |
123 | static size_t audit_q_len; | |
124 | static size_t audit_pre_q_len; | |
e5568f75 A |
125 | |
126 | static wait_queue_t audit_wait_queue; | |
127 | static zone_t audit_zone; | |
55e303ae A |
128 | |
129 | /* | |
130 | * Condition variable to signal to the worker that it has work to do: | |
131 | * either new records are in the queue, or a log replacement is taking | |
132 | * place. | |
133 | */ | |
e5568f75 A |
134 | static int audit_worker_event; |
135 | #define AUDIT_WORKER_EVENT ((event_t)&audit_worker_event) | |
55e303ae | 136 | |
91447636 A |
137 | /* |
138 | * The audit worker thread (which is lazy started when we first | |
139 | * rotate the audit log. | |
140 | */ | |
141 | static thread_t audit_worker_thread = THREAD_NULL; | |
142 | ||
55e303ae A |
143 | /* |
144 | * When an audit log is rotated, the actual rotation must be performed | |
145 | * by the audit worker thread, as it may have outstanding writes on the | |
146 | * current audit log. audit_replacement_vp holds the vnode replacing | |
147 | * the current vnode. We can't let more than one replacement occur | |
148 | * at a time, so if more than one thread requests a replacement, only | |
149 | * one can have the replacement "in progress" at any given moment. If | |
150 | * a thread tries to replace the audit vnode and discovers a replacement | |
151 | * is already in progress (i.e., audit_replacement_flag != 0), then it | |
152 | * will sleep on audit_replacement_cv waiting its turn to perform a | |
153 | * replacement. When a replacement is completed, this cv is signalled | |
154 | * by the worker thread so a waiting thread can start another replacement. | |
155 | * We also store a credential to perform audit log write operations with. | |
156 | */ | |
e5568f75 A |
157 | static int audit_replacement_event; |
158 | #define AUDIT_REPLACEMENT_EVENT ((event_t)&audit_replacement_event) | |
55e303ae | 159 | |
91447636 | 160 | static int audit_replacement_flag; |
55e303ae | 161 | static struct vnode *audit_replacement_vp; |
91447636 | 162 | static kauth_cred_t audit_replacement_cred; |
55e303ae | 163 | |
e5568f75 A |
164 | /* |
165 | * Wait queue for auditing threads that cannot commit the audit | |
166 | * record at the present time. Also, the queue control parameter | |
167 | * structure. | |
168 | */ | |
169 | static int audit_commit_event; | |
170 | #define AUDIT_COMMIT_EVENT ((event_t)&audit_commit_event) | |
171 | ||
172 | static struct au_qctrl audit_qctrl; | |
173 | ||
55e303ae A |
174 | /* |
175 | * Flags to use on audit files when opening and closing. | |
176 | */ | |
91447636 A |
177 | static const int audit_open_flags = FWRITE | O_APPEND; |
178 | static const int audit_close_flags = FWRITE | O_APPEND; | |
55e303ae | 179 | |
e5568f75 A |
180 | /* |
181 | * Global audit statistiscs. | |
182 | */ | |
183 | static struct audit_fstat audit_fstat; | |
184 | ||
185 | /* | |
186 | Preselection mask for non-attributable events. | |
187 | */ | |
188 | static struct au_mask audit_nae_mask; | |
189 | ||
190 | /* | |
191 | * Flags related to Kernel->user-space communication. | |
192 | */ | |
193 | static int audit_file_rotate_wait; | |
194 | ||
195 | /* | |
196 | * Flags controlling behavior in low storage situations. | |
197 | * Should we panic if a write fails? Should we fail stop | |
198 | * if we're out of disk space? Are we currently "failing | |
199 | * stop" due to out of disk space? | |
200 | */ | |
201 | static int audit_panic_on_write_fail; | |
202 | static int audit_fail_stop; | |
203 | static int audit_in_failure; | |
204 | ||
205 | /* | |
206 | * When in a fail-stop mode, threads will drop into this wait queue | |
207 | * rather than perform auditable events. They won't ever get woken | |
208 | * up. | |
209 | */ | |
210 | static int audit_failure_event; | |
211 | #define AUDIT_FAILURE_EVENT ((event_t)&audit_failure_event) | |
212 | ||
55e303ae A |
213 | /* |
214 | * XXX: Couldn't find the include file for this, so copied kern_exec.c's | |
215 | * behavior. | |
216 | */ | |
217 | extern task_t kernel_task; | |
218 | ||
219 | static void | |
220 | audit_free(struct kaudit_record *ar) | |
221 | { | |
222 | if (ar->k_ar.ar_arg_upath1 != NULL) { | |
91447636 | 223 | kfree(ar->k_ar.ar_arg_upath1, MAXPATHLEN); |
55e303ae A |
224 | } |
225 | if (ar->k_ar.ar_arg_upath2 != NULL) { | |
91447636 A |
226 | kfree(ar->k_ar.ar_arg_upath2, MAXPATHLEN); |
227 | ||
55e303ae A |
228 | } |
229 | if (ar->k_ar.ar_arg_kpath1 != NULL) { | |
91447636 A |
230 | kfree(ar->k_ar.ar_arg_kpath1, MAXPATHLEN); |
231 | ||
55e303ae A |
232 | } |
233 | if (ar->k_ar.ar_arg_kpath2 != NULL) { | |
91447636 A |
234 | kfree(ar->k_ar.ar_arg_kpath2, MAXPATHLEN); |
235 | ||
55e303ae A |
236 | } |
237 | if (ar->k_ar.ar_arg_text != NULL) { | |
91447636 A |
238 | kfree(ar->k_ar.ar_arg_text, MAXPATHLEN); |
239 | ||
55e303ae A |
240 | } |
241 | if (ar->k_udata != NULL) { | |
91447636 A |
242 | kfree(ar->k_udata, ar->k_ulen); |
243 | ||
55e303ae | 244 | } |
91447636 | 245 | zfree(audit_zone, ar); |
55e303ae A |
246 | } |
247 | ||
248 | static int | |
91447636 | 249 | audit_write(struct vnode *vp, struct kaudit_record *ar, kauth_cred_t cred, |
55e303ae A |
250 | struct proc *p) |
251 | { | |
91447636 | 252 | struct vfsstatfs *mnt_stat = &vp->v_mount->mnt_vfsstat; |
55e303ae A |
253 | int ret; |
254 | struct au_record *bsm; | |
91447636 A |
255 | /* KVV maybe we should take a context as a param to audit_write? */ |
256 | struct vfs_context context; | |
257 | off_t file_size; | |
e5568f75 A |
258 | |
259 | mach_port_t audit_port; | |
260 | ||
91447636 | 261 | /* |
e5568f75 A |
262 | * First, gather statistics on the audit log file and file system |
263 | * so that we know how we're doing on space. In both cases, | |
264 | * if we're unable to perform the operation, we drop the record | |
265 | * and return. However, this is arguably an assertion failure. | |
266 | */ | |
91447636 A |
267 | context.vc_proc = p; |
268 | context.vc_ucred = cred; | |
269 | ret = vfs_update_vfsstat(vp->v_mount, &context); | |
e5568f75 A |
270 | if (ret) |
271 | goto out; | |
272 | ||
273 | /* update the global stats struct */ | |
91447636 A |
274 | if ((ret = vnode_size(vp, &file_size, &context)) != 0) |
275 | goto out; | |
276 | audit_fstat.af_currsz = file_size; | |
277 | ||
e5568f75 A |
278 | /* |
279 | * Send a message to the audit daemon when disk space is getting | |
280 | * low. | |
281 | * XXX Need to decide what to do if the trigger to the audit daemon | |
282 | * fails. | |
283 | */ | |
284 | if(host_get_audit_control_port(host_priv_self(), &audit_port) | |
285 | != KERN_SUCCESS) | |
286 | printf("Cannot get audit control port\n"); | |
287 | ||
288 | if (audit_port != MACH_PORT_NULL) { | |
91447636 | 289 | uint64_t temp; |
e5568f75 A |
290 | |
291 | /* | |
292 | * If we fall below percent free blocks, then trigger the | |
293 | * audit daemon to do something about it. | |
294 | */ | |
295 | if (audit_qctrl.aq_minfree != 0) { | |
296 | temp = mnt_stat->f_blocks / (100 / audit_qctrl.aq_minfree); | |
297 | if (mnt_stat->f_bfree < temp) { | |
298 | ret = audit_triggers(audit_port, | |
299 | AUDIT_TRIGGER_LOW_SPACE); | |
300 | if (ret != KERN_SUCCESS) { | |
301 | printf( | |
302 | "Failed audit_triggers(AUDIT_TRIGGER_LOW_SPACE): %d\n", ret); | |
303 | /* | |
304 | * XXX: What to do here? Disable auditing? | |
305 | * panic? | |
306 | */ | |
307 | } | |
308 | } | |
309 | } | |
310 | /* Check if the current log file is full; if so, call for | |
311 | * a log rotate. This is not an exact comparison; we may | |
312 | * write some records over the limit. If that's not | |
313 | * acceptable, then add a fudge factor here. | |
314 | */ | |
315 | if ((audit_fstat.af_filesz != 0) && | |
316 | (audit_file_rotate_wait == 0) && | |
91447636 | 317 | (file_size >= audit_fstat.af_filesz)) { |
e5568f75 A |
318 | audit_file_rotate_wait = 1; |
319 | ret = audit_triggers(audit_port, | |
320 | AUDIT_TRIGGER_FILE_FULL); | |
321 | if (ret != KERN_SUCCESS) { | |
322 | printf( | |
323 | "Failed audit_triggers(AUDIT_TRIGGER_FILE_FULL): %d\n", ret); | |
324 | /* XXX what to do here? */ | |
325 | } | |
326 | } | |
327 | } | |
328 | ||
329 | /* | |
330 | * If the estimated amount of audit data in the audit event queue | |
331 | * (plus records allocated but not yet queued) has reached the | |
332 | * amount of free space on the disk, then we need to go into an | |
333 | * audit fail stop state, in which we do not permit the | |
334 | * allocation/committing of any new audit records. We continue to | |
335 | * process packets but don't allow any activities that might | |
336 | * generate new records. In the future, we might want to detect | |
337 | * when space is available again and allow operation to continue, | |
338 | * but this behavior is sufficient to meet fail stop requirements | |
339 | * in CAPP. | |
340 | */ | |
341 | if (audit_fail_stop && | |
342 | (unsigned long) | |
343 | ((audit_q_len + audit_pre_q_len + 1) * MAX_AUDIT_RECORD_SIZE) / | |
344 | mnt_stat->f_bsize >= (unsigned long)(mnt_stat->f_bfree)) { | |
345 | printf( | |
346 | "audit_worker: free space below size of audit queue, failing stop\n"); | |
347 | audit_in_failure = 1; | |
348 | } | |
55e303ae A |
349 | |
350 | /* | |
351 | * If there is a user audit record attached to the kernel record, | |
352 | * then write the user record. | |
353 | */ | |
354 | /* XXX Need to decide a few things here: IF the user audit | |
355 | * record is written, but the write of the kernel record fails, | |
356 | * what to do? Should the kernel record come before or after the | |
357 | * user record? For now, we write the user record first, and | |
358 | * we ignore errors. | |
359 | */ | |
e5568f75 | 360 | if (ar->k_ar_commit & AR_COMMIT_USER) { |
91447636 A |
361 | if (vnode_getwithref(vp) == 0) { |
362 | ret = vn_rdwr(UIO_WRITE, vp, (void *)ar->k_udata, ar->k_ulen, | |
363 | (off_t)0, UIO_SYSSPACE32, IO_APPEND|IO_UNIT, cred, NULL, p); | |
364 | vnode_put(vp); | |
365 | if (ret) | |
366 | goto out; | |
367 | } else { | |
e5568f75 | 368 | goto out; |
91447636 | 369 | } |
55e303ae A |
370 | } |
371 | ||
372 | /* | |
373 | * Convert the internal kernel record to BSM format and write it | |
374 | * out if everything's OK. | |
375 | */ | |
e5568f75 A |
376 | if (!(ar->k_ar_commit & AR_COMMIT_KERNEL)) { |
377 | ret = 0; | |
378 | goto out; | |
379 | } | |
380 | ||
55e303ae | 381 | ret = kaudit_to_bsm(ar, &bsm); |
e5568f75 A |
382 | if (ret == BSM_NOAUDIT) { |
383 | ret = 0; | |
384 | goto out; | |
385 | } | |
55e303ae | 386 | |
e5568f75 A |
387 | /* |
388 | * XXX: We drop the record on BSM conversion failure, but really | |
389 | * this is an assertion failure. | |
390 | */ | |
55e303ae A |
391 | if (ret == BSM_FAILURE) { |
392 | AUDIT_PRINTF(("BSM conversion failure\n")); | |
e5568f75 A |
393 | ret = EINVAL; |
394 | goto out; | |
55e303ae A |
395 | } |
396 | ||
397 | /* XXX This function can be called with the kernel funnel held, | |
398 | * which is not optimal. We should break the write functionality | |
399 | * away from the BSM record generation and have the BSM generation | |
400 | * done before this function is called. This function will then | |
401 | * take the BSM record as a parameter. | |
402 | */ | |
91447636 A |
403 | if ((ret = vnode_getwithref(vp)) == 0) { |
404 | ret = (vn_rdwr(UIO_WRITE, vp, (void *)bsm->data, bsm->len, | |
405 | (off_t)0, UIO_SYSSPACE32, IO_APPEND|IO_UNIT, cred, NULL, p)); | |
406 | vnode_put(vp); | |
407 | } | |
55e303ae A |
408 | kau_free(bsm); |
409 | ||
e5568f75 A |
410 | out: |
411 | /* | |
412 | * When we're done processing the current record, we have to | |
413 | * check to see if we're in a failure mode, and if so, whether | |
414 | * this was the last record left to be drained. If we're done | |
415 | * draining, then we fsync the vnode and panic. | |
416 | */ | |
417 | if (audit_in_failure && | |
418 | audit_q_len == 0 && audit_pre_q_len == 0) { | |
91447636 | 419 | (void)VNOP_FSYNC(vp, MNT_WAIT, &context); |
e5568f75 A |
420 | panic("Audit store overflow; record queue drained."); |
421 | } | |
422 | ||
55e303ae A |
423 | return (ret); |
424 | } | |
425 | ||
426 | static void | |
91447636 | 427 | audit_worker(void) |
55e303ae A |
428 | { |
429 | int do_replacement_signal, error, release_funnel; | |
430 | TAILQ_HEAD(, kaudit_record) ar_worklist; | |
91447636 | 431 | struct kaudit_record *ar; |
55e303ae | 432 | struct vnode *audit_vp, *old_vp; |
91447636 A |
433 | kauth_cred_t audit_cred; |
434 | kauth_cred_t old_cred; | |
55e303ae A |
435 | struct proc *audit_p; |
436 | ||
437 | AUDIT_PRINTF(("audit_worker starting\n")); | |
438 | ||
439 | TAILQ_INIT(&ar_worklist); | |
440 | audit_cred = NULL; | |
441 | audit_p = current_proc(); | |
442 | audit_vp = NULL; | |
443 | ||
444 | /* | |
445 | * XXX: Presumably we can assume Mach threads are started without | |
446 | * holding the BSD kernel funnel? | |
447 | */ | |
448 | thread_funnel_set(kernel_flock, FALSE); | |
449 | ||
450 | mutex_lock(audit_mtx); | |
451 | while (1) { | |
452 | /* | |
453 | * First priority: replace the audit log target if requested. | |
454 | * As we actually close the vnode in the worker thread, we | |
455 | * need to grab the funnel, which means releasing audit_mtx. | |
456 | * In case another replacement was scheduled while the mutex | |
457 | * we released, we loop. | |
458 | * | |
459 | * XXX It could well be we should drain existing records | |
460 | * first to ensure that the timestamps and ordering | |
461 | * are right. | |
462 | */ | |
463 | do_replacement_signal = 0; | |
464 | while (audit_replacement_flag != 0) { | |
465 | old_cred = audit_cred; | |
466 | old_vp = audit_vp; | |
467 | audit_cred = audit_replacement_cred; | |
468 | audit_vp = audit_replacement_vp; | |
469 | audit_replacement_cred = NULL; | |
470 | audit_replacement_vp = NULL; | |
471 | audit_replacement_flag = 0; | |
472 | ||
473 | audit_enabled = (audit_vp != NULL); | |
474 | ||
475 | if (old_vp != NULL || audit_vp != NULL) { | |
476 | mutex_unlock(audit_mtx); | |
477 | thread_funnel_set(kernel_flock, TRUE); | |
478 | release_funnel = 1; | |
479 | } else | |
480 | release_funnel = 0; | |
481 | /* | |
482 | * XXX: What to do about write failures here? | |
483 | */ | |
484 | if (old_vp != NULL) { | |
485 | AUDIT_PRINTF(("Closing old audit file\n")); | |
486 | vn_close(old_vp, audit_close_flags, old_cred, | |
487 | audit_p); | |
91447636 A |
488 | kauth_cred_rele(old_cred); |
489 | old_cred = NOCRED; | |
55e303ae A |
490 | old_vp = NULL; |
491 | AUDIT_PRINTF(("Audit file closed\n")); | |
492 | } | |
493 | if (audit_vp != NULL) { | |
494 | AUDIT_PRINTF(("Opening new audit file\n")); | |
495 | } | |
496 | if (release_funnel) { | |
497 | thread_funnel_set(kernel_flock, FALSE); | |
498 | mutex_lock(audit_mtx); | |
499 | } | |
500 | do_replacement_signal = 1; | |
501 | } | |
502 | /* | |
503 | * Signal that replacement have occurred to wake up and | |
504 | * start any other replacements started in parallel. We can | |
505 | * continue about our business in the mean time. We | |
506 | * broadcast so that both new replacements can be inserted, | |
507 | * but also so that the source(s) of replacement can return | |
508 | * successfully. | |
509 | */ | |
510 | if (do_replacement_signal) | |
e5568f75 A |
511 | wait_queue_wakeup_all(audit_wait_queue, |
512 | AUDIT_REPLACEMENT_EVENT, THREAD_AWAKENED); | |
55e303ae A |
513 | |
514 | /* | |
515 | * Next, check to see if we have any records to drain into | |
516 | * the vnode. If not, go back to waiting for an event. | |
517 | */ | |
518 | if (TAILQ_EMPTY(&audit_q)) { | |
519 | int ret; | |
520 | ||
521 | AUDIT_PRINTF(("audit_worker waiting\n")); | |
e5568f75 A |
522 | ret = wait_queue_assert_wait(audit_wait_queue, |
523 | AUDIT_WORKER_EVENT, | |
91447636 A |
524 | THREAD_UNINT, |
525 | 0); | |
55e303ae A |
526 | mutex_unlock(audit_mtx); |
527 | ||
528 | assert(ret == THREAD_WAITING); | |
529 | ret = thread_block(THREAD_CONTINUE_NULL); | |
530 | assert(ret == THREAD_AWAKENED); | |
531 | AUDIT_PRINTF(("audit_worker woken up\n")); | |
532 | AUDIT_PRINTF(("audit_worker: new vp = %p; value of flag %d\n", | |
533 | audit_replacement_vp, audit_replacement_flag)); | |
91447636 | 534 | |
55e303ae A |
535 | mutex_lock(audit_mtx); |
536 | continue; | |
537 | } | |
538 | ||
539 | /* | |
540 | * If we have records, but there's no active vnode to | |
541 | * write to, drain the record queue. Generally, we | |
542 | * prevent the unnecessary allocation of records | |
543 | * elsewhere, but we need to allow for races between | |
544 | * conditional allocation and queueing. Go back to | |
545 | * waiting when we're done. | |
546 | * | |
547 | * XXX: We go out of our way to avoid calling audit_free() | |
548 | * with the audit_mtx held, to avoid a lock order reversal | |
549 | * as free() may grab the funnel. This will be fixed at | |
550 | * some point. | |
551 | */ | |
552 | if (audit_vp == NULL) { | |
553 | while ((ar = TAILQ_FIRST(&audit_q))) { | |
554 | TAILQ_REMOVE(&audit_q, ar, k_q); | |
e5568f75 A |
555 | audit_q_len--; |
556 | if (audit_q_len <= audit_qctrl.aq_lowater) | |
557 | wait_queue_wakeup_one( | |
558 | audit_wait_queue, | |
559 | AUDIT_COMMIT_EVENT, | |
560 | THREAD_AWAKENED); | |
561 | ||
55e303ae A |
562 | TAILQ_INSERT_TAIL(&ar_worklist, ar, k_q); |
563 | } | |
564 | mutex_unlock(audit_mtx); | |
565 | while ((ar = TAILQ_FIRST(&ar_worklist))) { | |
566 | TAILQ_REMOVE(&ar_worklist, ar, k_q); | |
567 | audit_free(ar); | |
568 | } | |
569 | mutex_lock(audit_mtx); | |
570 | continue; | |
571 | } | |
572 | ||
573 | /* | |
574 | * We have both records to write, and an active vnode | |
575 | * to write to. Dequeue a record, and start the write. | |
576 | * Eventually, it might make sense to dequeue several | |
577 | * records and perform our own clustering, if the lower | |
578 | * layers aren't doing it automatically enough. | |
579 | * | |
580 | * XXX: We go out of our way to avoid calling audit_free() | |
581 | * with the audit_mtx held, to avoid a lock order reversal | |
582 | * as free() may grab the funnel. This will be fixed at | |
583 | * some point. | |
584 | */ | |
585 | while ((ar = TAILQ_FIRST(&audit_q))) { | |
586 | TAILQ_REMOVE(&audit_q, ar, k_q); | |
e5568f75 A |
587 | audit_q_len--; |
588 | if (audit_q_len <= audit_qctrl.aq_lowater) { | |
589 | wait_queue_wakeup_one(audit_wait_queue, | |
590 | AUDIT_COMMIT_EVENT, THREAD_AWAKENED); | |
591 | } | |
592 | ||
55e303ae A |
593 | TAILQ_INSERT_TAIL(&ar_worklist, ar, k_q); |
594 | } | |
595 | mutex_unlock(audit_mtx); | |
596 | release_funnel = 0; | |
597 | while ((ar = TAILQ_FIRST(&ar_worklist))) { | |
598 | TAILQ_REMOVE(&ar_worklist, ar, k_q); | |
599 | if (audit_vp != NULL) { | |
600 | /* | |
601 | * XXX: What should happen if there's a write | |
602 | * error here? | |
603 | */ | |
604 | if (!release_funnel) { | |
605 | thread_funnel_set(kernel_flock, TRUE); | |
606 | release_funnel = 1; | |
607 | } | |
55e303ae A |
608 | error = audit_write(audit_vp, ar, audit_cred, |
609 | audit_p); | |
91447636 | 610 | if (error && audit_panic_on_write_fail) { |
e5568f75 A |
611 | panic("audit_worker: write error %d\n", |
612 | error); | |
91447636 | 613 | } else if (error) { |
55e303ae A |
614 | printf("audit_worker: write error %d\n", |
615 | error); | |
616 | } | |
91447636 | 617 | } |
55e303ae A |
618 | audit_free(ar); |
619 | } | |
620 | if (release_funnel) | |
621 | thread_funnel_set(kernel_flock, FALSE); | |
622 | mutex_lock(audit_mtx); | |
623 | } | |
624 | } | |
625 | ||
626 | void | |
627 | audit_init(void) | |
628 | { | |
629 | ||
630 | /* Verify that the syscall to audit event table is the same | |
631 | * size as the system call table. | |
632 | */ | |
633 | if (nsys_au_event != nsysent) { | |
634 | printf("Security auditing service initialization failed, "); | |
635 | printf("audit event table doesn't match syscall table.\n"); | |
636 | return; | |
637 | } | |
638 | ||
639 | printf("Security auditing service present\n"); | |
640 | TAILQ_INIT(&audit_q); | |
e5568f75 | 641 | audit_q_len = 0; |
55e303ae A |
642 | audit_enabled = 0; |
643 | audit_suspended = 0; | |
644 | audit_replacement_cred = NULL; | |
645 | audit_replacement_flag = 0; | |
e5568f75 | 646 | audit_file_rotate_wait = 0; |
55e303ae | 647 | audit_replacement_vp = NULL; |
e5568f75 A |
648 | audit_fstat.af_filesz = 0; /* '0' means unset, unbounded */ |
649 | audit_fstat.af_currsz = 0; | |
650 | audit_qctrl.aq_hiwater = AQ_HIWATER; | |
651 | audit_qctrl.aq_lowater = AQ_LOWATER; | |
652 | audit_qctrl.aq_bufsz = AQ_BUFSZ; | |
653 | audit_qctrl.aq_minfree = AU_FS_MINFREE; | |
654 | ||
91447636 | 655 | audit_mtx = mutex_alloc(0); |
55e303ae | 656 | audit_wait_queue = wait_queue_alloc(SYNC_POLICY_FIFO); |
e5568f75 A |
657 | audit_zone = zinit(sizeof(struct kaudit_record), |
658 | AQ_HIWATER*sizeof(struct kaudit_record), | |
659 | 8192, | |
660 | "audit_zone"); | |
55e303ae A |
661 | |
662 | /* Initialize the BSM audit subsystem. */ | |
663 | kau_init(); | |
55e303ae A |
664 | } |
665 | ||
666 | static void | |
91447636 | 667 | audit_rotate_vnode(kauth_cred_t cred, struct vnode *vp) |
55e303ae A |
668 | { |
669 | int ret; | |
670 | ||
671 | /* | |
672 | * If other parallel log replacements have been requested, we wait | |
673 | * until they've finished before continuing. | |
674 | */ | |
675 | mutex_lock(audit_mtx); | |
676 | while (audit_replacement_flag != 0) { | |
677 | ||
678 | AUDIT_PRINTF(("audit_rotate_vnode: sleeping to wait for " | |
679 | "flag\n")); | |
e5568f75 A |
680 | ret = wait_queue_assert_wait(audit_wait_queue, |
681 | AUDIT_REPLACEMENT_EVENT, | |
91447636 A |
682 | THREAD_UNINT, |
683 | 0); | |
55e303ae A |
684 | mutex_unlock(audit_mtx); |
685 | ||
686 | assert(ret == THREAD_WAITING); | |
687 | ret = thread_block(THREAD_CONTINUE_NULL); | |
688 | assert(ret == THREAD_AWAKENED); | |
689 | AUDIT_PRINTF(("audit_rotate_vnode: woken up (flag %d)\n", | |
690 | audit_replacement_flag)); | |
691 | ||
692 | mutex_lock(audit_mtx); | |
693 | } | |
694 | audit_replacement_cred = cred; | |
695 | audit_replacement_flag = 1; | |
696 | audit_replacement_vp = vp; | |
697 | ||
698 | /* | |
91447636 A |
699 | * Start or wake up the audit worker to perform the exchange. |
700 | * It will have to wait until we release the mutex. | |
55e303ae | 701 | */ |
91447636 A |
702 | if (audit_worker_thread == THREAD_NULL) |
703 | audit_worker_thread = kernel_thread(kernel_task, | |
704 | audit_worker); | |
705 | else | |
706 | wait_queue_wakeup_one(audit_wait_queue, | |
707 | AUDIT_WORKER_EVENT, | |
708 | THREAD_AWAKENED); | |
55e303ae A |
709 | |
710 | /* | |
711 | * Wait for the audit_worker to broadcast that a replacement has | |
712 | * taken place; we know that once this has happened, our vnode | |
713 | * has been replaced in, so we can return successfully. | |
714 | */ | |
715 | AUDIT_PRINTF(("audit_rotate_vnode: waiting for news of " | |
716 | "replacement\n")); | |
e5568f75 A |
717 | ret = wait_queue_assert_wait(audit_wait_queue, |
718 | AUDIT_REPLACEMENT_EVENT, | |
91447636 A |
719 | THREAD_UNINT, |
720 | 0); | |
55e303ae A |
721 | mutex_unlock(audit_mtx); |
722 | ||
723 | assert(ret == THREAD_WAITING); | |
724 | ret = thread_block(THREAD_CONTINUE_NULL); | |
725 | assert(ret == THREAD_AWAKENED); | |
726 | AUDIT_PRINTF(("audit_rotate_vnode: change acknowledged by " | |
727 | "audit_worker (flag " "now %d)\n", audit_replacement_flag)); | |
e5568f75 A |
728 | |
729 | audit_file_rotate_wait = 0; /* We can now request another rotation */ | |
55e303ae A |
730 | } |
731 | ||
732 | /* | |
733 | * Drain the audit queue and close the log at shutdown. | |
734 | */ | |
735 | void | |
736 | audit_shutdown(void) | |
737 | { | |
55e303ae A |
738 | audit_rotate_vnode(NULL, NULL); |
739 | } | |
740 | ||
741 | static __inline__ struct uthread * | |
742 | curuthread(void) | |
743 | { | |
91447636 | 744 | return (get_bsdthread_info(current_thread())); |
55e303ae A |
745 | } |
746 | ||
747 | static __inline__ struct kaudit_record * | |
748 | currecord(void) | |
749 | { | |
55e303ae A |
750 | return (curuthread()->uu_ar); |
751 | } | |
752 | ||
753 | /********************************** | |
754 | * Begin system calls. * | |
755 | **********************************/ | |
756 | /* | |
757 | * System call to allow a user space application to submit a BSM audit | |
758 | * record to the kernel for inclusion in the audit log. This function | |
759 | * does little verification on the audit record that is submitted. | |
760 | * | |
761 | * XXXAUDIT: Audit preselection for user records does not currently | |
762 | * work, since we pre-select only based on the AUE_audit event type, | |
763 | * not the event type submitted as part of the user audit data. | |
764 | */ | |
55e303ae A |
765 | /* ARGSUSED */ |
766 | int | |
91447636 | 767 | audit(struct proc *p, struct audit_args *uap, __unused register_t *retval) |
55e303ae | 768 | { |
55e303ae A |
769 | int error; |
770 | void * rec; | |
771 | struct kaudit_record *ar; | |
e5568f75 | 772 | struct uthread *uthr; |
55e303ae | 773 | |
91447636 | 774 | error = suser(kauth_cred_get(), &p->p_acflag); |
55e303ae A |
775 | if (error) |
776 | return (error); | |
777 | ||
91447636 | 778 | if ((uap->length <= 0) || (uap->length > (int)audit_qctrl.aq_bufsz)) |
e5568f75 A |
779 | return (EINVAL); |
780 | ||
781 | ar = currecord(); | |
782 | ||
783 | /* If there's no current audit record (audit() itself not audited) | |
784 | * commit the user audit record. | |
785 | */ | |
786 | if (ar == NULL) { | |
787 | uthr = curuthread(); | |
788 | if (uthr == NULL) /* can this happen? */ | |
91447636 | 789 | return (ENOTSUP); |
e5568f75 A |
790 | |
791 | /* This is not very efficient; we're required to allocate | |
792 | * a complete kernel audit record just so the user record | |
793 | * can tag along. | |
794 | */ | |
795 | uthr->uu_ar = audit_new(AUE_NULL, p, uthr); | |
796 | if (uthr->uu_ar == NULL) /* auditing not on, or memory error */ | |
797 | return (ENOTSUP); | |
798 | ar = uthr->uu_ar; | |
799 | } | |
800 | ||
55e303ae A |
801 | if (uap->length > MAX_AUDIT_RECORD_SIZE) |
802 | return (EINVAL); | |
803 | ||
e5568f75 | 804 | rec = (void *)kalloc((vm_size_t)uap->length); |
55e303ae A |
805 | |
806 | error = copyin(uap->record, rec, uap->length); | |
807 | if (error) | |
808 | goto free_out; | |
809 | ||
810 | /* Verify the record */ | |
811 | if (bsm_rec_verify(rec) == 0) { | |
812 | error = EINVAL; | |
813 | goto free_out; | |
814 | } | |
815 | ||
816 | /* Attach the user audit record to the kernel audit record. Because | |
817 | * this system call is an auditable event, we will write the user | |
818 | * record along with the record for this audit event. | |
819 | */ | |
820 | ar->k_udata = rec; | |
e5568f75 | 821 | ar->k_ar_commit |= AR_COMMIT_USER; |
55e303ae A |
822 | ar->k_ulen = uap->length; |
823 | return (0); | |
824 | ||
825 | free_out: | |
e5568f75 A |
826 | /* audit_syscall_exit() will free the audit record on the thread |
827 | * even if we allocated it above. | |
828 | */ | |
91447636 | 829 | kfree(rec, uap->length); |
55e303ae A |
830 | return (error); |
831 | } | |
832 | ||
833 | /* | |
834 | * System call to manipulate auditing. | |
835 | */ | |
55e303ae A |
836 | /* ARGSUSED */ |
837 | int | |
91447636 | 838 | auditon(struct proc *p, __unused struct auditon_args *uap, __unused register_t *retval) |
55e303ae | 839 | { |
e5568f75 A |
840 | int ret; |
841 | int len; | |
842 | union auditon_udata udata; | |
843 | struct proc *tp; | |
55e303ae | 844 | |
e5568f75 | 845 | AUDIT_ARG(cmd, uap->cmd); |
91447636 | 846 | ret = suser(kauth_cred_get(), &p->p_acflag); |
e5568f75 A |
847 | if (ret) |
848 | return (ret); | |
55e303ae | 849 | |
e5568f75 | 850 | len = uap->length; |
91447636 | 851 | if ((len <= 0) || (len > (int)sizeof(union auditon_udata))) |
e5568f75 | 852 | return (EINVAL); |
55e303ae | 853 | |
e5568f75 A |
854 | memset((void *)&udata, 0, sizeof(udata)); |
855 | ||
856 | switch (uap->cmd) { | |
857 | /* Some of the GET commands use the arguments too */ | |
858 | case A_SETPOLICY: | |
859 | case A_SETKMASK: | |
860 | case A_SETQCTRL: | |
861 | case A_SETSTAT: | |
862 | case A_SETUMASK: | |
863 | case A_SETSMASK: | |
864 | case A_SETCOND: | |
865 | case A_SETCLASS: | |
866 | case A_SETPMASK: | |
867 | case A_SETFSIZE: | |
868 | case A_SETKAUDIT: | |
869 | case A_GETCLASS: | |
870 | case A_GETPINFO: | |
871 | case A_GETPINFO_ADDR: | |
872 | ret = copyin(uap->data, (void *)&udata, uap->length); | |
873 | if (ret) | |
874 | return (ret); | |
875 | AUDIT_ARG(auditon, &udata); | |
876 | break; | |
91447636 | 877 | } |
e5568f75 A |
878 | |
879 | /* XXX Need to implement these commands by accessing the global | |
880 | * values associated with the commands. | |
881 | */ | |
882 | switch (uap->cmd) { | |
883 | case A_GETPOLICY: | |
884 | if (!audit_fail_stop) | |
885 | udata.au_policy |= AUDIT_CNT; | |
886 | if (audit_panic_on_write_fail) | |
887 | udata.au_policy |= AUDIT_AHLT; | |
888 | break; | |
889 | case A_SETPOLICY: | |
890 | if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT)) | |
891 | return (EINVAL); | |
91447636 | 892 | /* |
e5568f75 | 893 | * XXX - Need to wake up waiters if the policy relaxes? |
91447636 | 894 | */ |
e5568f75 A |
895 | audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); |
896 | audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); | |
897 | break; | |
898 | case A_GETKMASK: | |
899 | udata.au_mask = audit_nae_mask; | |
900 | break; | |
901 | case A_SETKMASK: | |
902 | audit_nae_mask = udata.au_mask; | |
903 | break; | |
904 | case A_GETQCTRL: | |
905 | udata.au_qctrl = audit_qctrl; | |
906 | break; | |
907 | case A_SETQCTRL: | |
908 | if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || | |
909 | (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || | |
910 | (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || | |
911 | (udata.au_qctrl.aq_minfree < 0) || | |
912 | (udata.au_qctrl.aq_minfree > 100)) | |
913 | return (EINVAL); | |
914 | ||
915 | audit_qctrl = udata.au_qctrl; | |
916 | /* XXX The queue delay value isn't used with the kernel. */ | |
917 | audit_qctrl.aq_delay = -1; | |
918 | break; | |
919 | case A_GETCWD: | |
920 | return (ENOSYS); | |
921 | break; | |
922 | case A_GETCAR: | |
923 | return (ENOSYS); | |
924 | break; | |
925 | case A_GETSTAT: | |
926 | return (ENOSYS); | |
927 | break; | |
928 | case A_SETSTAT: | |
929 | return (ENOSYS); | |
930 | break; | |
931 | case A_SETUMASK: | |
932 | return (ENOSYS); | |
933 | break; | |
934 | case A_SETSMASK: | |
935 | return (ENOSYS); | |
936 | break; | |
937 | case A_GETCOND: | |
938 | if (audit_enabled && !audit_suspended) | |
939 | udata.au_cond = AUC_AUDITING; | |
940 | else | |
941 | udata.au_cond = AUC_NOAUDIT; | |
942 | break; | |
943 | case A_SETCOND: | |
944 | if (udata.au_cond == AUC_NOAUDIT) | |
945 | audit_suspended = 1; | |
946 | if (udata.au_cond == AUC_AUDITING) | |
947 | audit_suspended = 0; | |
948 | if (udata.au_cond == AUC_DISABLED) { | |
949 | audit_suspended = 1; | |
950 | audit_shutdown(); | |
951 | } | |
952 | break; | |
953 | case A_GETCLASS: | |
954 | udata.au_evclass.ec_class = | |
955 | au_event_class(udata.au_evclass.ec_number); | |
956 | break; | |
957 | case A_SETCLASS: | |
958 | au_evclassmap_insert(udata.au_evclass.ec_number, | |
959 | udata.au_evclass.ec_class); | |
960 | break; | |
961 | case A_GETPINFO: | |
962 | if (udata.au_aupinfo.ap_pid < 1) | |
963 | return (EINVAL); | |
964 | if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) | |
965 | return (EINVAL); | |
966 | ||
91447636 | 967 | udata.au_aupinfo.ap_auid = tp->p_ucred->cr_au.ai_auid; |
e5568f75 | 968 | udata.au_aupinfo.ap_mask.am_success = |
91447636 | 969 | tp->p_ucred->cr_au.ai_mask.am_success; |
e5568f75 | 970 | udata.au_aupinfo.ap_mask.am_failure = |
91447636 | 971 | tp->p_ucred->cr_au.ai_mask.am_failure; |
e5568f75 | 972 | udata.au_aupinfo.ap_termid.machine = |
91447636 | 973 | tp->p_ucred->cr_au.ai_termid.machine; |
e5568f75 | 974 | udata.au_aupinfo.ap_termid.port = |
91447636 A |
975 | tp->p_ucred->cr_au.ai_termid.port; |
976 | udata.au_aupinfo.ap_asid = tp->p_ucred->cr_au.ai_asid; | |
e5568f75 A |
977 | break; |
978 | case A_SETPMASK: | |
979 | if (udata.au_aupinfo.ap_pid < 1) | |
980 | return (EINVAL); | |
981 | if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) | |
982 | return (EINVAL); | |
983 | ||
91447636 A |
984 | /* |
985 | * we are modifying the audit info in a credential so we need a new | |
986 | * credential (or take another reference on an existing credential that | |
987 | * matches our new one). We must do this because the audit info in the | |
988 | * credential is used as part of our hash key. Get current credential | |
989 | * in the target process and take a reference while we muck with it. | |
990 | */ | |
991 | for (;;) { | |
992 | kauth_cred_t my_cred, my_new_cred; | |
993 | struct auditinfo temp_auditinfo; | |
994 | ||
995 | my_cred = kauth_cred_proc_ref(tp); | |
996 | /* | |
997 | * set the credential with new info. If there is no change we get back | |
998 | * the same credential we passed in. | |
999 | */ | |
1000 | temp_auditinfo = my_cred->cr_au; | |
1001 | temp_auditinfo.ai_mask.am_success = | |
1002 | udata.au_aupinfo.ap_mask.am_success; | |
1003 | temp_auditinfo.ai_mask.am_failure = | |
1004 | udata.au_aupinfo.ap_mask.am_failure; | |
1005 | my_new_cred = kauth_cred_setauditinfo(my_cred, &temp_auditinfo); | |
1006 | ||
1007 | if (my_cred != my_new_cred) { | |
1008 | proc_lock(tp); | |
1009 | /* need to protect for a race where another thread also changed | |
1010 | * the credential after we took our reference. If p_ucred has | |
1011 | * changed then we should restart this again with the new cred. | |
1012 | */ | |
1013 | if (tp->p_ucred != my_cred) { | |
1014 | proc_unlock(tp); | |
1015 | kauth_cred_rele(my_cred); | |
1016 | kauth_cred_rele(my_new_cred); | |
1017 | /* try again */ | |
1018 | continue; | |
1019 | } | |
1020 | tp->p_ucred = my_new_cred; | |
1021 | proc_unlock(tp); | |
1022 | } | |
1023 | /* drop our extra reference */ | |
1024 | kauth_cred_rele(my_cred); | |
1025 | break; | |
1026 | } | |
e5568f75 A |
1027 | break; |
1028 | case A_SETFSIZE: | |
1029 | if ((udata.au_fstat.af_filesz != 0) && | |
1030 | (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) | |
1031 | return (EINVAL); | |
1032 | audit_fstat.af_filesz = udata.au_fstat.af_filesz; | |
1033 | break; | |
1034 | case A_GETFSIZE: | |
1035 | udata.au_fstat.af_filesz = audit_fstat.af_filesz; | |
1036 | udata.au_fstat.af_currsz = audit_fstat.af_currsz; | |
1037 | break; | |
1038 | case A_GETPINFO_ADDR: | |
1039 | return (ENOSYS); | |
1040 | break; | |
1041 | case A_GETKAUDIT: | |
1042 | return (ENOSYS); | |
1043 | break; | |
1044 | case A_SETKAUDIT: | |
91447636 | 1045 | return (ENOSYS); |
e5568f75 | 1046 | break; |
91447636 | 1047 | } |
e5568f75 A |
1048 | /* Copy data back to userspace for the GET comands */ |
1049 | switch (uap->cmd) { | |
1050 | case A_GETPOLICY: | |
1051 | case A_GETKMASK: | |
1052 | case A_GETQCTRL: | |
1053 | case A_GETCWD: | |
1054 | case A_GETCAR: | |
1055 | case A_GETSTAT: | |
1056 | case A_GETCOND: | |
1057 | case A_GETCLASS: | |
1058 | case A_GETPINFO: | |
1059 | case A_GETFSIZE: | |
1060 | case A_GETPINFO_ADDR: | |
1061 | case A_GETKAUDIT: | |
1062 | ret = copyout((void *)&udata, uap->data, uap->length); | |
1063 | if (ret) | |
1064 | return (ret); | |
1065 | break; | |
1066 | } | |
1067 | ||
1068 | return (0); | |
55e303ae A |
1069 | } |
1070 | ||
1071 | /* | |
1072 | * System calls to manage the user audit information. | |
1073 | * XXXAUDIT May need to lock the proc structure. | |
1074 | */ | |
55e303ae A |
1075 | /* ARGSUSED */ |
1076 | int | |
91447636 | 1077 | getauid(struct proc *p, struct getauid_args *uap, __unused register_t *retval) |
55e303ae | 1078 | { |
55e303ae A |
1079 | int error; |
1080 | ||
91447636 A |
1081 | error = copyout((void *)&kauth_cred_get()->cr_au.ai_auid, |
1082 | uap->auid, sizeof(au_id_t)); | |
55e303ae A |
1083 | if (error) |
1084 | return (error); | |
1085 | ||
1086 | return (0); | |
1087 | } | |
1088 | ||
55e303ae A |
1089 | /* ARGSUSED */ |
1090 | int | |
91447636 | 1091 | setauid(struct proc *p, struct setauid_args *uap, __unused register_t *retval) |
55e303ae | 1092 | { |
55e303ae | 1093 | int error; |
91447636 | 1094 | au_id_t temp_au_id; |
55e303ae | 1095 | |
91447636 | 1096 | error = suser(kauth_cred_get(), &p->p_acflag); |
55e303ae A |
1097 | if (error) |
1098 | return (error); | |
1099 | ||
91447636 A |
1100 | error = copyin(uap->auid, |
1101 | (void *)&temp_au_id, | |
1102 | sizeof(au_id_t)); | |
55e303ae A |
1103 | if (error) |
1104 | return (error); | |
1105 | ||
91447636 A |
1106 | /* |
1107 | * we are modifying the audit info in a credential so we need a new | |
1108 | * credential (or take another reference on an existing credential that | |
1109 | * matches our new one). We must do this because the audit info in the | |
1110 | * credential is used as part of our hash key. Get current credential | |
1111 | * in the target process and take a reference while we muck with it. | |
1112 | */ | |
1113 | for (;;) { | |
1114 | kauth_cred_t my_cred, my_new_cred; | |
1115 | struct auditinfo temp_auditinfo; | |
1116 | ||
1117 | my_cred = kauth_cred_proc_ref(p); | |
1118 | /* | |
1119 | * set the credential with new info. If there is no change we get back | |
1120 | * the same credential we passed in. | |
1121 | */ | |
1122 | temp_auditinfo = my_cred->cr_au; | |
1123 | temp_auditinfo.ai_auid = temp_au_id; | |
1124 | my_new_cred = kauth_cred_setauditinfo(my_cred, &temp_auditinfo); | |
1125 | ||
1126 | if (my_cred != my_new_cred) { | |
1127 | proc_lock(p); | |
1128 | /* need to protect for a race where another thread also changed | |
1129 | * the credential after we took our reference. If p_ucred has | |
1130 | * changed then we should restart this again with the new cred. | |
1131 | */ | |
1132 | if (p->p_ucred != my_cred) { | |
1133 | proc_unlock(p); | |
1134 | kauth_cred_rele(my_cred); | |
1135 | kauth_cred_rele(my_new_cred); | |
1136 | /* try again */ | |
1137 | continue; | |
1138 | } | |
1139 | p->p_ucred = my_new_cred; | |
1140 | proc_unlock(p); | |
1141 | } | |
1142 | /* drop our extra reference */ | |
1143 | kauth_cred_rele(my_cred); | |
1144 | break; | |
1145 | } | |
1146 | ||
e5568f75 A |
1147 | /* propagate the change from the process to Mach task */ |
1148 | set_security_token(p); | |
1149 | ||
91447636 | 1150 | audit_arg_auid(kauth_cred_get()->cr_au.ai_auid); |
55e303ae A |
1151 | return (0); |
1152 | } | |
1153 | ||
1154 | /* | |
1155 | * System calls to get and set process audit information. | |
a3d08fcd A |
1156 | * If the caller is privileged, they get the whole set of |
1157 | * audit information. Otherwise, the real audit mask is | |
1158 | * filtered out - but the rest of the information is | |
1159 | * returned. | |
55e303ae | 1160 | */ |
55e303ae A |
1161 | /* ARGSUSED */ |
1162 | int | |
91447636 | 1163 | getaudit(struct proc *p, struct getaudit_args *uap, __unused register_t *retval) |
55e303ae | 1164 | { |
91447636 | 1165 | struct auditinfo ai; |
55e303ae A |
1166 | int error; |
1167 | ||
91447636 A |
1168 | ai = kauth_cred_get()->cr_au; |
1169 | ||
a3d08fcd | 1170 | /* only superuser gets to see the real mask */ |
91447636 | 1171 | error = suser(kauth_cred_get(), &p->p_acflag); |
a3d08fcd A |
1172 | if (error) { |
1173 | ai.ai_mask.am_success = ~0; | |
1174 | ai.ai_mask.am_failure = ~0; | |
1175 | } | |
1176 | ||
91447636 | 1177 | error = copyout(&ai, uap->auditinfo, sizeof(ai)); |
55e303ae A |
1178 | if (error) |
1179 | return (error); | |
1180 | ||
1181 | return (0); | |
1182 | } | |
1183 | ||
55e303ae A |
1184 | /* ARGSUSED */ |
1185 | int | |
91447636 | 1186 | setaudit(struct proc *p, struct setaudit_args *uap, __unused register_t *retval) |
55e303ae | 1187 | { |
55e303ae | 1188 | int error; |
91447636 | 1189 | struct auditinfo temp_auditinfo; |
55e303ae | 1190 | |
91447636 | 1191 | error = suser(kauth_cred_get(), &p->p_acflag); |
55e303ae A |
1192 | if (error) |
1193 | return (error); | |
91447636 A |
1194 | |
1195 | error = copyin(uap->auditinfo, | |
1196 | (void *)&temp_auditinfo, | |
1197 | sizeof(temp_auditinfo)); | |
55e303ae A |
1198 | if (error) |
1199 | return (error); | |
1200 | ||
91447636 A |
1201 | /* |
1202 | * we are modifying the audit info in a credential so we need a new | |
1203 | * credential (or take another reference on an existing credential that | |
1204 | * matches our new one). We must do this because the audit info in the | |
1205 | * credential is used as part of our hash key. Get current credential | |
1206 | * in the target process and take a reference while we muck with it. | |
1207 | */ | |
1208 | for (;;) { | |
1209 | kauth_cred_t my_cred, my_new_cred; | |
1210 | ||
1211 | my_cred = kauth_cred_proc_ref(p); | |
1212 | /* | |
1213 | * set the credential with new info. If there is no change we get back | |
1214 | * the same credential we passed in. | |
1215 | */ | |
1216 | my_new_cred = kauth_cred_setauditinfo(my_cred, &temp_auditinfo); | |
1217 | ||
1218 | if (my_cred != my_new_cred) { | |
1219 | proc_lock(p); | |
1220 | /* need to protect for a race where another thread also changed | |
1221 | * the credential after we took our reference. If p_ucred has | |
1222 | * changed then we should restart this again with the new cred. | |
1223 | */ | |
1224 | if (p->p_ucred != my_cred) { | |
1225 | proc_unlock(p); | |
1226 | kauth_cred_rele(my_cred); | |
1227 | kauth_cred_rele(my_new_cred); | |
1228 | /* try again */ | |
1229 | continue; | |
1230 | } | |
1231 | p->p_ucred = my_new_cred; | |
1232 | proc_unlock(p); | |
1233 | } | |
1234 | /* drop our extra reference */ | |
1235 | kauth_cred_rele(my_cred); | |
1236 | break; | |
1237 | } | |
1238 | ||
e5568f75 A |
1239 | /* propagate the change from the process to Mach task */ |
1240 | set_security_token(p); | |
1241 | ||
91447636 | 1242 | audit_arg_auditinfo(&p->p_ucred->cr_au); |
e5568f75 | 1243 | |
55e303ae A |
1244 | return (0); |
1245 | } | |
1246 | ||
55e303ae A |
1247 | /* ARGSUSED */ |
1248 | int | |
91447636 | 1249 | getaudit_addr(struct proc *p, __unused struct getaudit_addr_args *uap, __unused register_t *retval) |
55e303ae | 1250 | { |
55e303ae A |
1251 | return (ENOSYS); |
1252 | } | |
1253 | ||
55e303ae A |
1254 | /* ARGSUSED */ |
1255 | int | |
91447636 | 1256 | setaudit_addr(struct proc *p, __unused struct setaudit_addr_args *uap, __unused register_t *retval) |
55e303ae | 1257 | { |
55e303ae A |
1258 | int error; |
1259 | ||
91447636 | 1260 | error = suser(kauth_cred_get(), &p->p_acflag); |
55e303ae A |
1261 | if (error) |
1262 | return (error); | |
1263 | return (ENOSYS); | |
1264 | } | |
1265 | ||
1266 | /* | |
1267 | * Syscall to manage audit files. | |
1268 | * | |
55e303ae | 1269 | */ |
55e303ae A |
1270 | /* ARGSUSED */ |
1271 | int | |
91447636 | 1272 | auditctl(struct proc *p, struct auditctl_args *uap, __unused register_t *retval) |
55e303ae | 1273 | { |
55e303ae | 1274 | struct nameidata nd; |
91447636 | 1275 | kauth_cred_t cred; |
55e303ae | 1276 | struct vnode *vp; |
91447636 A |
1277 | int error, flags; |
1278 | struct vfs_context context; | |
1279 | ||
1280 | context.vc_proc = p; | |
1281 | context.vc_ucred = kauth_cred_get(); | |
55e303ae | 1282 | |
91447636 | 1283 | error = suser(kauth_cred_get(), &p->p_acflag); |
55e303ae A |
1284 | if (error) |
1285 | return (error); | |
1286 | ||
1287 | vp = NULL; | |
1288 | cred = NULL; | |
1289 | ||
1290 | /* | |
1291 | * If a path is specified, open the replacement vnode, perform | |
1292 | * validity checks, and grab another reference to the current | |
1293 | * credential. | |
1294 | */ | |
91447636 | 1295 | if (uap->path != 0) { |
e5568f75 | 1296 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, |
91447636 A |
1297 | (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), |
1298 | uap->path, &context); | |
55e303ae A |
1299 | flags = audit_open_flags; |
1300 | error = vn_open(&nd, flags, 0); | |
1301 | if (error) | |
1302 | goto out; | |
55e303ae A |
1303 | vp = nd.ni_vp; |
1304 | if (vp->v_type != VREG) { | |
91447636 A |
1305 | vn_close(vp, audit_close_flags, kauth_cred_get(), p); |
1306 | vnode_put(vp); | |
55e303ae A |
1307 | error = EINVAL; |
1308 | goto out; | |
1309 | } | |
91447636 | 1310 | cred = kauth_cred_get_with_ref(); |
e5568f75 | 1311 | audit_suspended = 0; |
55e303ae | 1312 | } |
91447636 A |
1313 | /* |
1314 | * a vp and cred of NULL is valid at this point | |
1315 | * and indicates we're to turn off auditing... | |
1316 | */ | |
55e303ae | 1317 | audit_rotate_vnode(cred, vp); |
91447636 A |
1318 | if (vp) |
1319 | vnode_put(vp); | |
55e303ae A |
1320 | out: |
1321 | return (error); | |
1322 | } | |
1323 | ||
1324 | /********************************** | |
1325 | * End of system calls. * | |
1326 | **********************************/ | |
1327 | ||
1328 | /* | |
1329 | * MPSAFE | |
1330 | */ | |
1331 | struct kaudit_record * | |
91447636 | 1332 | audit_new(int event, struct proc *p, __unused struct uthread *uthread) |
55e303ae A |
1333 | { |
1334 | struct kaudit_record *ar; | |
1335 | int no_record; | |
1336 | ||
1337 | /* | |
1338 | * Eventually, there may be certain classes of events that | |
1339 | * we will audit regardless of the audit state at the time | |
1340 | * the record is created. These events will generally | |
1341 | * correspond to changes in the audit state. The dummy | |
1342 | * code below is from our first prototype, but may also | |
1343 | * be used in the final version (with modified event numbers). | |
1344 | */ | |
1345 | #if 0 | |
1346 | if (event != AUDIT_EVENT_FILESTOP && event != AUDIT_EVENT_FILESTART) { | |
1347 | #endif | |
1348 | mutex_lock(audit_mtx); | |
1349 | no_record = (audit_suspended || !audit_enabled); | |
1350 | mutex_unlock(audit_mtx); | |
1351 | if (no_record) | |
1352 | return (NULL); | |
1353 | #if 0 | |
1354 | } | |
1355 | #endif | |
1356 | ||
55e303ae A |
1357 | /* |
1358 | * Initialize the audit record header. | |
55e303ae | 1359 | * XXX: We may want to fail-stop if allocation fails. |
e5568f75 A |
1360 | * XXX: The number of outstanding uncommitted audit records is |
1361 | * limited by the number of concurrent threads servicing system | |
1362 | * calls in the kernel. | |
55e303ae | 1363 | */ |
e5568f75 A |
1364 | |
1365 | ar = (struct kaudit_record *)zalloc(audit_zone); | |
55e303ae A |
1366 | if (ar == NULL) |
1367 | return NULL; | |
1368 | ||
e5568f75 A |
1369 | mutex_lock(audit_mtx); |
1370 | audit_pre_q_len++; | |
1371 | mutex_unlock(audit_mtx); | |
1372 | ||
55e303ae A |
1373 | bzero(ar, sizeof(*ar)); |
1374 | ar->k_ar.ar_magic = AUDIT_RECORD_MAGIC; | |
1375 | ar->k_ar.ar_event = event; | |
1376 | nanotime(&ar->k_ar.ar_starttime); | |
1377 | ||
1378 | /* Export the subject credential. */ | |
1379 | cru2x(p->p_ucred, &ar->k_ar.ar_subj_cred); | |
91447636 A |
1380 | ar->k_ar.ar_subj_ruid = p->p_ucred->cr_ruid; |
1381 | ar->k_ar.ar_subj_rgid = p->p_ucred->cr_rgid; | |
55e303ae | 1382 | ar->k_ar.ar_subj_egid = p->p_ucred->cr_groups[0]; |
91447636 A |
1383 | ar->k_ar.ar_subj_auid = p->p_ucred->cr_au.ai_auid; |
1384 | ar->k_ar.ar_subj_asid = p->p_ucred->cr_au.ai_asid; | |
55e303ae | 1385 | ar->k_ar.ar_subj_pid = p->p_pid; |
91447636 A |
1386 | ar->k_ar.ar_subj_amask = p->p_ucred->cr_au.ai_mask; |
1387 | ar->k_ar.ar_subj_term = p->p_ucred->cr_au.ai_termid; | |
55e303ae | 1388 | bcopy(p->p_comm, ar->k_ar.ar_subj_comm, MAXCOMLEN); |
55e303ae A |
1389 | |
1390 | return (ar); | |
1391 | } | |
1392 | ||
1393 | /* | |
1394 | * MPSAFE | |
1395 | * XXXAUDIT: So far, this is unused, and should probably be GC'd. | |
1396 | */ | |
1397 | void | |
1398 | audit_abort(struct kaudit_record *ar) | |
1399 | { | |
e5568f75 A |
1400 | mutex_lock(audit_mtx); |
1401 | audit_pre_q_len--; | |
1402 | mutex_unlock(audit_mtx); | |
55e303ae A |
1403 | audit_free(ar); |
1404 | } | |
1405 | ||
1406 | /* | |
1407 | * MPSAFE | |
1408 | */ | |
1409 | void | |
1410 | audit_commit(struct kaudit_record *ar, int error, int retval) | |
1411 | { | |
e5568f75 A |
1412 | int ret; |
1413 | int sorf; | |
1414 | struct au_mask *aumask; | |
55e303ae A |
1415 | |
1416 | if (ar == NULL) | |
1417 | return; | |
1418 | ||
e5568f75 A |
1419 | /* |
1420 | * Decide whether to commit the audit record by checking the | |
1421 | * error value from the system call and using the appropriate | |
1422 | * audit mask. | |
1423 | */ | |
1424 | if (ar->k_ar.ar_subj_auid == AU_DEFAUDITID) | |
1425 | aumask = &audit_nae_mask; | |
1426 | else | |
1427 | aumask = &ar->k_ar.ar_subj_amask; | |
1428 | ||
1429 | if (error) | |
1430 | sorf = AU_PRS_FAILURE; | |
1431 | else | |
1432 | sorf = AU_PRS_SUCCESS; | |
1433 | ||
1434 | switch(ar->k_ar.ar_event) { | |
1435 | ||
1436 | case AUE_OPEN_RWTC: | |
1437 | /* The open syscall always writes a OPEN_RWTC event; limit the | |
1438 | * to the proper type of event based on the flags and the error | |
1439 | * value. | |
1440 | */ | |
1441 | ar->k_ar.ar_event = flags_and_error_to_openevent(ar->k_ar.ar_arg_fflags, error); | |
1442 | break; | |
1443 | ||
1444 | case AUE_SYSCTL: | |
1445 | ar->k_ar.ar_event = ctlname_to_sysctlevent(ar->k_ar.ar_arg_ctlname, ar->k_ar.ar_valid_arg); | |
1446 | break; | |
1447 | ||
1448 | case AUE_AUDITON: | |
1449 | /* Convert the auditon() command to an event */ | |
1450 | ar->k_ar.ar_event = auditon_command_event(ar->k_ar.ar_arg_cmd); | |
1451 | break; | |
1452 | } | |
1453 | ||
1454 | if (au_preselect(ar->k_ar.ar_event, aumask, sorf) != 0) | |
1455 | ar->k_ar_commit |= AR_COMMIT_KERNEL; | |
1456 | ||
91447636 | 1457 | if ((ar->k_ar_commit & (AR_COMMIT_USER | AR_COMMIT_KERNEL)) == 0) { |
e5568f75 A |
1458 | mutex_lock(audit_mtx); |
1459 | audit_pre_q_len--; | |
1460 | mutex_unlock(audit_mtx); | |
1461 | audit_free(ar); | |
1462 | return; | |
1463 | } | |
1464 | ||
55e303ae A |
1465 | ar->k_ar.ar_errno = error; |
1466 | ar->k_ar.ar_retval = retval; | |
1467 | ||
1468 | /* | |
1469 | * We might want to do some system-wide post-filtering | |
1470 | * here at some point. | |
1471 | */ | |
1472 | ||
1473 | /* | |
1474 | * Timestamp system call end. | |
1475 | */ | |
1476 | nanotime(&ar->k_ar.ar_endtime); | |
1477 | ||
55e303ae A |
1478 | mutex_lock(audit_mtx); |
1479 | /* | |
1480 | * Note: it could be that some records initiated while audit was | |
1481 | * enabled should still be committed? | |
1482 | */ | |
1483 | if (audit_suspended || !audit_enabled) { | |
e5568f75 | 1484 | audit_pre_q_len--; |
55e303ae A |
1485 | mutex_unlock(audit_mtx); |
1486 | audit_free(ar); | |
1487 | return; | |
1488 | } | |
91447636 | 1489 | |
e5568f75 A |
1490 | /* |
1491 | * Constrain the number of committed audit records based on | |
1492 | * the configurable parameter. | |
1493 | */ | |
1494 | while (audit_q_len >= audit_qctrl.aq_hiwater) { | |
1495 | ||
1496 | ret = wait_queue_assert_wait(audit_wait_queue, | |
1497 | AUDIT_COMMIT_EVENT, | |
91447636 A |
1498 | THREAD_UNINT, |
1499 | 0); | |
e5568f75 A |
1500 | mutex_unlock(audit_mtx); |
1501 | ||
1502 | assert(ret == THREAD_WAITING); | |
1503 | ||
1504 | ret = thread_block(THREAD_CONTINUE_NULL); | |
1505 | assert(ret == THREAD_AWAKENED); | |
1506 | mutex_lock(audit_mtx); | |
1507 | } | |
1508 | ||
55e303ae | 1509 | TAILQ_INSERT_TAIL(&audit_q, ar, k_q); |
e5568f75 A |
1510 | audit_q_len++; |
1511 | audit_pre_q_len--; | |
1512 | wait_queue_wakeup_one(audit_wait_queue, AUDIT_WORKER_EVENT, THREAD_AWAKENED); | |
55e303ae A |
1513 | mutex_unlock(audit_mtx); |
1514 | } | |
1515 | ||
1516 | /* | |
1517 | * Calls to set up and tear down audit structures associated with | |
1518 | * each system call. | |
1519 | */ | |
1520 | void | |
1521 | audit_syscall_enter(unsigned short code, struct proc *proc, | |
1522 | struct uthread *uthread) | |
1523 | { | |
1524 | int audit_event; | |
e5568f75 | 1525 | struct au_mask *aumask; |
55e303ae A |
1526 | |
1527 | audit_event = sys_au_event[code]; | |
e5568f75 A |
1528 | if (audit_event == AUE_NULL) |
1529 | return; | |
1530 | ||
1531 | assert(uthread->uu_ar == NULL); | |
55e303ae | 1532 | |
e5568f75 A |
1533 | /* Check which audit mask to use; either the kernel non-attributable |
1534 | * event mask or the process audit mask. | |
1535 | */ | |
91447636 | 1536 | if (proc->p_ucred->cr_au.ai_auid == AU_DEFAUDITID) |
e5568f75 A |
1537 | aumask = &audit_nae_mask; |
1538 | else | |
91447636 A |
1539 | aumask = &proc->p_ucred->cr_au.ai_mask; |
1540 | ||
55e303ae | 1541 | /* |
e5568f75 A |
1542 | * Allocate an audit record, if preselection allows it, and store |
1543 | * in the BSD thread for later use. | |
55e303ae | 1544 | */ |
e5568f75 | 1545 | if (au_preselect(audit_event, aumask, |
91447636 | 1546 | AU_PRS_FAILURE | AU_PRS_SUCCESS)) { |
e5568f75 A |
1547 | /* |
1548 | * If we're out of space and need to suspend unprivileged | |
1549 | * processes, do that here rather than trying to allocate | |
1550 | * another audit record. | |
1551 | */ | |
1552 | if (audit_in_failure && | |
91447636 | 1553 | suser(kauth_cred_get(), &proc->p_acflag) != 0) { |
e5568f75 A |
1554 | int ret; |
1555 | ||
91447636 | 1556 | assert(audit_worker_thread != THREAD_NULL); |
e5568f75 | 1557 | ret = wait_queue_assert_wait(audit_wait_queue, |
91447636 | 1558 | AUDIT_FAILURE_EVENT, THREAD_UNINT, 0); |
e5568f75 A |
1559 | assert(ret == THREAD_WAITING); |
1560 | (void)thread_block(THREAD_CONTINUE_NULL); | |
1561 | panic("audit_failing_stop: thread continued"); | |
55e303ae | 1562 | } |
91447636 A |
1563 | uthread->uu_ar = audit_new(audit_event, proc, uthread); |
1564 | } else { | |
1565 | uthread->uu_ar = NULL; | |
1566 | } | |
1567 | } | |
55e303ae A |
1568 | |
1569 | void | |
91447636 | 1570 | audit_syscall_exit(int error, AUDIT_PRINTF_ONLY struct proc *proc, struct uthread *uthread) |
55e303ae A |
1571 | { |
1572 | int retval; | |
1573 | ||
1574 | /* | |
1575 | * Commit the audit record as desired; once we pass the record | |
1576 | * into audit_commit(), the memory is owned by the audit | |
1577 | * subsystem. | |
1578 | * The return value from the system call is stored on the user | |
1579 | * thread. If there was an error, the return value is set to -1, | |
1580 | * imitating the behavior of the cerror routine. | |
1581 | */ | |
1582 | if (error) | |
1583 | retval = -1; | |
1584 | else | |
1585 | retval = uthread->uu_rval[0]; | |
1586 | ||
1587 | audit_commit(uthread->uu_ar, error, retval); | |
91447636 | 1588 | if (uthread->uu_ar != NULL) { |
55e303ae | 1589 | AUDIT_PRINTF(("audit record committed by pid %d\n", proc->p_pid)); |
91447636 | 1590 | } |
55e303ae A |
1591 | uthread->uu_ar = NULL; |
1592 | ||
1593 | } | |
1594 | ||
e5568f75 A |
1595 | /* |
1596 | * Calls to set up and tear down audit structures used during Mach | |
1597 | * system calls. | |
1598 | */ | |
1599 | void | |
1600 | audit_mach_syscall_enter(unsigned short audit_event) | |
1601 | { | |
1602 | struct uthread *uthread; | |
1603 | struct proc *proc; | |
1604 | struct au_mask *aumask; | |
1605 | ||
1606 | if (audit_event == AUE_NULL) | |
1607 | return; | |
1608 | ||
1609 | uthread = curuthread(); | |
1610 | if (uthread == NULL) | |
1611 | return; | |
1612 | ||
1613 | proc = current_proc(); | |
1614 | if (proc == NULL) | |
1615 | return; | |
1616 | ||
1617 | assert(uthread->uu_ar == NULL); | |
1618 | ||
1619 | /* Check which audit mask to use; either the kernel non-attributable | |
1620 | * event mask or the process audit mask. | |
1621 | */ | |
91447636 | 1622 | if (proc->p_ucred->cr_au.ai_auid == AU_DEFAUDITID) |
e5568f75 A |
1623 | aumask = &audit_nae_mask; |
1624 | else | |
91447636 | 1625 | aumask = &proc->p_ucred->cr_au.ai_mask; |
e5568f75 A |
1626 | |
1627 | /* | |
1628 | * Allocate an audit record, if desired, and store in the BSD | |
1629 | * thread for later use. | |
1630 | */ | |
1631 | if (au_preselect(audit_event, aumask, | |
1632 | AU_PRS_FAILURE | AU_PRS_SUCCESS)) { | |
1633 | uthread->uu_ar = audit_new(audit_event, proc, uthread); | |
1634 | } else { | |
1635 | uthread->uu_ar = NULL; | |
1636 | } | |
1637 | } | |
1638 | ||
1639 | void | |
1640 | audit_mach_syscall_exit(int retval, struct uthread *uthread) | |
1641 | { | |
1642 | /* The error code from Mach system calls is the same as the | |
1643 | * return value | |
1644 | */ | |
1645 | /* XXX Is the above statement always true? */ | |
1646 | audit_commit(uthread->uu_ar, retval, retval); | |
1647 | uthread->uu_ar = NULL; | |
1648 | ||
1649 | } | |
1650 | ||
55e303ae A |
1651 | /* |
1652 | * Calls to manipulate elements of the audit record structure from system | |
1653 | * call code. Macro wrappers will prevent this functions from being | |
1654 | * entered if auditing is disabled, avoiding the function call cost. We | |
1655 | * check the thread audit record pointer anyway, as the audit condition | |
1656 | * could change, and pre-selection may not have allocated an audit | |
1657 | * record for this event. | |
1658 | */ | |
1659 | void | |
91447636 | 1660 | audit_arg_addr(user_addr_t addr) |
55e303ae A |
1661 | { |
1662 | struct kaudit_record *ar; | |
1663 | ||
1664 | ar = currecord(); | |
1665 | if (ar == NULL) | |
1666 | return; | |
1667 | ||
91447636 | 1668 | ar->k_ar.ar_arg_addr = CAST_DOWN(void *, addr); /* XXX */ |
e5568f75 | 1669 | ar->k_ar.ar_valid_arg |= ARG_ADDR; |
55e303ae A |
1670 | } |
1671 | ||
1672 | void | |
91447636 | 1673 | audit_arg_len(user_size_t len) |
55e303ae A |
1674 | { |
1675 | struct kaudit_record *ar; | |
1676 | ||
1677 | ar = currecord(); | |
1678 | if (ar == NULL) | |
1679 | return; | |
1680 | ||
91447636 | 1681 | ar->k_ar.ar_arg_len = CAST_DOWN(int, len); /* XXX */ |
e5568f75 | 1682 | ar->k_ar.ar_valid_arg |= ARG_LEN; |
55e303ae A |
1683 | } |
1684 | ||
1685 | void | |
1686 | audit_arg_fd(int fd) | |
1687 | { | |
1688 | struct kaudit_record *ar; | |
1689 | ||
1690 | ar = currecord(); | |
1691 | if (ar == NULL) | |
1692 | return; | |
1693 | ||
1694 | ar->k_ar.ar_arg_fd = fd; | |
1695 | ar->k_ar.ar_valid_arg |= ARG_FD; | |
1696 | } | |
1697 | ||
1698 | void | |
1699 | audit_arg_fflags(int fflags) | |
1700 | { | |
1701 | struct kaudit_record *ar; | |
1702 | ||
1703 | ar = currecord(); | |
1704 | if (ar == NULL) | |
1705 | return; | |
1706 | ||
1707 | ar->k_ar.ar_arg_fflags = fflags; | |
1708 | ar->k_ar.ar_valid_arg |= ARG_FFLAGS; | |
1709 | } | |
1710 | ||
1711 | void | |
1712 | audit_arg_gid(gid_t gid, gid_t egid, gid_t rgid, gid_t sgid) | |
1713 | { | |
1714 | struct kaudit_record *ar; | |
1715 | ||
1716 | ar = currecord(); | |
1717 | if (ar == NULL) | |
1718 | return; | |
1719 | ||
1720 | ar->k_ar.ar_arg_gid = gid; | |
1721 | ar->k_ar.ar_arg_egid = egid; | |
1722 | ar->k_ar.ar_arg_rgid = rgid; | |
1723 | ar->k_ar.ar_arg_sgid = sgid; | |
1724 | ar->k_ar.ar_valid_arg |= (ARG_GID | ARG_EGID | ARG_RGID | ARG_SGID); | |
1725 | } | |
1726 | ||
1727 | void | |
1728 | audit_arg_uid(uid_t uid, uid_t euid, uid_t ruid, uid_t suid) | |
1729 | { | |
1730 | struct kaudit_record *ar; | |
1731 | ||
1732 | ar = currecord(); | |
1733 | if (ar == NULL) | |
1734 | return; | |
1735 | ||
1736 | ar->k_ar.ar_arg_uid = uid; | |
1737 | ar->k_ar.ar_arg_euid = euid; | |
1738 | ar->k_ar.ar_arg_ruid = ruid; | |
1739 | ar->k_ar.ar_arg_suid = suid; | |
1740 | ar->k_ar.ar_valid_arg |= (ARG_UID | ARG_EUID | ARG_RUID | ARG_SUID); | |
1741 | } | |
1742 | ||
1743 | void | |
91447636 | 1744 | audit_arg_groupset(const gid_t *gidset, u_int gidset_size) |
55e303ae | 1745 | { |
91447636 | 1746 | uint i; |
55e303ae A |
1747 | struct kaudit_record *ar; |
1748 | ||
1749 | ar = currecord(); | |
1750 | if (ar == NULL) | |
1751 | return; | |
1752 | ||
1753 | for (i = 0; i < gidset_size; i++) | |
1754 | ar->k_ar.ar_arg_groups.gidset[i] = gidset[i]; | |
1755 | ar->k_ar.ar_arg_groups.gidset_size = gidset_size; | |
1756 | ar->k_ar.ar_valid_arg |= ARG_GROUPSET; | |
1757 | } | |
1758 | ||
1759 | void | |
91447636 | 1760 | audit_arg_login(const char *login) |
55e303ae A |
1761 | { |
1762 | struct kaudit_record *ar; | |
1763 | ||
1764 | ar = currecord(); | |
1765 | if (ar == NULL) | |
1766 | return; | |
1767 | ||
1768 | #if 0 | |
1769 | /* | |
1770 | * XXX: Add strlcpy() to Darwin for improved safety. | |
1771 | */ | |
1772 | strlcpy(ar->k_ar.ar_arg_login, login, MAXLOGNAME); | |
1773 | #else | |
1774 | strcpy(ar->k_ar.ar_arg_login, login); | |
1775 | #endif | |
1776 | ||
1777 | ar->k_ar.ar_valid_arg |= ARG_LOGIN; | |
1778 | } | |
1779 | ||
e5568f75 | 1780 | void |
91447636 | 1781 | audit_arg_ctlname(const int *name, int namelen) |
e5568f75 A |
1782 | { |
1783 | struct kaudit_record *ar; | |
1784 | ||
1785 | ar = currecord(); | |
1786 | if (ar == NULL) | |
1787 | return; | |
1788 | ||
1789 | bcopy(name, &ar->k_ar.ar_arg_ctlname, namelen * sizeof(int)); | |
1790 | ar->k_ar.ar_arg_len = namelen; | |
1791 | ar->k_ar.ar_valid_arg |= (ARG_CTLNAME | ARG_LEN); | |
1792 | } | |
1793 | ||
55e303ae A |
1794 | void |
1795 | audit_arg_mask(int mask) | |
1796 | { | |
1797 | struct kaudit_record *ar; | |
1798 | ||
1799 | ar = currecord(); | |
1800 | if (ar == NULL) | |
1801 | return; | |
1802 | ||
1803 | ar->k_ar.ar_arg_mask = mask; | |
1804 | ar->k_ar.ar_valid_arg |= ARG_MASK; | |
1805 | } | |
1806 | ||
1807 | void | |
1808 | audit_arg_mode(mode_t mode) | |
1809 | { | |
1810 | struct kaudit_record *ar; | |
1811 | ||
1812 | ar = currecord(); | |
1813 | if (ar == NULL) | |
1814 | return; | |
1815 | ||
1816 | ar->k_ar.ar_arg_mode = mode; | |
1817 | ar->k_ar.ar_valid_arg |= ARG_MODE; | |
1818 | } | |
1819 | ||
1820 | void | |
1821 | audit_arg_dev(int dev) | |
1822 | { | |
1823 | struct kaudit_record *ar; | |
1824 | ||
1825 | ar = currecord(); | |
1826 | if (ar == NULL) | |
1827 | return; | |
1828 | ||
1829 | ar->k_ar.ar_arg_dev = dev; | |
1830 | ar->k_ar.ar_valid_arg |= ARG_DEV; | |
1831 | } | |
1832 | ||
e5568f75 A |
1833 | void |
1834 | audit_arg_value(long value) | |
1835 | { | |
1836 | struct kaudit_record *ar; | |
1837 | ||
1838 | ar = currecord(); | |
1839 | if (ar == NULL) | |
1840 | return; | |
1841 | ||
1842 | ar->k_ar.ar_arg_value = value; | |
1843 | ar->k_ar.ar_valid_arg |= ARG_VALUE; | |
1844 | } | |
1845 | ||
55e303ae A |
1846 | void |
1847 | audit_arg_owner(uid_t uid, gid_t gid) | |
1848 | { | |
1849 | struct kaudit_record *ar; | |
1850 | ||
1851 | ar = currecord(); | |
1852 | if (ar == NULL) | |
1853 | return; | |
1854 | ||
1855 | ar->k_ar.ar_arg_uid = uid; | |
1856 | ar->k_ar.ar_arg_gid = gid; | |
1857 | ar->k_ar.ar_valid_arg |= (ARG_UID | ARG_GID); | |
1858 | } | |
1859 | ||
1860 | void | |
1861 | audit_arg_pid(pid_t pid) | |
1862 | { | |
1863 | struct kaudit_record *ar; | |
1864 | ||
1865 | ar = currecord(); | |
1866 | if (ar == NULL) | |
1867 | return; | |
1868 | ||
1869 | ar->k_ar.ar_arg_pid = pid; | |
1870 | ar->k_ar.ar_valid_arg |= ARG_PID; | |
e5568f75 A |
1871 | } |
1872 | ||
1873 | void | |
1874 | audit_arg_process(struct proc *p) | |
1875 | { | |
1876 | struct kaudit_record *ar; | |
1877 | ||
1878 | ar = currecord(); | |
1879 | if ((ar == NULL) || (p == NULL)) | |
1880 | return; | |
1881 | ||
91447636 | 1882 | ar->k_ar.ar_arg_auid = p->p_ucred->cr_au.ai_auid; |
e5568f75 A |
1883 | ar->k_ar.ar_arg_euid = p->p_ucred->cr_uid; |
1884 | ar->k_ar.ar_arg_egid = p->p_ucred->cr_groups[0]; | |
91447636 A |
1885 | ar->k_ar.ar_arg_ruid = p->p_ucred->cr_ruid; |
1886 | ar->k_ar.ar_arg_rgid = p->p_ucred->cr_rgid; | |
1887 | ar->k_ar.ar_arg_asid = p->p_ucred->cr_au.ai_asid; | |
1888 | ar->k_ar.ar_arg_termid = p->p_ucred->cr_au.ai_termid; | |
e5568f75 A |
1889 | |
1890 | ar->k_ar.ar_valid_arg |= ARG_AUID | ARG_EUID | ARG_EGID | ARG_RUID | | |
1891 | ARG_RGID | ARG_ASID | ARG_TERMID | ARG_PROCESS; | |
55e303ae A |
1892 | } |
1893 | ||
1894 | void | |
1895 | audit_arg_signum(u_int signum) | |
1896 | { | |
1897 | struct kaudit_record *ar; | |
1898 | ||
1899 | ar = currecord(); | |
1900 | if (ar == NULL) | |
1901 | return; | |
1902 | ||
1903 | ar->k_ar.ar_arg_signum = signum; | |
1904 | ar->k_ar.ar_valid_arg |= ARG_SIGNUM; | |
1905 | } | |
1906 | ||
1907 | void | |
1908 | audit_arg_socket(int sodomain, int sotype, int soprotocol) | |
1909 | { | |
1910 | ||
1911 | struct kaudit_record *ar; | |
1912 | ||
1913 | ar = currecord(); | |
1914 | if (ar == NULL) | |
1915 | return; | |
1916 | ||
e5568f75 A |
1917 | ar->k_ar.ar_arg_sockinfo.so_domain = sodomain; |
1918 | ar->k_ar.ar_arg_sockinfo.so_type = sotype; | |
1919 | ar->k_ar.ar_arg_sockinfo.so_protocol = soprotocol; | |
55e303ae A |
1920 | ar->k_ar.ar_valid_arg |= ARG_SOCKINFO; |
1921 | } | |
1922 | ||
1923 | void | |
1924 | audit_arg_sockaddr(struct proc *p, struct sockaddr *so) | |
1925 | { | |
1926 | struct kaudit_record *ar; | |
1927 | ||
1928 | ar = currecord(); | |
1929 | if (ar == NULL || p == NULL || so == NULL) | |
1930 | return; | |
1931 | ||
1932 | bcopy(so, &ar->k_ar.ar_arg_sockaddr, sizeof(ar->k_ar.ar_arg_sockaddr)); | |
1933 | switch (so->sa_family) { | |
1934 | case AF_INET: | |
1935 | ar->k_ar.ar_valid_arg |= ARG_SADDRINET; | |
1936 | break; | |
1937 | case AF_INET6: | |
1938 | ar->k_ar.ar_valid_arg |= ARG_SADDRINET6; | |
1939 | break; | |
1940 | case AF_UNIX: | |
1941 | audit_arg_upath(p, ((struct sockaddr_un *)so)->sun_path, | |
1942 | ARG_UPATH1); | |
1943 | ar->k_ar.ar_valid_arg |= ARG_SADDRUNIX; | |
1944 | break; | |
1945 | } | |
1946 | } | |
1947 | ||
1948 | void | |
1949 | audit_arg_auid(uid_t auid) | |
1950 | { | |
1951 | struct kaudit_record *ar; | |
1952 | ||
1953 | ar = currecord(); | |
1954 | if (ar == NULL) | |
1955 | return; | |
1956 | ||
1957 | ar->k_ar.ar_arg_auid = auid; | |
1958 | ar->k_ar.ar_valid_arg |= ARG_AUID; | |
1959 | } | |
1960 | ||
e5568f75 | 1961 | void |
91447636 | 1962 | audit_arg_auditinfo(const struct auditinfo *au_info) |
e5568f75 A |
1963 | { |
1964 | struct kaudit_record *ar; | |
1965 | ||
1966 | ar = currecord(); | |
1967 | if (ar == NULL) | |
1968 | return; | |
1969 | ||
1970 | ar->k_ar.ar_arg_auid = au_info->ai_auid; | |
1971 | ar->k_ar.ar_arg_asid = au_info->ai_asid; | |
1972 | ar->k_ar.ar_arg_amask.am_success = au_info->ai_mask.am_success; | |
1973 | ar->k_ar.ar_arg_amask.am_failure = au_info->ai_mask.am_failure; | |
1974 | ar->k_ar.ar_arg_termid.port = au_info->ai_termid.port; | |
1975 | ar->k_ar.ar_arg_termid.machine = au_info->ai_termid.machine; | |
1976 | ar->k_ar.ar_valid_arg |= ARG_AUID | ARG_ASID | ARG_AMASK | ARG_TERMID; | |
1977 | } | |
1978 | ||
55e303ae | 1979 | void |
91447636 | 1980 | audit_arg_text(const char *text) |
55e303ae A |
1981 | { |
1982 | struct kaudit_record *ar; | |
1983 | ||
1984 | ar = currecord(); | |
1985 | if (ar == NULL) | |
1986 | return; | |
1987 | ||
1988 | /* Invalidate the text string */ | |
1989 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_TEXT); | |
1990 | if (text == NULL) | |
1991 | return; | |
1992 | ||
1993 | if (ar->k_ar.ar_arg_text == NULL) { | |
e5568f75 | 1994 | ar->k_ar.ar_arg_text = (char *)kalloc(MAXPATHLEN); |
55e303ae A |
1995 | if (ar->k_ar.ar_arg_text == NULL) |
1996 | return; | |
1997 | } | |
1998 | ||
e5568f75 | 1999 | strncpy(ar->k_ar.ar_arg_text, text, MAXPATHLEN); |
55e303ae A |
2000 | ar->k_ar.ar_valid_arg |= ARG_TEXT; |
2001 | } | |
2002 | ||
2003 | void | |
2004 | audit_arg_cmd(int cmd) | |
2005 | { | |
2006 | struct kaudit_record *ar; | |
2007 | ||
2008 | ar = currecord(); | |
2009 | if (ar == NULL) | |
2010 | return; | |
2011 | ||
2012 | ar->k_ar.ar_arg_cmd = cmd; | |
2013 | ar->k_ar.ar_valid_arg |= ARG_CMD; | |
2014 | } | |
2015 | ||
2016 | void | |
2017 | audit_arg_svipc_cmd(int cmd) | |
2018 | { | |
2019 | struct kaudit_record *ar; | |
2020 | ||
2021 | ar = currecord(); | |
2022 | if (ar == NULL) | |
2023 | return; | |
2024 | ||
2025 | ar->k_ar.ar_arg_svipc_cmd = cmd; | |
2026 | ar->k_ar.ar_valid_arg |= ARG_SVIPC_CMD; | |
2027 | } | |
2028 | ||
2029 | void | |
91447636 | 2030 | audit_arg_svipc_perm(const struct ipc_perm *perm) |
55e303ae A |
2031 | { |
2032 | struct kaudit_record *ar; | |
2033 | ||
2034 | ar = currecord(); | |
2035 | if (ar == NULL) | |
2036 | return; | |
2037 | ||
2038 | bcopy(perm, &ar->k_ar.ar_arg_svipc_perm, | |
2039 | sizeof(ar->k_ar.ar_arg_svipc_perm)); | |
2040 | ar->k_ar.ar_valid_arg |= ARG_SVIPC_PERM; | |
2041 | } | |
2042 | ||
2043 | void | |
2044 | audit_arg_svipc_id(int id) | |
2045 | { | |
2046 | struct kaudit_record *ar; | |
2047 | ||
2048 | ar = currecord(); | |
2049 | if (ar == NULL) | |
2050 | return; | |
2051 | ||
2052 | ar->k_ar.ar_arg_svipc_id = id; | |
2053 | ar->k_ar.ar_valid_arg |= ARG_SVIPC_ID; | |
2054 | } | |
2055 | ||
2056 | void | |
2057 | audit_arg_svipc_addr(void * addr) | |
2058 | { | |
2059 | struct kaudit_record *ar; | |
2060 | ||
2061 | ar = currecord(); | |
2062 | if (ar == NULL) | |
2063 | return; | |
2064 | ||
2065 | ar->k_ar.ar_arg_svipc_addr = addr; | |
2066 | ar->k_ar.ar_valid_arg |= ARG_SVIPC_ADDR; | |
2067 | } | |
2068 | ||
e5568f75 A |
2069 | void |
2070 | audit_arg_posix_ipc_perm(uid_t uid, gid_t gid, mode_t mode) | |
2071 | { | |
2072 | struct kaudit_record *ar; | |
2073 | ||
2074 | ar = currecord(); | |
2075 | if (ar == NULL) | |
2076 | return; | |
2077 | ||
2078 | ar->k_ar.ar_arg_pipc_perm.pipc_uid = uid; | |
2079 | ar->k_ar.ar_arg_pipc_perm.pipc_gid = gid; | |
2080 | ar->k_ar.ar_arg_pipc_perm.pipc_mode = mode; | |
2081 | ar->k_ar.ar_valid_arg |= ARG_POSIX_IPC_PERM; | |
2082 | } | |
2083 | ||
2084 | void | |
91447636 | 2085 | audit_arg_auditon(const union auditon_udata *udata) |
e5568f75 A |
2086 | { |
2087 | struct kaudit_record *ar; | |
2088 | ||
2089 | ar = currecord(); | |
2090 | if (ar == NULL) | |
2091 | return; | |
2092 | ||
91447636 | 2093 | bcopy((const void *)udata, &ar->k_ar.ar_arg_auditon, |
e5568f75 A |
2094 | sizeof(ar->k_ar.ar_arg_auditon)); |
2095 | ar->k_ar.ar_valid_arg |= ARG_AUDITON; | |
2096 | } | |
2097 | ||
91447636 | 2098 | /* |
e5568f75 A |
2099 | * Audit information about a file, either the file's vnode info, or its |
2100 | * socket address info. | |
2101 | */ | |
2102 | void | |
91447636 | 2103 | audit_arg_file(__unused struct proc *p, const struct fileproc *fp) |
e5568f75 A |
2104 | { |
2105 | struct kaudit_record *ar; | |
2106 | struct socket *so; | |
2107 | struct inpcb *pcb; | |
2108 | ||
91447636 A |
2109 | if (fp->f_fglob->fg_type == DTYPE_VNODE) { |
2110 | audit_arg_vnpath_withref((struct vnode *)fp->f_fglob->fg_data, ARG_VNODE1); | |
e5568f75 A |
2111 | return; |
2112 | } | |
2113 | ||
91447636 | 2114 | if (fp->f_fglob->fg_type == DTYPE_SOCKET) { |
e5568f75 A |
2115 | ar = currecord(); |
2116 | if (ar == NULL) | |
2117 | return; | |
91447636 | 2118 | so = (struct socket *)fp->f_fglob->fg_data; |
e5568f75 A |
2119 | if (INP_CHECK_SOCKAF(so, PF_INET)) { |
2120 | if (so->so_pcb == NULL) | |
2121 | return; | |
2122 | ar->k_ar.ar_arg_sockinfo.so_type = | |
2123 | so->so_type; | |
2124 | ar->k_ar.ar_arg_sockinfo.so_domain = | |
2125 | INP_SOCKAF(so); | |
2126 | ar->k_ar.ar_arg_sockinfo.so_protocol = | |
2127 | so->so_proto->pr_protocol; | |
2128 | pcb = (struct inpcb *)so->so_pcb; | |
2129 | ar->k_ar.ar_arg_sockinfo.so_raddr = | |
2130 | pcb->inp_faddr.s_addr; | |
2131 | ar->k_ar.ar_arg_sockinfo.so_laddr = | |
2132 | pcb->inp_laddr.s_addr; | |
2133 | ar->k_ar.ar_arg_sockinfo.so_rport = | |
2134 | pcb->inp_fport; | |
2135 | ar->k_ar.ar_arg_sockinfo.so_lport = | |
2136 | pcb->inp_lport; | |
2137 | ar->k_ar.ar_valid_arg |= ARG_SOCKINFO; | |
2138 | } | |
2139 | } | |
2140 | ||
2141 | } | |
2142 | ||
55e303ae A |
2143 | |
2144 | /* | |
2145 | * Store a path as given by the user process for auditing into the audit | |
2146 | * record stored on the user thread. This function will allocate the memory to | |
2147 | * store the path info if not already available. This memory will be | |
2148 | * freed when the audit record is freed. | |
2149 | */ | |
2150 | void | |
2151 | audit_arg_upath(struct proc *p, char *upath, u_int64_t flags) | |
2152 | { | |
2153 | struct kaudit_record *ar; | |
2154 | char **pathp; | |
2155 | ||
2156 | if (p == NULL || upath == NULL) | |
2157 | return; /* nothing to do! */ | |
2158 | ||
91447636 | 2159 | if ((flags & (ARG_UPATH1 | ARG_UPATH2)) == 0) |
55e303ae A |
2160 | return; |
2161 | ||
2162 | ar = currecord(); | |
2163 | if (ar == NULL) /* This will be the case for unaudited system calls */ | |
2164 | return; | |
2165 | ||
2166 | if (flags & ARG_UPATH1) { | |
2167 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_UPATH1); | |
2168 | pathp = &ar->k_ar.ar_arg_upath1; | |
2169 | } | |
2170 | else { | |
2171 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_UPATH2); | |
2172 | pathp = &ar->k_ar.ar_arg_upath2; | |
2173 | } | |
2174 | ||
2175 | if (*pathp == NULL) { | |
e5568f75 | 2176 | *pathp = (char *)kalloc(MAXPATHLEN); |
55e303ae A |
2177 | if (*pathp == NULL) |
2178 | return; | |
2179 | } | |
2180 | ||
e5568f75 A |
2181 | if (canon_path(p, upath, *pathp) == 0) { |
2182 | if (flags & ARG_UPATH1) | |
2183 | ar->k_ar.ar_valid_arg |= ARG_UPATH1; | |
2184 | else | |
2185 | ar->k_ar.ar_valid_arg |= ARG_UPATH2; | |
91447636 A |
2186 | } else { |
2187 | kfree(*pathp, MAXPATHLEN); | |
2188 | *pathp = NULL; | |
e5568f75 | 2189 | } |
55e303ae A |
2190 | } |
2191 | ||
2192 | /* | |
2193 | * Function to save the path and vnode attr information into the audit | |
2194 | * record. | |
2195 | * | |
2196 | * It is assumed that the caller will hold any vnode locks necessary to | |
91447636 | 2197 | * perform a VNOP_GETATTR() on the passed vnode. |
55e303ae A |
2198 | * |
2199 | * XXX: The attr code is very similar to vfs_vnops.c:vn_stat(), but | |
2200 | * always provides access to the generation number as we need that | |
2201 | * to construct the BSM file ID. | |
2202 | * XXX: We should accept the process argument from the caller, since | |
2203 | * it's very likely they already have a reference. | |
2204 | * XXX: Error handling in this function is poor. | |
2205 | */ | |
2206 | void | |
2207 | audit_arg_vnpath(struct vnode *vp, u_int64_t flags) | |
2208 | { | |
2209 | struct kaudit_record *ar; | |
91447636 | 2210 | struct vnode_attr va; |
55e303ae A |
2211 | int error; |
2212 | int len; | |
2213 | char **pathp; | |
2214 | struct vnode_au_info *vnp; | |
2215 | struct proc *p; | |
91447636 | 2216 | struct vfs_context context; |
55e303ae A |
2217 | |
2218 | if (vp == NULL) | |
2219 | return; | |
2220 | ||
2221 | ar = currecord(); | |
2222 | if (ar == NULL) /* This will be the case for unaudited system calls */ | |
2223 | return; | |
2224 | ||
91447636 | 2225 | if ((flags & (ARG_VNODE1 | ARG_VNODE2)) == 0) |
55e303ae A |
2226 | return; |
2227 | ||
2228 | p = current_proc(); | |
2229 | ||
2230 | if (flags & ARG_VNODE1) { | |
2231 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_KPATH1); | |
2232 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE1); | |
2233 | pathp = &ar->k_ar.ar_arg_kpath1; | |
2234 | vnp = &ar->k_ar.ar_arg_vnode1; | |
2235 | } | |
2236 | else { | |
2237 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_KPATH2); | |
2238 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE2); | |
2239 | pathp = &ar->k_ar.ar_arg_kpath2; | |
2240 | vnp = &ar->k_ar.ar_arg_vnode2; | |
2241 | } | |
2242 | ||
2243 | if (*pathp == NULL) { | |
e5568f75 | 2244 | *pathp = (char *)kalloc(MAXPATHLEN); |
55e303ae A |
2245 | if (*pathp == NULL) |
2246 | return; | |
2247 | } | |
2248 | ||
e5568f75 A |
2249 | /* |
2250 | * If vn_getpath() succeeds, place it in a string buffer | |
2251 | * attached to the audit record, and set a flag indicating | |
2252 | * it is present. | |
2253 | */ | |
55e303ae | 2254 | len = MAXPATHLEN; |
e5568f75 | 2255 | if (vn_getpath(vp, *pathp, &len) == 0) { |
91447636 A |
2256 | if (flags & ARG_VNODE1) |
2257 | ar->k_ar.ar_valid_arg |= ARG_KPATH1; | |
2258 | else | |
2259 | ar->k_ar.ar_valid_arg |= ARG_KPATH2; | |
e5568f75 | 2260 | } else { |
91447636 | 2261 | kfree(*pathp, MAXPATHLEN); |
e5568f75 A |
2262 | *pathp = NULL; |
2263 | } | |
55e303ae | 2264 | |
91447636 A |
2265 | context.vc_proc = p; |
2266 | context.vc_ucred = kauth_cred_get(); | |
2267 | ||
2268 | VATTR_INIT(&va); | |
2269 | VATTR_WANTED(&va, va_mode); | |
2270 | VATTR_WANTED(&va, va_uid); | |
2271 | VATTR_WANTED(&va, va_gid); | |
2272 | VATTR_WANTED(&va, va_rdev); | |
2273 | VATTR_WANTED(&va, va_fsid); | |
2274 | VATTR_WANTED(&va, va_fileid); | |
2275 | VATTR_WANTED(&va, va_gen); | |
2276 | error = vnode_getattr(vp, &va, &context); | |
55e303ae A |
2277 | if (error) { |
2278 | /* XXX: How to handle this case? */ | |
2279 | return; | |
2280 | } | |
2281 | ||
91447636 A |
2282 | /* XXX do we want to fall back here when these aren't supported? */ |
2283 | vnp->vn_mode = va.va_mode; | |
2284 | vnp->vn_uid = va.va_uid; | |
2285 | vnp->vn_gid = va.va_gid; | |
2286 | vnp->vn_dev = va.va_rdev; | |
2287 | vnp->vn_fsid = va.va_fsid; | |
2288 | vnp->vn_fileid = (u_long)va.va_fileid; | |
2289 | vnp->vn_gen = va.va_gen; | |
55e303ae A |
2290 | if (flags & ARG_VNODE1) |
2291 | ar->k_ar.ar_valid_arg |= ARG_VNODE1; | |
2292 | else | |
2293 | ar->k_ar.ar_valid_arg |= ARG_VNODE2; | |
2294 | ||
2295 | } | |
2296 | ||
e5568f75 | 2297 | void |
91447636 A |
2298 | audit_arg_vnpath_withref(struct vnode *vp, u_int64_t flags) |
2299 | { | |
2300 | if (vp == NULL || vnode_getwithref(vp)) | |
2301 | return; | |
2302 | audit_arg_vnpath(vp, flags); | |
2303 | (void)vnode_put(vp); | |
2304 | } | |
2305 | ||
2306 | void | |
2307 | audit_arg_mach_port1(mach_port_name_t port) | |
e5568f75 A |
2308 | { |
2309 | struct kaudit_record *ar; | |
2310 | ||
2311 | ar = currecord(); | |
2312 | if (ar == NULL) | |
2313 | return; | |
2314 | ||
2315 | ar->k_ar.ar_arg_mach_port1 = port; | |
2316 | ar->k_ar.ar_valid_arg |= ARG_MACHPORT1; | |
2317 | } | |
2318 | ||
2319 | void | |
91447636 | 2320 | audit_arg_mach_port2(mach_port_name_t port) |
e5568f75 A |
2321 | { |
2322 | struct kaudit_record *ar; | |
2323 | ||
2324 | ar = currecord(); | |
2325 | if (ar == NULL) | |
2326 | return; | |
2327 | ||
2328 | ar->k_ar.ar_arg_mach_port2 = port; | |
2329 | ar->k_ar.ar_valid_arg |= ARG_MACHPORT2; | |
2330 | } | |
2331 | ||
2332 | /* | |
2333 | * The close() system call uses it's own audit call to capture the | |
2334 | * path/vnode information because those pieces are not easily obtained | |
2335 | * within the system call itself. | |
2336 | */ | |
2337 | void | |
2338 | audit_sysclose(struct proc *p, int fd) | |
2339 | { | |
91447636 A |
2340 | struct fileproc *fp; |
2341 | struct vnode *vp; | |
e5568f75 A |
2342 | |
2343 | audit_arg_fd(fd); | |
2344 | ||
91447636 | 2345 | if (fp_getfvp(p, fd, &fp, &vp) != 0) |
e5568f75 A |
2346 | return; |
2347 | ||
91447636 A |
2348 | audit_arg_vnpath_withref((struct vnode *)fp->f_fglob->fg_data, ARG_VNODE1); |
2349 | file_drop(fd); | |
e5568f75 A |
2350 | } |
2351 | ||
55e303ae A |
2352 | #else /* !AUDIT */ |
2353 | ||
2354 | void | |
2355 | audit_init(void) | |
2356 | { | |
2357 | ||
2358 | } | |
2359 | ||
2360 | void | |
2361 | audit_shutdown(void) | |
2362 | { | |
2363 | ||
2364 | } | |
2365 | ||
2366 | int | |
2367 | audit(struct proc *p, struct audit_args *uap, register_t *retval) | |
2368 | { | |
2369 | return (ENOSYS); | |
2370 | } | |
2371 | ||
2372 | int | |
2373 | auditon(struct proc *p, struct auditon_args *uap, register_t *retval) | |
2374 | { | |
2375 | return (ENOSYS); | |
2376 | } | |
2377 | ||
55e303ae A |
2378 | int |
2379 | getauid(struct proc *p, struct getauid_args *uap, register_t *retval) | |
2380 | { | |
2381 | return (ENOSYS); | |
2382 | } | |
2383 | ||
2384 | int | |
2385 | setauid(struct proc *p, struct setauid_args *uap, register_t *retval) | |
2386 | { | |
2387 | return (ENOSYS); | |
2388 | } | |
2389 | ||
2390 | int | |
2391 | getaudit(struct proc *p, struct getaudit_args *uap, register_t *retval) | |
2392 | { | |
2393 | return (ENOSYS); | |
2394 | } | |
2395 | ||
2396 | int | |
2397 | setaudit(struct proc *p, struct setaudit_args *uap, register_t *retval) | |
2398 | { | |
2399 | return (ENOSYS); | |
2400 | } | |
2401 | ||
2402 | int | |
2403 | getaudit_addr(struct proc *p, struct getaudit_addr_args *uap, register_t *retval) | |
2404 | { | |
2405 | return (ENOSYS); | |
2406 | } | |
2407 | ||
2408 | int | |
2409 | setaudit_addr(struct proc *p, struct setaudit_addr_args *uap, register_t *retval) | |
2410 | { | |
2411 | return (ENOSYS); | |
2412 | } | |
2413 | ||
2414 | int | |
2415 | auditctl(struct proc *p, struct auditctl_args *uap, register_t *retval) | |
2416 | { | |
2417 | return (ENOSYS); | |
2418 | } | |
2419 | ||
55e303ae | 2420 | #endif /* AUDIT */ |