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.4/sys/security/audit/audit_syscalls.c 177146 2008-03-13 13:53:20Z csjp $
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 * XXXAUDIT: Locking?
196 */
197 switch (uap->cmd) {
198 case A_GETPOLICY:
199 if (!audit_fail_stop)
200 udata.au_policy |= AUDIT_CNT;
201 if (audit_panic_on_write_fail)
202 udata.au_policy |= AUDIT_AHLT;
203 if (audit_argv)
204 udata.au_policy |= AUDIT_ARGV;
205 if (audit_arge)
206 udata.au_policy |= AUDIT_ARGE;
207 break;
208
209 case A_SETPOLICY:
210 if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
211 AUDIT_ARGE))
212 return (EINVAL);
213 /*
214 * XXX - Need to wake up waiters if the policy relaxes?
215 */
216 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
217 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
218 audit_argv = (udata.au_policy & AUDIT_ARGV);
219 audit_arge = (udata.au_policy & AUDIT_ARGE);
220 break;
221
222 case A_GETKMASK:
223 udata.au_mask = audit_nae_mask;
224 break;
225
226 case A_SETKMASK:
227 audit_nae_mask = udata.au_mask;
228 break;
229
230 case A_GETQCTRL:
231 udata.au_qctrl = audit_qctrl;
232 break;
233
234 case A_SETQCTRL:
235 if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
236 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
237 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
238 (udata.au_qctrl.aq_minfree < 0) ||
239 (udata.au_qctrl.aq_minfree > 100))
240 return (EINVAL);
241
242 audit_qctrl = udata.au_qctrl;
243 /* XXX The queue delay value isn't used with the kernel. */
244 audit_qctrl.aq_delay = -1;
245 break;
246
247 case A_GETCWD:
248 return (ENOSYS);
249 break;
250
251 case A_GETCAR:
252 return (ENOSYS);
253 break;
254
255 case A_GETSTAT:
256 return (ENOSYS);
257 break;
258
259 case A_SETSTAT:
260 return (ENOSYS);
261 break;
262
263 case A_SETUMASK:
264 return (ENOSYS);
265 break;
266
267 case A_SETSMASK:
268 return (ENOSYS);
269 break;
270
271 case A_GETCOND:
272 if (audit_enabled && !audit_suspended)
273 udata.au_cond = AUC_AUDITING;
274 else
275 udata.au_cond = AUC_NOAUDIT;
276 break;
277
278 case A_SETCOND:
279 if (udata.au_cond == AUC_NOAUDIT)
280 audit_suspended = 1;
281 if (udata.au_cond == AUC_AUDITING)
282 audit_suspended = 0;
283 if (udata.au_cond == AUC_DISABLED) {
284 audit_suspended = 1;
285 audit_shutdown(NULL, 0);
286 }
287 break;
288
289 case A_GETCLASS:
290 udata.au_evclass.ec_class = au_event_class(
291 udata.au_evclass.ec_number);
292 break;
293
294 case A_SETCLASS:
295 au_evclassmap_insert(udata.au_evclass.ec_number,
296 udata.au_evclass.ec_class);
297 break;
298
299 case A_GETPINFO:
300 if (udata.au_aupinfo.ap_pid < 1)
301 return (EINVAL);
302
303 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
304 return (EINVAL);
305 if (p_cansee(td, tp) != 0) {
306 PROC_UNLOCK(tp);
307 return (EINVAL);
308 }
309
310 if (tp->p_au->ai_termid.at_type == AU_IPv6) {
311 PROC_UNLOCK(tp);
312 return (EINVAL);
313 }
314 udata.au_aupinfo.ap_auid = tp->p_au->ai_auid;
315 udata.au_aupinfo.ap_mask.am_success =
316 tp->p_au->ai_mask.am_success;
317 udata.au_aupinfo.ap_mask.am_failure =
318 tp->p_au->ai_mask.am_failure;
319 udata.au_aupinfo.ap_termid.machine =
320 tp->p_au->ai_termid.at_addr[0];
321 udata.au_aupinfo.ap_termid.port =
322 (dev_t)tp->p_au->ai_termid.at_port;
323 udata.au_aupinfo.ap_asid = tp->p_au->ai_asid;
324 PROC_UNLOCK(tp);
325 break;
326
327 case A_SETPMASK:
328 if (udata.au_aupinfo.ap_pid < 1)
329 return (EINVAL);
330
331 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
332 return (EINVAL);
333 if (p_cansee(td, tp) != 0) {
334 PROC_UNLOCK(tp);
335 return (EINVAL);
336 }
337
338 tp->p_au->ai_mask.am_success =
339 udata.au_aupinfo.ap_mask.am_success;
340 tp->p_au->ai_mask.am_failure =
341 udata.au_aupinfo.ap_mask.am_failure;
342 PROC_UNLOCK(tp);
343 break;
344
345 case A_SETFSIZE:
346 if ((udata.au_fstat.af_filesz != 0) &&
347 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))
348 return (EINVAL);
349 audit_fstat.af_filesz = udata.au_fstat.af_filesz;
350 break;
351
352 case A_GETFSIZE:
353 udata.au_fstat.af_filesz = audit_fstat.af_filesz;
354 udata.au_fstat.af_currsz = audit_fstat.af_currsz;
355 break;
356
357 case A_GETPINFO_ADDR:
358 if (udata.au_aupinfo_addr.ap_pid < 1)
359 return (EINVAL);
360 if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL)
361 return (EINVAL);
362 udata.au_aupinfo_addr.ap_auid = tp->p_au->ai_auid;
363 udata.au_aupinfo_addr.ap_mask.am_success =
364 tp->p_au->ai_mask.am_success;
365 udata.au_aupinfo_addr.ap_mask.am_failure =
366 tp->p_au->ai_mask.am_failure;
367 udata.au_aupinfo_addr.ap_termid = tp->p_au->ai_termid;
368 udata.au_aupinfo_addr.ap_asid = tp->p_au->ai_asid;
369 PROC_UNLOCK(tp);
370 break;
371
372 case A_GETKAUDIT:
373 return (ENOSYS);
374 break;
375
376 case A_SETKAUDIT:
377 return (ENOSYS);
378 break;
379
380 case A_SENDTRIGGER:
381 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) ||
382 (udata.au_trigger > AUDIT_TRIGGER_MAX))
383 return (EINVAL);
384 return (send_trigger(udata.au_trigger));
385
386 default:
387 return (EINVAL);
388 }
389
390 /*
391 * Copy data back to userspace for the GET comands.
392 */
393 switch (uap->cmd) {
394 case A_GETPOLICY:
395 case A_GETKMASK:
396 case A_GETQCTRL:
397 case A_GETCWD:
398 case A_GETCAR:
399 case A_GETSTAT:
400 case A_GETCOND:
401 case A_GETCLASS:
402 case A_GETPINFO:
403 case A_GETFSIZE:
404 case A_GETPINFO_ADDR:
405 case A_GETKAUDIT:
406 error = copyout((void *)&udata, uap->data, uap->length);
407 if (error)
408 return (error);
409 break;
410 }
411
412 return (0);
413 }
414
415 /*
416 * MPSAFE
417 *
418 * System calls to manage the user audit information.
419 */
420 /* ARGSUSED */
421 int
422 getauid(struct thread *td, struct getauid_args *uap)
423 {
424 int error;
425 au_id_t id;
426
427 if (jailed(td->td_ucred))
428 return (ENOSYS);
429 error = suser(td);
430 if (error)
431 return (error);
432
433 /*
434 * XXX: Integer read on static pointer dereference: doesn't need
435 * locking?
436 */
437 PROC_LOCK(td->td_proc);
438 id = td->td_proc->p_au->ai_auid;
439 PROC_UNLOCK(td->td_proc);
440 return copyout(&id, uap->auid, sizeof(id));
441 }
442
443 /* MPSAFE */
444 /* ARGSUSED */
445 int
446 setauid(struct thread *td, struct setauid_args *uap)
447 {
448 int error;
449 au_id_t id;
450
451 if (jailed(td->td_ucred))
452 return (ENOSYS);
453 error = suser(td);
454 if (error)
455 return (error);
456
457 error = copyin(uap->auid, &id, sizeof(id));
458 if (error)
459 return (error);
460
461 audit_arg_auid(id);
462
463 /*
464 * XXX: Integer write on static pointer dereference: doesn't need
465 * locking?
466 *
467 * XXXAUDIT: Might need locking to serialize audit events in the same
468 * order as change events? Or maybe that's an under-solveable
469 * problem.
470 *
471 * XXXRW: Test privilege while holding the proc lock?
472 */
473 PROC_LOCK(td->td_proc);
474 td->td_proc->p_au->ai_auid = id;
475 PROC_UNLOCK(td->td_proc);
476
477 return (0);
478 }
479
480 /*
481 * MPSAFE
482 * System calls to get and set process audit information.
483 */
484 /* ARGSUSED */
485 int
486 getaudit(struct thread *td, struct getaudit_args *uap)
487 {
488 struct auditinfo ai;
489 int error;
490
491 if (jailed(td->td_ucred))
492 return (ENOSYS);
493 error = suser(td);
494 if (error)
495 return (error);
496
497 PROC_LOCK(td->td_proc);
498 if (td->td_proc->p_au->ai_termid.at_type == AU_IPv6) {
499 PROC_UNLOCK(td->td_proc);
500 return (E2BIG);
501 }
502 bzero(&ai, sizeof(ai));
503 ai.ai_auid = td->td_proc->p_au->ai_auid;
504 ai.ai_mask = td->td_proc->p_au->ai_mask;
505 ai.ai_asid = td->td_proc->p_au->ai_asid;
506 ai.ai_termid.machine = td->td_proc->p_au->ai_termid.at_addr[0];
507 ai.ai_termid.port = td->td_proc->p_au->ai_termid.at_port;
508 PROC_UNLOCK(td->td_proc);
509
510 return (copyout(&ai, uap->auditinfo, sizeof(ai)));
511 }
512
513 /* MPSAFE */
514 /* ARGSUSED */
515 int
516 setaudit(struct thread *td, struct setaudit_args *uap)
517 {
518 struct auditinfo ai;
519 int error;
520
521 if (jailed(td->td_ucred))
522 return (ENOSYS);
523 error = suser(td);
524 if (error)
525 return (error);
526
527 error = copyin(uap->auditinfo, &ai, sizeof(ai));
528 if (error)
529 return (error);
530
531 audit_arg_auditinfo(&ai);
532
533 /*
534 * XXXRW: Test privilege while holding the proc lock?
535 */
536 PROC_LOCK(td->td_proc);
537 bzero(td->td_proc->p_au, sizeof(struct auditinfo_addr));
538 td->td_proc->p_au->ai_auid = ai.ai_auid;
539 td->td_proc->p_au->ai_mask = ai.ai_mask;
540 td->td_proc->p_au->ai_asid = ai.ai_asid;
541 td->td_proc->p_au->ai_termid.at_addr[0] = ai.ai_termid.machine;
542 td->td_proc->p_au->ai_termid.at_port = ai.ai_termid.port;
543 td->td_proc->p_au->ai_termid.at_type = AU_IPv4;
544 PROC_UNLOCK(td->td_proc);
545
546 return (0);
547 }
548
549 /* MPSAFE */
550 /* ARGSUSED */
551 int
552 getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
553 {
554 struct auditinfo_addr aia;
555 int error;
556
557 if (jailed(td->td_ucred))
558 return (ENOSYS);
559 error = suser(td);
560 if (error)
561 return (error);
562 if (uap->length < sizeof(aia))
563 return (EOVERFLOW);
564 PROC_LOCK(td->td_proc);
565 aia = *td->td_proc->p_au;
566 PROC_UNLOCK(td->td_proc);
567 return (copyout(&aia, uap->auditinfo_addr, sizeof(aia)));
568 }
569
570 /* MPSAFE */
571 /* ARGSUSED */
572 int
573 setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
574 {
575 struct auditinfo_addr aia;
576 int error;
577
578 if (jailed(td->td_ucred))
579 return (ENOSYS);
580 error = suser(td);
581 if (error)
582 return (error);
583
584 error = copyin(uap->auditinfo_addr, &aia, sizeof(aia));
585 if (error)
586 return (error);
587 audit_arg_auditinfo_addr(&aia);
588 if (aia.ai_termid.at_type != AU_IPv6 &&
589 aia.ai_termid.at_type != AU_IPv4)
590 return (EINVAL);
591 PROC_LOCK(td->td_proc);
592 *td->td_proc->p_au = aia;
593 PROC_UNLOCK(td->td_proc);
594 return (error);
595 }
596
597 /*
598 * MPSAFE
599 * Syscall to manage audit files.
600 */
601 /* ARGSUSED */
602 int
603 auditctl(struct thread *td, struct auditctl_args *uap)
604 {
605 struct nameidata nd;
606 struct ucred *cred;
607 struct vnode *vp;
608 int error = 0;
609 int flags, vfslocked;
610
611 if (jailed(td->td_ucred))
612 return (ENOSYS);
613 error = suser(td);
614 if (error)
615 return (error);
616
617 vp = NULL;
618 cred = NULL;
619
620 /*
621 * If a path is specified, open the replacement vnode, perform
622 * validity checks, and grab another reference to the current
623 * credential.
624 *
625 * On Darwin, a NULL path argument is also used to disable audit.
626 */
627 if (uap->path == NULL)
628 return (EINVAL);
629
630 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
631 UIO_USERSPACE, uap->path, td);
632 flags = AUDIT_OPEN_FLAGS;
633 error = vn_open(&nd, &flags, 0, -1);
634 if (error)
635 return (error);
636 vp = nd.ni_vp;
637 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
638 VOP_UNLOCK(vp, 0, td);
639 NDFREE(&nd, NDF_ONLY_PNBUF);
640 if (vp->v_type != VREG) {
641 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
642 VFS_UNLOCK_GIANT(vfslocked);
643 return (EINVAL);
644 }
645 VFS_UNLOCK_GIANT(vfslocked);
646 cred = td->td_ucred;
647 crhold(cred);
648
649 /*
650 * XXXAUDIT: Should audit_suspended actually be cleared by
651 * audit_worker?
652 */
653 audit_suspended = 0;
654
655 audit_rotate_vnode(cred, vp);
656
657 return (error);
658 }
659
660 #else /* !AUDIT */
661
662 int
663 audit(struct thread *td, struct audit_args *uap)
664 {
665
666 return (ENOSYS);
667 }
668
669 int
670 auditon(struct thread *td, struct auditon_args *uap)
671 {
672
673 return (ENOSYS);
674 }
675
676 int
677 getauid(struct thread *td, struct getauid_args *uap)
678 {
679
680 return (ENOSYS);
681 }
682
683 int
684 setauid(struct thread *td, struct setauid_args *uap)
685 {
686
687 return (ENOSYS);
688 }
689
690 int
691 getaudit(struct thread *td, struct getaudit_args *uap)
692 {
693
694 return (ENOSYS);
695 }
696
697 int
698 setaudit(struct thread *td, struct setaudit_args *uap)
699 {
700
701 return (ENOSYS);
702 }
703
704 int
705 getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
706 {
707
708 return (ENOSYS);
709 }
710
711 int
712 setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
713 {
714
715 return (ENOSYS);
716 }
717
718 int
719 auditctl(struct thread *td, struct auditctl_args *uap)
720 {
721
722 return (ENOSYS);
723 }
724 #endif /* AUDIT */
Cache object: 9eb222797fd9b1cca750ddc1b74f0cf9
|