kern_jail.c revision 72786
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 72786 2001-02-21 06:39:57Z 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/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
47int
48jail(p, uap)
49	struct proc *p;
50	struct jail_args /* {
51		syscallarg(struct jail *) jail;
52	} */ *uap;
53{
54	int error;
55	struct prison *pr;
56	struct jail j;
57	struct chroot_args ca;
58
59	/* Implicitly fail if already in jail.  */
60	error = suser(p);
61	if (error)
62		return (error);
63	error = copyin(uap->jail, &j, sizeof j);
64	if (error)
65		return (error);
66	if (j.version != 0)
67		return (EINVAL);
68	MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
69	error = copyinstr(j.hostname, &pr->pr_host, sizeof pr->pr_host, 0);
70	if (error)
71		goto bail;
72	pr->pr_ip = j.ip_number;
73
74	ca.path = j.path;
75	error = chroot(p, &ca);
76	if (error)
77		goto bail;
78
79	p->p_ucred = crcopy(p->p_ucred);
80	p->p_ucred->cr_prison = pr;
81	pr->pr_ref = 1;
82	return (0);
83
84bail:
85	FREE(pr, M_PRISON);
86	return (error);
87}
88
89void
90prison_free(struct prison *pr)
91{
92
93	pr->pr_ref--;
94	if (pr->pr_ref == 0) {
95		if (pr->pr_linux != NULL)
96			FREE(pr->pr_linux, M_PRISON);
97		FREE(pr, M_PRISON);
98	}
99}
100
101void
102prison_hold(struct prison *pr)
103{
104
105	pr->pr_ref++;
106}
107
108int
109prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
110{
111	u_int32_t tmp;
112
113	if (!jailed(cred))
114		return (0);
115	if (flag)
116		tmp = *ip;
117	else
118		tmp = ntohl(*ip);
119	if (tmp == INADDR_ANY) {
120		if (flag)
121			*ip = cred->cr_prison->pr_ip;
122		else
123			*ip = htonl(cred->cr_prison->pr_ip);
124		return (0);
125	}
126	if (cred->cr_prison->pr_ip != tmp)
127		return (1);
128	return (0);
129}
130
131void
132prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
133{
134	u_int32_t tmp;
135
136	if (!jailed(cred))
137		return;
138	if (flag)
139		tmp = *ip;
140	else
141		tmp = ntohl(*ip);
142	if (tmp == 0x7f000001) {
143		if (flag)
144			*ip = cred->cr_prison->pr_ip;
145		else
146			*ip = htonl(cred->cr_prison->pr_ip);
147		return;
148	}
149	return;
150}
151
152int
153prison_if(struct ucred *cred, struct sockaddr *sa)
154{
155	struct sockaddr_in *sai = (struct sockaddr_in*) sa;
156	int ok;
157
158	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
159		ok = 1;
160	else if (sai->sin_family != AF_INET)
161		ok = 0;
162	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
163		ok = 1;
164	else
165		ok = 0;
166	return (ok);
167}
168
169/*
170 * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
171 */
172int
173prison_check(cred1, cred2)
174	struct ucred *cred1, *cred2;
175{
176
177	if (jailed(cred1)) {
178		if (!jailed(cred2))
179			return (ESRCH);
180		if (cred2->cr_prison != cred1->cr_prison)
181			return (ESRCH);
182	}
183
184	return (0);
185}
186
187/*
188 * Return 1 if the passed credential is in a jail, otherwise 0.
189 */
190int
191jailed(cred)
192	struct ucred *cred;
193{
194
195	return (cred->cr_prison != NULL);
196}
197