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