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