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 184412 2008-10-28 12:49:07Z 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 PROC_UNLOCK(p);
207 crfree(oldcred);
208 mac_proc_vm_revoke(td);
209
210out:
211 mac_cred_label_free(intlabel);
212 return (error);
213}
214
215int
216__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
217{
218 char *elements, *buffer;
219 struct label *intlabel;
220 struct file *fp;
221 struct mac mac;
222 struct vnode *vp;
223 struct pipe *pipe;
224 struct socket *so;
225 short label_type;
226 int vfslocked, error;
227
228 error = copyin(uap->mac_p, &mac, sizeof(mac));
229 if (error)
230 return (error);
231
232 error = mac_check_structmac_consistent(&mac);
233 if (error)
234 return (error);
235
236 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
237 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
238 if (error) {
239 free(elements, M_MACTEMP);
240 return (error);
241 }
242
243 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
244 error = fget(td, uap->fd, &fp);
245 if (error)
246 goto out;
247
248 label_type = fp->f_type;
249 switch (fp->f_type) {
250 case DTYPE_FIFO:
251 case DTYPE_VNODE:
252 if (!(mac_labeled & MPC_OBJECT_VNODE))
253 return (EINVAL);
254 vp = fp->f_vnode;
255 intlabel = mac_vnode_label_alloc();
256 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
257 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
258 mac_vnode_copy_label(vp->v_label, intlabel);
259 VOP_UNLOCK(vp, 0);
260 VFS_UNLOCK_GIANT(vfslocked);
261 error = mac_vnode_externalize_label(intlabel, elements,
262 buffer, mac.m_buflen);
263 mac_vnode_label_free(intlabel);
264 break;
265
266 case DTYPE_PIPE:
267 if (!(mac_labeled & MPC_OBJECT_PIPE))
268 return (EINVAL);
269 pipe = fp->f_data;
270 intlabel = mac_pipe_label_alloc();
271 PIPE_LOCK(pipe);
272 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
273 PIPE_UNLOCK(pipe);
274 error = mac_pipe_externalize_label(intlabel, elements,
275 buffer, mac.m_buflen);
276 mac_pipe_label_free(intlabel);
277 break;
278
279 case DTYPE_SOCKET:
280 if (!(mac_labeled & MPC_OBJECT_SOCKET))
281 return (EINVAL);
282 so = fp->f_data;
283 intlabel = mac_socket_label_alloc(M_WAITOK);
284 SOCK_LOCK(so);
285 mac_socket_copy_label(so->so_label, intlabel);
286 SOCK_UNLOCK(so);
287 error = mac_socket_externalize_label(intlabel, elements,
288 buffer, mac.m_buflen);
289 mac_socket_label_free(intlabel);
290 break;
291
292 default:
293 error = EINVAL;
294 }
295 fdrop(fp, td);
296 if (error == 0)
297 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
298
299out:
300 free(buffer, M_MACTEMP);
301 free(elements, M_MACTEMP);
302 return (error);
303}
304
305int
306__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
307{
308 char *elements, *buffer;
309 struct nameidata nd;
310 struct label *intlabel;
311 struct mac mac;
312 int vfslocked, error;
313
314 if (!(mac_labeled & MPC_OBJECT_VNODE))
315 return (EINVAL);
316
317 error = copyin(uap->mac_p, &mac, sizeof(mac));
318 if (error)
319 return (error);
320
321 error = mac_check_structmac_consistent(&mac);
322 if (error)
323 return (error);
324
325 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
326 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
327 if (error) {
328 free(elements, M_MACTEMP);
329 return (error);
330 }
331
332 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
333 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
334 uap->path_p, td);
335 error = namei(&nd);
336 if (error)
337 goto out;
338
339 intlabel = mac_vnode_label_alloc();
340 vfslocked = NDHASGIANT(&nd);
341 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
342 error = mac_vnode_externalize_label(intlabel, elements, buffer,
343 mac.m_buflen);
344
345 NDFREE(&nd, 0);
346 VFS_UNLOCK_GIANT(vfslocked);
347 mac_vnode_label_free(intlabel);
348 if (error == 0)
349 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
350
351out:
352 free(buffer, M_MACTEMP);
353 free(elements, M_MACTEMP);
354
355 return (error);
356}
357
358int
359__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
360{
361 char *elements, *buffer;
362 struct nameidata nd;
363 struct label *intlabel;
364 struct mac mac;
365 int vfslocked, error;
366
367 if (!(mac_labeled & MPC_OBJECT_VNODE))
368 return (EINVAL);
369
370 error = copyin(uap->mac_p, &mac, sizeof(mac));
371 if (error)
372 return (error);
373
374 error = mac_check_structmac_consistent(&mac);
375 if (error)
376 return (error);
377
378 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
379 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
380 if (error) {
381 free(elements, M_MACTEMP);
382 return (error);
383 }
384
385 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
386 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
387 uap->path_p, td);
388 error = namei(&nd);
389 if (error)
390 goto out;
391
392 intlabel = mac_vnode_label_alloc();
393 vfslocked = NDHASGIANT(&nd);
394 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
395 error = mac_vnode_externalize_label(intlabel, elements, buffer,
396 mac.m_buflen);
397 NDFREE(&nd, 0);
398 VFS_UNLOCK_GIANT(vfslocked);
399 mac_vnode_label_free(intlabel);
400
401 if (error == 0)
402 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
403
404out:
405 free(buffer, M_MACTEMP);
406 free(elements, M_MACTEMP);
407
408 return (error);
409}
410
411int
412__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
413{
414 struct label *intlabel;
415 struct pipe *pipe;
416 struct socket *so;
417 struct file *fp;
418 struct mount *mp;
419 struct vnode *vp;
420 struct mac mac;
421 char *buffer;
422 int error, vfslocked;
423
424 error = copyin(uap->mac_p, &mac, sizeof(mac));
425 if (error)
426 return (error);
427
428 error = mac_check_structmac_consistent(&mac);
429 if (error)
430 return (error);
431
432 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
433 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
434 if (error) {
435 free(buffer, M_MACTEMP);
436 return (error);
437 }
438
439 error = fget(td, uap->fd, &fp);
440 if (error)
441 goto out;
442
443 switch (fp->f_type) {
444 case DTYPE_FIFO:
445 case DTYPE_VNODE:
446 if (!(mac_labeled & MPC_OBJECT_VNODE))
447 return (EINVAL);
448 intlabel = mac_vnode_label_alloc();
449 error = mac_vnode_internalize_label(intlabel, buffer);
450 if (error) {
451 mac_vnode_label_free(intlabel);
452 break;
453 }
454 vp = fp->f_vnode;
455 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
456 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
457 if (error != 0) {
458 VFS_UNLOCK_GIANT(vfslocked);
459 mac_vnode_label_free(intlabel);
460 break;
461 }
462 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
463 error = vn_setlabel(vp, intlabel, td->td_ucred);
464 VOP_UNLOCK(vp, 0);
465 vn_finished_write(mp);
466 VFS_UNLOCK_GIANT(vfslocked);
467 mac_vnode_label_free(intlabel);
468 break;
469
470 case DTYPE_PIPE:
471 if (!(mac_labeled & MPC_OBJECT_PIPE))
472 return (EINVAL);
473 intlabel = mac_pipe_label_alloc();
474 error = mac_pipe_internalize_label(intlabel, buffer);
475 if (error == 0) {
476 pipe = fp->f_data;
477 PIPE_LOCK(pipe);
478 error = mac_pipe_label_set(td->td_ucred,
479 pipe->pipe_pair, intlabel);
480 PIPE_UNLOCK(pipe);
481 }
482 mac_pipe_label_free(intlabel);
483 break;
484
485 case DTYPE_SOCKET:
486 if (!(mac_labeled & MPC_OBJECT_SOCKET))
487 return (EINVAL);
488 intlabel = mac_socket_label_alloc(M_WAITOK);
489 error = mac_socket_internalize_label(intlabel, buffer);
490 if (error == 0) {
491 so = fp->f_data;
492 error = mac_socket_label_set(td->td_ucred, so,
493 intlabel);
494 }
495 mac_socket_label_free(intlabel);
496 break;
497
498 default:
499 error = EINVAL;
500 }
501 fdrop(fp, td);
502out:
503 free(buffer, M_MACTEMP);
504 return (error);
505}
506
507int
508__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
509{
510 struct label *intlabel;
511 struct nameidata nd;
512 struct mount *mp;
513 struct mac mac;
514 char *buffer;
515 int vfslocked, error;
516
517 if (!(mac_labeled & MPC_OBJECT_VNODE))
518 return (EINVAL);
519
520 error = copyin(uap->mac_p, &mac, sizeof(mac));
521 if (error)
522 return (error);
523
524 error = mac_check_structmac_consistent(&mac);
525 if (error)
526 return (error);
527
528 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
529 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
530 if (error) {
531 free(buffer, M_MACTEMP);
532 return (error);
533 }
534
535 intlabel = mac_vnode_label_alloc();
536 error = mac_vnode_internalize_label(intlabel, buffer);
537 free(buffer, M_MACTEMP);
538 if (error)
539 goto out;
540
541 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
542 uap->path_p, td);
543 error = namei(&nd);
544 vfslocked = NDHASGIANT(&nd);
545 if (error == 0) {
546 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
547 if (error == 0) {
548 error = vn_setlabel(nd.ni_vp, intlabel,
549 td->td_ucred);
550 vn_finished_write(mp);
551 }
552 }
553
554 NDFREE(&nd, 0);
555 VFS_UNLOCK_GIANT(vfslocked);
556out:
557 mac_vnode_label_free(intlabel);
558 return (error);
559}
560
561int
562__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
563{
564 struct label *intlabel;
565 struct nameidata nd;
566 struct mount *mp;
567 struct mac mac;
568 char *buffer;
569 int vfslocked, error;
570
571 if (!(mac_labeled & MPC_OBJECT_VNODE))
572 return (EINVAL);
573
574 error = copyin(uap->mac_p, &mac, sizeof(mac));
575 if (error)
576 return (error);
577
578 error = mac_check_structmac_consistent(&mac);
579 if (error)
580 return (error);
581
582 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
583 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
584 if (error) {
585 free(buffer, M_MACTEMP);
586 return (error);
587 }
588
589 intlabel = mac_vnode_label_alloc();
590 error = mac_vnode_internalize_label(intlabel, buffer);
591 free(buffer, M_MACTEMP);
592 if (error)
593 goto out;
594
595 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
596 uap->path_p, td);
597 error = namei(&nd);
598 vfslocked = NDHASGIANT(&nd);
599 if (error == 0) {
600 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
601 if (error == 0) {
602 error = vn_setlabel(nd.ni_vp, intlabel,
603 td->td_ucred);
604 vn_finished_write(mp);
605 }
606 }
607
608 NDFREE(&nd, 0);
609 VFS_UNLOCK_GIANT(vfslocked);
610out:
611 mac_vnode_label_free(intlabel);
612 return (error);
613}
614
615int
616mac_syscall(struct thread *td, struct mac_syscall_args *uap)
617{
618 struct mac_policy_conf *mpc;
619 char target[MAC_MAX_POLICY_NAME];
620 int entrycount, error;
621
622 error = copyinstr(uap->policy, target, sizeof(target), NULL);
623 if (error)
624 return (error);
625
626 error = ENOSYS;
627 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
628 if (strcmp(mpc->mpc_name, target) == 0 &&
629 mpc->mpc_ops->mpo_syscall != NULL) {
630 error = mpc->mpc_ops->mpo_syscall(td,
631 uap->call, uap->arg);
632 goto out;
633 }
634 }
635
636 if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
637 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
638 if (strcmp(mpc->mpc_name, target) == 0 &&
639 mpc->mpc_ops->mpo_syscall != NULL) {
640 error = mpc->mpc_ops->mpo_syscall(td,
641 uap->call, uap->arg);
642 break;
643 }
644 }
645 mac_policy_list_unbusy();
646 }
647out:
648 return (error);
649}
650
651#else /* !MAC */
652
653int
654__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
655{
656
657 return (ENOSYS);
658}
659
660int
661__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
662{
663
664 return (ENOSYS);
665}
666
667int
668__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
669{
670
671 return (ENOSYS);
672}
673
674int
675__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
676{
677
678 return (ENOSYS);
679}
680
681int
682__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
683{
684
685 return (ENOSYS);
686}
687
688int
689__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
690{
691
692 return (ENOSYS);
693}
694
695int
696__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
697{
698
699 return (ENOSYS);
700}
701
702int
703__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
704{
705
706 return (ENOSYS);
707}
708
709int
710__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
711{
712
713 return (ENOSYS);
714}
715
716int
717mac_syscall(struct thread *td, struct mac_syscall_args *uap)
718{
719
720 return (ENOSYS);
721}
722
723#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 184412 2008-10-28 12:49:07Z 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 PROC_UNLOCK(p);
207 crfree(oldcred);
208 mac_proc_vm_revoke(td);
209
210out:
211 mac_cred_label_free(intlabel);
212 return (error);
213}
214
215int
216__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
217{
218 char *elements, *buffer;
219 struct label *intlabel;
220 struct file *fp;
221 struct mac mac;
222 struct vnode *vp;
223 struct pipe *pipe;
224 struct socket *so;
225 short label_type;
226 int vfslocked, error;
227
228 error = copyin(uap->mac_p, &mac, sizeof(mac));
229 if (error)
230 return (error);
231
232 error = mac_check_structmac_consistent(&mac);
233 if (error)
234 return (error);
235
236 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
237 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
238 if (error) {
239 free(elements, M_MACTEMP);
240 return (error);
241 }
242
243 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
244 error = fget(td, uap->fd, &fp);
245 if (error)
246 goto out;
247
248 label_type = fp->f_type;
249 switch (fp->f_type) {
250 case DTYPE_FIFO:
251 case DTYPE_VNODE:
252 if (!(mac_labeled & MPC_OBJECT_VNODE))
253 return (EINVAL);
254 vp = fp->f_vnode;
255 intlabel = mac_vnode_label_alloc();
256 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
257 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
258 mac_vnode_copy_label(vp->v_label, intlabel);
259 VOP_UNLOCK(vp, 0);
260 VFS_UNLOCK_GIANT(vfslocked);
261 error = mac_vnode_externalize_label(intlabel, elements,
262 buffer, mac.m_buflen);
263 mac_vnode_label_free(intlabel);
264 break;
265
266 case DTYPE_PIPE:
267 if (!(mac_labeled & MPC_OBJECT_PIPE))
268 return (EINVAL);
269 pipe = fp->f_data;
270 intlabel = mac_pipe_label_alloc();
271 PIPE_LOCK(pipe);
272 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
273 PIPE_UNLOCK(pipe);
274 error = mac_pipe_externalize_label(intlabel, elements,
275 buffer, mac.m_buflen);
276 mac_pipe_label_free(intlabel);
277 break;
278
279 case DTYPE_SOCKET:
280 if (!(mac_labeled & MPC_OBJECT_SOCKET))
281 return (EINVAL);
282 so = fp->f_data;
283 intlabel = mac_socket_label_alloc(M_WAITOK);
284 SOCK_LOCK(so);
285 mac_socket_copy_label(so->so_label, intlabel);
286 SOCK_UNLOCK(so);
287 error = mac_socket_externalize_label(intlabel, elements,
288 buffer, mac.m_buflen);
289 mac_socket_label_free(intlabel);
290 break;
291
292 default:
293 error = EINVAL;
294 }
295 fdrop(fp, td);
296 if (error == 0)
297 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
298
299out:
300 free(buffer, M_MACTEMP);
301 free(elements, M_MACTEMP);
302 return (error);
303}
304
305int
306__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
307{
308 char *elements, *buffer;
309 struct nameidata nd;
310 struct label *intlabel;
311 struct mac mac;
312 int vfslocked, error;
313
314 if (!(mac_labeled & MPC_OBJECT_VNODE))
315 return (EINVAL);
316
317 error = copyin(uap->mac_p, &mac, sizeof(mac));
318 if (error)
319 return (error);
320
321 error = mac_check_structmac_consistent(&mac);
322 if (error)
323 return (error);
324
325 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
326 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
327 if (error) {
328 free(elements, M_MACTEMP);
329 return (error);
330 }
331
332 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
333 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
334 uap->path_p, td);
335 error = namei(&nd);
336 if (error)
337 goto out;
338
339 intlabel = mac_vnode_label_alloc();
340 vfslocked = NDHASGIANT(&nd);
341 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
342 error = mac_vnode_externalize_label(intlabel, elements, buffer,
343 mac.m_buflen);
344
345 NDFREE(&nd, 0);
346 VFS_UNLOCK_GIANT(vfslocked);
347 mac_vnode_label_free(intlabel);
348 if (error == 0)
349 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
350
351out:
352 free(buffer, M_MACTEMP);
353 free(elements, M_MACTEMP);
354
355 return (error);
356}
357
358int
359__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
360{
361 char *elements, *buffer;
362 struct nameidata nd;
363 struct label *intlabel;
364 struct mac mac;
365 int vfslocked, error;
366
367 if (!(mac_labeled & MPC_OBJECT_VNODE))
368 return (EINVAL);
369
370 error = copyin(uap->mac_p, &mac, sizeof(mac));
371 if (error)
372 return (error);
373
374 error = mac_check_structmac_consistent(&mac);
375 if (error)
376 return (error);
377
378 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
379 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
380 if (error) {
381 free(elements, M_MACTEMP);
382 return (error);
383 }
384
385 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
386 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
387 uap->path_p, td);
388 error = namei(&nd);
389 if (error)
390 goto out;
391
392 intlabel = mac_vnode_label_alloc();
393 vfslocked = NDHASGIANT(&nd);
394 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
395 error = mac_vnode_externalize_label(intlabel, elements, buffer,
396 mac.m_buflen);
397 NDFREE(&nd, 0);
398 VFS_UNLOCK_GIANT(vfslocked);
399 mac_vnode_label_free(intlabel);
400
401 if (error == 0)
402 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
403
404out:
405 free(buffer, M_MACTEMP);
406 free(elements, M_MACTEMP);
407
408 return (error);
409}
410
411int
412__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
413{
414 struct label *intlabel;
415 struct pipe *pipe;
416 struct socket *so;
417 struct file *fp;
418 struct mount *mp;
419 struct vnode *vp;
420 struct mac mac;
421 char *buffer;
422 int error, vfslocked;
423
424 error = copyin(uap->mac_p, &mac, sizeof(mac));
425 if (error)
426 return (error);
427
428 error = mac_check_structmac_consistent(&mac);
429 if (error)
430 return (error);
431
432 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
433 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
434 if (error) {
435 free(buffer, M_MACTEMP);
436 return (error);
437 }
438
439 error = fget(td, uap->fd, &fp);
440 if (error)
441 goto out;
442
443 switch (fp->f_type) {
444 case DTYPE_FIFO:
445 case DTYPE_VNODE:
446 if (!(mac_labeled & MPC_OBJECT_VNODE))
447 return (EINVAL);
448 intlabel = mac_vnode_label_alloc();
449 error = mac_vnode_internalize_label(intlabel, buffer);
450 if (error) {
451 mac_vnode_label_free(intlabel);
452 break;
453 }
454 vp = fp->f_vnode;
455 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
456 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
457 if (error != 0) {
458 VFS_UNLOCK_GIANT(vfslocked);
459 mac_vnode_label_free(intlabel);
460 break;
461 }
462 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
463 error = vn_setlabel(vp, intlabel, td->td_ucred);
464 VOP_UNLOCK(vp, 0);
465 vn_finished_write(mp);
466 VFS_UNLOCK_GIANT(vfslocked);
467 mac_vnode_label_free(intlabel);
468 break;
469
470 case DTYPE_PIPE:
471 if (!(mac_labeled & MPC_OBJECT_PIPE))
472 return (EINVAL);
473 intlabel = mac_pipe_label_alloc();
474 error = mac_pipe_internalize_label(intlabel, buffer);
475 if (error == 0) {
476 pipe = fp->f_data;
477 PIPE_LOCK(pipe);
478 error = mac_pipe_label_set(td->td_ucred,
479 pipe->pipe_pair, intlabel);
480 PIPE_UNLOCK(pipe);
481 }
482 mac_pipe_label_free(intlabel);
483 break;
484
485 case DTYPE_SOCKET:
486 if (!(mac_labeled & MPC_OBJECT_SOCKET))
487 return (EINVAL);
488 intlabel = mac_socket_label_alloc(M_WAITOK);
489 error = mac_socket_internalize_label(intlabel, buffer);
490 if (error == 0) {
491 so = fp->f_data;
492 error = mac_socket_label_set(td->td_ucred, so,
493 intlabel);
494 }
495 mac_socket_label_free(intlabel);
496 break;
497
498 default:
499 error = EINVAL;
500 }
501 fdrop(fp, td);
502out:
503 free(buffer, M_MACTEMP);
504 return (error);
505}
506
507int
508__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
509{
510 struct label *intlabel;
511 struct nameidata nd;
512 struct mount *mp;
513 struct mac mac;
514 char *buffer;
515 int vfslocked, error;
516
517 if (!(mac_labeled & MPC_OBJECT_VNODE))
518 return (EINVAL);
519
520 error = copyin(uap->mac_p, &mac, sizeof(mac));
521 if (error)
522 return (error);
523
524 error = mac_check_structmac_consistent(&mac);
525 if (error)
526 return (error);
527
528 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
529 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
530 if (error) {
531 free(buffer, M_MACTEMP);
532 return (error);
533 }
534
535 intlabel = mac_vnode_label_alloc();
536 error = mac_vnode_internalize_label(intlabel, buffer);
537 free(buffer, M_MACTEMP);
538 if (error)
539 goto out;
540
541 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
542 uap->path_p, td);
543 error = namei(&nd);
544 vfslocked = NDHASGIANT(&nd);
545 if (error == 0) {
546 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
547 if (error == 0) {
548 error = vn_setlabel(nd.ni_vp, intlabel,
549 td->td_ucred);
550 vn_finished_write(mp);
551 }
552 }
553
554 NDFREE(&nd, 0);
555 VFS_UNLOCK_GIANT(vfslocked);
556out:
557 mac_vnode_label_free(intlabel);
558 return (error);
559}
560
561int
562__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
563{
564 struct label *intlabel;
565 struct nameidata nd;
566 struct mount *mp;
567 struct mac mac;
568 char *buffer;
569 int vfslocked, error;
570
571 if (!(mac_labeled & MPC_OBJECT_VNODE))
572 return (EINVAL);
573
574 error = copyin(uap->mac_p, &mac, sizeof(mac));
575 if (error)
576 return (error);
577
578 error = mac_check_structmac_consistent(&mac);
579 if (error)
580 return (error);
581
582 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
583 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
584 if (error) {
585 free(buffer, M_MACTEMP);
586 return (error);
587 }
588
589 intlabel = mac_vnode_label_alloc();
590 error = mac_vnode_internalize_label(intlabel, buffer);
591 free(buffer, M_MACTEMP);
592 if (error)
593 goto out;
594
595 NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
596 uap->path_p, td);
597 error = namei(&nd);
598 vfslocked = NDHASGIANT(&nd);
599 if (error == 0) {
600 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
601 if (error == 0) {
602 error = vn_setlabel(nd.ni_vp, intlabel,
603 td->td_ucred);
604 vn_finished_write(mp);
605 }
606 }
607
608 NDFREE(&nd, 0);
609 VFS_UNLOCK_GIANT(vfslocked);
610out:
611 mac_vnode_label_free(intlabel);
612 return (error);
613}
614
615int
616mac_syscall(struct thread *td, struct mac_syscall_args *uap)
617{
618 struct mac_policy_conf *mpc;
619 char target[MAC_MAX_POLICY_NAME];
620 int entrycount, error;
621
622 error = copyinstr(uap->policy, target, sizeof(target), NULL);
623 if (error)
624 return (error);
625
626 error = ENOSYS;
627 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
628 if (strcmp(mpc->mpc_name, target) == 0 &&
629 mpc->mpc_ops->mpo_syscall != NULL) {
630 error = mpc->mpc_ops->mpo_syscall(td,
631 uap->call, uap->arg);
632 goto out;
633 }
634 }
635
636 if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
637 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
638 if (strcmp(mpc->mpc_name, target) == 0 &&
639 mpc->mpc_ops->mpo_syscall != NULL) {
640 error = mpc->mpc_ops->mpo_syscall(td,
641 uap->call, uap->arg);
642 break;
643 }
644 }
645 mac_policy_list_unbusy();
646 }
647out:
648 return (error);
649}
650
651#else /* !MAC */
652
653int
654__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
655{
656
657 return (ENOSYS);
658}
659
660int
661__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
662{
663
664 return (ENOSYS);
665}
666
667int
668__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
669{
670
671 return (ENOSYS);
672}
673
674int
675__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
676{
677
678 return (ENOSYS);
679}
680
681int
682__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
683{
684
685 return (ENOSYS);
686}
687
688int
689__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
690{
691
692 return (ENOSYS);
693}
694
695int
696__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
697{
698
699 return (ENOSYS);
700}
701
702int
703__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
704{
705
706 return (ENOSYS);
707}
708
709int
710__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
711{
712
713 return (ENOSYS);
714}
715
716int
717mac_syscall(struct thread *td, struct mac_syscall_args *uap)
718{
719
720 return (ENOSYS);
721}
722
723#endif /* !MAC */