mac_syscalls.c revision 241896
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 241896 2012-10-22 17:50:54Z kib $");
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 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			error = EINVAL;
261			goto out_fdrop;
262		}
263		vp = fp->f_vnode;
264		intlabel = mac_vnode_label_alloc();
265		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
266		mac_vnode_copy_label(vp->v_label, intlabel);
267		VOP_UNLOCK(vp, 0);
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			error = EINVAL;
276			goto out_fdrop;
277		}
278		pipe = fp->f_data;
279		intlabel = mac_pipe_label_alloc();
280		PIPE_LOCK(pipe);
281		mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
282		PIPE_UNLOCK(pipe);
283		error = mac_pipe_externalize_label(intlabel, elements,
284		    buffer, mac.m_buflen);
285		mac_pipe_label_free(intlabel);
286		break;
287
288	case DTYPE_SOCKET:
289		if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
290			error = EINVAL;
291			goto out_fdrop;
292		}
293		so = fp->f_data;
294		intlabel = mac_socket_label_alloc(M_WAITOK);
295		SOCK_LOCK(so);
296		mac_socket_copy_label(so->so_label, intlabel);
297		SOCK_UNLOCK(so);
298		error = mac_socket_externalize_label(intlabel, elements,
299		    buffer, mac.m_buflen);
300		mac_socket_label_free(intlabel);
301		break;
302
303	default:
304		error = EINVAL;
305	}
306	if (error == 0)
307		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
308out_fdrop:
309	fdrop(fp, td);
310out:
311	free(buffer, M_MACTEMP);
312	free(elements, M_MACTEMP);
313	return (error);
314}
315
316int
317sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
318{
319	char *elements, *buffer;
320	struct nameidata nd;
321	struct label *intlabel;
322	struct mac mac;
323	int error;
324
325	if (!(mac_labeled & MPC_OBJECT_VNODE))
326		return (EINVAL);
327
328	error = copyin(uap->mac_p, &mac, sizeof(mac));
329	if (error)
330		return (error);
331
332	error = mac_check_structmac_consistent(&mac);
333	if (error)
334		return (error);
335
336	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
337	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
338	if (error) {
339		free(elements, M_MACTEMP);
340		return (error);
341	}
342
343	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
344	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE,
345	    uap->path_p, td);
346	error = namei(&nd);
347	if (error)
348		goto out;
349
350	intlabel = mac_vnode_label_alloc();
351	mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
352	error = mac_vnode_externalize_label(intlabel, elements, buffer,
353	    mac.m_buflen);
354
355	NDFREE(&nd, 0);
356	mac_vnode_label_free(intlabel);
357	if (error == 0)
358		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
359
360out:
361	free(buffer, M_MACTEMP);
362	free(elements, M_MACTEMP);
363
364	return (error);
365}
366
367int
368sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
369{
370	char *elements, *buffer;
371	struct nameidata nd;
372	struct label *intlabel;
373	struct mac mac;
374	int error;
375
376	if (!(mac_labeled & MPC_OBJECT_VNODE))
377		return (EINVAL);
378
379	error = copyin(uap->mac_p, &mac, sizeof(mac));
380	if (error)
381		return (error);
382
383	error = mac_check_structmac_consistent(&mac);
384	if (error)
385		return (error);
386
387	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
388	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
389	if (error) {
390		free(elements, M_MACTEMP);
391		return (error);
392	}
393
394	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
395	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
396	    uap->path_p, td);
397	error = namei(&nd);
398	if (error)
399		goto out;
400
401	intlabel = mac_vnode_label_alloc();
402	mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
403	error = mac_vnode_externalize_label(intlabel, elements, buffer,
404	    mac.m_buflen);
405	NDFREE(&nd, 0);
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;
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			error = EINVAL;
455			goto out_fdrop;
456		}
457		intlabel = mac_vnode_label_alloc();
458		error = mac_vnode_internalize_label(intlabel, buffer);
459		if (error) {
460			mac_vnode_label_free(intlabel);
461			break;
462		}
463		vp = fp->f_vnode;
464		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
465		if (error != 0) {
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		mac_vnode_label_free(intlabel);
474		break;
475
476	case DTYPE_PIPE:
477		if (!(mac_labeled & MPC_OBJECT_PIPE)) {
478			error = EINVAL;
479			goto out_fdrop;
480		}
481		intlabel = mac_pipe_label_alloc();
482		error = mac_pipe_internalize_label(intlabel, buffer);
483		if (error == 0) {
484			pipe = fp->f_data;
485			PIPE_LOCK(pipe);
486			error = mac_pipe_label_set(td->td_ucred,
487			    pipe->pipe_pair, intlabel);
488			PIPE_UNLOCK(pipe);
489		}
490		mac_pipe_label_free(intlabel);
491		break;
492
493	case DTYPE_SOCKET:
494		if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
495			error = EINVAL;
496			goto out_fdrop;
497		}
498		intlabel = mac_socket_label_alloc(M_WAITOK);
499		error = mac_socket_internalize_label(intlabel, buffer);
500		if (error == 0) {
501			so = fp->f_data;
502			error = mac_socket_label_set(td->td_ucred, so,
503			    intlabel);
504		}
505		mac_socket_label_free(intlabel);
506		break;
507
508	default:
509		error = EINVAL;
510	}
511out_fdrop:
512	fdrop(fp, td);
513out:
514	free(buffer, M_MACTEMP);
515	return (error);
516}
517
518int
519sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
520{
521	struct label *intlabel;
522	struct nameidata nd;
523	struct mount *mp;
524	struct mac mac;
525	char *buffer;
526	int error;
527
528	if (!(mac_labeled & MPC_OBJECT_VNODE))
529		return (EINVAL);
530
531	error = copyin(uap->mac_p, &mac, sizeof(mac));
532	if (error)
533		return (error);
534
535	error = mac_check_structmac_consistent(&mac);
536	if (error)
537		return (error);
538
539	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
540	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
541	if (error) {
542		free(buffer, M_MACTEMP);
543		return (error);
544	}
545
546	intlabel = mac_vnode_label_alloc();
547	error = mac_vnode_internalize_label(intlabel, buffer);
548	free(buffer, M_MACTEMP);
549	if (error)
550		goto out;
551
552	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE,
553	    uap->path_p, td);
554	error = namei(&nd);
555	if (error == 0) {
556		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
557		if (error == 0) {
558			error = vn_setlabel(nd.ni_vp, intlabel,
559			    td->td_ucred);
560			vn_finished_write(mp);
561		}
562	}
563
564	NDFREE(&nd, 0);
565out:
566	mac_vnode_label_free(intlabel);
567	return (error);
568}
569
570int
571sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
572{
573	struct label *intlabel;
574	struct nameidata nd;
575	struct mount *mp;
576	struct mac mac;
577	char *buffer;
578	int error;
579
580	if (!(mac_labeled & MPC_OBJECT_VNODE))
581		return (EINVAL);
582
583	error = copyin(uap->mac_p, &mac, sizeof(mac));
584	if (error)
585		return (error);
586
587	error = mac_check_structmac_consistent(&mac);
588	if (error)
589		return (error);
590
591	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
592	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
593	if (error) {
594		free(buffer, M_MACTEMP);
595		return (error);
596	}
597
598	intlabel = mac_vnode_label_alloc();
599	error = mac_vnode_internalize_label(intlabel, buffer);
600	free(buffer, M_MACTEMP);
601	if (error)
602		goto out;
603
604	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
605	    uap->path_p, td);
606	error = namei(&nd);
607	if (error == 0) {
608		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
609		if (error == 0) {
610			error = vn_setlabel(nd.ni_vp, intlabel,
611			    td->td_ucred);
612			vn_finished_write(mp);
613		}
614	}
615
616	NDFREE(&nd, 0);
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