mac_syscalls.c revision 172930
1/*-
2 * Copyright (c) 1999-2002, 2006 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 * All rights reserved.
7 *
8 * This software was developed by Robert Watson and Ilmar Habibulin for the
9 * TrustedBSD Project.
10 *
11 * This software was developed for the FreeBSD Project in part by Network
12 * Associates Laboratories, the Security Research Division of Network
13 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
14 * as part of the DARPA CHATS research program.
15 *
16 * This software was enhanced by SPARTA ISSO under SPAWAR contract
17 * N66001-04-C-6019 ("SEFOS").
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 *    notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 *    notice, this list of conditions and the following disclaimer in the
26 *    documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: head/sys/security/mac/mac_syscalls.c 172930 2007-10-24 19:04:04Z rwatson $");
43
44#include "opt_mac.h"
45
46#include <sys/param.h>
47#include <sys/kernel.h>
48#include <sys/lock.h>
49#include <sys/malloc.h>
50#include <sys/mutex.h>
51#include <sys/mac.h>
52#include <sys/proc.h>
53#include <sys/systm.h>
54#include <sys/sysproto.h>
55#include <sys/sysent.h>
56#include <sys/vnode.h>
57#include <sys/mount.h>
58#include <sys/file.h>
59#include <sys/namei.h>
60#include <sys/socket.h>
61#include <sys/pipe.h>
62#include <sys/socketvar.h>
63
64#include <security/mac/mac_framework.h>
65#include <security/mac/mac_internal.h>
66#include <security/mac/mac_policy.h>
67
68#ifdef MAC
69
70int
71__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
72{
73	char *elements, *buffer;
74	struct mac mac;
75	struct proc *tproc;
76	struct ucred *tcred;
77	int error;
78
79	error = copyin(uap->mac_p, &mac, sizeof(mac));
80	if (error)
81		return (error);
82
83	error = mac_check_structmac_consistent(&mac);
84	if (error)
85		return (error);
86
87	tproc = pfind(uap->pid);
88	if (tproc == NULL)
89		return (ESRCH);
90
91	tcred = NULL;				/* Satisfy gcc. */
92	error = p_cansee(td, tproc);
93	if (error == 0)
94		tcred = crhold(tproc->p_ucred);
95	PROC_UNLOCK(tproc);
96	if (error)
97		return (error);
98
99	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
100	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
101	if (error) {
102		free(elements, M_MACTEMP);
103		crfree(tcred);
104		return (error);
105	}
106
107	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
108	error = mac_cred_externalize_label(tcred->cr_label, elements,
109	    buffer, mac.m_buflen);
110	if (error == 0)
111		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
112
113	free(buffer, M_MACTEMP);
114	free(elements, M_MACTEMP);
115	crfree(tcred);
116	return (error);
117}
118
119int
120__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
121{
122	char *elements, *buffer;
123	struct mac mac;
124	int error;
125
126	error = copyin(uap->mac_p, &mac, sizeof(mac));
127	if (error)
128		return (error);
129
130	error = mac_check_structmac_consistent(&mac);
131	if (error)
132		return (error);
133
134	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
135	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
136	if (error) {
137		free(elements, M_MACTEMP);
138		return (error);
139	}
140
141	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
142	error = mac_cred_externalize_label(td->td_ucred->cr_label,
143	    elements, buffer, mac.m_buflen);
144	if (error == 0)
145		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
146
147	free(buffer, M_MACTEMP);
148	free(elements, M_MACTEMP);
149	return (error);
150}
151
152int
153__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
154{
155	struct ucred *newcred, *oldcred;
156	struct label *intlabel;
157	struct proc *p;
158	struct mac mac;
159	char *buffer;
160	int error;
161
162	error = copyin(uap->mac_p, &mac, sizeof(mac));
163	if (error)
164		return (error);
165
166	error = mac_check_structmac_consistent(&mac);
167	if (error)
168		return (error);
169
170	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
171	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
172	if (error) {
173		free(buffer, M_MACTEMP);
174		return (error);
175	}
176
177	intlabel = mac_cred_label_alloc();
178	error = mac_cred_internalize_label(intlabel, buffer);
179	free(buffer, M_MACTEMP);
180	if (error)
181		goto out;
182
183	newcred = crget();
184
185	p = td->td_proc;
186	PROC_LOCK(p);
187	oldcred = p->p_ucred;
188
189	error = mac_cred_check_relabel(oldcred, intlabel);
190	if (error) {
191		PROC_UNLOCK(p);
192		crfree(newcred);
193		goto out;
194	}
195
196	setsugid(p);
197	crcopy(newcred, oldcred);
198	mac_cred_relabel(newcred, intlabel);
199	p->p_ucred = newcred;
200
201	/*
202	 * Grab additional reference for use while revoking mmaps, prior to
203	 * releasing the proc lock and sharing the cred.
204	 */
205	crhold(newcred);
206	PROC_UNLOCK(p);
207
208	mac_cred_mmapped_drop_perms(td, newcred);
209
210	crfree(newcred);	/* Free revocation reference. */
211	crfree(oldcred);
212
213out:
214	mac_cred_label_free(intlabel);
215	return (error);
216}
217
218int
219__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
220{
221	char *elements, *buffer;
222	struct label *intlabel;
223	struct file *fp;
224	struct mac mac;
225	struct vnode *vp;
226	struct pipe *pipe;
227	struct socket *so;
228	short label_type;
229	int vfslocked, error;
230
231	error = copyin(uap->mac_p, &mac, sizeof(mac));
232	if (error)
233		return (error);
234
235	error = mac_check_structmac_consistent(&mac);
236	if (error)
237		return (error);
238
239	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
240	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
241	if (error) {
242		free(elements, M_MACTEMP);
243		return (error);
244	}
245
246	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
247	error = fget(td, uap->fd, &fp);
248	if (error)
249		goto out;
250
251	label_type = fp->f_type;
252	switch (fp->f_type) {
253	case DTYPE_FIFO:
254	case DTYPE_VNODE:
255		vp = fp->f_vnode;
256		intlabel = mac_vnode_label_alloc();
257		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
258		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
259		mac_vnode_copy_label(vp->v_label, intlabel);
260		VOP_UNLOCK(vp, 0, td);
261		VFS_UNLOCK_GIANT(vfslocked);
262		error = mac_vnode_externalize_label(intlabel, elements,
263		    buffer, mac.m_buflen);
264		mac_vnode_label_free(intlabel);
265		break;
266
267	case DTYPE_PIPE:
268		pipe = fp->f_data;
269		intlabel = mac_pipe_label_alloc();
270		PIPE_LOCK(pipe);
271		mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
272		PIPE_UNLOCK(pipe);
273		error = mac_pipe_externalize_label(intlabel, elements,
274		    buffer, mac.m_buflen);
275		mac_pipe_label_free(intlabel);
276		break;
277
278	case DTYPE_SOCKET:
279		so = fp->f_data;
280		intlabel = mac_socket_label_alloc(M_WAITOK);
281		SOCK_LOCK(so);
282		mac_socket_copy_label(so->so_label, intlabel);
283		SOCK_UNLOCK(so);
284		error = mac_socket_externalize_label(intlabel, elements,
285		    buffer, mac.m_buflen);
286		mac_socket_label_free(intlabel);
287		break;
288
289	default:
290		error = EINVAL;
291	}
292	fdrop(fp, td);
293	if (error == 0)
294		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
295
296out:
297	free(buffer, M_MACTEMP);
298	free(elements, M_MACTEMP);
299	return (error);
300}
301
302int
303__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
304{
305	char *elements, *buffer;
306	struct nameidata nd;
307	struct label *intlabel;
308	struct mac mac;
309	int vfslocked, error;
310
311	error = copyin(uap->mac_p, &mac, sizeof(mac));
312	if (error)
313		return (error);
314
315	error = mac_check_structmac_consistent(&mac);
316	if (error)
317		return (error);
318
319	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
320	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
321	if (error) {
322		free(elements, M_MACTEMP);
323		return (error);
324	}
325
326	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
327	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
328	    uap->path_p, td);
329	error = namei(&nd);
330	if (error)
331		goto out;
332
333	intlabel = mac_vnode_label_alloc();
334	vfslocked = NDHASGIANT(&nd);
335	mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
336	error = mac_vnode_externalize_label(intlabel, elements, buffer,
337	    mac.m_buflen);
338
339	NDFREE(&nd, 0);
340	VFS_UNLOCK_GIANT(vfslocked);
341	mac_vnode_label_free(intlabel);
342	if (error == 0)
343		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
344
345out:
346	free(buffer, M_MACTEMP);
347	free(elements, M_MACTEMP);
348
349	return (error);
350}
351
352int
353__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
354{
355	char *elements, *buffer;
356	struct nameidata nd;
357	struct label *intlabel;
358	struct mac mac;
359	int vfslocked, error;
360
361	error = copyin(uap->mac_p, &mac, sizeof(mac));
362	if (error)
363		return (error);
364
365	error = mac_check_structmac_consistent(&mac);
366	if (error)
367		return (error);
368
369	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
370	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
371	if (error) {
372		free(elements, M_MACTEMP);
373		return (error);
374	}
375
376	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
377	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
378	    uap->path_p, td);
379	error = namei(&nd);
380	if (error)
381		goto out;
382
383	intlabel = mac_vnode_label_alloc();
384	vfslocked = NDHASGIANT(&nd);
385	mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
386	error = mac_vnode_externalize_label(intlabel, elements, buffer,
387	    mac.m_buflen);
388	NDFREE(&nd, 0);
389	VFS_UNLOCK_GIANT(vfslocked);
390	mac_vnode_label_free(intlabel);
391
392	if (error == 0)
393		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
394
395out:
396	free(buffer, M_MACTEMP);
397	free(elements, M_MACTEMP);
398
399	return (error);
400}
401
402int
403__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
404{
405	struct label *intlabel;
406	struct pipe *pipe;
407	struct socket *so;
408	struct file *fp;
409	struct mount *mp;
410	struct vnode *vp;
411	struct mac mac;
412	char *buffer;
413	int error, vfslocked;
414
415	error = copyin(uap->mac_p, &mac, sizeof(mac));
416	if (error)
417		return (error);
418
419	error = mac_check_structmac_consistent(&mac);
420	if (error)
421		return (error);
422
423	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
424	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
425	if (error) {
426		free(buffer, M_MACTEMP);
427		return (error);
428	}
429
430	error = fget(td, uap->fd, &fp);
431	if (error)
432		goto out;
433
434	switch (fp->f_type) {
435	case DTYPE_FIFO:
436	case DTYPE_VNODE:
437		intlabel = mac_vnode_label_alloc();
438		error = mac_vnode_internalize_label(intlabel, buffer);
439		if (error) {
440			mac_vnode_label_free(intlabel);
441			break;
442		}
443		vp = fp->f_vnode;
444		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
445		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
446		if (error != 0) {
447			VFS_UNLOCK_GIANT(vfslocked);
448			mac_vnode_label_free(intlabel);
449			break;
450		}
451		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
452		error = vn_setlabel(vp, intlabel, td->td_ucred);
453		VOP_UNLOCK(vp, 0, td);
454		vn_finished_write(mp);
455		VFS_UNLOCK_GIANT(vfslocked);
456		mac_vnode_label_free(intlabel);
457		break;
458
459	case DTYPE_PIPE:
460		intlabel = mac_pipe_label_alloc();
461		error = mac_pipe_internalize_label(intlabel, buffer);
462		if (error == 0) {
463			pipe = fp->f_data;
464			PIPE_LOCK(pipe);
465			error = mac_pipe_label_set(td->td_ucred,
466			    pipe->pipe_pair, intlabel);
467			PIPE_UNLOCK(pipe);
468		}
469		mac_pipe_label_free(intlabel);
470		break;
471
472	case DTYPE_SOCKET:
473		intlabel = mac_socket_label_alloc(M_WAITOK);
474		error = mac_socket_internalize_label(intlabel, buffer);
475		if (error == 0) {
476			so = fp->f_data;
477			error = mac_socket_label_set(td->td_ucred, so,
478			    intlabel);
479		}
480		mac_socket_label_free(intlabel);
481		break;
482
483	default:
484		error = EINVAL;
485	}
486	fdrop(fp, td);
487out:
488	free(buffer, M_MACTEMP);
489	return (error);
490}
491
492int
493__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
494{
495	struct label *intlabel;
496	struct nameidata nd;
497	struct mount *mp;
498	struct mac mac;
499	char *buffer;
500	int vfslocked, error;
501
502	error = copyin(uap->mac_p, &mac, sizeof(mac));
503	if (error)
504		return (error);
505
506	error = mac_check_structmac_consistent(&mac);
507	if (error)
508		return (error);
509
510	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
511	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
512	if (error) {
513		free(buffer, M_MACTEMP);
514		return (error);
515	}
516
517	intlabel = mac_vnode_label_alloc();
518	error = mac_vnode_internalize_label(intlabel, buffer);
519	free(buffer, M_MACTEMP);
520	if (error)
521		goto out;
522
523	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
524	    uap->path_p, td);
525	error = namei(&nd);
526	vfslocked = NDHASGIANT(&nd);
527	if (error == 0) {
528		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
529		if (error == 0) {
530			error = vn_setlabel(nd.ni_vp, intlabel,
531			    td->td_ucred);
532			vn_finished_write(mp);
533		}
534	}
535
536	NDFREE(&nd, 0);
537	VFS_UNLOCK_GIANT(vfslocked);
538out:
539	mac_vnode_label_free(intlabel);
540	return (error);
541}
542
543int
544__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
545{
546	struct label *intlabel;
547	struct nameidata nd;
548	struct mount *mp;
549	struct mac mac;
550	char *buffer;
551	int vfslocked, error;
552
553	error = copyin(uap->mac_p, &mac, sizeof(mac));
554	if (error)
555		return (error);
556
557	error = mac_check_structmac_consistent(&mac);
558	if (error)
559		return (error);
560
561	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
562	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
563	if (error) {
564		free(buffer, M_MACTEMP);
565		return (error);
566	}
567
568	intlabel = mac_vnode_label_alloc();
569	error = mac_vnode_internalize_label(intlabel, buffer);
570	free(buffer, M_MACTEMP);
571	if (error)
572		goto out;
573
574	NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
575	    uap->path_p, td);
576	error = namei(&nd);
577	vfslocked = NDHASGIANT(&nd);
578	if (error == 0) {
579		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
580		if (error == 0) {
581			error = vn_setlabel(nd.ni_vp, intlabel,
582			    td->td_ucred);
583			vn_finished_write(mp);
584		}
585	}
586
587	NDFREE(&nd, 0);
588	VFS_UNLOCK_GIANT(vfslocked);
589out:
590	mac_vnode_label_free(intlabel);
591	return (error);
592}
593
594int
595mac_syscall(struct thread *td, struct mac_syscall_args *uap)
596{
597	struct mac_policy_conf *mpc;
598	char target[MAC_MAX_POLICY_NAME];
599	int entrycount, error;
600
601	error = copyinstr(uap->policy, target, sizeof(target), NULL);
602	if (error)
603		return (error);
604
605	error = ENOSYS;
606	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
607		if (strcmp(mpc->mpc_name, target) == 0 &&
608		    mpc->mpc_ops->mpo_syscall != NULL) {
609			error = mpc->mpc_ops->mpo_syscall(td,
610			    uap->call, uap->arg);
611			goto out;
612		}
613	}
614
615	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
616		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
617			if (strcmp(mpc->mpc_name, target) == 0 &&
618			    mpc->mpc_ops->mpo_syscall != NULL) {
619				error = mpc->mpc_ops->mpo_syscall(td,
620				    uap->call, uap->arg);
621				break;
622			}
623		}
624		mac_policy_list_unbusy();
625	}
626out:
627	return (error);
628}
629
630#else /* !MAC */
631
632int
633__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
634{
635
636	return (ENOSYS);
637}
638
639int
640__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
641{
642
643	return (ENOSYS);
644}
645
646int
647__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
648{
649
650	return (ENOSYS);
651}
652
653int
654__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
655{
656
657	return (ENOSYS);
658}
659
660int
661__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
662{
663
664	return (ENOSYS);
665}
666
667int
668__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
669{
670
671	return (ENOSYS);
672}
673
674int
675__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
676{
677
678	return (ENOSYS);
679}
680
681int
682__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
683{
684
685	return (ENOSYS);
686}
687
688int
689__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
690{
691
692	return (ENOSYS);
693}
694
695int
696mac_syscall(struct thread *td, struct mac_syscall_args *uap)
697{
698
699	return (ENOSYS);
700}
701
702#endif /* !MAC */
703