kern_jail.c revision 87275
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 *
9 * $FreeBSD: head/sys/kern/kern_jail.c 87275 2001-12-03 16:12:27Z rwatson $
10 *
11 */
12
13#include <sys/param.h>
14#include <sys/types.h>
15#include <sys/kernel.h>
16#include <sys/systm.h>
17#include <sys/errno.h>
18#include <sys/sysproto.h>
19#include <sys/malloc.h>
20#include <sys/proc.h>
21#include <sys/jail.h>
22#include <sys/lock.h>
23#include <sys/mutex.h>
24#include <sys/socket.h>
25#include <sys/sysctl.h>
26#include <net/if.h>
27#include <netinet/in.h>
28
29MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
30
31SYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RW, 0,
32    "Jail rules");
33
34mp_fixme("these variables need a lock")
35
36int	jail_set_hostname_allowed = 1;
37SYSCTL_INT(_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
38    &jail_set_hostname_allowed, 0,
39    "Processes in jail can set their hostnames");
40
41int	jail_socket_unixiproute_only = 1;
42SYSCTL_INT(_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
43    &jail_socket_unixiproute_only, 0,
44    "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
45
46int	jail_sysvipc_allowed = 0;
47SYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
48    &jail_sysvipc_allowed, 0,
49    "Processes in jail can use System V IPC primitives");
50
51/*
52 * MPSAFE
53 */
54int
55jail(td, uap)
56	struct thread *td;
57	struct jail_args /* {
58		syscallarg(struct jail *) jail;
59	} */ *uap;
60{
61	struct proc *p = td->td_proc;
62	int error;
63	struct prison *pr;
64	struct jail j;
65	struct chroot_args ca;
66	struct ucred *newcred = NULL, *oldcred;
67
68	error = copyin(uap->jail, &j, sizeof j);
69	if (error)
70		return (error);
71	if (j.version != 0)
72		return (EINVAL);
73
74	mtx_lock(&Giant);
75	MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
76	mtx_init(&pr->pr_mtx, "jail mutex", MTX_DEF);
77	pr->pr_securelevel = securelevel;
78	error = copyinstr(j.hostname, &pr->pr_host, sizeof pr->pr_host, 0);
79	if (error)
80		goto bail;
81	ca.path = j.path;
82	error = chroot(td, &ca);
83	if (error)
84		goto bail;
85	newcred = crget();
86	pr->pr_ip = j.ip_number;
87	PROC_LOCK(p);
88	/* Implicitly fail if already in jail.  */
89	error = suser_xxx(p->p_ucred, NULL, 0);
90	if (error)
91		goto badcred;
92	oldcred = p->p_ucred;
93	crcopy(newcred, oldcred);
94	p->p_ucred = newcred;
95	p->p_ucred->cr_prison = pr;
96	pr->pr_ref = 1;
97	PROC_UNLOCK(p);
98	crfree(oldcred);
99	mtx_unlock(&Giant);
100	return (0);
101badcred:
102	PROC_UNLOCK(p);
103	crfree(newcred);
104bail:
105	FREE(pr, M_PRISON);
106	mtx_unlock(&Giant);
107	return (error);
108}
109
110void
111prison_free(struct prison *pr)
112{
113
114	mtx_lock(&pr->pr_mtx);
115	pr->pr_ref--;
116	if (pr->pr_ref == 0) {
117		mtx_unlock(&pr->pr_mtx);
118		mtx_destroy(&pr->pr_mtx);
119		if (pr->pr_linux != NULL)
120			FREE(pr->pr_linux, M_PRISON);
121		FREE(pr, M_PRISON);
122		return;
123	}
124	mtx_unlock(&pr->pr_mtx);
125}
126
127void
128prison_hold(struct prison *pr)
129{
130
131	mtx_lock(&pr->pr_mtx);
132	pr->pr_ref++;
133	mtx_unlock(&pr->pr_mtx);
134}
135
136u_int32_t
137prison_getip(struct ucred *cred)
138{
139
140	return (cred->cr_prison->pr_ip);
141}
142
143int
144prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
145{
146	u_int32_t tmp;
147
148	if (!jailed(cred))
149		return (0);
150	if (flag)
151		tmp = *ip;
152	else
153		tmp = ntohl(*ip);
154	if (tmp == INADDR_ANY) {
155		if (flag)
156			*ip = cred->cr_prison->pr_ip;
157		else
158			*ip = htonl(cred->cr_prison->pr_ip);
159		return (0);
160	}
161	if (tmp == INADDR_LOOPBACK) {
162		if (flag)
163			*ip = cred->cr_prison->pr_ip;
164		else
165			*ip = htonl(cred->cr_prison->pr_ip);
166		return (0);
167	}
168	if (cred->cr_prison->pr_ip != tmp)
169		return (1);
170	return (0);
171}
172
173void
174prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
175{
176	u_int32_t tmp;
177
178	if (!jailed(cred))
179		return;
180	if (flag)
181		tmp = *ip;
182	else
183		tmp = ntohl(*ip);
184	if (tmp == INADDR_LOOPBACK) {
185		if (flag)
186			*ip = cred->cr_prison->pr_ip;
187		else
188			*ip = htonl(cred->cr_prison->pr_ip);
189		return;
190	}
191	return;
192}
193
194int
195prison_if(struct ucred *cred, struct sockaddr *sa)
196{
197	struct sockaddr_in *sai = (struct sockaddr_in*) sa;
198	int ok;
199
200	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
201		ok = 1;
202	else if (sai->sin_family != AF_INET)
203		ok = 0;
204	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
205		ok = 1;
206	else
207		ok = 0;
208	return (ok);
209}
210
211/*
212 * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
213 */
214int
215prison_check(cred1, cred2)
216	struct ucred *cred1, *cred2;
217{
218
219	if (jailed(cred1)) {
220		if (!jailed(cred2))
221			return (ESRCH);
222		if (cred2->cr_prison != cred1->cr_prison)
223			return (ESRCH);
224	}
225
226	return (0);
227}
228
229/*
230 * Return 1 if the passed credential is in a jail, otherwise 0.
231 */
232int
233jailed(cred)
234	struct ucred *cred;
235{
236
237	return (cred->cr_prison != NULL);
238}
239