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