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.3/sys/security/audit/audit_syscalls.c 173524 2007-11-10 17:08:41Z 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
387 /*
388 * Copy data back to userspace for the GET comands.
389 */
390 switch (uap->cmd) {
391 case A_GETPOLICY:
392 case A_GETKMASK:
393 case A_GETQCTRL:
394 case A_GETCWD:
395 case A_GETCAR:
396 case A_GETSTAT:
397 case A_GETCOND:
398 case A_GETCLASS:
399 case A_GETPINFO:
400 case A_GETFSIZE:
401 case A_GETPINFO_ADDR:
402 case A_GETKAUDIT:
403 error = copyout((void *)&udata, uap->data, uap->length);
404 if (error)
405 return (error);
406 break;
407 }
408
409 return (0);
410 }
411
412 /*
413 * MPSAFE
414 *
415 * System calls to manage the user audit information.
416 */
417 /* ARGSUSED */
418 int
419 getauid(struct thread *td, struct getauid_args *uap)
420 {
421 int error;
422 au_id_t id;
423
424 if (jailed(td->td_ucred))
425 return (ENOSYS);
426 error = suser(td);
427 if (error)
428 return (error);
429
430 /*
431 * XXX: Integer read on static pointer dereference: doesn't need
432 * locking?
433 */
434 PROC_LOCK(td->td_proc);
435 id = td->td_proc->p_au->ai_auid;
436 PROC_UNLOCK(td->td_proc);
437 return copyout(&id, uap->auid, sizeof(id));
438 }
439
440 /* MPSAFE */
441 /* ARGSUSED */
442 int
443 setauid(struct thread *td, struct setauid_args *uap)
444 {
445 int error;
446 au_id_t id;
447
448 if (jailed(td->td_ucred))
449 return (ENOSYS);
450 error = suser(td);
451 if (error)
452 return (error);
453
454 error = copyin(uap->auid, &id, sizeof(id));
455 if (error)
456 return (error);
457
458 audit_arg_auid(id);
459
460 /*
461 * XXX: Integer write on static pointer dereference: doesn't need
462 * locking?
463 *
464 * XXXAUDIT: Might need locking to serialize audit events in the same
465 * order as change events? Or maybe that's an under-solveable
466 * problem.
467 *
468 * XXXRW: Test privilege while holding the proc lock?
469 */
470 PROC_LOCK(td->td_proc);
471 td->td_proc->p_au->ai_auid = id;
472 PROC_UNLOCK(td->td_proc);
473
474 return (0);
475 }
476
477 /*
478 * MPSAFE
479 * System calls to get and set process audit information.
480 */
481 /* ARGSUSED */
482 int
483 getaudit(struct thread *td, struct getaudit_args *uap)
484 {
485 struct auditinfo ai;
486 int error;
487
488 if (jailed(td->td_ucred))
489 return (ENOSYS);
490 error = suser(td);
491 if (error)
492 return (error);
493
494 PROC_LOCK(td->td_proc);
495 if (td->td_proc->p_au->ai_termid.at_type == AU_IPv6) {
496 PROC_UNLOCK(td->td_proc);
497 return (E2BIG);
498 }
499 bzero(&ai, sizeof(ai));
500 ai.ai_auid = td->td_proc->p_au->ai_auid;
501 ai.ai_mask = td->td_proc->p_au->ai_mask;
502 ai.ai_asid = td->td_proc->p_au->ai_asid;
503 ai.ai_termid.machine = td->td_proc->p_au->ai_termid.at_addr[0];
504 ai.ai_termid.port = td->td_proc->p_au->ai_termid.at_port;
505 PROC_UNLOCK(td->td_proc);
506
507 return (copyout(&ai, uap->auditinfo, sizeof(ai)));
508 }
509
510 /* MPSAFE */
511 /* ARGSUSED */
512 int
513 setaudit(struct thread *td, struct setaudit_args *uap)
514 {
515 struct auditinfo ai;
516 int error;
517
518 if (jailed(td->td_ucred))
519 return (ENOSYS);
520 error = suser(td);
521 if (error)
522 return (error);
523
524 error = copyin(uap->auditinfo, &ai, sizeof(ai));
525 if (error)
526 return (error);
527
528 audit_arg_auditinfo(&ai);
529
530 /*
531 * XXXRW: Test privilege while holding the proc lock?
532 */
533 PROC_LOCK(td->td_proc);
534 bzero(td->td_proc->p_au, sizeof(struct auditinfo_addr));
535 td->td_proc->p_au->ai_auid = ai.ai_auid;
536 td->td_proc->p_au->ai_mask = ai.ai_mask;
537 td->td_proc->p_au->ai_asid = ai.ai_asid;
538 td->td_proc->p_au->ai_termid.at_addr[0] = ai.ai_termid.machine;
539 td->td_proc->p_au->ai_termid.at_port = ai.ai_termid.port;
540 td->td_proc->p_au->ai_termid.at_type = AU_IPv4;
541 PROC_UNLOCK(td->td_proc);
542
543 return (0);
544 }
545
546 /* MPSAFE */
547 /* ARGSUSED */
548 int
549 getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
550 {
551 struct auditinfo_addr aia;
552 int error;
553
554 if (jailed(td->td_ucred))
555 return (ENOSYS);
556 error = suser(td);
557 if (error)
558 return (error);
559 if (uap->length < sizeof(aia))
560 return (EOVERFLOW);
561 PROC_LOCK(td->td_proc);
562 aia = *td->td_proc->p_au;
563 PROC_UNLOCK(td->td_proc);
564 return (copyout(&aia, uap->auditinfo_addr, sizeof(aia)));
565 }
566
567 /* MPSAFE */
568 /* ARGSUSED */
569 int
570 setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
571 {
572 struct auditinfo_addr aia;
573 int error;
574
575 if (jailed(td->td_ucred))
576 return (ENOSYS);
577 error = suser(td);
578 if (error)
579 return (error);
580
581 error = copyin(uap->auditinfo_addr, &aia, sizeof(aia));
582 if (error)
583 return (error);
584 audit_arg_auditinfo_addr(&aia);
585 if (aia.ai_termid.at_type != AU_IPv6 &&
586 aia.ai_termid.at_type != AU_IPv4)
587 return (EINVAL);
588 PROC_LOCK(td->td_proc);
589 *td->td_proc->p_au = aia;
590 PROC_UNLOCK(td->td_proc);
591 return (error);
592 }
593
594 /*
595 * MPSAFE
596 * Syscall to manage audit files.
597 */
598 /* ARGSUSED */
599 int
600 auditctl(struct thread *td, struct auditctl_args *uap)
601 {
602 struct nameidata nd;
603 struct ucred *cred;
604 struct vnode *vp;
605 int error = 0;
606 int flags, vfslocked;
607
608 if (jailed(td->td_ucred))
609 return (ENOSYS);
610 error = suser(td);
611 if (error)
612 return (error);
613
614 vp = NULL;
615 cred = NULL;
616
617 /*
618 * If a path is specified, open the replacement vnode, perform
619 * validity checks, and grab another reference to the current
620 * credential.
621 *
622 * On Darwin, a NULL path argument is also used to disable audit.
623 */
624 if (uap->path == NULL)
625 return (EINVAL);
626
627 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
628 UIO_USERSPACE, uap->path, td);
629 flags = AUDIT_OPEN_FLAGS;
630 error = vn_open(&nd, &flags, 0, -1);
631 if (error)
632 return (error);
633 vp = nd.ni_vp;
634 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
635 VOP_UNLOCK(vp, 0, td);
636 NDFREE(&nd, NDF_ONLY_PNBUF);
637 if (vp->v_type != VREG) {
638 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
639 VFS_UNLOCK_GIANT(vfslocked);
640 return (EINVAL);
641 }
642 VFS_UNLOCK_GIANT(vfslocked);
643 cred = td->td_ucred;
644 crhold(cred);
645
646 /*
647 * XXXAUDIT: Should audit_suspended actually be cleared by
648 * audit_worker?
649 */
650 audit_suspended = 0;
651
652 audit_rotate_vnode(cred, vp);
653
654 return (error);
655 }
656
657 #else /* !AUDIT */
658
659 int
660 audit(struct thread *td, struct audit_args *uap)
661 {
662
663 return (ENOSYS);
664 }
665
666 int
667 auditon(struct thread *td, struct auditon_args *uap)
668 {
669
670 return (ENOSYS);
671 }
672
673 int
674 getauid(struct thread *td, struct getauid_args *uap)
675 {
676
677 return (ENOSYS);
678 }
679
680 int
681 setauid(struct thread *td, struct setauid_args *uap)
682 {
683
684 return (ENOSYS);
685 }
686
687 int
688 getaudit(struct thread *td, struct getaudit_args *uap)
689 {
690
691 return (ENOSYS);
692 }
693
694 int
695 setaudit(struct thread *td, struct setaudit_args *uap)
696 {
697
698 return (ENOSYS);
699 }
700
701 int
702 getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
703 {
704
705 return (ENOSYS);
706 }
707
708 int
709 setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
710 {
711
712 return (ENOSYS);
713 }
714
715 int
716 auditctl(struct thread *td, struct auditctl_args *uap)
717 {
718
719 return (ENOSYS);
720 }
721 #endif /* AUDIT */
Cache object: 628e0cd73d3d42bbc672666864c8a7cf
|