xref: /freebsd/sys/kern/kern_jail.c (revision ad1ff0997e957cb2a8d1c05e0ed940ad5066a480)
107901f22SPoul-Henning Kamp /*
207901f22SPoul-Henning Kamp  * ----------------------------------------------------------------------------
307901f22SPoul-Henning Kamp  * "THE BEER-WARE LICENSE" (Revision 42):
407901f22SPoul-Henning Kamp  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
507901f22SPoul-Henning Kamp  * can do whatever you want with this stuff. If we meet some day, and you think
607901f22SPoul-Henning Kamp  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
707901f22SPoul-Henning Kamp  * ----------------------------------------------------------------------------
807901f22SPoul-Henning Kamp  *
9c3aac50fSPeter Wemm  * $FreeBSD$
1007901f22SPoul-Henning Kamp  *
1107901f22SPoul-Henning Kamp  */
1275c13541SPoul-Henning Kamp 
1375c13541SPoul-Henning Kamp #include <sys/param.h>
1475c13541SPoul-Henning Kamp #include <sys/types.h>
1575c13541SPoul-Henning Kamp #include <sys/kernel.h>
1675c13541SPoul-Henning Kamp #include <sys/systm.h>
1775c13541SPoul-Henning Kamp #include <sys/errno.h>
1875c13541SPoul-Henning Kamp #include <sys/sysproto.h>
1975c13541SPoul-Henning Kamp #include <sys/malloc.h>
2075c13541SPoul-Henning Kamp #include <sys/proc.h>
2175c13541SPoul-Henning Kamp #include <sys/jail.h>
2201137630SRobert Watson #include <sys/lock.h>
2301137630SRobert Watson #include <sys/mutex.h>
2475c13541SPoul-Henning Kamp #include <sys/socket.h>
2583f1e257SRobert Watson #include <sys/sysctl.h>
2675c13541SPoul-Henning Kamp #include <net/if.h>
2775c13541SPoul-Henning Kamp #include <netinet/in.h>
2875c13541SPoul-Henning Kamp 
2975c13541SPoul-Henning Kamp MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
3075c13541SPoul-Henning Kamp 
31d0615c64SAndrew R. Reiter SYSCTL_DECL(_security);
32d0615c64SAndrew R. Reiter SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
3383f1e257SRobert Watson     "Jail rules");
3483f1e257SRobert Watson 
35a2f2b3afSJohn Baldwin mp_fixme("these variables need a lock")
36a2f2b3afSJohn Baldwin 
3783f1e257SRobert Watson int	jail_set_hostname_allowed = 1;
38d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
3983f1e257SRobert Watson     &jail_set_hostname_allowed, 0,
4083f1e257SRobert Watson     "Processes in jail can set their hostnames");
4183f1e257SRobert Watson 
427cadc266SRobert Watson int	jail_socket_unixiproute_only = 1;
43d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
447cadc266SRobert Watson     &jail_socket_unixiproute_only, 0,
457cadc266SRobert Watson     "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
467cadc266SRobert Watson 
47cb1f0db9SRobert Watson int	jail_sysvipc_allowed = 0;
48d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
49cb1f0db9SRobert Watson     &jail_sysvipc_allowed, 0,
50cb1f0db9SRobert Watson     "Processes in jail can use System V IPC primitives");
51cb1f0db9SRobert Watson 
52116734c4SMatthew Dillon /*
53116734c4SMatthew Dillon  * MPSAFE
54116734c4SMatthew Dillon  */
5575c13541SPoul-Henning Kamp int
56b40ce416SJulian Elischer jail(td, uap)
57b40ce416SJulian Elischer 	struct thread *td;
5875c13541SPoul-Henning Kamp 	struct jail_args /* {
5975c13541SPoul-Henning Kamp 		syscallarg(struct jail *) jail;
6075c13541SPoul-Henning Kamp 	} */ *uap;
6175c13541SPoul-Henning Kamp {
62b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
6375c13541SPoul-Henning Kamp 	int error;
6475c13541SPoul-Henning Kamp 	struct prison *pr;
6575c13541SPoul-Henning Kamp 	struct jail j;
6675c13541SPoul-Henning Kamp 	struct chroot_args ca;
67a2f2b3afSJohn Baldwin 	struct ucred *newcred = NULL, *oldcred;
6875c13541SPoul-Henning Kamp 
6975c13541SPoul-Henning Kamp 	error = copyin(uap->jail, &j, sizeof j);
7075c13541SPoul-Henning Kamp 	if (error)
71a2f2b3afSJohn Baldwin 		return (error);
72a2f2b3afSJohn Baldwin 	if (j.version != 0)
73a2f2b3afSJohn Baldwin 		return (EINVAL);
74a2f2b3afSJohn Baldwin 
75a2f2b3afSJohn Baldwin 	mtx_lock(&Giant);
767cc0979fSDavid Malone 	MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
7701137630SRobert Watson 	mtx_init(&pr->pr_mtx, "jail mutex", MTX_DEF);
78567931c8SRobert Watson 	pr->pr_securelevel = securelevel;
7975c13541SPoul-Henning Kamp 	error = copyinstr(j.hostname, &pr->pr_host, sizeof pr->pr_host, 0);
8075c13541SPoul-Henning Kamp 	if (error)
8175c13541SPoul-Henning Kamp 		goto bail;
8275c13541SPoul-Henning Kamp 	ca.path = j.path;
83b40ce416SJulian Elischer 	error = chroot(td, &ca);
8475c13541SPoul-Henning Kamp 	if (error)
8575c13541SPoul-Henning Kamp 		goto bail;
86a2f2b3afSJohn Baldwin 	newcred = crget();
87a2f2b3afSJohn Baldwin 	pr->pr_ip = j.ip_number;
88a2f2b3afSJohn Baldwin 	PROC_LOCK(p);
89a2f2b3afSJohn Baldwin 	/* Implicitly fail if already in jail.  */
90fc5d29efSRobert Watson 	error = suser_xxx(p->p_ucred, NULL, 0);
91a2f2b3afSJohn Baldwin 	if (error)
92a2f2b3afSJohn Baldwin 		goto badcred;
93a2f2b3afSJohn Baldwin 	oldcred = p->p_ucred;
94a2f2b3afSJohn Baldwin 	crcopy(newcred, oldcred);
95a2f2b3afSJohn Baldwin 	p->p_ucred = newcred;
9691421ba2SRobert Watson 	p->p_ucred->cr_prison = pr;
9791421ba2SRobert Watson 	pr->pr_ref = 1;
98a2f2b3afSJohn Baldwin 	PROC_UNLOCK(p);
99a2f2b3afSJohn Baldwin 	crfree(oldcred);
100116734c4SMatthew Dillon 	mtx_unlock(&Giant);
10175c13541SPoul-Henning Kamp 	return (0);
102a2f2b3afSJohn Baldwin badcred:
103a2f2b3afSJohn Baldwin 	PROC_UNLOCK(p);
104a2f2b3afSJohn Baldwin 	crfree(newcred);
10575c13541SPoul-Henning Kamp bail:
10675c13541SPoul-Henning Kamp 	FREE(pr, M_PRISON);
107116734c4SMatthew Dillon 	mtx_unlock(&Giant);
10875c13541SPoul-Henning Kamp 	return (error);
10975c13541SPoul-Henning Kamp }
11075c13541SPoul-Henning Kamp 
11191421ba2SRobert Watson void
11291421ba2SRobert Watson prison_free(struct prison *pr)
11391421ba2SRobert Watson {
11491421ba2SRobert Watson 
11501137630SRobert Watson 	mtx_lock(&pr->pr_mtx);
11691421ba2SRobert Watson 	pr->pr_ref--;
11791421ba2SRobert Watson 	if (pr->pr_ref == 0) {
11801137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
11901137630SRobert Watson 		mtx_destroy(&pr->pr_mtx);
12091421ba2SRobert Watson 		if (pr->pr_linux != NULL)
12191421ba2SRobert Watson 			FREE(pr->pr_linux, M_PRISON);
12291421ba2SRobert Watson 		FREE(pr, M_PRISON);
12301137630SRobert Watson 		return;
12491421ba2SRobert Watson 	}
12501137630SRobert Watson 	mtx_unlock(&pr->pr_mtx);
12691421ba2SRobert Watson }
12791421ba2SRobert Watson 
12891421ba2SRobert Watson void
12991421ba2SRobert Watson prison_hold(struct prison *pr)
13091421ba2SRobert Watson {
13191421ba2SRobert Watson 
13201137630SRobert Watson 	mtx_lock(&pr->pr_mtx);
13391421ba2SRobert Watson 	pr->pr_ref++;
13401137630SRobert Watson 	mtx_unlock(&pr->pr_mtx);
13501137630SRobert Watson }
13601137630SRobert Watson 
13701137630SRobert Watson u_int32_t
13801137630SRobert Watson prison_getip(struct ucred *cred)
13901137630SRobert Watson {
14001137630SRobert Watson 
14101137630SRobert Watson 	return (cred->cr_prison->pr_ip);
14291421ba2SRobert Watson }
14391421ba2SRobert Watson 
14475c13541SPoul-Henning Kamp int
14591421ba2SRobert Watson prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
14675c13541SPoul-Henning Kamp {
14775c13541SPoul-Henning Kamp 	u_int32_t tmp;
14875c13541SPoul-Henning Kamp 
14991421ba2SRobert Watson 	if (!jailed(cred))
15075c13541SPoul-Henning Kamp 		return (0);
15175c13541SPoul-Henning Kamp 	if (flag)
15275c13541SPoul-Henning Kamp 		tmp = *ip;
15375c13541SPoul-Henning Kamp 	else
15475c13541SPoul-Henning Kamp 		tmp = ntohl(*ip);
15575c13541SPoul-Henning Kamp 	if (tmp == INADDR_ANY) {
15675c13541SPoul-Henning Kamp 		if (flag)
15791421ba2SRobert Watson 			*ip = cred->cr_prison->pr_ip;
15875c13541SPoul-Henning Kamp 		else
15991421ba2SRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
16075c13541SPoul-Henning Kamp 		return (0);
16175c13541SPoul-Henning Kamp 	}
162fd6aaf7fSRobert Watson 	if (tmp == INADDR_LOOPBACK) {
163fd6aaf7fSRobert Watson 		if (flag)
164fd6aaf7fSRobert Watson 			*ip = cred->cr_prison->pr_ip;
165fd6aaf7fSRobert Watson 		else
166fd6aaf7fSRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
167fd6aaf7fSRobert Watson 		return (0);
168fd6aaf7fSRobert Watson 	}
16991421ba2SRobert Watson 	if (cred->cr_prison->pr_ip != tmp)
17075c13541SPoul-Henning Kamp 		return (1);
17175c13541SPoul-Henning Kamp 	return (0);
17275c13541SPoul-Henning Kamp }
17375c13541SPoul-Henning Kamp 
17475c13541SPoul-Henning Kamp void
17591421ba2SRobert Watson prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
17675c13541SPoul-Henning Kamp {
17775c13541SPoul-Henning Kamp 	u_int32_t tmp;
17875c13541SPoul-Henning Kamp 
17991421ba2SRobert Watson 	if (!jailed(cred))
18075c13541SPoul-Henning Kamp 		return;
18175c13541SPoul-Henning Kamp 	if (flag)
18275c13541SPoul-Henning Kamp 		tmp = *ip;
18375c13541SPoul-Henning Kamp 	else
18475c13541SPoul-Henning Kamp 		tmp = ntohl(*ip);
185fd6aaf7fSRobert Watson 	if (tmp == INADDR_LOOPBACK) {
18675c13541SPoul-Henning Kamp 		if (flag)
18791421ba2SRobert Watson 			*ip = cred->cr_prison->pr_ip;
18875c13541SPoul-Henning Kamp 		else
18991421ba2SRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
19075c13541SPoul-Henning Kamp 		return;
19175c13541SPoul-Henning Kamp 	}
19275c13541SPoul-Henning Kamp 	return;
19375c13541SPoul-Henning Kamp }
19475c13541SPoul-Henning Kamp 
19575c13541SPoul-Henning Kamp int
19691421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa)
19775c13541SPoul-Henning Kamp {
19875c13541SPoul-Henning Kamp 	struct sockaddr_in *sai = (struct sockaddr_in*) sa;
19975c13541SPoul-Henning Kamp 	int ok;
20075c13541SPoul-Henning Kamp 
2017cadc266SRobert Watson 	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
2027cadc266SRobert Watson 		ok = 1;
2037cadc266SRobert Watson 	else if (sai->sin_family != AF_INET)
20475c13541SPoul-Henning Kamp 		ok = 0;
20591421ba2SRobert Watson 	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
20675c13541SPoul-Henning Kamp 		ok = 1;
20775c13541SPoul-Henning Kamp 	else
20875c13541SPoul-Henning Kamp 		ok = 0;
20975c13541SPoul-Henning Kamp 	return (ok);
21075c13541SPoul-Henning Kamp }
21191421ba2SRobert Watson 
21291421ba2SRobert Watson /*
21391421ba2SRobert Watson  * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
21491421ba2SRobert Watson  */
21591421ba2SRobert Watson int
21691421ba2SRobert Watson prison_check(cred1, cred2)
21791421ba2SRobert Watson 	struct ucred *cred1, *cred2;
21891421ba2SRobert Watson {
21991421ba2SRobert Watson 
22091421ba2SRobert Watson 	if (jailed(cred1)) {
22191421ba2SRobert Watson 		if (!jailed(cred2))
22291421ba2SRobert Watson 			return (ESRCH);
22391421ba2SRobert Watson 		if (cred2->cr_prison != cred1->cr_prison)
22491421ba2SRobert Watson 			return (ESRCH);
22591421ba2SRobert Watson 	}
22691421ba2SRobert Watson 
22791421ba2SRobert Watson 	return (0);
22891421ba2SRobert Watson }
22991421ba2SRobert Watson 
23091421ba2SRobert Watson /*
23191421ba2SRobert Watson  * Return 1 if the passed credential is in a jail, otherwise 0.
23291421ba2SRobert Watson  */
23391421ba2SRobert Watson int
23491421ba2SRobert Watson jailed(cred)
23591421ba2SRobert Watson 	struct ucred *cred;
23691421ba2SRobert Watson {
23791421ba2SRobert Watson 
23891421ba2SRobert Watson 	return (cred->cr_prison != NULL);
23991421ba2SRobert Watson }
2409484d0c0SRobert Drehmel 
2419484d0c0SRobert Drehmel /*
2429484d0c0SRobert Drehmel  * Return the correct hostname for the passed credential.
2439484d0c0SRobert Drehmel  */
244ad1ff099SRobert Drehmel void
245ad1ff099SRobert Drehmel getcredhostname(cred, buf, size)
2469484d0c0SRobert Drehmel 	struct ucred *cred;
247ad1ff099SRobert Drehmel 	char *buf;
248ad1ff099SRobert Drehmel 	size_t size;
2499484d0c0SRobert Drehmel {
2509484d0c0SRobert Drehmel 
251ad1ff099SRobert Drehmel 	if (jailed(cred)) {
252ad1ff099SRobert Drehmel 		mtx_lock(&cred->cr_prison->pr_mtx);
253ad1ff099SRobert Drehmel 		strncpy(buf, cred->cr_prison->pr_host, size);
254ad1ff099SRobert Drehmel 		mtx_unlock(&cred->cr_prison->pr_mtx);
255ad1ff099SRobert Drehmel 	}
256ad1ff099SRobert Drehmel 	else
257ad1ff099SRobert Drehmel 		strncpy(buf, hostname, size);
258ad1ff099SRobert Drehmel 	buf[size - 1] = '\0';
2599484d0c0SRobert Drehmel }
260