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/sysent.h>
63 #include <sys/vnode.h>
64 #include <sys/mount.h>
65 #include <sys/file.h>
66 #include <sys/namei.h>
67 #include <sys/socket.h>
68 #include <sys/pipe.h>
69 #include <sys/socketvar.h>
70
71 #include <security/mac/mac_framework.h>
72 #include <security/mac/mac_internal.h>
73 #include <security/mac/mac_policy.h>
74
75 #ifdef MAC
76
77 FEATURE(security_mac, "Mandatory Access Control Framework support");
78
79 static int kern___mac_get_path(struct thread *td, const char *path_p,
80 struct mac *mac_p, int follow);
81 static int kern___mac_set_path(struct thread *td, const char *path_p,
82 struct mac *mac_p, int follow);
83
84 int
85 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
86 {
87 char *elements, *buffer;
88 struct mac mac;
89 struct proc *tproc;
90 struct ucred *tcred;
91 int error;
92
93 error = copyin(uap->mac_p, &mac, sizeof(mac));
94 if (error)
95 return (error);
96
97 error = mac_check_structmac_consistent(&mac);
98 if (error)
99 return (error);
100
101 tproc = pfind(uap->pid);
102 if (tproc == NULL)
103 return (ESRCH);
104
105 tcred = NULL; /* Satisfy gcc. */
106 error = p_cansee(td, tproc);
107 if (error == 0)
108 tcred = crhold(tproc->p_ucred);
109 PROC_UNLOCK(tproc);
110 if (error)
111 return (error);
112
113 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
114 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
115 if (error) {
116 free(elements, M_MACTEMP);
117 crfree(tcred);
118 return (error);
119 }
120
121 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
122 error = mac_cred_externalize_label(tcred->cr_label, elements,
123 buffer, mac.m_buflen);
124 if (error == 0)
125 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
126
127 free(buffer, M_MACTEMP);
128 free(elements, M_MACTEMP);
129 crfree(tcred);
130 return (error);
131 }
132
133 int
134 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
135 {
136 char *elements, *buffer;
137 struct mac mac;
138 int error;
139
140 error = copyin(uap->mac_p, &mac, sizeof(mac));
141 if (error)
142 return (error);
143
144 error = mac_check_structmac_consistent(&mac);
145 if (error)
146 return (error);
147
148 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
149 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
150 if (error) {
151 free(elements, M_MACTEMP);
152 return (error);
153 }
154
155 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
156 error = mac_cred_externalize_label(td->td_ucred->cr_label,
157 elements, buffer, mac.m_buflen);
158 if (error == 0)
159 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
160
161 free(buffer, M_MACTEMP);
162 free(elements, M_MACTEMP);
163 return (error);
164 }
165
166 int
167 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
168 {
169 struct ucred *newcred, *oldcred;
170 struct label *intlabel;
171 struct proc *p;
172 struct mac mac;
173 char *buffer;
174 int error;
175
176 if (!(mac_labeled & MPC_OBJECT_CRED))
177 return (EINVAL);
178
179 error = copyin(uap->mac_p, &mac, sizeof(mac));
180 if (error)
181 return (error);
182
183 error = mac_check_structmac_consistent(&mac);
184 if (error)
185 return (error);
186
187 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
188 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
189 if (error) {
190 free(buffer, M_MACTEMP);
191 return (error);
192 }
193
194 intlabel = mac_cred_label_alloc();
195 error = mac_cred_internalize_label(intlabel, buffer);
196 free(buffer, M_MACTEMP);
197 if (error)
198 goto out;
199
200 newcred = crget();
201
202 p = td->td_proc;
203 PROC_LOCK(p);
204 oldcred = p->p_ucred;
205
206 error = mac_cred_check_relabel(oldcred, intlabel);
207 if (error) {
208 PROC_UNLOCK(p);
209 crfree(newcred);
210 goto out;
211 }
212
213 setsugid(p);
214 crcopy(newcred, oldcred);
215 mac_cred_relabel(newcred, intlabel);
216 proc_set_cred(p, newcred);
217
218 PROC_UNLOCK(p);
219 crfree(oldcred);
220 mac_proc_vm_revoke(td);
221
222 out:
223 mac_cred_label_free(intlabel);
224 return (error);
225 }
226
227 int
228 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
229 {
230 char *elements, *buffer;
231 struct label *intlabel;
232 struct file *fp;
233 struct mac mac;
234 struct vnode *vp;
235 struct pipe *pipe;
236 struct socket *so;
237 cap_rights_t rights;
238 int error;
239
240 error = copyin(uap->mac_p, &mac, sizeof(mac));
241 if (error)
242 return (error);
243
244 error = mac_check_structmac_consistent(&mac);
245 if (error)
246 return (error);
247
248 elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
249 error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
250 if (error) {
251 free(elements, M_MACTEMP);
252 return (error);
253 }
254
255 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
256 error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_GET), &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, 0);
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, td);
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 NDFREE(&nd, 0);
373 mac_vnode_label_free(intlabel);
374
375 if (error == 0)
376 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
377
378 out:
379 free(buffer, M_MACTEMP);
380 free(elements, M_MACTEMP);
381
382 return (error);
383 }
384
385 int
386 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
387 {
388 struct label *intlabel;
389 struct pipe *pipe;
390 struct socket *so;
391 struct file *fp;
392 struct mount *mp;
393 struct vnode *vp;
394 struct mac mac;
395 cap_rights_t rights;
396 char *buffer;
397 int error;
398
399 error = copyin(uap->mac_p, &mac, sizeof(mac));
400 if (error)
401 return (error);
402
403 error = mac_check_structmac_consistent(&mac);
404 if (error)
405 return (error);
406
407 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
408 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
409 if (error) {
410 free(buffer, M_MACTEMP);
411 return (error);
412 }
413
414 error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_SET), &fp);
415 if (error)
416 goto out;
417
418 switch (fp->f_type) {
419 case DTYPE_FIFO:
420 case DTYPE_VNODE:
421 if (!(mac_labeled & MPC_OBJECT_VNODE)) {
422 error = EINVAL;
423 goto out_fdrop;
424 }
425 intlabel = mac_vnode_label_alloc();
426 error = mac_vnode_internalize_label(intlabel, buffer);
427 if (error) {
428 mac_vnode_label_free(intlabel);
429 break;
430 }
431 vp = fp->f_vnode;
432 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
433 if (error != 0) {
434 mac_vnode_label_free(intlabel);
435 break;
436 }
437 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
438 error = vn_setlabel(vp, intlabel, td->td_ucred);
439 VOP_UNLOCK(vp, 0);
440 vn_finished_write(mp);
441 mac_vnode_label_free(intlabel);
442 break;
443
444 case DTYPE_PIPE:
445 if (!(mac_labeled & MPC_OBJECT_PIPE)) {
446 error = EINVAL;
447 goto out_fdrop;
448 }
449 intlabel = mac_pipe_label_alloc();
450 error = mac_pipe_internalize_label(intlabel, buffer);
451 if (error == 0) {
452 pipe = fp->f_data;
453 PIPE_LOCK(pipe);
454 error = mac_pipe_label_set(td->td_ucred,
455 pipe->pipe_pair, intlabel);
456 PIPE_UNLOCK(pipe);
457 }
458 mac_pipe_label_free(intlabel);
459 break;
460
461 case DTYPE_SOCKET:
462 if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
463 error = EINVAL;
464 goto out_fdrop;
465 }
466 intlabel = mac_socket_label_alloc(M_WAITOK);
467 error = mac_socket_internalize_label(intlabel, buffer);
468 if (error == 0) {
469 so = fp->f_data;
470 error = mac_socket_label_set(td->td_ucred, so,
471 intlabel);
472 }
473 mac_socket_label_free(intlabel);
474 break;
475
476 default:
477 error = EINVAL;
478 }
479 out_fdrop:
480 fdrop(fp, td);
481 out:
482 free(buffer, M_MACTEMP);
483 return (error);
484 }
485
486 int
487 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
488 {
489
490 return (kern___mac_set_path(td, uap->path_p, uap->mac_p, FOLLOW));
491 }
492
493 int
494 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
495 {
496
497 return (kern___mac_set_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
498 }
499
500 static int
501 kern___mac_set_path(struct thread *td, const char *path_p, struct mac *mac_p,
502 int follow)
503 {
504 struct label *intlabel;
505 struct nameidata nd;
506 struct mount *mp;
507 struct mac mac;
508 char *buffer;
509 int error;
510
511 if (!(mac_labeled & MPC_OBJECT_VNODE))
512 return (EINVAL);
513
514 error = copyin(mac_p, &mac, sizeof(mac));
515 if (error)
516 return (error);
517
518 error = mac_check_structmac_consistent(&mac);
519 if (error)
520 return (error);
521
522 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
523 error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
524 if (error) {
525 free(buffer, M_MACTEMP);
526 return (error);
527 }
528
529 intlabel = mac_vnode_label_alloc();
530 error = mac_vnode_internalize_label(intlabel, buffer);
531 free(buffer, M_MACTEMP);
532 if (error)
533 goto out;
534
535 NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p, td);
536 error = namei(&nd);
537 if (error == 0) {
538 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
539 if (error == 0) {
540 error = vn_setlabel(nd.ni_vp, intlabel,
541 td->td_ucred);
542 vn_finished_write(mp);
543 }
544 }
545
546 NDFREE(&nd, 0);
547 out:
548 mac_vnode_label_free(intlabel);
549 return (error);
550 }
551
552 int
553 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
554 {
555 struct mac_policy_conf *mpc;
556 char target[MAC_MAX_POLICY_NAME];
557 int error;
558
559 error = copyinstr(uap->policy, target, sizeof(target), NULL);
560 if (error)
561 return (error);
562
563 error = ENOSYS;
564 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
565 if (strcmp(mpc->mpc_name, target) == 0 &&
566 mpc->mpc_ops->mpo_syscall != NULL) {
567 error = mpc->mpc_ops->mpo_syscall(td,
568 uap->call, uap->arg);
569 goto out;
570 }
571 }
572
573 if (!LIST_EMPTY(&mac_policy_list)) {
574 mac_policy_slock_sleep();
575 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
576 if (strcmp(mpc->mpc_name, target) == 0 &&
577 mpc->mpc_ops->mpo_syscall != NULL) {
578 error = mpc->mpc_ops->mpo_syscall(td,
579 uap->call, uap->arg);
580 break;
581 }
582 }
583 mac_policy_sunlock_sleep();
584 }
585 out:
586 return (error);
587 }
588
589 #else /* !MAC */
590
591 int
592 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
593 {
594
595 return (ENOSYS);
596 }
597
598 int
599 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
600 {
601
602 return (ENOSYS);
603 }
604
605 int
606 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
607 {
608
609 return (ENOSYS);
610 }
611
612 int
613 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
614 {
615
616 return (ENOSYS);
617 }
618
619 int
620 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
621 {
622
623 return (ENOSYS);
624 }
625
626 int
627 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
628 {
629
630 return (ENOSYS);
631 }
632
633 int
634 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
635 {
636
637 return (ENOSYS);
638 }
639
640 int
641 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
642 {
643
644 return (ENOSYS);
645 }
646
647 int
648 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
649 {
650
651 return (ENOSYS);
652 }
653
654 int
655 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
656 {
657
658 return (ENOSYS);
659 }
660
661 #endif /* !MAC */
Cache object: 6034e6e005382b50fb7978d91d044445
|