1 /*
2 * Copyright (c) 1999-2005 Apple Computer, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * $FreeBSD: releng/6.2/sys/security/audit/audit_syscalls.c 164507 2006-11-22 11:51:12Z kib $
30 */
31
32 #include <sys/param.h>
33 #include <sys/mount.h>
34 #include <sys/namei.h>
35 #include <sys/proc.h>
36 #include <sys/sysproto.h>
37 #include <sys/systm.h>
38 #include <sys/vnode.h>
39 #include <sys/jail.h>
40
41 #include <bsm/audit.h>
42 #include <bsm/audit_kevents.h>
43 #include <security/audit/audit.h>
44 #include <security/audit/audit_private.h>
45
46 #ifdef AUDIT
47
48 /*
49 * MPSAFE
50 *
51 * System call to allow a user space application to submit a BSM audit record
52 * to the kernel for inclusion in the audit log. This function does little
53 * verification on the audit record that is submitted.
54 *
55 * XXXAUDIT: Audit preselection for user records does not currently work,
56 * since we pre-select only based on the AUE_audit event type, not the event
57 * type submitted as part of the user audit data.
58 */
59 /* ARGSUSED */
60 int
61 audit(struct thread *td, struct audit_args *uap)
62 {
63 int error;
64 void * rec;
65 struct kaudit_record *ar;
66
67 if (jailed(td->td_ucred))
68 return (ENOSYS);
69 error = suser(td);
70 if (error)
71 return (error);
72
73 if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz))
74 return (EINVAL);
75
76 ar = currecord();
77
78 /*
79 * If there's no current audit record (audit() itself not audited)
80 * commit the user audit record.
81 */
82 if (ar == NULL) {
83
84 /*
85 * This is not very efficient; we're required to allocate a
86 * complete kernel audit record just so the user record can
87 * tag along.
88 *
89 * XXXAUDIT: Maybe AUE_AUDIT in the system call context and
90 * special pre-select handling?
91 */
92 td->td_ar = audit_new(AUE_NULL, td);
93 if (td->td_ar == NULL)
94 return (ENOTSUP);
95 ar = td->td_ar;
96 }
97
98 if (uap->length > MAX_AUDIT_RECORD_SIZE)
99 return (EINVAL);
100
101 rec = malloc(uap->length, M_AUDITDATA, M_WAITOK);
102
103 error = copyin(uap->record, rec, uap->length);
104 if (error)
105 goto free_out;
106
107 /* Verify the record. */
108 if (bsm_rec_verify(rec) == 0) {
109 error = EINVAL;
110 goto free_out;
111 }
112
113 /*
114 * Attach the user audit record to the kernel audit record. Because
115 * this system call is an auditable event, we will write the user
116 * record along with the record for this audit event.
117 *
118 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen,
119 * k_ar_commit & AR_COMMIT_USER?
120 */
121 ar->k_udata = rec;
122 ar->k_ulen = uap->length;
123 ar->k_ar_commit |= AR_COMMIT_USER;
124
125 /*
126 * Currently we assume that all preselection has been performed in
127 * userspace. We unconditionally set these masks so that the records
128 * get committed both to the trail and pipe. In the future we will
129 * want to setup kernel based preselection.
130 */
131 ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE);
132 return (0);
133
134 free_out:
135 /*
136 * audit_syscall_exit() will free the audit record on the thread even
137 * if we allocated it above.
138 */
139 free(rec, M_AUDITDATA);
140 return (error);
141 }
142
143 /*
144 * MPSAFE
145 *
146 * System call to manipulate auditing.
147 */
148 /* ARGSUSED */
149 int
150 auditon(struct thread *td, struct auditon_args *uap)
151 {
152 int error;
153 union auditon_udata udata;
154 struct proc *tp;
155
156 if (jailed(td->td_ucred))
157 return (ENOSYS);
158 AUDIT_ARG(cmd, uap->cmd);
159 error = suser(td);
160 if (error)
161 return (error);
162
163 if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata)))
164 return (EINVAL);
165
166 memset((void *)&udata, 0, sizeof(udata));
167
168 /*
169 * Some of the GET commands use the arguments too.
170 */
171 switch (uap->cmd) {
172 case A_SETPOLICY:
173 case A_SETKMASK:
174 case A_SETQCTRL:
175 case A_SETSTAT:
176 case A_SETUMASK:
177 case A_SETSMASK:
178 case A_SETCOND:
179 case A_SETCLASS:
180 case A_SETPMASK:
181 case A_SETFSIZE:
182 case A_SETKAUDIT:
183 case A_GETCLASS:
184 case A_GETPINFO:
185 case A_GETPINFO_ADDR:
186 case A_SENDTRIGGER:
187 error = copyin(uap->data, (void *)&udata, uap->length);
188 if (error)
189 return (error);
190 AUDIT_ARG(auditon, &udata);
191 break;
192 }
193
194 /*
195 * XXX Need to implement these commands by accessing the global
196 * values associated with the commands.
197 *
198 * XXXAUDIT: Locking?
199 */
200 switch (uap->cmd) {
201 case A_GETPOLICY:
202 if (!audit_fail_stop)
203 udata.au_policy |= AUDIT_CNT;
204 if (audit_panic_on_write_fail)
205 udata.au_policy |= AUDIT_AHLT;
206 if (audit_argv)
207 udata.au_policy |= AUDIT_ARGV;
208 if (audit_arge)
209 udata.au_policy |= AUDIT_ARGE;
210 break;
211
212 case A_SETPOLICY:
213 if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
214 AUDIT_ARGE))
215 return (EINVAL);
216 /*
217 * XXX - Need to wake up waiters if the policy relaxes?
218 */
219 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
220 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
221 audit_argv = (udata.au_policy & AUDIT_ARGV);
222 audit_arge = (udata.au_policy & AUDIT_ARGE);
223 break;
224
225 case A_GETKMASK:
226 udata.au_mask = audit_nae_mask;
227 break;
228
229 case A_SETKMASK:
230 audit_nae_mask = udata.au_mask;
231 break;
232
233 case A_GETQCTRL:
234 udata.au_qctrl = audit_qctrl;
235 break;
236
237 case A_SETQCTRL:
238 if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
239 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
240 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
241 (udata.au_qctrl.aq_minfree < 0) ||
242 (udata.au_qctrl.aq_minfree > 100))
243 return (EINVAL);
244
245 audit_qctrl = udata.au_qctrl;
246 /* XXX The queue delay value isn't used with the kernel. */
247 audit_qctrl.aq_delay = -1;
248 break;
249
250 case A_GETCWD:
251 return (ENOSYS);
252 break;
253
254 case A_GETCAR:
255 return (ENOSYS);
256 break;
257
258 case A_GETSTAT:
259 return (ENOSYS);
260 break;
261
262 case A_SETSTAT:
263 return (ENOSYS);
264 break;
265
266 case A_SETUMASK:
267 return (ENOSYS);
268 break;
269
270 case A_SETSMASK:
271 return (ENOSYS);
272 break;
273
274 case A_GETCOND:
275 if (audit_enabled && !audit_suspended)
276 udata.au_cond = AUC_AUDITING;
277 else
278 udata.au_cond = AUC_NOAUDIT;
279 break;
280
281 case A_SETCOND:
282 if (udata.au_cond == AUC_NOAUDIT)
283 audit_suspended = 1;
284 if (udata.au_cond == AUC_AUDITING)
285 audit_suspended = 0;
286 if (udata.au_cond == AUC_DISABLED) {
287 audit_suspended = 1;
288 audit_shutdown(NULL, 0);
289 }
290 break;
291
292 case A_GETCLASS:
293 udata.au_evclass.ec_class = au_event_class(
294 udata.au_evclass.ec_number);
295 break;
296
297 case A_SETCLASS:
298 au_evclassmap_insert(udata.au_evclass.ec_number,
299 udata.au_evclass.ec_class);
300 break;
301
302 case A_GETPINFO:
303 if (udata.au_aupinfo.ap_pid < 1)
304 return (EINVAL);
305
306 /* XXXAUDIT: p_cansee()? */
307 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
308 return (EINVAL);
309
310 udata.au_aupinfo.ap_auid = tp->p_au->ai_auid;
311 udata.au_aupinfo.ap_mask.am_success =
312 tp->p_au->ai_mask.am_success;
313 udata.au_aupinfo.ap_mask.am_failure =
314 tp->p_au->ai_mask.am_failure;
315 udata.au_aupinfo.ap_termid.machine =
316 tp->p_au->ai_termid.machine;
317 udata.au_aupinfo.ap_termid.port = tp->p_au->ai_termid.port;
318 udata.au_aupinfo.ap_asid = tp->p_au->ai_asid;
319 PROC_UNLOCK(tp);
320 break;
321
322 case A_SETPMASK:
323 if (udata.au_aupinfo.ap_pid < 1)
324 return (EINVAL);
325
326 /* XXXAUDIT: p_cansee()? */
327 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
328 return (EINVAL);
329
330 tp->p_au->ai_mask.am_success =
331 udata.au_aupinfo.ap_mask.am_success;
332 tp->p_au->ai_mask.am_failure =
333 udata.au_aupinfo.ap_mask.am_failure;
334 PROC_UNLOCK(tp);
335 break;
336
337 case A_SETFSIZE:
338 if ((udata.au_fstat.af_filesz != 0) &&
339 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))
340 return (EINVAL);
341 audit_fstat.af_filesz = udata.au_fstat.af_filesz;
342 break;
343
344 case A_GETFSIZE:
345 udata.au_fstat.af_filesz = audit_fstat.af_filesz;
346 udata.au_fstat.af_currsz = audit_fstat.af_currsz;
347 break;
348
349 case A_GETPINFO_ADDR:
350 return (ENOSYS);
351 break;
352
353 case A_GETKAUDIT:
354 return (ENOSYS);
355 break;
356
357 case A_SETKAUDIT:
358 return (ENOSYS);
359 break;
360
361 case A_SENDTRIGGER:
362 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) ||
363 (udata.au_trigger > AUDIT_TRIGGER_MAX))
364 return (EINVAL);
365 return (send_trigger(udata.au_trigger));
366 }
367
368 /*
369 * Copy data back to userspace for the GET comands.
370 */
371 switch (uap->cmd) {
372 case A_GETPOLICY:
373 case A_GETKMASK:
374 case A_GETQCTRL:
375 case A_GETCWD:
376 case A_GETCAR:
377 case A_GETSTAT:
378 case A_GETCOND:
379 case A_GETCLASS:
380 case A_GETPINFO:
381 case A_GETFSIZE:
382 case A_GETPINFO_ADDR:
383 case A_GETKAUDIT:
384 error = copyout((void *)&udata, uap->data, uap->length);
385 if (error)
386 return (error);
387 break;
388 }
389
390 return (0);
391 }
392
393 /*
394 * MPSAFE
395 *
396 * System calls to manage the user audit information.
397 */
398 /* ARGSUSED */
399 int
400 getauid(struct thread *td, struct getauid_args *uap)
401 {
402 int error;
403 au_id_t id;
404
405 if (jailed(td->td_ucred))
406 return (ENOSYS);
407 error = suser(td);
408 if (error)
409 return (error);
410
411 /*
412 * XXX: Integer read on static pointer dereference: doesn't need
413 * locking?
414 */
415 PROC_LOCK(td->td_proc);
416 id = td->td_proc->p_au->ai_auid;
417 PROC_UNLOCK(td->td_proc);
418 return copyout(&id, uap->auid, sizeof(id));
419 }
420
421 /* MPSAFE */
422 /* ARGSUSED */
423 int
424 setauid(struct thread *td, struct setauid_args *uap)
425 {
426 int error;
427 au_id_t id;
428
429 if (jailed(td->td_ucred))
430 return (ENOSYS);
431 error = suser(td);
432 if (error)
433 return (error);
434
435 error = copyin(uap->auid, &id, sizeof(id));
436 if (error)
437 return (error);
438
439 audit_arg_auid(id);
440
441 /*
442 * XXX: Integer write on static pointer dereference: doesn't need
443 * locking?
444 *
445 * XXXAUDIT: Might need locking to serialize audit events in the same
446 * order as change events? Or maybe that's an under-solveable
447 * problem.
448 *
449 * XXXRW: Test privilege while holding the proc lock?
450 */
451 PROC_LOCK(td->td_proc);
452 td->td_proc->p_au->ai_auid = id;
453 PROC_UNLOCK(td->td_proc);
454
455 return (0);
456 }
457
458 /*
459 * MPSAFE
460 * System calls to get and set process audit information.
461 */
462 /* ARGSUSED */
463 int
464 getaudit(struct thread *td, struct getaudit_args *uap)
465 {
466 struct auditinfo ai;
467 int error;
468
469 if (jailed(td->td_ucred))
470 return (ENOSYS);
471 error = suser(td);
472 if (error)
473 return (error);
474
475 PROC_LOCK(td->td_proc);
476 ai = *td->td_proc->p_au;
477 PROC_UNLOCK(td->td_proc);
478
479 return (copyout(&ai, uap->auditinfo, sizeof(ai)));
480 }
481
482 /* MPSAFE */
483 /* ARGSUSED */
484 int
485 setaudit(struct thread *td, struct setaudit_args *uap)
486 {
487 struct auditinfo ai;
488 int error;
489
490 if (jailed(td->td_ucred))
491 return (ENOSYS);
492 error = suser(td);
493 if (error)
494 return (error);
495
496 error = copyin(uap->auditinfo, &ai, sizeof(ai));
497 if (error)
498 return (error);
499
500 audit_arg_auditinfo(&ai);
501
502 /*
503 * XXXRW: Test privilege while holding the proc lock?
504 */
505 PROC_LOCK(td->td_proc);
506 *td->td_proc->p_au = ai;
507 PROC_UNLOCK(td->td_proc);
508
509 return (0);
510 }
511
512 /* MPSAFE */
513 /* ARGSUSED */
514 int
515 getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
516 {
517 int error;
518
519 if (jailed(td->td_ucred))
520 return (ENOSYS);
521 error = suser(td);
522 if (error)
523 return (error);
524 return (ENOSYS);
525 }
526
527 /* MPSAFE */
528 /* ARGSUSED */
529 int
530 setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
531 {
532 int error;
533
534 if (jailed(td->td_ucred))
535 return (ENOSYS);
536 error = suser(td);
537 if (error)
538 return (error);
539 return (ENOSYS);
540 }
541
542 /*
543 * MPSAFE
544 * Syscall to manage audit files.
545 *
546 * XXX: Should generate an audit event.
547 */
548 /* ARGSUSED */
549 int
550 auditctl(struct thread *td, struct auditctl_args *uap)
551 {
552 struct nameidata nd;
553 struct ucred *cred;
554 struct vnode *vp;
555 int error = 0;
556 int flags, vfslocked;
557
558 if (jailed(td->td_ucred))
559 return (ENOSYS);
560 error = suser(td);
561 if (error)
562 return (error);
563
564 vp = NULL;
565 cred = NULL;
566
567 /*
568 * If a path is specified, open the replacement vnode, perform
569 * validity checks, and grab another reference to the current
570 * credential.
571 *
572 * XXXAUDIT: On Darwin, a NULL path is used to disable audit.
573 */
574 if (uap->path == NULL)
575 return (EINVAL);
576
577 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE, UIO_USERSPACE,
578 uap->path, td);
579 flags = AUDIT_OPEN_FLAGS;
580 error = vn_open(&nd, &flags, 0, -1);
581 if (error)
582 return (error);
583 vp = nd.ni_vp;
584 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
585 VOP_UNLOCK(vp, 0, td);
586 if (vp->v_type != VREG) {
587 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
588 VFS_UNLOCK_GIANT(vfslocked);
589 return (EINVAL);
590 }
591 VFS_UNLOCK_GIANT(vfslocked);
592 cred = td->td_ucred;
593 crhold(cred);
594
595 /*
596 * XXXAUDIT: Should audit_suspended actually be cleared by
597 * audit_worker?
598 */
599 audit_suspended = 0;
600
601 audit_rotate_vnode(cred, vp);
602
603 return (error);
604 }
605
606 #else /* !AUDIT */
607
608 int
609 audit(struct thread *td, struct audit_args *uap)
610 {
611
612 return (ENOSYS);
613 }
614
615 int
616 auditon(struct thread *td, struct auditon_args *uap)
617 {
618
619 return (ENOSYS);
620 }
621
622 int
623 getauid(struct thread *td, struct getauid_args *uap)
624 {
625
626 return (ENOSYS);
627 }
628
629 int
630 setauid(struct thread *td, struct setauid_args *uap)
631 {
632
633 return (ENOSYS);
634 }
635
636 int
637 getaudit(struct thread *td, struct getaudit_args *uap)
638 {
639
640 return (ENOSYS);
641 }
642
643 int
644 setaudit(struct thread *td, struct setaudit_args *uap)
645 {
646
647 return (ENOSYS);
648 }
649
650 int
651 getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
652 {
653
654 return (ENOSYS);
655 }
656
657 int
658 setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
659 {
660
661 return (ENOSYS);
662 }
663
664 int
665 auditctl(struct thread *td, struct auditctl_args *uap)
666 {
667
668 return (ENOSYS);
669 }
670
671 void
672 audit_proc_init(struct proc *p)
673 {
674
675 }
676
677 void
678 audit_proc_fork(struct proc *parent, struct proc *child)
679 {
680
681 }
682
683 void
684 audit_proc_free(struct proc *p)
685 {
686
687 }
688
689 #endif /* AUDIT */
Cache object: 6ada5992650dc5ee1610c17b4ac8caf7
|