xref: /freebsd/sys/kern/kern_jail.c (revision 011376308f954457a26cc632ad96816a76d25b00)
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 
3183f1e257SRobert Watson SYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RW, 0,
3283f1e257SRobert Watson     "Jail rules");
3383f1e257SRobert Watson 
34a2f2b3afSJohn Baldwin mp_fixme("these variables need a lock")
35a2f2b3afSJohn Baldwin 
3683f1e257SRobert Watson int	jail_set_hostname_allowed = 1;
3783f1e257SRobert Watson SYSCTL_INT(_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
3883f1e257SRobert Watson     &jail_set_hostname_allowed, 0,
3983f1e257SRobert Watson     "Processes in jail can set their hostnames");
4083f1e257SRobert Watson 
417cadc266SRobert Watson int	jail_socket_unixiproute_only = 1;
427cadc266SRobert Watson SYSCTL_INT(_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
437cadc266SRobert Watson     &jail_socket_unixiproute_only, 0,
447cadc266SRobert Watson     "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
457cadc266SRobert Watson 
46cb1f0db9SRobert Watson int	jail_sysvipc_allowed = 0;
47cb1f0db9SRobert Watson SYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
48cb1f0db9SRobert Watson     &jail_sysvipc_allowed, 0,
49cb1f0db9SRobert Watson     "Processes in jail can use System V IPC primitives");
50cb1f0db9SRobert Watson 
51116734c4SMatthew Dillon /*
52116734c4SMatthew Dillon  * MPSAFE
53116734c4SMatthew Dillon  */
5475c13541SPoul-Henning Kamp int
55b40ce416SJulian Elischer jail(td, uap)
56b40ce416SJulian Elischer 	struct thread *td;
5775c13541SPoul-Henning Kamp 	struct jail_args /* {
5875c13541SPoul-Henning Kamp 		syscallarg(struct jail *) jail;
5975c13541SPoul-Henning Kamp 	} */ *uap;
6075c13541SPoul-Henning Kamp {
61b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
6275c13541SPoul-Henning Kamp 	int error;
6375c13541SPoul-Henning Kamp 	struct prison *pr;
6475c13541SPoul-Henning Kamp 	struct jail j;
6575c13541SPoul-Henning Kamp 	struct chroot_args ca;
66a2f2b3afSJohn Baldwin 	struct ucred *newcred = NULL, *oldcred;
6775c13541SPoul-Henning Kamp 
6875c13541SPoul-Henning Kamp 	error = copyin(uap->jail, &j, sizeof j);
6975c13541SPoul-Henning Kamp 	if (error)
70a2f2b3afSJohn Baldwin 		return (error);
71a2f2b3afSJohn Baldwin 	if (j.version != 0)
72a2f2b3afSJohn Baldwin 		return (EINVAL);
73a2f2b3afSJohn Baldwin 
74a2f2b3afSJohn Baldwin 	mtx_lock(&Giant);
757cc0979fSDavid Malone 	MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
7601137630SRobert Watson 	mtx_init(&pr->pr_mtx, "jail mutex", MTX_DEF);
77567931c8SRobert Watson 	pr->pr_securelevel = securelevel;
7875c13541SPoul-Henning Kamp 	error = copyinstr(j.hostname, &pr->pr_host, sizeof pr->pr_host, 0);
7975c13541SPoul-Henning Kamp 	if (error)
8075c13541SPoul-Henning Kamp 		goto bail;
8175c13541SPoul-Henning Kamp 	ca.path = j.path;
82b40ce416SJulian Elischer 	error = chroot(td, &ca);
8375c13541SPoul-Henning Kamp 	if (error)
8475c13541SPoul-Henning Kamp 		goto bail;
85a2f2b3afSJohn Baldwin 	newcred = crget();
86a2f2b3afSJohn Baldwin 	pr->pr_ip = j.ip_number;
87a2f2b3afSJohn Baldwin 	PROC_LOCK(p);
88a2f2b3afSJohn Baldwin 	/* Implicitly fail if already in jail.  */
89fc5d29efSRobert Watson 	error = suser_xxx(p->p_ucred, NULL, 0);
90a2f2b3afSJohn Baldwin 	if (error)
91a2f2b3afSJohn Baldwin 		goto badcred;
92a2f2b3afSJohn Baldwin 	oldcred = p->p_ucred;
93a2f2b3afSJohn Baldwin 	crcopy(newcred, oldcred);
94a2f2b3afSJohn Baldwin 	p->p_ucred = newcred;
9591421ba2SRobert Watson 	p->p_ucred->cr_prison = pr;
9691421ba2SRobert Watson 	pr->pr_ref = 1;
97a2f2b3afSJohn Baldwin 	PROC_UNLOCK(p);
98a2f2b3afSJohn Baldwin 	crfree(oldcred);
99116734c4SMatthew Dillon 	mtx_unlock(&Giant);
10075c13541SPoul-Henning Kamp 	return (0);
101a2f2b3afSJohn Baldwin badcred:
102a2f2b3afSJohn Baldwin 	PROC_UNLOCK(p);
103a2f2b3afSJohn Baldwin 	crfree(newcred);
10475c13541SPoul-Henning Kamp bail:
10575c13541SPoul-Henning Kamp 	FREE(pr, M_PRISON);
106116734c4SMatthew Dillon 	mtx_unlock(&Giant);
10775c13541SPoul-Henning Kamp 	return (error);
10875c13541SPoul-Henning Kamp }
10975c13541SPoul-Henning Kamp 
11091421ba2SRobert Watson void
11191421ba2SRobert Watson prison_free(struct prison *pr)
11291421ba2SRobert Watson {
11391421ba2SRobert Watson 
11401137630SRobert Watson 	mtx_lock(&pr->pr_mtx);
11591421ba2SRobert Watson 	pr->pr_ref--;
11691421ba2SRobert Watson 	if (pr->pr_ref == 0) {
11701137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
11801137630SRobert Watson 		mtx_destroy(&pr->pr_mtx);
11991421ba2SRobert Watson 		if (pr->pr_linux != NULL)
12091421ba2SRobert Watson 			FREE(pr->pr_linux, M_PRISON);
12191421ba2SRobert Watson 		FREE(pr, M_PRISON);
12201137630SRobert Watson 		return;
12391421ba2SRobert Watson 	}
12401137630SRobert Watson 	mtx_unlock(&pr->pr_mtx);
12591421ba2SRobert Watson }
12691421ba2SRobert Watson 
12791421ba2SRobert Watson void
12891421ba2SRobert Watson prison_hold(struct prison *pr)
12991421ba2SRobert Watson {
13091421ba2SRobert Watson 
13101137630SRobert Watson 	mtx_lock(&pr->pr_mtx);
13291421ba2SRobert Watson 	pr->pr_ref++;
13301137630SRobert Watson 	mtx_unlock(&pr->pr_mtx);
13401137630SRobert Watson }
13501137630SRobert Watson 
13601137630SRobert Watson u_int32_t
13701137630SRobert Watson prison_getip(struct ucred *cred)
13801137630SRobert Watson {
13901137630SRobert Watson 
14001137630SRobert Watson 	return (cred->cr_prison->pr_ip);
14191421ba2SRobert Watson }
14291421ba2SRobert Watson 
14375c13541SPoul-Henning Kamp int
14491421ba2SRobert Watson prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
14575c13541SPoul-Henning Kamp {
14675c13541SPoul-Henning Kamp 	u_int32_t tmp;
14775c13541SPoul-Henning Kamp 
14891421ba2SRobert Watson 	if (!jailed(cred))
14975c13541SPoul-Henning Kamp 		return (0);
15075c13541SPoul-Henning Kamp 	if (flag)
15175c13541SPoul-Henning Kamp 		tmp = *ip;
15275c13541SPoul-Henning Kamp 	else
15375c13541SPoul-Henning Kamp 		tmp = ntohl(*ip);
15475c13541SPoul-Henning Kamp 	if (tmp == INADDR_ANY) {
15575c13541SPoul-Henning Kamp 		if (flag)
15691421ba2SRobert Watson 			*ip = cred->cr_prison->pr_ip;
15775c13541SPoul-Henning Kamp 		else
15891421ba2SRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
15975c13541SPoul-Henning Kamp 		return (0);
16075c13541SPoul-Henning Kamp 	}
161fd6aaf7fSRobert Watson 	if (tmp == INADDR_LOOPBACK) {
162fd6aaf7fSRobert Watson 		if (flag)
163fd6aaf7fSRobert Watson 			*ip = cred->cr_prison->pr_ip;
164fd6aaf7fSRobert Watson 		else
165fd6aaf7fSRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
166fd6aaf7fSRobert Watson 		return (0);
167fd6aaf7fSRobert Watson 	}
16891421ba2SRobert Watson 	if (cred->cr_prison->pr_ip != tmp)
16975c13541SPoul-Henning Kamp 		return (1);
17075c13541SPoul-Henning Kamp 	return (0);
17175c13541SPoul-Henning Kamp }
17275c13541SPoul-Henning Kamp 
17375c13541SPoul-Henning Kamp void
17491421ba2SRobert Watson prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
17575c13541SPoul-Henning Kamp {
17675c13541SPoul-Henning Kamp 	u_int32_t tmp;
17775c13541SPoul-Henning Kamp 
17891421ba2SRobert Watson 	if (!jailed(cred))
17975c13541SPoul-Henning Kamp 		return;
18075c13541SPoul-Henning Kamp 	if (flag)
18175c13541SPoul-Henning Kamp 		tmp = *ip;
18275c13541SPoul-Henning Kamp 	else
18375c13541SPoul-Henning Kamp 		tmp = ntohl(*ip);
184fd6aaf7fSRobert Watson 	if (tmp == INADDR_LOOPBACK) {
18575c13541SPoul-Henning Kamp 		if (flag)
18691421ba2SRobert Watson 			*ip = cred->cr_prison->pr_ip;
18775c13541SPoul-Henning Kamp 		else
18891421ba2SRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
18975c13541SPoul-Henning Kamp 		return;
19075c13541SPoul-Henning Kamp 	}
19175c13541SPoul-Henning Kamp 	return;
19275c13541SPoul-Henning Kamp }
19375c13541SPoul-Henning Kamp 
19475c13541SPoul-Henning Kamp int
19591421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa)
19675c13541SPoul-Henning Kamp {
19775c13541SPoul-Henning Kamp 	struct sockaddr_in *sai = (struct sockaddr_in*) sa;
19875c13541SPoul-Henning Kamp 	int ok;
19975c13541SPoul-Henning Kamp 
2007cadc266SRobert Watson 	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
2017cadc266SRobert Watson 		ok = 1;
2027cadc266SRobert Watson 	else if (sai->sin_family != AF_INET)
20375c13541SPoul-Henning Kamp 		ok = 0;
20491421ba2SRobert Watson 	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
20575c13541SPoul-Henning Kamp 		ok = 1;
20675c13541SPoul-Henning Kamp 	else
20775c13541SPoul-Henning Kamp 		ok = 0;
20875c13541SPoul-Henning Kamp 	return (ok);
20975c13541SPoul-Henning Kamp }
21091421ba2SRobert Watson 
21191421ba2SRobert Watson /*
21291421ba2SRobert Watson  * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
21391421ba2SRobert Watson  */
21491421ba2SRobert Watson int
21591421ba2SRobert Watson prison_check(cred1, cred2)
21691421ba2SRobert Watson 	struct ucred *cred1, *cred2;
21791421ba2SRobert Watson {
21891421ba2SRobert Watson 
21991421ba2SRobert Watson 	if (jailed(cred1)) {
22091421ba2SRobert Watson 		if (!jailed(cred2))
22191421ba2SRobert Watson 			return (ESRCH);
22291421ba2SRobert Watson 		if (cred2->cr_prison != cred1->cr_prison)
22391421ba2SRobert Watson 			return (ESRCH);
22491421ba2SRobert Watson 	}
22591421ba2SRobert Watson 
22691421ba2SRobert Watson 	return (0);
22791421ba2SRobert Watson }
22891421ba2SRobert Watson 
22991421ba2SRobert Watson /*
23091421ba2SRobert Watson  * Return 1 if the passed credential is in a jail, otherwise 0.
23191421ba2SRobert Watson  */
23291421ba2SRobert Watson int
23391421ba2SRobert Watson jailed(cred)
23491421ba2SRobert Watson 	struct ucred *cred;
23591421ba2SRobert Watson {
23691421ba2SRobert Watson 
23791421ba2SRobert Watson 	return (cred->cr_prison != NULL);
23891421ba2SRobert Watson }
239