kern_jail.c revision 82710
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 82710 2001-09-01 03:04:31Z dillon $
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/socket.h>
23#include <sys/sysctl.h>
24#include <net/if.h>
25#include <netinet/in.h>
26
27MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
28
29SYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RW, 0,
30    "Jail rules");
31
32int	jail_set_hostname_allowed = 1;
33SYSCTL_INT(_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
34    &jail_set_hostname_allowed, 0,
35    "Processes in jail can set their hostnames");
36
37int	jail_socket_unixiproute_only = 1;
38SYSCTL_INT(_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
39    &jail_socket_unixiproute_only, 0,
40    "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
41
42int	jail_sysvipc_allowed = 0;
43SYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
44    &jail_sysvipc_allowed, 0,
45    "Processes in jail can use System V IPC primitives");
46
47/*
48 * MPSAFE
49 */
50int
51jail(p, uap)
52	struct proc *p;
53	struct jail_args /* {
54		syscallarg(struct jail *) jail;
55	} */ *uap;
56{
57	int error;
58	struct prison *pr;
59	struct jail j;
60	struct chroot_args ca;
61
62	mtx_lock(&Giant);
63
64	/* Implicitly fail if already in jail.  */
65	error = suser(p);
66	if (error)
67		goto done2;
68	error = copyin(uap->jail, &j, sizeof j);
69	if (error)
70		goto done2;
71	if (j.version != 0) {
72		error = EINVAL;
73		goto done2;
74	}
75	MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
76	error = copyinstr(j.hostname, &pr->pr_host, sizeof pr->pr_host, 0);
77	if (error)
78		goto bail;
79	pr->pr_ip = j.ip_number;
80
81	ca.path = j.path;
82	error = chroot(p, &ca);
83	if (error)
84		goto bail;
85
86	p->p_ucred = crcopy(p->p_ucred);
87	p->p_ucred->cr_prison = pr;
88	pr->pr_ref = 1;
89	mtx_unlock(&Giant);
90	return (0);
91
92bail:
93	FREE(pr, M_PRISON);
94done2:
95	mtx_unlock(&Giant);
96	return (error);
97}
98
99void
100prison_free(struct prison *pr)
101{
102
103	pr->pr_ref--;
104	if (pr->pr_ref == 0) {
105		if (pr->pr_linux != NULL)
106			FREE(pr->pr_linux, M_PRISON);
107		FREE(pr, M_PRISON);
108	}
109}
110
111void
112prison_hold(struct prison *pr)
113{
114
115	pr->pr_ref++;
116}
117
118int
119prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
120{
121	u_int32_t tmp;
122
123	if (!jailed(cred))
124		return (0);
125	if (flag)
126		tmp = *ip;
127	else
128		tmp = ntohl(*ip);
129	if (tmp == INADDR_ANY) {
130		if (flag)
131			*ip = cred->cr_prison->pr_ip;
132		else
133			*ip = htonl(cred->cr_prison->pr_ip);
134		return (0);
135	}
136	if (tmp == INADDR_LOOPBACK) {
137		if (flag)
138			*ip = cred->cr_prison->pr_ip;
139		else
140			*ip = htonl(cred->cr_prison->pr_ip);
141		return (0);
142	}
143	if (cred->cr_prison->pr_ip != tmp)
144		return (1);
145	return (0);
146}
147
148void
149prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
150{
151	u_int32_t tmp;
152
153	if (!jailed(cred))
154		return;
155	if (flag)
156		tmp = *ip;
157	else
158		tmp = ntohl(*ip);
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;
165	}
166	return;
167}
168
169int
170prison_if(struct ucred *cred, struct sockaddr *sa)
171{
172	struct sockaddr_in *sai = (struct sockaddr_in*) sa;
173	int ok;
174
175	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
176		ok = 1;
177	else if (sai->sin_family != AF_INET)
178		ok = 0;
179	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
180		ok = 1;
181	else
182		ok = 0;
183	return (ok);
184}
185
186/*
187 * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
188 */
189int
190prison_check(cred1, cred2)
191	struct ucred *cred1, *cred2;
192{
193
194	if (jailed(cred1)) {
195		if (!jailed(cred2))
196			return (ESRCH);
197		if (cred2->cr_prison != cred1->cr_prison)
198			return (ESRCH);
199	}
200
201	return (0);
202}
203
204/*
205 * Return 1 if the passed credential is in a jail, otherwise 0.
206 */
207int
208jailed(cred)
209	struct ucred *cred;
210{
211
212	return (cred->cr_prison != NULL);
213}
214