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