mac_syscalls.c revision 225617
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: head/sys/security/mac/mac_syscalls.c 225617 2011-09-16 13:58:51Z kmacy $");
47
48#include "opt_mac.h"
49
50#include <sys/param.h>
51#include <sys/capability.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	short label_type;
233	int vfslocked, error;
234
235	error = copyin(uap->mac_p, &mac, sizeof(mac));
236	if (error)
237		return (error);
238
239	error = mac_check_structmac_consistent(&mac);
240	if (error)
241		return (error);
242
243	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
244	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
245	if (error) {
246		free(elements, M_MACTEMP);
247		return (error);
248	}
249
250	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
251	error = fget(td, uap->fd, CAP_MAC_GET, &fp);
252	if (error)
253		goto out;
254
255	label_type = fp->f_type;
256	switch (fp->f_type) {
257	case DTYPE_FIFO:
258	case DTYPE_VNODE:
259		if (!(mac_labeled & MPC_OBJECT_VNODE))
260			return (EINVAL);
261		vp = fp->f_vnode;
262		intlabel = mac_vnode_label_alloc();
263		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
264		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
265		mac_vnode_copy_label(vp->v_label, intlabel);
266		VOP_UNLOCK(vp, 0);
267		VFS_UNLOCK_GIANT(vfslocked);
268		error = mac_vnode_externalize_label(intlabel, elements,
269		    buffer, mac.m_buflen);
270		mac_vnode_label_free(intlabel);
271		break;
272
273	case DTYPE_PIPE:
274		if (!(mac_labeled & MPC_OBJECT_PIPE))
275			return (EINVAL);
276		pipe = fp->f_data;
277		intlabel = mac_pipe_label_alloc();
278		PIPE_LOCK(pipe);
279		mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
280		PIPE_UNLOCK(pipe);
281		error = mac_pipe_externalize_label(intlabel, elements,
282		    buffer, mac.m_buflen);
283		mac_pipe_label_free(intlabel);
284		break;
285
286	case DTYPE_SOCKET:
287		if (!(mac_labeled & MPC_OBJECT_SOCKET))
288			return (EINVAL);
289		so = fp->f_data;
290		intlabel = mac_socket_label_alloc(M_WAITOK);
291		SOCK_LOCK(so);
292		mac_socket_copy_label(so->so_label, intlabel);
293		SOCK_UNLOCK(so);
294		error = mac_socket_externalize_label(intlabel, elements,
295		    buffer, mac.m_buflen);
296		mac_socket_label_free(intlabel);
297		break;
298
299	default:
300		error = EINVAL;
301	}
302	fdrop(fp, td);
303	if (error == 0)
304		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
305
306out:
307	free(buffer, M_MACTEMP);
308	free(elements, M_MACTEMP);
309	return (error);
310}
311
312int
313sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
314{
315	char *elements, *buffer;
316	struct nameidata nd;
317	struct label *intlabel;
318	struct mac mac;
319	int vfslocked, error;
320
321	if (!(mac_labeled & MPC_OBJECT_VNODE))
322		return (EINVAL);
323
324	error = copyin(uap->mac_p, &mac, sizeof(mac));
325	if (error)
326		return (error);
327
328	error = mac_check_structmac_consistent(&mac);
329	if (error)
330		return (error);
331
332	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
333	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
334	if (error) {
335		free(elements, M_MACTEMP);
336		return (error);
337	}
338
339	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
340	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
341	    uap->path_p, td);
342	error = namei(&nd);
343	if (error)
344		goto out;
345
346	intlabel = mac_vnode_label_alloc();
347	vfslocked = NDHASGIANT(&nd);
348	mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
349	error = mac_vnode_externalize_label(intlabel, elements, buffer,
350	    mac.m_buflen);
351
352	NDFREE(&nd, 0);
353	VFS_UNLOCK_GIANT(vfslocked);
354	mac_vnode_label_free(intlabel);
355	if (error == 0)
356		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
357
358out:
359	free(buffer, M_MACTEMP);
360	free(elements, M_MACTEMP);
361
362	return (error);
363}
364
365int
366sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
367{
368	char *elements, *buffer;
369	struct nameidata nd;
370	struct label *intlabel;
371	struct mac mac;
372	int vfslocked, error;
373
374	if (!(mac_labeled & MPC_OBJECT_VNODE))
375		return (EINVAL);
376
377	error = copyin(uap->mac_p, &mac, sizeof(mac));
378	if (error)
379		return (error);
380
381	error = mac_check_structmac_consistent(&mac);
382	if (error)
383		return (error);
384
385	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
386	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
387	if (error) {
388		free(elements, M_MACTEMP);
389		return (error);
390	}
391
392	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
393	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
394	    uap->path_p, td);
395	error = namei(&nd);
396	if (error)
397		goto out;
398
399	intlabel = mac_vnode_label_alloc();
400	vfslocked = NDHASGIANT(&nd);
401	mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
402	error = mac_vnode_externalize_label(intlabel, elements, buffer,
403	    mac.m_buflen);
404	NDFREE(&nd, 0);
405	VFS_UNLOCK_GIANT(vfslocked);
406	mac_vnode_label_free(intlabel);
407
408	if (error == 0)
409		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
410
411out:
412	free(buffer, M_MACTEMP);
413	free(elements, M_MACTEMP);
414
415	return (error);
416}
417
418int
419sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
420{
421	struct label *intlabel;
422	struct pipe *pipe;
423	struct socket *so;
424	struct file *fp;
425	struct mount *mp;
426	struct vnode *vp;
427	struct mac mac;
428	char *buffer;
429	int error, vfslocked;
430
431	error = copyin(uap->mac_p, &mac, sizeof(mac));
432	if (error)
433		return (error);
434
435	error = mac_check_structmac_consistent(&mac);
436	if (error)
437		return (error);
438
439	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
440	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
441	if (error) {
442		free(buffer, M_MACTEMP);
443		return (error);
444	}
445
446	error = fget(td, uap->fd, CAP_MAC_SET, &fp);
447	if (error)
448		goto out;
449
450	switch (fp->f_type) {
451	case DTYPE_FIFO:
452	case DTYPE_VNODE:
453		if (!(mac_labeled & MPC_OBJECT_VNODE))
454			return (EINVAL);
455		intlabel = mac_vnode_label_alloc();
456		error = mac_vnode_internalize_label(intlabel, buffer);
457		if (error) {
458			mac_vnode_label_free(intlabel);
459			break;
460		}
461		vp = fp->f_vnode;
462		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
463		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
464		if (error != 0) {
465			VFS_UNLOCK_GIANT(vfslocked);
466			mac_vnode_label_free(intlabel);
467			break;
468		}
469		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
470		error = vn_setlabel(vp, intlabel, td->td_ucred);
471		VOP_UNLOCK(vp, 0);
472		vn_finished_write(mp);
473		VFS_UNLOCK_GIANT(vfslocked);
474		mac_vnode_label_free(intlabel);
475		break;
476
477	case DTYPE_PIPE:
478		if (!(mac_labeled & MPC_OBJECT_PIPE))
479			return (EINVAL);
480		intlabel = mac_pipe_label_alloc();
481		error = mac_pipe_internalize_label(intlabel, buffer);
482		if (error == 0) {
483			pipe = fp->f_data;
484			PIPE_LOCK(pipe);
485			error = mac_pipe_label_set(td->td_ucred,
486			    pipe->pipe_pair, intlabel);
487			PIPE_UNLOCK(pipe);
488		}
489		mac_pipe_label_free(intlabel);
490		break;
491
492	case DTYPE_SOCKET:
493		if (!(mac_labeled & MPC_OBJECT_SOCKET))
494			return (EINVAL);
495		intlabel = mac_socket_label_alloc(M_WAITOK);
496		error = mac_socket_internalize_label(intlabel, buffer);
497		if (error == 0) {
498			so = fp->f_data;
499			error = mac_socket_label_set(td->td_ucred, so,
500			    intlabel);
501		}
502		mac_socket_label_free(intlabel);
503		break;
504
505	default:
506		error = EINVAL;
507	}
508	fdrop(fp, td);
509out:
510	free(buffer, M_MACTEMP);
511	return (error);
512}
513
514int
515sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
516{
517	struct label *intlabel;
518	struct nameidata nd;
519	struct mount *mp;
520	struct mac mac;
521	char *buffer;
522	int vfslocked, error;
523
524	if (!(mac_labeled & MPC_OBJECT_VNODE))
525		return (EINVAL);
526
527	error = copyin(uap->mac_p, &mac, sizeof(mac));
528	if (error)
529		return (error);
530
531	error = mac_check_structmac_consistent(&mac);
532	if (error)
533		return (error);
534
535	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
536	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
537	if (error) {
538		free(buffer, M_MACTEMP);
539		return (error);
540	}
541
542	intlabel = mac_vnode_label_alloc();
543	error = mac_vnode_internalize_label(intlabel, buffer);
544	free(buffer, M_MACTEMP);
545	if (error)
546		goto out;
547
548	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
549	    uap->path_p, td);
550	error = namei(&nd);
551	vfslocked = NDHASGIANT(&nd);
552	if (error == 0) {
553		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
554		if (error == 0) {
555			error = vn_setlabel(nd.ni_vp, intlabel,
556			    td->td_ucred);
557			vn_finished_write(mp);
558		}
559	}
560
561	NDFREE(&nd, 0);
562	VFS_UNLOCK_GIANT(vfslocked);
563out:
564	mac_vnode_label_free(intlabel);
565	return (error);
566}
567
568int
569sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
570{
571	struct label *intlabel;
572	struct nameidata nd;
573	struct mount *mp;
574	struct mac mac;
575	char *buffer;
576	int vfslocked, error;
577
578	if (!(mac_labeled & MPC_OBJECT_VNODE))
579		return (EINVAL);
580
581	error = copyin(uap->mac_p, &mac, sizeof(mac));
582	if (error)
583		return (error);
584
585	error = mac_check_structmac_consistent(&mac);
586	if (error)
587		return (error);
588
589	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
590	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
591	if (error) {
592		free(buffer, M_MACTEMP);
593		return (error);
594	}
595
596	intlabel = mac_vnode_label_alloc();
597	error = mac_vnode_internalize_label(intlabel, buffer);
598	free(buffer, M_MACTEMP);
599	if (error)
600		goto out;
601
602	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
603	    uap->path_p, td);
604	error = namei(&nd);
605	vfslocked = NDHASGIANT(&nd);
606	if (error == 0) {
607		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
608		if (error == 0) {
609			error = vn_setlabel(nd.ni_vp, intlabel,
610			    td->td_ucred);
611			vn_finished_write(mp);
612		}
613	}
614
615	NDFREE(&nd, 0);
616	VFS_UNLOCK_GIANT(vfslocked);
617out:
618	mac_vnode_label_free(intlabel);
619	return (error);
620}
621
622int
623sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
624{
625	struct mac_policy_conf *mpc;
626	char target[MAC_MAX_POLICY_NAME];
627	int error;
628
629	error = copyinstr(uap->policy, target, sizeof(target), NULL);
630	if (error)
631		return (error);
632
633	error = ENOSYS;
634	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
635		if (strcmp(mpc->mpc_name, target) == 0 &&
636		    mpc->mpc_ops->mpo_syscall != NULL) {
637			error = mpc->mpc_ops->mpo_syscall(td,
638			    uap->call, uap->arg);
639			goto out;
640		}
641	}
642
643	if (!LIST_EMPTY(&mac_policy_list)) {
644		mac_policy_slock_sleep();
645		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
646			if (strcmp(mpc->mpc_name, target) == 0 &&
647			    mpc->mpc_ops->mpo_syscall != NULL) {
648				error = mpc->mpc_ops->mpo_syscall(td,
649				    uap->call, uap->arg);
650				break;
651			}
652		}
653		mac_policy_sunlock_sleep();
654	}
655out:
656	return (error);
657}
658
659#else /* !MAC */
660
661int
662sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
663{
664
665	return (ENOSYS);
666}
667
668int
669sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
670{
671
672	return (ENOSYS);
673}
674
675int
676sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
677{
678
679	return (ENOSYS);
680}
681
682int
683sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
684{
685
686	return (ENOSYS);
687}
688
689int
690sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
691{
692
693	return (ENOSYS);
694}
695
696int
697sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
698{
699
700	return (ENOSYS);
701}
702
703int
704sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
705{
706
707	return (ENOSYS);
708}
709
710int
711sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
712{
713
714	return (ENOSYS);
715}
716
717int
718sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
719{
720
721	return (ENOSYS);
722}
723
724int
725sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
726{
727
728	return (ENOSYS);
729}
730
731#endif /* !MAC */
732