1 /*-
2 * Copyright (c) 1999-2002, 2006, 2009 Robert N. M. Watson
3 * Copyright (c) 2001 Ilmar S. Habibulin
4 * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5 * Copyright (c) 2005-2006 SPARTA, Inc.
6 * Copyright (c) 2008 Apple Inc.
7 * All rights reserved.
8 *
9 * This software was developed by Robert Watson and Ilmar Habibulin for the
10 * TrustedBSD Project.
11 *
12 * This software was developed for the FreeBSD Project in part by Network
13 * Associates Laboratories, the Security Research Division of Network
14 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
15 * as part of the DARPA CHATS research program.
16 *
17 * This software was enhanced by SPARTA ISSO under SPAWAR contract
18 * N66001-04-C-6019 ("SEFOS").
19 *
20 * This software was developed at the University of Cambridge Computer
21 * Laboratory with support from a grant from Google, Inc.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 */
44
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD: releng/8.0/sys/security/mac/mac_syscalls.c 189797 2009-03-14 16:06:06Z rwatson $");
47
48 #include "opt_mac.h"
49
50 #include <sys/param.h>
51 #include <sys/fcntl.h>
52 #include <sys/kernel.h>
53 #include <sys/lock.h>
54 #include <sys/malloc.h>
55 #include <sys/mutex.h>
56 #include <sys/mac.h>
57 #include <sys/proc.h>
58 #include <sys/systm.h>
59 #include <sys/sysproto.h>
60 #include <sys/sysent.h>
61 #include <sys/vnode.h>
62 #include <sys/mount.h>
63 #include <sys/file.h>
64 #include <sys/namei.h>
65 #include <sys/socket.h>
66 #include <sys/pipe.h>
67 #include <sys/socketvar.h>
68
69 #include <security/mac/mac_framework.h>
70 #include <security/mac/mac_internal.h>
71 #include <security/mac/mac_policy.h>
72
73 #ifdef MAC
74
75 int
76 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
77 {
78 char *elements, *buffer;
79 struct mac mac;
80 struct proc *tproc;
81 struct ucred *tcred;
82 int error;
83
84 error = copyin(uap->mac_p, &mac, sizeof(mac));
85 if (error)
86 return (error);
87
88 error = mac_check_structmac_consistent(&mac);
89 if (error)
90 return (error);
91
92 tproc = pfind(uap->pid);
93 if (tproc == NULL)
94 return (ESRCH);
95
96 tcred = NULL; /* Satisfy gcc. */
97 error = p_cansee(td, tproc);
98 if (error == 0)
99 tcred = crhold(tproc->p_ucred);
100 PROC_UNLOCK(tproc);
101 if (error)
102 return (error);
103
104 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
105 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
106 if (error) {
107 free(elements, M_MACTEMP);
108 crfree(tcred);
109 return (error);
110 }
111
112 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
113 error = mac_cred_externalize_label(tcred->cr_label, elements,
114 buffer, mac.m_buflen);
115 if (error == 0)
116 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
117
118 free(buffer, M_MACTEMP);
119 free(elements, M_MACTEMP);
120 crfree(tcred);
121 return (error);
122 }
123
124 int
125 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
126 {
127 char *elements, *buffer;
128 struct mac mac;
129 int error;
130
131 error = copyin(uap->mac_p, &mac, sizeof(mac));
132 if (error)
133 return (error);
134
135 error = mac_check_structmac_consistent(&mac);
136 if (error)
137 return (error);
138
139 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
140 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
141 if (error) {
142 free(elements, M_MACTEMP);
143 return (error);
144 }
145
146 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
147 error = mac_cred_externalize_label(td->td_ucred->cr_label,
148 elements, buffer, mac.m_buflen);
149 if (error == 0)
150 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
151
152 free(buffer, M_MACTEMP);
153 free(elements, M_MACTEMP);
154 return (error);
155 }
156
157 int
158 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
159 {
160 struct ucred *newcred, *oldcred;
161 struct label *intlabel;
162 struct proc *p;
163 struct mac mac;
164 char *buffer;
165 int error;
166
167 if (!(mac_labeled & MPC_OBJECT_CRED))
168 return (EINVAL);
169
170 error = copyin(uap->mac_p, &mac, sizeof(mac));
171 if (error)
172 return (error);
173
174 error = mac_check_structmac_consistent(&mac);
175 if (error)
176 return (error);
177
178 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
179 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
180 if (error) {
181 free(buffer, M_MACTEMP);
182 return (error);
183 }
184
185 intlabel = mac_cred_label_alloc();
186 error = mac_cred_internalize_label(intlabel, buffer);
187 free(buffer, M_MACTEMP);
188 if (error)
189 goto out;
190
191 newcred = crget();
192
193 p = td->td_proc;
194 PROC_LOCK(p);
195 oldcred = p->p_ucred;
196
197 error = mac_cred_check_relabel(oldcred, intlabel);
198 if (error) {
199 PROC_UNLOCK(p);
200 crfree(newcred);
201 goto out;
202 }
203
204 setsugid(p);
205 crcopy(newcred, oldcred);
206 mac_cred_relabel(newcred, intlabel);
207 p->p_ucred = newcred;
208
209 PROC_UNLOCK(p);
210 crfree(oldcred);
211 mac_proc_vm_revoke(td);
212
213 out:
214 mac_cred_label_free(intlabel);
215 return (error);
216 }
217
218 int
219 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
220 {
221 char *elements, *buffer;
222 struct label *intlabel;
223 struct file *fp;
224 struct mac mac;
225 struct vnode *vp;
226 struct pipe *pipe;
227 struct socket *so;
228 short label_type;
229 int vfslocked, error;
230
231 error = copyin(uap->mac_p, &mac, sizeof(mac));
232 if (error)
233 return (error);
234
235 error = mac_check_structmac_consistent(&mac);
236 if (error)
237 return (error);
238
239 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
240 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
241 if (error) {
242 free(elements, M_MACTEMP);
243 return (error);
244 }
245
246 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
247 error = fget(td, uap->fd, &fp);
248 if (error)
249 goto out;
250
251 label_type = fp->f_type;
252 switch (fp->f_type) {
253 case DTYPE_FIFO:
254 case DTYPE_VNODE:
255 if (!(mac_labeled & MPC_OBJECT_VNODE))
256 return (EINVAL);
257 vp = fp->f_vnode;
258 intlabel = mac_vnode_label_alloc();
259 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
260 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
261 mac_vnode_copy_label(vp->v_label, intlabel);
262 VOP_UNLOCK(vp, 0);
263 VFS_UNLOCK_GIANT(vfslocked);
264 error = mac_vnode_externalize_label(intlabel, elements,
265 buffer, mac.m_buflen);
266 mac_vnode_label_free(intlabel);
267 break;
268
269 case DTYPE_PIPE:
270 if (!(mac_labeled & MPC_OBJECT_PIPE))
271 return (EINVAL);
272 pipe = fp->f_data;
273 intlabel = mac_pipe_label_alloc();
274 PIPE_LOCK(pipe);
275 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
276 PIPE_UNLOCK(pipe);
277 error = mac_pipe_externalize_label(intlabel, elements,
278 buffer, mac.m_buflen);
279 mac_pipe_label_free(intlabel);
280 break;
281
282 case DTYPE_SOCKET:
283 if (!(mac_labeled & MPC_OBJECT_SOCKET))
284 return (EINVAL);
285 so = fp->f_data;
286 intlabel = mac_socket_label_alloc(M_WAITOK);
287 SOCK_LOCK(so);
288 mac_socket_copy_label(so->so_label, intlabel);
289 SOCK_UNLOCK(so);
290 error = mac_socket_externalize_label(intlabel, elements,
291 buffer, mac.m_buflen);
292 mac_socket_label_free(intlabel);
293 break;
294
295 default:
296 error = EINVAL;
297 }
298 fdrop(fp, td);
299 if (error == 0)
300 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
301
302 out:
303 free(buffer, M_MACTEMP);
304 free(elements, M_MACTEMP);
305 return (error);
306 }
307
308 int
309 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
310 {
311 char *elements, *buffer;
312 struct nameidata nd;
313 struct label *intlabel;
314 struct mac mac;
315 int vfslocked, error;
316
317 if (!(mac_labeled & MPC_OBJECT_VNODE))
318 return (EINVAL);
319
320 error = copyin(uap->mac_p, &mac, sizeof(mac));
321 if (error)
322 return (error);
323
324 error = mac_check_structmac_consistent(&mac);
325 if (error)
326 return (error);
327
328 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
329 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
330 if (error) {
331 free(elements, M_MACTEMP);
332 return (error);
333 }
334
335 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
336 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
337 uap->path_p, td);
338 error = namei(&nd);
339 if (error)
340 goto out;
341
342 intlabel = mac_vnode_label_alloc();
343 vfslocked = NDHASGIANT(&nd);
344 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
345 error = mac_vnode_externalize_label(intlabel, elements, buffer,
346 mac.m_buflen);
347
348 NDFREE(&nd, 0);
349 VFS_UNLOCK_GIANT(vfslocked);
350 mac_vnode_label_free(intlabel);
351 if (error == 0)
352 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
353
354 out:
355 free(buffer, M_MACTEMP);
356 free(elements, M_MACTEMP);
357
358 return (error);
359 }
360
361 int
362 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
363 {
364 char *elements, *buffer;
365 struct nameidata nd;
366 struct label *intlabel;
367 struct mac mac;
368 int vfslocked, error;
369
370 if (!(mac_labeled & MPC_OBJECT_VNODE))
371 return (EINVAL);
372
373 error = copyin(uap->mac_p, &mac, sizeof(mac));
374 if (error)
375 return (error);
376
377 error = mac_check_structmac_consistent(&mac);
378 if (error)
379 return (error);
380
381 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
382 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
383 if (error) {
384 free(elements, M_MACTEMP);
385 return (error);
386 }
387
388 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
389 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
390 uap->path_p, td);
391 error = namei(&nd);
392 if (error)
393 goto out;
394
395 intlabel = mac_vnode_label_alloc();
396 vfslocked = NDHASGIANT(&nd);
397 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
398 error = mac_vnode_externalize_label(intlabel, elements, buffer,
399 mac.m_buflen);
400 NDFREE(&nd, 0);
401 VFS_UNLOCK_GIANT(vfslocked);
402 mac_vnode_label_free(intlabel);
403
404 if (error == 0)
405 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
406
407 out:
408 free(buffer, M_MACTEMP);
409 free(elements, M_MACTEMP);
410
411 return (error);
412 }
413
414 int
415 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
416 {
417 struct label *intlabel;
418 struct pipe *pipe;
419 struct socket *so;
420 struct file *fp;
421 struct mount *mp;
422 struct vnode *vp;
423 struct mac mac;
424 char *buffer;
425 int error, vfslocked;
426
427 error = copyin(uap->mac_p, &mac, sizeof(mac));
428 if (error)
429 return (error);
430
431 error = mac_check_structmac_consistent(&mac);
432 if (error)
433 return (error);
434
435 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
436 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
437 if (error) {
438 free(buffer, M_MACTEMP);
439 return (error);
440 }
441
442 error = fget(td, uap->fd, &fp);
443 if (error)
444 goto out;
445
446 switch (fp->f_type) {
447 case DTYPE_FIFO:
448 case DTYPE_VNODE:
449 if (!(mac_labeled & MPC_OBJECT_VNODE))
450 return (EINVAL);
451 intlabel = mac_vnode_label_alloc();
452 error = mac_vnode_internalize_label(intlabel, buffer);
453 if (error) {
454 mac_vnode_label_free(intlabel);
455 break;
456 }
457 vp = fp->f_vnode;
458 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
459 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
460 if (error != 0) {
461 VFS_UNLOCK_GIANT(vfslocked);
462 mac_vnode_label_free(intlabel);
463 break;
464 }
465 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
466 error = vn_setlabel(vp, intlabel, td->td_ucred);
467 VOP_UNLOCK(vp, 0);
468 vn_finished_write(mp);
469 VFS_UNLOCK_GIANT(vfslocked);
470 mac_vnode_label_free(intlabel);
471 break;
472
473 case DTYPE_PIPE:
474 if (!(mac_labeled & MPC_OBJECT_PIPE))
475 return (EINVAL);
476 intlabel = mac_pipe_label_alloc();
477 error = mac_pipe_internalize_label(intlabel, buffer);
478 if (error == 0) {
479 pipe = fp->f_data;
480 PIPE_LOCK(pipe);
481 error = mac_pipe_label_set(td->td_ucred,
482 pipe->pipe_pair, intlabel);
483 PIPE_UNLOCK(pipe);
484 }
485 mac_pipe_label_free(intlabel);
486 break;
487
488 case DTYPE_SOCKET:
489 if (!(mac_labeled & MPC_OBJECT_SOCKET))
490 return (EINVAL);
491 intlabel = mac_socket_label_alloc(M_WAITOK);
492 error = mac_socket_internalize_label(intlabel, buffer);
493 if (error == 0) {
494 so = fp->f_data;
495 error = mac_socket_label_set(td->td_ucred, so,
496 intlabel);
497 }
498 mac_socket_label_free(intlabel);
499 break;
500
501 default:
502 error = EINVAL;
503 }
504 fdrop(fp, td);
505 out:
506 free(buffer, M_MACTEMP);
507 return (error);
508 }
509
510 int
511 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
512 {
513 struct label *intlabel;
514 struct nameidata nd;
515 struct mount *mp;
516 struct mac mac;
517 char *buffer;
518 int vfslocked, error;
519
520 if (!(mac_labeled & MPC_OBJECT_VNODE))
521 return (EINVAL);
522
523 error = copyin(uap->mac_p, &mac, sizeof(mac));
524 if (error)
525 return (error);
526
527 error = mac_check_structmac_consistent(&mac);
528 if (error)
529 return (error);
530
531 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
532 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
533 if (error) {
534 free(buffer, M_MACTEMP);
535 return (error);
536 }
537
538 intlabel = mac_vnode_label_alloc();
539 error = mac_vnode_internalize_label(intlabel, buffer);
540 free(buffer, M_MACTEMP);
541 if (error)
542 goto out;
543
544 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
545 uap->path_p, td);
546 error = namei(&nd);
547 vfslocked = NDHASGIANT(&nd);
548 if (error == 0) {
549 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
550 if (error == 0) {
551 error = vn_setlabel(nd.ni_vp, intlabel,
552 td->td_ucred);
553 vn_finished_write(mp);
554 }
555 }
556
557 NDFREE(&nd, 0);
558 VFS_UNLOCK_GIANT(vfslocked);
559 out:
560 mac_vnode_label_free(intlabel);
561 return (error);
562 }
563
564 int
565 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
566 {
567 struct label *intlabel;
568 struct nameidata nd;
569 struct mount *mp;
570 struct mac mac;
571 char *buffer;
572 int vfslocked, error;
573
574 if (!(mac_labeled & MPC_OBJECT_VNODE))
575 return (EINVAL);
576
577 error = copyin(uap->mac_p, &mac, sizeof(mac));
578 if (error)
579 return (error);
580
581 error = mac_check_structmac_consistent(&mac);
582 if (error)
583 return (error);
584
585 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
586 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
587 if (error) {
588 free(buffer, M_MACTEMP);
589 return (error);
590 }
591
592 intlabel = mac_vnode_label_alloc();
593 error = mac_vnode_internalize_label(intlabel, buffer);
594 free(buffer, M_MACTEMP);
595 if (error)
596 goto out;
597
598 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
599 uap->path_p, td);
600 error = namei(&nd);
601 vfslocked = NDHASGIANT(&nd);
602 if (error == 0) {
603 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
604 if (error == 0) {
605 error = vn_setlabel(nd.ni_vp, intlabel,
606 td->td_ucred);
607 vn_finished_write(mp);
608 }
609 }
610
611 NDFREE(&nd, 0);
612 VFS_UNLOCK_GIANT(vfslocked);
613 out:
614 mac_vnode_label_free(intlabel);
615 return (error);
616 }
617
618 int
619 mac_syscall(struct thread *td, struct mac_syscall_args *uap)
620 {
621 struct mac_policy_conf *mpc;
622 char target[MAC_MAX_POLICY_NAME];
623 int error;
624
625 error = copyinstr(uap->policy, target, sizeof(target), NULL);
626 if (error)
627 return (error);
628
629 error = ENOSYS;
630 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
631 if (strcmp(mpc->mpc_name, target) == 0 &&
632 mpc->mpc_ops->mpo_syscall != NULL) {
633 error = mpc->mpc_ops->mpo_syscall(td,
634 uap->call, uap->arg);
635 goto out;
636 }
637 }
638
639 if (!LIST_EMPTY(&mac_policy_list)) {
640 mac_policy_slock_sleep();
641 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
642 if (strcmp(mpc->mpc_name, target) == 0 &&
643 mpc->mpc_ops->mpo_syscall != NULL) {
644 error = mpc->mpc_ops->mpo_syscall(td,
645 uap->call, uap->arg);
646 break;
647 }
648 }
649 mac_policy_sunlock_sleep();
650 }
651 out:
652 return (error);
653 }
654
655 #else /* !MAC */
656
657 int
658 __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
659 {
660
661 return (ENOSYS);
662 }
663
664 int
665 __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
666 {
667
668 return (ENOSYS);
669 }
670
671 int
672 __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
673 {
674
675 return (ENOSYS);
676 }
677
678 int
679 __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
680 {
681
682 return (ENOSYS);
683 }
684
685 int
686 __mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
687 {
688
689 return (ENOSYS);
690 }
691
692 int
693 __mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
694 {
695
696 return (ENOSYS);
697 }
698
699 int
700 __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
701 {
702
703 return (ENOSYS);
704 }
705
706 int
707 __mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
708 {
709
710 return (ENOSYS);
711 }
712
713 int
714 __mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
715 {
716
717 return (ENOSYS);
718 }
719
720 int
721 mac_syscall(struct thread *td, struct mac_syscall_args *uap)
722 {
723
724 return (ENOSYS);
725 }
726
727 #endif /* !MAC */
Cache object: 9a817b4f2a31f142f1603a95044fa08b
|