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/10.0/sys/security/mac/mac_syscalls.c 255219 2013-09-05 00:09:56Z pjd $");
47
48 #include "opt_mac.h"
49
50 #include <sys/param.h>
51 #include <sys/capability.h>
52 #include <sys/fcntl.h>
53 #include <sys/kernel.h>
54 #include <sys/lock.h>
55 #include <sys/malloc.h>
56 #include <sys/mutex.h>
57 #include <sys/mac.h>
58 #include <sys/proc.h>
59 #include <sys/systm.h>
60 #include <sys/sysctl.h>
61 #include <sys/sysproto.h>
62 #include <sys/sysent.h>
63 #include <sys/vnode.h>
64 #include <sys/mount.h>
65 #include <sys/file.h>
66 #include <sys/namei.h>
67 #include <sys/socket.h>
68 #include <sys/pipe.h>
69 #include <sys/socketvar.h>
70
71 #include <security/mac/mac_framework.h>
72 #include <security/mac/mac_internal.h>
73 #include <security/mac/mac_policy.h>
74
75 #ifdef MAC
76
77 FEATURE(security_mac, "Mandatory Access Control Framework support");
78
79 int
80 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
81 {
82 char *elements, *buffer;
83 struct mac mac;
84 struct proc *tproc;
85 struct ucred *tcred;
86 int error;
87
88 error = copyin(uap->mac_p, &mac, sizeof(mac));
89 if (error)
90 return (error);
91
92 error = mac_check_structmac_consistent(&mac);
93 if (error)
94 return (error);
95
96 tproc = pfind(uap->pid);
97 if (tproc == NULL)
98 return (ESRCH);
99
100 tcred = NULL; /* Satisfy gcc. */
101 error = p_cansee(td, tproc);
102 if (error == 0)
103 tcred = crhold(tproc->p_ucred);
104 PROC_UNLOCK(tproc);
105 if (error)
106 return (error);
107
108 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
109 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
110 if (error) {
111 free(elements, M_MACTEMP);
112 crfree(tcred);
113 return (error);
114 }
115
116 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
117 error = mac_cred_externalize_label(tcred->cr_label, elements,
118 buffer, mac.m_buflen);
119 if (error == 0)
120 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
121
122 free(buffer, M_MACTEMP);
123 free(elements, M_MACTEMP);
124 crfree(tcred);
125 return (error);
126 }
127
128 int
129 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
130 {
131 char *elements, *buffer;
132 struct mac mac;
133 int error;
134
135 error = copyin(uap->mac_p, &mac, sizeof(mac));
136 if (error)
137 return (error);
138
139 error = mac_check_structmac_consistent(&mac);
140 if (error)
141 return (error);
142
143 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
144 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
145 if (error) {
146 free(elements, M_MACTEMP);
147 return (error);
148 }
149
150 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
151 error = mac_cred_externalize_label(td->td_ucred->cr_label,
152 elements, buffer, mac.m_buflen);
153 if (error == 0)
154 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
155
156 free(buffer, M_MACTEMP);
157 free(elements, M_MACTEMP);
158 return (error);
159 }
160
161 int
162 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
163 {
164 struct ucred *newcred, *oldcred;
165 struct label *intlabel;
166 struct proc *p;
167 struct mac mac;
168 char *buffer;
169 int error;
170
171 if (!(mac_labeled & MPC_OBJECT_CRED))
172 return (EINVAL);
173
174 error = copyin(uap->mac_p, &mac, sizeof(mac));
175 if (error)
176 return (error);
177
178 error = mac_check_structmac_consistent(&mac);
179 if (error)
180 return (error);
181
182 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
183 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
184 if (error) {
185 free(buffer, M_MACTEMP);
186 return (error);
187 }
188
189 intlabel = mac_cred_label_alloc();
190 error = mac_cred_internalize_label(intlabel, buffer);
191 free(buffer, M_MACTEMP);
192 if (error)
193 goto out;
194
195 newcred = crget();
196
197 p = td->td_proc;
198 PROC_LOCK(p);
199 oldcred = p->p_ucred;
200
201 error = mac_cred_check_relabel(oldcred, intlabel);
202 if (error) {
203 PROC_UNLOCK(p);
204 crfree(newcred);
205 goto out;
206 }
207
208 setsugid(p);
209 crcopy(newcred, oldcred);
210 mac_cred_relabel(newcred, intlabel);
211 p->p_ucred = newcred;
212
213 PROC_UNLOCK(p);
214 crfree(oldcred);
215 mac_proc_vm_revoke(td);
216
217 out:
218 mac_cred_label_free(intlabel);
219 return (error);
220 }
221
222 int
223 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
224 {
225 char *elements, *buffer;
226 struct label *intlabel;
227 struct file *fp;
228 struct mac mac;
229 struct vnode *vp;
230 struct pipe *pipe;
231 struct socket *so;
232 cap_rights_t rights;
233 short label_type;
234 int error;
235
236 error = copyin(uap->mac_p, &mac, sizeof(mac));
237 if (error)
238 return (error);
239
240 error = mac_check_structmac_consistent(&mac);
241 if (error)
242 return (error);
243
244 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
245 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
246 if (error) {
247 free(elements, M_MACTEMP);
248 return (error);
249 }
250
251 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
252 error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_GET), &fp);
253 if (error)
254 goto out;
255
256 label_type = fp->f_type;
257 switch (fp->f_type) {
258 case DTYPE_FIFO:
259 case DTYPE_VNODE:
260 if (!(mac_labeled & MPC_OBJECT_VNODE)) {
261 error = EINVAL;
262 goto out_fdrop;
263 }
264 vp = fp->f_vnode;
265 intlabel = mac_vnode_label_alloc();
266 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
267 mac_vnode_copy_label(vp->v_label, intlabel);
268 VOP_UNLOCK(vp, 0);
269 error = mac_vnode_externalize_label(intlabel, elements,
270 buffer, mac.m_buflen);
271 mac_vnode_label_free(intlabel);
272 break;
273
274 case DTYPE_PIPE:
275 if (!(mac_labeled & MPC_OBJECT_PIPE)) {
276 error = EINVAL;
277 goto out_fdrop;
278 }
279 pipe = fp->f_data;
280 intlabel = mac_pipe_label_alloc();
281 PIPE_LOCK(pipe);
282 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
283 PIPE_UNLOCK(pipe);
284 error = mac_pipe_externalize_label(intlabel, elements,
285 buffer, mac.m_buflen);
286 mac_pipe_label_free(intlabel);
287 break;
288
289 case DTYPE_SOCKET:
290 if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
291 error = EINVAL;
292 goto out_fdrop;
293 }
294 so = fp->f_data;
295 intlabel = mac_socket_label_alloc(M_WAITOK);
296 SOCK_LOCK(so);
297 mac_socket_copy_label(so->so_label, intlabel);
298 SOCK_UNLOCK(so);
299 error = mac_socket_externalize_label(intlabel, elements,
300 buffer, mac.m_buflen);
301 mac_socket_label_free(intlabel);
302 break;
303
304 default:
305 error = EINVAL;
306 }
307 if (error == 0)
308 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
309 out_fdrop:
310 fdrop(fp, td);
311 out:
312 free(buffer, M_MACTEMP);
313 free(elements, M_MACTEMP);
314 return (error);
315 }
316
317 int
318 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
319 {
320 char *elements, *buffer;
321 struct nameidata nd;
322 struct label *intlabel;
323 struct mac mac;
324 int error;
325
326 if (!(mac_labeled & MPC_OBJECT_VNODE))
327 return (EINVAL);
328
329 error = copyin(uap->mac_p, &mac, sizeof(mac));
330 if (error)
331 return (error);
332
333 error = mac_check_structmac_consistent(&mac);
334 if (error)
335 return (error);
336
337 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
338 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
339 if (error) {
340 free(elements, M_MACTEMP);
341 return (error);
342 }
343
344 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
345 NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE,
346 uap->path_p, td);
347 error = namei(&nd);
348 if (error)
349 goto out;
350
351 intlabel = mac_vnode_label_alloc();
352 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
353 error = mac_vnode_externalize_label(intlabel, elements, buffer,
354 mac.m_buflen);
355
356 NDFREE(&nd, 0);
357 mac_vnode_label_free(intlabel);
358 if (error == 0)
359 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
360
361 out:
362 free(buffer, M_MACTEMP);
363 free(elements, M_MACTEMP);
364
365 return (error);
366 }
367
368 int
369 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
370 {
371 char *elements, *buffer;
372 struct nameidata nd;
373 struct label *intlabel;
374 struct mac mac;
375 int error;
376
377 if (!(mac_labeled & MPC_OBJECT_VNODE))
378 return (EINVAL);
379
380 error = copyin(uap->mac_p, &mac, sizeof(mac));
381 if (error)
382 return (error);
383
384 error = mac_check_structmac_consistent(&mac);
385 if (error)
386 return (error);
387
388 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
389 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
390 if (error) {
391 free(elements, M_MACTEMP);
392 return (error);
393 }
394
395 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
396 NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
397 uap->path_p, td);
398 error = namei(&nd);
399 if (error)
400 goto out;
401
402 intlabel = mac_vnode_label_alloc();
403 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
404 error = mac_vnode_externalize_label(intlabel, elements, buffer,
405 mac.m_buflen);
406 NDFREE(&nd, 0);
407 mac_vnode_label_free(intlabel);
408
409 if (error == 0)
410 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
411
412 out:
413 free(buffer, M_MACTEMP);
414 free(elements, M_MACTEMP);
415
416 return (error);
417 }
418
419 int
420 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
421 {
422 struct label *intlabel;
423 struct pipe *pipe;
424 struct socket *so;
425 struct file *fp;
426 struct mount *mp;
427 struct vnode *vp;
428 struct mac mac;
429 cap_rights_t rights;
430 char *buffer;
431 int error;
432
433 error = copyin(uap->mac_p, &mac, sizeof(mac));
434 if (error)
435 return (error);
436
437 error = mac_check_structmac_consistent(&mac);
438 if (error)
439 return (error);
440
441 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
442 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
443 if (error) {
444 free(buffer, M_MACTEMP);
445 return (error);
446 }
447
448 error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_SET), &fp);
449 if (error)
450 goto out;
451
452 switch (fp->f_type) {
453 case DTYPE_FIFO:
454 case DTYPE_VNODE:
455 if (!(mac_labeled & MPC_OBJECT_VNODE)) {
456 error = EINVAL;
457 goto out_fdrop;
458 }
459 intlabel = mac_vnode_label_alloc();
460 error = mac_vnode_internalize_label(intlabel, buffer);
461 if (error) {
462 mac_vnode_label_free(intlabel);
463 break;
464 }
465 vp = fp->f_vnode;
466 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
467 if (error != 0) {
468 mac_vnode_label_free(intlabel);
469 break;
470 }
471 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
472 error = vn_setlabel(vp, intlabel, td->td_ucred);
473 VOP_UNLOCK(vp, 0);
474 vn_finished_write(mp);
475 mac_vnode_label_free(intlabel);
476 break;
477
478 case DTYPE_PIPE:
479 if (!(mac_labeled & MPC_OBJECT_PIPE)) {
480 error = EINVAL;
481 goto out_fdrop;
482 }
483 intlabel = mac_pipe_label_alloc();
484 error = mac_pipe_internalize_label(intlabel, buffer);
485 if (error == 0) {
486 pipe = fp->f_data;
487 PIPE_LOCK(pipe);
488 error = mac_pipe_label_set(td->td_ucred,
489 pipe->pipe_pair, intlabel);
490 PIPE_UNLOCK(pipe);
491 }
492 mac_pipe_label_free(intlabel);
493 break;
494
495 case DTYPE_SOCKET:
496 if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
497 error = EINVAL;
498 goto out_fdrop;
499 }
500 intlabel = mac_socket_label_alloc(M_WAITOK);
501 error = mac_socket_internalize_label(intlabel, buffer);
502 if (error == 0) {
503 so = fp->f_data;
504 error = mac_socket_label_set(td->td_ucred, so,
505 intlabel);
506 }
507 mac_socket_label_free(intlabel);
508 break;
509
510 default:
511 error = EINVAL;
512 }
513 out_fdrop:
514 fdrop(fp, td);
515 out:
516 free(buffer, M_MACTEMP);
517 return (error);
518 }
519
520 int
521 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
522 {
523 struct label *intlabel;
524 struct nameidata nd;
525 struct mount *mp;
526 struct mac mac;
527 char *buffer;
528 int error;
529
530 if (!(mac_labeled & MPC_OBJECT_VNODE))
531 return (EINVAL);
532
533 error = copyin(uap->mac_p, &mac, sizeof(mac));
534 if (error)
535 return (error);
536
537 error = mac_check_structmac_consistent(&mac);
538 if (error)
539 return (error);
540
541 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
542 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
543 if (error) {
544 free(buffer, M_MACTEMP);
545 return (error);
546 }
547
548 intlabel = mac_vnode_label_alloc();
549 error = mac_vnode_internalize_label(intlabel, buffer);
550 free(buffer, M_MACTEMP);
551 if (error)
552 goto out;
553
554 NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE,
555 uap->path_p, td);
556 error = namei(&nd);
557 if (error == 0) {
558 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
559 if (error == 0) {
560 error = vn_setlabel(nd.ni_vp, intlabel,
561 td->td_ucred);
562 vn_finished_write(mp);
563 }
564 }
565
566 NDFREE(&nd, 0);
567 out:
568 mac_vnode_label_free(intlabel);
569 return (error);
570 }
571
572 int
573 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
574 {
575 struct label *intlabel;
576 struct nameidata nd;
577 struct mount *mp;
578 struct mac mac;
579 char *buffer;
580 int error;
581
582 if (!(mac_labeled & MPC_OBJECT_VNODE))
583 return (EINVAL);
584
585 error = copyin(uap->mac_p, &mac, sizeof(mac));
586 if (error)
587 return (error);
588
589 error = mac_check_structmac_consistent(&mac);
590 if (error)
591 return (error);
592
593 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
594 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
595 if (error) {
596 free(buffer, M_MACTEMP);
597 return (error);
598 }
599
600 intlabel = mac_vnode_label_alloc();
601 error = mac_vnode_internalize_label(intlabel, buffer);
602 free(buffer, M_MACTEMP);
603 if (error)
604 goto out;
605
606 NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
607 uap->path_p, td);
608 error = namei(&nd);
609 if (error == 0) {
610 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
611 if (error == 0) {
612 error = vn_setlabel(nd.ni_vp, intlabel,
613 td->td_ucred);
614 vn_finished_write(mp);
615 }
616 }
617
618 NDFREE(&nd, 0);
619 out:
620 mac_vnode_label_free(intlabel);
621 return (error);
622 }
623
624 int
625 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
626 {
627 struct mac_policy_conf *mpc;
628 char target[MAC_MAX_POLICY_NAME];
629 int error;
630
631 error = copyinstr(uap->policy, target, sizeof(target), NULL);
632 if (error)
633 return (error);
634
635 error = ENOSYS;
636 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
637 if (strcmp(mpc->mpc_name, target) == 0 &&
638 mpc->mpc_ops->mpo_syscall != NULL) {
639 error = mpc->mpc_ops->mpo_syscall(td,
640 uap->call, uap->arg);
641 goto out;
642 }
643 }
644
645 if (!LIST_EMPTY(&mac_policy_list)) {
646 mac_policy_slock_sleep();
647 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
648 if (strcmp(mpc->mpc_name, target) == 0 &&
649 mpc->mpc_ops->mpo_syscall != NULL) {
650 error = mpc->mpc_ops->mpo_syscall(td,
651 uap->call, uap->arg);
652 break;
653 }
654 }
655 mac_policy_sunlock_sleep();
656 }
657 out:
658 return (error);
659 }
660
661 #else /* !MAC */
662
663 int
664 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
665 {
666
667 return (ENOSYS);
668 }
669
670 int
671 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
672 {
673
674 return (ENOSYS);
675 }
676
677 int
678 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
679 {
680
681 return (ENOSYS);
682 }
683
684 int
685 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
686 {
687
688 return (ENOSYS);
689 }
690
691 int
692 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
693 {
694
695 return (ENOSYS);
696 }
697
698 int
699 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
700 {
701
702 return (ENOSYS);
703 }
704
705 int
706 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
707 {
708
709 return (ENOSYS);
710 }
711
712 int
713 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
714 {
715
716 return (ENOSYS);
717 }
718
719 int
720 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
721 {
722
723 return (ENOSYS);
724 }
725
726 int
727 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
728 {
729
730 return (ENOSYS);
731 }
732
733 #endif /* !MAC */
Cache object: a5d7a8cbf72f341db25fb08e8c400b50
|