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/abi_compat.h>
50 #include <sys/capsicum.h>
51 #include <sys/fcntl.h>
52 #include <sys/jail.h>
53 #include <sys/jaildesc.h>
54 #include <sys/kernel.h>
55 #include <sys/lock.h>
56 #include <sys/malloc.h>
57 #include <sys/mutex.h>
58 #include <sys/mac.h>
59 #include <sys/proc.h>
60 #include <sys/systm.h>
61 #include <sys/sysctl.h>
62 #include <sys/sysent.h>
63 #include <sys/sysproto.h>
64 #include <sys/vnode.h>
65 #include <sys/mount.h>
66 #include <sys/file.h>
67 #include <sys/namei.h>
68 #include <sys/socket.h>
69 #include <sys/pipe.h>
70 #include <sys/socketvar.h>
71
72 #include <security/mac/mac_framework.h>
73 #include <security/mac/mac_internal.h>
74 #include <security/mac/mac_policy.h>
75 #include <security/mac/mac_syscalls.h>
76
77 #ifdef MAC
78
79 FEATURE(security_mac, "Mandatory Access Control Framework support");
80
81 static int kern___mac_get_path(struct thread *td, const char *path_p,
82 struct mac *mac_p, int follow);
83 static int kern___mac_set_path(struct thread *td, const char *path_p,
84 struct mac *mac_p, int follow);
85
86 #ifdef COMPAT_FREEBSD32
87 struct mac32 {
88 uint32_t m_buflen; /* size_t */
89 uint32_t m_string; /* char * */
90 };
91 #endif
92
93 static int
mac_label_copyin_string(struct mac * const mac,char ** const u_string,int flag)94 mac_label_copyin_string(struct mac *const mac, char **const u_string,
95 int flag)
96 {
97 char *buffer;
98 int error;
99
100 error = mac_check_structmac_consistent(mac);
101 if (error != 0)
102 return (error);
103
104 /* 'm_buflen' not too big checked by function call above. */
105 buffer = malloc(mac->m_buflen, M_MACTEMP, flag);
106 if (buffer == NULL)
107 return (ENOMEM);
108
109 error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
110 if (error != 0) {
111 free(buffer, M_MACTEMP);
112 return (error);
113 }
114
115 MPASS(error == 0);
116 if (u_string != NULL)
117 *u_string = mac->m_string;
118 mac->m_string = buffer;
119 return (0);
120 }
121
122 /*
123 * Copyin a 'struct mac', including the string pointed to by 'm_string'.
124 *
125 * On success (0 returned), fills '*mac', whose associated storage must be freed
126 * after use by calling free_copied_label() (which see). On success, 'u_string'
127 * if not NULL is filled with the userspace address for 'u_mac->m_string'.
128 */
129 int
mac_label_copyin(const void * const u_mac,struct mac * const mac,char ** const u_string)130 mac_label_copyin(const void *const u_mac, struct mac *const mac,
131 char **const u_string)
132 {
133 int error;
134
135 #ifdef COMPAT_FREEBSD32
136 if (SV_CURPROC_FLAG(SV_ILP32)) {
137 struct mac32 mac32;
138
139 error = copyin(u_mac, &mac32, sizeof(mac32));
140 if (error != 0)
141 return (error);
142
143 CP(mac32, *mac, m_buflen);
144 PTRIN_CP(mac32, *mac, m_string);
145 } else
146 #endif
147 {
148 error = copyin(u_mac, mac, sizeof(*mac));
149 if (error != 0)
150 return (error);
151 }
152
153 return (mac_label_copyin_string(mac, u_string, M_WAITOK));
154 }
155
156 void
free_copied_label(const struct mac * const mac)157 free_copied_label(const struct mac *const mac)
158 {
159 free(mac->m_string, M_MACTEMP);
160 }
161
162 int
sys___mac_get_pid(struct thread * td,struct __mac_get_pid_args * uap)163 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
164 {
165 char *buffer, *u_buffer;
166 struct mac mac;
167 struct proc *tproc;
168 struct ucred *tcred;
169 int error;
170
171 error = mac_label_copyin(uap->mac_p, &mac, &u_buffer);
172 if (error)
173 return (error);
174
175 tproc = pfind(uap->pid);
176 if (tproc == NULL) {
177 error = ESRCH;
178 goto free_mac_and_exit;
179 }
180
181 tcred = NULL; /* Satisfy gcc. */
182 error = p_cansee(td, tproc);
183 if (error == 0)
184 tcred = crhold(tproc->p_ucred);
185 PROC_UNLOCK(tproc);
186 if (error)
187 goto free_mac_and_exit;
188
189 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
190 error = mac_cred_externalize_label(tcred->cr_label, mac.m_string,
191 buffer, mac.m_buflen);
192 if (error == 0)
193 error = copyout(buffer, u_buffer, strlen(buffer)+1);
194 free(buffer, M_MACTEMP);
195 crfree(tcred);
196
197 free_mac_and_exit:
198 free_copied_label(&mac);
199 return (error);
200 }
201
202 int
sys___mac_get_proc(struct thread * td,struct __mac_get_proc_args * uap)203 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
204 {
205 char *buffer, *u_buffer;
206 struct mac mac;
207 int error;
208
209 error = mac_label_copyin(uap->mac_p, &mac, &u_buffer);
210 if (error)
211 return (error);
212
213 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
214 error = mac_cred_externalize_label(td->td_ucred->cr_label,
215 mac.m_string, buffer, mac.m_buflen);
216 if (error == 0)
217 error = copyout(buffer, u_buffer, strlen(buffer)+1);
218
219 free(buffer, M_MACTEMP);
220 free_copied_label(&mac);
221 return (error);
222 }
223
224 /*
225 * Performs preparation (including allocations) for mac_set_proc().
226 *
227 * No lock should be held while calling this function. On success,
228 * mac_set_proc_finish() must be called to free the data associated to
229 * 'mac_set_proc_data', even if mac_set_proc_core() fails. 'mac_set_proc_data'
230 * is not set in case of error, and is set to a non-NULL value on success.
231 */
232 int
mac_set_proc_prepare(struct thread * const td,const struct mac * const mac,void ** const mac_set_proc_data)233 mac_set_proc_prepare(struct thread *const td, const struct mac *const mac,
234 void **const mac_set_proc_data)
235 {
236 struct label *intlabel;
237 int error;
238
239 PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
240
241 if (!(mac_labeled & MPC_OBJECT_CRED))
242 return (EINVAL);
243
244 intlabel = mac_cred_label_alloc();
245 error = mac_cred_internalize_label(intlabel, mac->m_string);
246 if (error) {
247 mac_cred_label_free(intlabel);
248 return (error);
249 }
250
251 *mac_set_proc_data = intlabel;
252 return (0);
253 }
254
255 /*
256 * Actually sets the MAC label on 'newcred'.
257 *
258 * The current process' lock *must* be held. This function only sets the label
259 * on 'newcred', but does not put 'newcred' in place on the current process'
260 * (consequently, it also does not call setsugid()). 'mac_set_proc_data' must
261 * be the pointer returned by mac_set_proc_prepare(). If called, this function
262 * must be so between a successful call to mac_set_proc_prepare() and
263 * mac_set_proc_finish(), but calling it is not mandatory (e.g., if some other
264 * error occured under the process lock that obsoletes setting the MAC label).
265 */
266 int
mac_set_proc_core(struct thread * const td,struct ucred * const newcred,void * const mac_set_proc_data)267 mac_set_proc_core(struct thread *const td, struct ucred *const newcred,
268 void *const mac_set_proc_data)
269 {
270 struct label *const intlabel = mac_set_proc_data;
271 struct proc *const p = td->td_proc;
272 int error;
273
274 MPASS(td == curthread);
275 PROC_LOCK_ASSERT(p, MA_OWNED);
276
277 error = mac_cred_check_relabel(p->p_ucred, intlabel);
278 if (error)
279 return (error);
280
281 mac_cred_relabel(newcred, intlabel);
282 return (0);
283 }
284
285 /*
286 * Performs mac_set_proc() last operations, without the process lock.
287 *
288 * 'proc_label_set' indicates whether the label was actually set by a call to
289 * mac_set_proc_core() that succeeded. 'mac_set_proc_data' must be the pointer
290 * returned by mac_set_proc_prepare(), and its associated data will be freed.
291 */
292 void
mac_set_proc_finish(struct thread * const td,bool proc_label_set,void * const mac_set_proc_data)293 mac_set_proc_finish(struct thread *const td, bool proc_label_set,
294 void *const mac_set_proc_data)
295 {
296 struct label *const intlabel = mac_set_proc_data;
297
298 PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
299
300 if (proc_label_set)
301 mac_proc_vm_revoke(td);
302 mac_cred_label_free(intlabel);
303 }
304
305 int
mac_get_prison(struct thread * const td,struct prison * pr,struct vfsoptlist * opts)306 mac_get_prison(struct thread *const td, struct prison *pr,
307 struct vfsoptlist *opts)
308 {
309 char *buffer = NULL, *u_buffer;
310 struct label *intlabel = NULL;
311 struct mac mac;
312 int error;
313 bool locked = true;
314
315 mtx_assert(&pr->pr_mtx, MA_OWNED);
316 #ifdef COMPAT_FREEBSD32
317 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
318 struct mac32 mac32;
319
320 error = vfs_copyopt(opts, "mac.label", &mac32, sizeof(mac32));
321 if (error == 0) {
322 CP(mac32, mac, m_buflen);
323 PTRIN_CP(mac32, mac, m_string);
324 }
325 } else
326 #endif
327 error = vfs_copyopt(opts, "mac.label", &mac, sizeof(mac));
328 if (error) {
329 if (error != ENOENT)
330 vfs_opterror(opts, "bad mac.label");
331 goto out_nomac;
332 }
333
334 intlabel = mac_prison_label_alloc(M_NOWAIT);
335 if (intlabel == NULL) {
336 error = ENOMEM;
337 goto out;
338 }
339
340 if ((mac_labeled & MPC_OBJECT_PRISON) != 0)
341 mac_prison_copy_label(pr->pr_label, intlabel);
342
343 /*
344 * Externalization may want to acquire an rmlock. We already tapped out
345 * a copy of the label from when the jail_get(2) operation started and
346 * we're expected to be called near the end of jail_get(2) when the lock
347 * is about to be dropped anyways, so this is safe.
348 */
349 mtx_unlock(&pr->pr_mtx);
350 locked = false;
351
352 error = mac_label_copyin_string(&mac, &u_buffer, M_WAITOK);
353 if (error) {
354 vfs_opterror(opts, "mac.label: string copy failure");
355 goto out;
356 }
357
358 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
359 if (buffer == NULL) {
360 error = ENOMEM;
361 goto out;
362 }
363
364 error = mac_prison_externalize_label(intlabel, mac.m_string,
365 buffer, mac.m_buflen);
366
367 if (error == 0)
368 error = copyout(buffer, u_buffer, strlen(buffer)+1);
369
370 out:
371 mac_prison_label_free(intlabel);
372 free_copied_label(&mac);
373 free(buffer, M_MACTEMP);
374
375 out_nomac:
376 if (locked) {
377 MPASS(error != 0);
378 mtx_unlock(&pr->pr_mtx);
379 }
380
381 return (error);
382 }
383
384 int
mac_set_prison_prepare(struct thread * const td,struct vfsoptlist * opts,void ** const mac_set_prison_data)385 mac_set_prison_prepare(struct thread *const td, struct vfsoptlist *opts,
386 void **const mac_set_prison_data)
387 {
388 struct mac mac;
389 struct label *intlabel;
390 int error;
391
392 #ifdef COMPAT_FREEBSD32
393 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
394 struct mac32 mac32;
395
396 error = vfs_copyopt(opts, "mac.label", &mac32, sizeof(mac32));
397 if (error == 0) {
398 CP(mac32, mac, m_buflen);
399 PTRIN_CP(mac32, mac, m_string);
400 }
401 } else
402 #endif
403 error = vfs_copyopt(opts, "mac.label", &mac, sizeof(mac));
404 if (error) {
405 if (error != ENOENT)
406 vfs_opterror(opts, "bad mac.label");
407 return (error);
408 }
409
410 error = mac_label_copyin_string(&mac, NULL, M_WAITOK);
411 if (error) {
412 vfs_opterror(opts, "mac.label: string copy failure");
413 return (error);
414 }
415
416 /*
417 * If the option wasn't set, then we return ENOENT above. If we don't
418 * have any policies applicable to prisons, we can return EINVAL early.
419 */
420 if (!(mac_labeled & MPC_OBJECT_PRISON)) {
421 vfs_opterror(opts, "no labelled jail policies");
422 return (EINVAL);
423 }
424
425 intlabel = mac_prison_label_alloc(M_WAITOK);
426 error = mac_prison_internalize_label(intlabel, mac.m_string);
427 if (error) {
428 mac_prison_label_free(intlabel);
429 vfs_opterror(opts, "internalize_label error");
430 return (error);
431 }
432
433 *mac_set_prison_data = intlabel;
434 return (0);
435 }
436
437 int
mac_set_prison_core(struct thread * const td,struct prison * pr,void * const mac_set_prison_data)438 mac_set_prison_core(struct thread *const td, struct prison *pr,
439 void *const mac_set_prison_data)
440 {
441 struct label *const intlabel = mac_set_prison_data;
442
443 return (mac_prison_label_set(td->td_ucred, pr, intlabel));
444 }
445
446 void
mac_set_prison_finish(struct thread * const td,bool prison_label_set __unused,void * const mac_set_prison_data)447 mac_set_prison_finish(struct thread *const td, bool prison_label_set __unused,
448 void *const mac_set_prison_data)
449 {
450 struct label *const intlabel = mac_set_prison_data;
451
452 mac_prison_label_free(intlabel);
453 }
454
455 int
sys___mac_set_proc(struct thread * td,struct __mac_set_proc_args * uap)456 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
457 {
458 struct ucred *newcred, *oldcred;
459 void *intlabel;
460 struct proc *const p = td->td_proc;
461 struct mac mac;
462 int error;
463
464 error = mac_label_copyin(uap->mac_p, &mac, NULL);
465 if (error)
466 return (error);
467
468 error = mac_set_proc_prepare(td, &mac, &intlabel);
469 if (error)
470 goto free_label;
471
472 newcred = crget();
473
474 PROC_LOCK(p);
475 oldcred = p->p_ucred;
476 crcopy(newcred, oldcred);
477
478 error = mac_set_proc_core(td, newcred, intlabel);
479 if (error) {
480 PROC_UNLOCK(p);
481 crfree(newcred);
482 goto finish;
483 }
484
485 setsugid(p);
486 proc_set_cred(p, newcred);
487 PROC_UNLOCK(p);
488
489 crfree(oldcred);
490 finish:
491 mac_set_proc_finish(td, error == 0, intlabel);
492 free_label:
493 free_copied_label(&mac);
494 return (error);
495 }
496
497 int
sys___mac_get_fd(struct thread * td,struct __mac_get_fd_args * uap)498 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
499 {
500 char *u_buffer, *buffer;
501 struct label *intlabel;
502 struct file *fp;
503 struct mac mac;
504 struct vnode *vp;
505 struct pipe *pipe;
506 struct prison *pr;
507 struct socket *so;
508 cap_rights_t rights;
509 int error;
510
511 error = mac_label_copyin(uap->mac_p, &mac, &u_buffer);
512 if (error)
513 return (error);
514
515 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
516 error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_GET),
517 &fp);
518 if (error)
519 goto out;
520
521 switch (fp->f_type) {
522 case DTYPE_FIFO:
523 case DTYPE_VNODE:
524 if (!(mac_labeled & MPC_OBJECT_VNODE)) {
525 error = EINVAL;
526 goto out_fdrop;
527 }
528 vp = fp->f_vnode;
529 intlabel = mac_vnode_label_alloc();
530 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
531 mac_vnode_copy_label(vp->v_label, intlabel);
532 VOP_UNLOCK(vp);
533 error = mac_vnode_externalize_label(intlabel, mac.m_string,
534 buffer, mac.m_buflen);
535 mac_vnode_label_free(intlabel);
536 break;
537
538 case DTYPE_PIPE:
539 if (!(mac_labeled & MPC_OBJECT_PIPE)) {
540 error = EINVAL;
541 goto out_fdrop;
542 }
543 pipe = fp->f_data;
544 intlabel = mac_pipe_label_alloc();
545 PIPE_LOCK(pipe);
546 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
547 PIPE_UNLOCK(pipe);
548 error = mac_pipe_externalize_label(intlabel, mac.m_string,
549 buffer, mac.m_buflen);
550 mac_pipe_label_free(intlabel);
551 break;
552
553 case DTYPE_SOCKET:
554 if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
555 error = EINVAL;
556 goto out_fdrop;
557 }
558 so = fp->f_data;
559 intlabel = mac_socket_label_alloc(M_WAITOK);
560 SOCK_LOCK(so);
561 mac_socket_copy_label(so->so_label, intlabel);
562 SOCK_UNLOCK(so);
563 error = mac_socket_externalize_label(intlabel, mac.m_string,
564 buffer, mac.m_buflen);
565 mac_socket_label_free(intlabel);
566 break;
567
568 case DTYPE_JAILDESC:
569 if (!(mac_labeled & MPC_OBJECT_PRISON)) {
570 error = EINVAL;
571 goto out_fdrop;
572 }
573
574 error = jaildesc_get_prison(fp, &pr);
575 if (error != 0)
576 goto out_fdrop;
577
578 intlabel = mac_prison_label_alloc(M_WAITOK);
579 mac_prison_copy_label(pr->pr_label, intlabel);
580 prison_free(pr);
581
582 error = mac_prison_externalize_label(intlabel, mac.m_string,
583 buffer, mac.m_buflen);
584 mac_prison_label_free(intlabel);
585 break;
586
587 default:
588 error = EINVAL;
589 }
590 if (error == 0)
591 error = copyout(buffer, u_buffer, strlen(buffer)+1);
592 out_fdrop:
593 fdrop(fp, td);
594 out:
595 free(buffer, M_MACTEMP);
596 free_copied_label(&mac);
597 return (error);
598 }
599
600 int
sys___mac_get_file(struct thread * td,struct __mac_get_file_args * uap)601 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
602 {
603
604 return (kern___mac_get_path(td, uap->path_p, uap->mac_p, FOLLOW));
605 }
606
607 int
sys___mac_get_link(struct thread * td,struct __mac_get_link_args * uap)608 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
609 {
610
611 return (kern___mac_get_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
612 }
613
614 static int
kern___mac_get_path(struct thread * td,const char * path_p,struct mac * mac_p,int follow)615 kern___mac_get_path(struct thread *td, const char *path_p, struct mac *mac_p,
616 int follow)
617 {
618 char *u_buffer, *buffer;
619 struct nameidata nd;
620 struct label *intlabel;
621 struct mac mac;
622 int error;
623
624 if (!(mac_labeled & MPC_OBJECT_VNODE))
625 return (EINVAL);
626
627 error = mac_label_copyin(mac_p, &mac, &u_buffer);
628 if (error)
629 return (error);
630
631 buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
632 NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p);
633 error = namei(&nd);
634 if (error)
635 goto out;
636
637 intlabel = mac_vnode_label_alloc();
638 mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
639 error = mac_vnode_externalize_label(intlabel, mac.m_string, buffer,
640 mac.m_buflen);
641 vput(nd.ni_vp);
642 NDFREE_PNBUF(&nd);
643 mac_vnode_label_free(intlabel);
644
645 if (error == 0)
646 error = copyout(buffer, u_buffer, strlen(buffer)+1);
647
648 out:
649 free(buffer, M_MACTEMP);
650 free_copied_label(&mac);
651
652 return (error);
653 }
654
655 int
sys___mac_set_fd(struct thread * td,struct __mac_set_fd_args * uap)656 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
657 {
658 struct label *intlabel;
659 struct pipe *pipe;
660 struct prison *pr;
661 struct socket *so;
662 struct file *fp;
663 struct mount *mp;
664 struct vnode *vp;
665 struct mac mac;
666 cap_rights_t rights;
667 int error;
668
669 error = mac_label_copyin(uap->mac_p, &mac, NULL);
670 if (error)
671 return (error);
672
673 error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_SET),
674 &fp);
675 if (error)
676 goto out;
677
678 switch (fp->f_type) {
679 case DTYPE_FIFO:
680 case DTYPE_VNODE:
681 if (!(mac_labeled & MPC_OBJECT_VNODE)) {
682 error = EINVAL;
683 goto out_fdrop;
684 }
685 intlabel = mac_vnode_label_alloc();
686 error = mac_vnode_internalize_label(intlabel, mac.m_string);
687 if (error) {
688 mac_vnode_label_free(intlabel);
689 break;
690 }
691 vp = fp->f_vnode;
692 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
693 if (error != 0) {
694 mac_vnode_label_free(intlabel);
695 break;
696 }
697 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
698 error = vn_setlabel(vp, intlabel, td->td_ucred);
699 VOP_UNLOCK(vp);
700 vn_finished_write(mp);
701 mac_vnode_label_free(intlabel);
702 break;
703
704 case DTYPE_PIPE:
705 if (!(mac_labeled & MPC_OBJECT_PIPE)) {
706 error = EINVAL;
707 goto out_fdrop;
708 }
709 intlabel = mac_pipe_label_alloc();
710 error = mac_pipe_internalize_label(intlabel, mac.m_string);
711 if (error == 0) {
712 pipe = fp->f_data;
713 PIPE_LOCK(pipe);
714 error = mac_pipe_label_set(td->td_ucred,
715 pipe->pipe_pair, intlabel);
716 PIPE_UNLOCK(pipe);
717 }
718 mac_pipe_label_free(intlabel);
719 break;
720
721 case DTYPE_SOCKET:
722 if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
723 error = EINVAL;
724 goto out_fdrop;
725 }
726 intlabel = mac_socket_label_alloc(M_WAITOK);
727 error = mac_socket_internalize_label(intlabel, mac.m_string);
728 if (error == 0) {
729 so = fp->f_data;
730 error = mac_socket_label_set(td->td_ucred, so,
731 intlabel);
732 }
733 mac_socket_label_free(intlabel);
734 break;
735
736 case DTYPE_JAILDESC:
737 if (!(mac_labeled & MPC_OBJECT_PRISON)) {
738 error = EINVAL;
739 goto out_fdrop;
740 }
741
742 pr = NULL;
743 intlabel = mac_prison_label_alloc(M_WAITOK);
744 error = mac_prison_internalize_label(intlabel, mac.m_string);
745 if (error == 0)
746 error = jaildesc_get_prison(fp, &pr);
747 if (error == 0) {
748 prison_lock(pr);
749 error = mac_prison_label_set(td->td_ucred, pr,
750 intlabel);
751 prison_free_locked(pr);
752 }
753
754 mac_prison_label_free(intlabel);
755 break;
756
757 default:
758 error = EINVAL;
759 }
760 out_fdrop:
761 fdrop(fp, td);
762 out:
763 free_copied_label(&mac);
764 return (error);
765 }
766
767 int
sys___mac_set_file(struct thread * td,struct __mac_set_file_args * uap)768 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
769 {
770
771 return (kern___mac_set_path(td, uap->path_p, uap->mac_p, FOLLOW));
772 }
773
774 int
sys___mac_set_link(struct thread * td,struct __mac_set_link_args * uap)775 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
776 {
777
778 return (kern___mac_set_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
779 }
780
781 static int
kern___mac_set_path(struct thread * td,const char * path_p,struct mac * mac_p,int follow)782 kern___mac_set_path(struct thread *td, const char *path_p, struct mac *mac_p,
783 int follow)
784 {
785 struct label *intlabel;
786 struct nameidata nd;
787 struct mount *mp;
788 struct mac mac;
789 int error;
790
791 if (!(mac_labeled & MPC_OBJECT_VNODE))
792 return (EINVAL);
793
794 error = mac_label_copyin(mac_p, &mac, NULL);
795 if (error)
796 return (error);
797
798 intlabel = mac_vnode_label_alloc();
799 error = mac_vnode_internalize_label(intlabel, mac.m_string);
800 free_copied_label(&mac);
801 if (error)
802 goto out;
803
804 NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p);
805 error = namei(&nd);
806 if (error == 0) {
807 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
808 if (error == 0) {
809 error = vn_setlabel(nd.ni_vp, intlabel,
810 td->td_ucred);
811 vn_finished_write(mp);
812 }
813 vput(nd.ni_vp);
814 NDFREE_PNBUF(&nd);
815 }
816 out:
817 mac_vnode_label_free(intlabel);
818 return (error);
819 }
820
821 int
sys_mac_syscall(struct thread * td,struct mac_syscall_args * uap)822 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
823 {
824 struct mac_policy_conf *mpc;
825 char target[MAC_MAX_POLICY_NAME];
826 int error;
827
828 error = copyinstr(uap->policy, target, sizeof(target), NULL);
829 if (error)
830 return (error);
831
832 error = ENOSYS;
833 LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
834 if (strcmp(mpc->mpc_name, target) == 0 &&
835 mpc->mpc_ops->mpo_syscall != NULL) {
836 error = mpc->mpc_ops->mpo_syscall(td,
837 uap->call, uap->arg);
838 goto out;
839 }
840 }
841
842 if (!LIST_EMPTY(&mac_policy_list)) {
843 mac_policy_slock_sleep();
844 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
845 if (strcmp(mpc->mpc_name, target) == 0 &&
846 mpc->mpc_ops->mpo_syscall != NULL) {
847 error = mpc->mpc_ops->mpo_syscall(td,
848 uap->call, uap->arg);
849 break;
850 }
851 }
852 mac_policy_sunlock_sleep();
853 }
854 out:
855 return (error);
856 }
857
858 #else /* !MAC */
859
860 int
sys___mac_get_pid(struct thread * td,struct __mac_get_pid_args * uap)861 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
862 {
863
864 return (ENOSYS);
865 }
866
867 int
sys___mac_get_proc(struct thread * td,struct __mac_get_proc_args * uap)868 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
869 {
870
871 return (ENOSYS);
872 }
873
874 int
sys___mac_set_proc(struct thread * td,struct __mac_set_proc_args * uap)875 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
876 {
877
878 return (ENOSYS);
879 }
880
881 int
sys___mac_get_fd(struct thread * td,struct __mac_get_fd_args * uap)882 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
883 {
884
885 return (ENOSYS);
886 }
887
888 int
sys___mac_get_file(struct thread * td,struct __mac_get_file_args * uap)889 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
890 {
891
892 return (ENOSYS);
893 }
894
895 int
sys___mac_get_link(struct thread * td,struct __mac_get_link_args * uap)896 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
897 {
898
899 return (ENOSYS);
900 }
901
902 int
sys___mac_set_fd(struct thread * td,struct __mac_set_fd_args * uap)903 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
904 {
905
906 return (ENOSYS);
907 }
908
909 int
sys___mac_set_file(struct thread * td,struct __mac_set_file_args * uap)910 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
911 {
912
913 return (ENOSYS);
914 }
915
916 int
sys___mac_set_link(struct thread * td,struct __mac_set_link_args * uap)917 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
918 {
919
920 return (ENOSYS);
921 }
922
923 int
sys_mac_syscall(struct thread * td,struct mac_syscall_args * uap)924 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
925 {
926
927 return (ENOSYS);
928 }
929
930 #endif /* !MAC */
931