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