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