kern_jail.c revision 98832
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 98832 2002-06-26 00:29:01Z arr $
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_DECL(_security);
32SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
33    "Jail rules");
34
35mp_fixme("these variables need a lock")
36
37int	jail_set_hostname_allowed = 1;
38SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
39    &jail_set_hostname_allowed, 0,
40    "Processes in jail can set their hostnames");
41
42int	jail_socket_unixiproute_only = 1;
43SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
44    &jail_socket_unixiproute_only, 0,
45    "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
46
47int	jail_sysvipc_allowed = 0;
48SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
49    &jail_sysvipc_allowed, 0,
50    "Processes in jail can use System V IPC primitives");
51
52/*
53 * MPSAFE
54 */
55int
56jail(td, uap)
57	struct thread *td;
58	struct jail_args /* {
59		syscallarg(struct jail *) jail;
60	} */ *uap;
61{
62	struct proc *p = td->td_proc;
63	int error;
64	struct prison *pr;
65	struct jail j;
66	struct chroot_args ca;
67	struct ucred *newcred = NULL, *oldcred;
68
69	error = copyin(uap->jail, &j, sizeof j);
70	if (error)
71		return (error);
72	if (j.version != 0)
73		return (EINVAL);
74
75	MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
76	mtx_init(&pr->pr_mtx, "jail mutex", NULL, 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_cred(p->p_ucred, 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	return (0);
100badcred:
101	PROC_UNLOCK(p);
102	crfree(newcred);
103bail:
104	FREE(pr, M_PRISON);
105	return (error);
106}
107
108void
109prison_free(struct prison *pr)
110{
111
112	mtx_lock(&pr->pr_mtx);
113	pr->pr_ref--;
114	if (pr->pr_ref == 0) {
115		mtx_unlock(&pr->pr_mtx);
116		mtx_destroy(&pr->pr_mtx);
117		if (pr->pr_linux != NULL)
118			FREE(pr->pr_linux, M_PRISON);
119		FREE(pr, M_PRISON);
120		return;
121	}
122	mtx_unlock(&pr->pr_mtx);
123}
124
125void
126prison_hold(struct prison *pr)
127{
128
129	mtx_lock(&pr->pr_mtx);
130	pr->pr_ref++;
131	mtx_unlock(&pr->pr_mtx);
132}
133
134u_int32_t
135prison_getip(struct ucred *cred)
136{
137
138	return (cred->cr_prison->pr_ip);
139}
140
141int
142prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
143{
144	u_int32_t tmp;
145
146	if (!jailed(cred))
147		return (0);
148	if (flag)
149		tmp = *ip;
150	else
151		tmp = ntohl(*ip);
152	if (tmp == INADDR_ANY) {
153		if (flag)
154			*ip = cred->cr_prison->pr_ip;
155		else
156			*ip = htonl(cred->cr_prison->pr_ip);
157		return (0);
158	}
159	if (tmp == INADDR_LOOPBACK) {
160		if (flag)
161			*ip = cred->cr_prison->pr_ip;
162		else
163			*ip = htonl(cred->cr_prison->pr_ip);
164		return (0);
165	}
166	if (cred->cr_prison->pr_ip != tmp)
167		return (1);
168	return (0);
169}
170
171void
172prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
173{
174	u_int32_t tmp;
175
176	if (!jailed(cred))
177		return;
178	if (flag)
179		tmp = *ip;
180	else
181		tmp = ntohl(*ip);
182	if (tmp == INADDR_LOOPBACK) {
183		if (flag)
184			*ip = cred->cr_prison->pr_ip;
185		else
186			*ip = htonl(cred->cr_prison->pr_ip);
187		return;
188	}
189	return;
190}
191
192int
193prison_if(struct ucred *cred, struct sockaddr *sa)
194{
195	struct sockaddr_in *sai = (struct sockaddr_in*) sa;
196	int ok;
197
198	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
199		ok = 1;
200	else if (sai->sin_family != AF_INET)
201		ok = 0;
202	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
203		ok = 1;
204	else
205		ok = 0;
206	return (ok);
207}
208
209/*
210 * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
211 */
212int
213prison_check(cred1, cred2)
214	struct ucred *cred1, *cred2;
215{
216
217	if (jailed(cred1)) {
218		if (!jailed(cred2))
219			return (ESRCH);
220		if (cred2->cr_prison != cred1->cr_prison)
221			return (ESRCH);
222	}
223
224	return (0);
225}
226
227/*
228 * Return 1 if the passed credential is in a jail, otherwise 0.
229 */
230int
231jailed(cred)
232	struct ucred *cred;
233{
234
235	return (cred->cr_prison != NULL);
236}
237
238/*
239 * Return the correct hostname for the passed credential.
240 */
241void
242getcredhostname(cred, buf, size)
243	struct ucred *cred;
244	char *buf;
245	size_t size;
246{
247
248	if (jailed(cred)) {
249		mtx_lock(&cred->cr_prison->pr_mtx);
250		strncpy(buf, cred->cr_prison->pr_host, size);
251		mtx_unlock(&cred->cr_prison->pr_mtx);
252	}
253	else
254		strncpy(buf, hostname, size);
255	buf[size - 1] = '\0';
256}
257