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