xref: /freebsd/sys/kern/kern_jail.c (revision 116734c4d17fa35e66385279e8e57e89e878c27d)
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>
2275c13541SPoul-Henning Kamp #include <sys/socket.h>
2383f1e257SRobert Watson #include <sys/sysctl.h>
2475c13541SPoul-Henning Kamp #include <net/if.h>
2575c13541SPoul-Henning Kamp #include <netinet/in.h>
2675c13541SPoul-Henning Kamp 
2775c13541SPoul-Henning Kamp MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
2875c13541SPoul-Henning Kamp 
2983f1e257SRobert Watson SYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RW, 0,
3083f1e257SRobert Watson     "Jail rules");
3183f1e257SRobert Watson 
3283f1e257SRobert Watson int	jail_set_hostname_allowed = 1;
3383f1e257SRobert Watson SYSCTL_INT(_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
3483f1e257SRobert Watson     &jail_set_hostname_allowed, 0,
3583f1e257SRobert Watson     "Processes in jail can set their hostnames");
3683f1e257SRobert Watson 
377cadc266SRobert Watson int	jail_socket_unixiproute_only = 1;
387cadc266SRobert Watson SYSCTL_INT(_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
397cadc266SRobert Watson     &jail_socket_unixiproute_only, 0,
407cadc266SRobert Watson     "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
417cadc266SRobert Watson 
42cb1f0db9SRobert Watson int	jail_sysvipc_allowed = 0;
43cb1f0db9SRobert Watson SYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
44cb1f0db9SRobert Watson     &jail_sysvipc_allowed, 0,
45cb1f0db9SRobert Watson     "Processes in jail can use System V IPC primitives");
46cb1f0db9SRobert Watson 
47116734c4SMatthew Dillon /*
48116734c4SMatthew Dillon  * MPSAFE
49116734c4SMatthew Dillon  */
5075c13541SPoul-Henning Kamp int
5175c13541SPoul-Henning Kamp jail(p, uap)
5275c13541SPoul-Henning Kamp 	struct proc *p;
5375c13541SPoul-Henning Kamp 	struct jail_args /* {
5475c13541SPoul-Henning Kamp 		syscallarg(struct jail *) jail;
5575c13541SPoul-Henning Kamp 	} */ *uap;
5675c13541SPoul-Henning Kamp {
5775c13541SPoul-Henning Kamp 	int error;
5875c13541SPoul-Henning Kamp 	struct prison *pr;
5975c13541SPoul-Henning Kamp 	struct jail j;
6075c13541SPoul-Henning Kamp 	struct chroot_args ca;
6175c13541SPoul-Henning Kamp 
62116734c4SMatthew Dillon 	mtx_lock(&Giant);
63116734c4SMatthew Dillon 
6491421ba2SRobert Watson 	/* Implicitly fail if already in jail.  */
6575c13541SPoul-Henning Kamp 	error = suser(p);
6675c13541SPoul-Henning Kamp 	if (error)
67116734c4SMatthew Dillon 		goto done2;
6875c13541SPoul-Henning Kamp 	error = copyin(uap->jail, &j, sizeof j);
6975c13541SPoul-Henning Kamp 	if (error)
70116734c4SMatthew Dillon 		goto done2;
71116734c4SMatthew Dillon 	if (j.version != 0) {
72116734c4SMatthew Dillon 		error = EINVAL;
73116734c4SMatthew Dillon 		goto done2;
74116734c4SMatthew Dillon 	}
757cc0979fSDavid Malone 	MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
7675c13541SPoul-Henning Kamp 	error = copyinstr(j.hostname, &pr->pr_host, sizeof pr->pr_host, 0);
7775c13541SPoul-Henning Kamp 	if (error)
7875c13541SPoul-Henning Kamp 		goto bail;
7975c13541SPoul-Henning Kamp 	pr->pr_ip = j.ip_number;
8075c13541SPoul-Henning Kamp 
8175c13541SPoul-Henning Kamp 	ca.path = j.path;
8275c13541SPoul-Henning Kamp 	error = chroot(p, &ca);
8375c13541SPoul-Henning Kamp 	if (error)
8475c13541SPoul-Henning Kamp 		goto bail;
8575c13541SPoul-Henning Kamp 
8691421ba2SRobert Watson 	p->p_ucred = crcopy(p->p_ucred);
8791421ba2SRobert Watson 	p->p_ucred->cr_prison = pr;
8891421ba2SRobert Watson 	pr->pr_ref = 1;
89116734c4SMatthew Dillon 	mtx_unlock(&Giant);
9075c13541SPoul-Henning Kamp 	return (0);
9175c13541SPoul-Henning Kamp 
9275c13541SPoul-Henning Kamp bail:
9375c13541SPoul-Henning Kamp 	FREE(pr, M_PRISON);
94116734c4SMatthew Dillon done2:
95116734c4SMatthew Dillon 	mtx_unlock(&Giant);
9675c13541SPoul-Henning Kamp 	return (error);
9775c13541SPoul-Henning Kamp }
9875c13541SPoul-Henning Kamp 
9991421ba2SRobert Watson void
10091421ba2SRobert Watson prison_free(struct prison *pr)
10191421ba2SRobert Watson {
10291421ba2SRobert Watson 
10391421ba2SRobert Watson 	pr->pr_ref--;
10491421ba2SRobert Watson 	if (pr->pr_ref == 0) {
10591421ba2SRobert Watson 		if (pr->pr_linux != NULL)
10691421ba2SRobert Watson 			FREE(pr->pr_linux, M_PRISON);
10791421ba2SRobert Watson 		FREE(pr, M_PRISON);
10891421ba2SRobert Watson 	}
10991421ba2SRobert Watson }
11091421ba2SRobert Watson 
11191421ba2SRobert Watson void
11291421ba2SRobert Watson prison_hold(struct prison *pr)
11391421ba2SRobert Watson {
11491421ba2SRobert Watson 
11591421ba2SRobert Watson 	pr->pr_ref++;
11691421ba2SRobert Watson }
11791421ba2SRobert Watson 
11875c13541SPoul-Henning Kamp int
11991421ba2SRobert Watson prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
12075c13541SPoul-Henning Kamp {
12175c13541SPoul-Henning Kamp 	u_int32_t tmp;
12275c13541SPoul-Henning Kamp 
12391421ba2SRobert Watson 	if (!jailed(cred))
12475c13541SPoul-Henning Kamp 		return (0);
12575c13541SPoul-Henning Kamp 	if (flag)
12675c13541SPoul-Henning Kamp 		tmp = *ip;
12775c13541SPoul-Henning Kamp 	else
12875c13541SPoul-Henning Kamp 		tmp = ntohl(*ip);
12975c13541SPoul-Henning Kamp 	if (tmp == INADDR_ANY) {
13075c13541SPoul-Henning Kamp 		if (flag)
13191421ba2SRobert Watson 			*ip = cred->cr_prison->pr_ip;
13275c13541SPoul-Henning Kamp 		else
13391421ba2SRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
13475c13541SPoul-Henning Kamp 		return (0);
13575c13541SPoul-Henning Kamp 	}
136fd6aaf7fSRobert Watson 	if (tmp == INADDR_LOOPBACK) {
137fd6aaf7fSRobert Watson 		if (flag)
138fd6aaf7fSRobert Watson 			*ip = cred->cr_prison->pr_ip;
139fd6aaf7fSRobert Watson 		else
140fd6aaf7fSRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
141fd6aaf7fSRobert Watson 		return (0);
142fd6aaf7fSRobert Watson 	}
14391421ba2SRobert Watson 	if (cred->cr_prison->pr_ip != tmp)
14475c13541SPoul-Henning Kamp 		return (1);
14575c13541SPoul-Henning Kamp 	return (0);
14675c13541SPoul-Henning Kamp }
14775c13541SPoul-Henning Kamp 
14875c13541SPoul-Henning Kamp void
14991421ba2SRobert Watson prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
15075c13541SPoul-Henning Kamp {
15175c13541SPoul-Henning Kamp 	u_int32_t tmp;
15275c13541SPoul-Henning Kamp 
15391421ba2SRobert Watson 	if (!jailed(cred))
15475c13541SPoul-Henning Kamp 		return;
15575c13541SPoul-Henning Kamp 	if (flag)
15675c13541SPoul-Henning Kamp 		tmp = *ip;
15775c13541SPoul-Henning Kamp 	else
15875c13541SPoul-Henning Kamp 		tmp = ntohl(*ip);
159fd6aaf7fSRobert Watson 	if (tmp == INADDR_LOOPBACK) {
16075c13541SPoul-Henning Kamp 		if (flag)
16191421ba2SRobert Watson 			*ip = cred->cr_prison->pr_ip;
16275c13541SPoul-Henning Kamp 		else
16391421ba2SRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
16475c13541SPoul-Henning Kamp 		return;
16575c13541SPoul-Henning Kamp 	}
16675c13541SPoul-Henning Kamp 	return;
16775c13541SPoul-Henning Kamp }
16875c13541SPoul-Henning Kamp 
16975c13541SPoul-Henning Kamp int
17091421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa)
17175c13541SPoul-Henning Kamp {
17275c13541SPoul-Henning Kamp 	struct sockaddr_in *sai = (struct sockaddr_in*) sa;
17375c13541SPoul-Henning Kamp 	int ok;
17475c13541SPoul-Henning Kamp 
1757cadc266SRobert Watson 	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
1767cadc266SRobert Watson 		ok = 1;
1777cadc266SRobert Watson 	else if (sai->sin_family != AF_INET)
17875c13541SPoul-Henning Kamp 		ok = 0;
17991421ba2SRobert Watson 	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
18075c13541SPoul-Henning Kamp 		ok = 1;
18175c13541SPoul-Henning Kamp 	else
18275c13541SPoul-Henning Kamp 		ok = 0;
18375c13541SPoul-Henning Kamp 	return (ok);
18475c13541SPoul-Henning Kamp }
18591421ba2SRobert Watson 
18691421ba2SRobert Watson /*
18791421ba2SRobert Watson  * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
18891421ba2SRobert Watson  */
18991421ba2SRobert Watson int
19091421ba2SRobert Watson prison_check(cred1, cred2)
19191421ba2SRobert Watson 	struct ucred *cred1, *cred2;
19291421ba2SRobert Watson {
19391421ba2SRobert Watson 
19491421ba2SRobert Watson 	if (jailed(cred1)) {
19591421ba2SRobert Watson 		if (!jailed(cred2))
19691421ba2SRobert Watson 			return (ESRCH);
19791421ba2SRobert Watson 		if (cred2->cr_prison != cred1->cr_prison)
19891421ba2SRobert Watson 			return (ESRCH);
19991421ba2SRobert Watson 	}
20091421ba2SRobert Watson 
20191421ba2SRobert Watson 	return (0);
20291421ba2SRobert Watson }
20391421ba2SRobert Watson 
20491421ba2SRobert Watson /*
20591421ba2SRobert Watson  * Return 1 if the passed credential is in a jail, otherwise 0.
20691421ba2SRobert Watson  */
20791421ba2SRobert Watson int
20891421ba2SRobert Watson jailed(cred)
20991421ba2SRobert Watson 	struct ucred *cred;
21091421ba2SRobert Watson {
21191421ba2SRobert Watson 
21291421ba2SRobert Watson 	return (cred->cr_prison != NULL);
21391421ba2SRobert Watson }
214