FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_jail.c
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: releng/5.0/sys/kern/kern_jail.c 108086 2002-12-19 09:40:13Z alfred $
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
29 MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
30
31 SYSCTL_DECL(_security);
32 SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
33 "Jail rules");
34
35 mp_fixme("these variables need a lock")
36
37 int jail_set_hostname_allowed = 1;
38 SYSCTL_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
42 int jail_socket_unixiproute_only = 1;
43 SYSCTL_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
47 int jail_sysvipc_allowed = 0;
48 SYSCTL_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 */
55 int
56 jail(td, uap)
57 struct thread *td;
58 struct jail_args /* {
59 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 mtx_lock(&Giant);
83 error = chroot(td, &ca);
84 mtx_unlock(&Giant);
85 if (error)
86 goto bail;
87 newcred = crget();
88 pr->pr_ip = j.ip_number;
89 PROC_LOCK(p);
90 /* Implicitly fail if already in jail. */
91 error = suser_cred(p->p_ucred, 0);
92 if (error)
93 goto badcred;
94 oldcred = p->p_ucred;
95 crcopy(newcred, oldcred);
96 p->p_ucred = newcred;
97 p->p_ucred->cr_prison = pr;
98 pr->pr_ref = 1;
99 PROC_UNLOCK(p);
100 crfree(oldcred);
101 return (0);
102 badcred:
103 PROC_UNLOCK(p);
104 crfree(newcred);
105 bail:
106 FREE(pr, M_PRISON);
107 return (error);
108 }
109
110 void
111 prison_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
127 void
128 prison_hold(struct prison *pr)
129 {
130
131 mtx_lock(&pr->pr_mtx);
132 pr->pr_ref++;
133 mtx_unlock(&pr->pr_mtx);
134 }
135
136 u_int32_t
137 prison_getip(struct ucred *cred)
138 {
139
140 return (cred->cr_prison->pr_ip);
141 }
142
143 int
144 prison_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
173 void
174 prison_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
194 int
195 prison_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 */
214 int
215 prison_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 */
232 int
233 jailed(cred)
234 struct ucred *cred;
235 {
236
237 return (cred->cr_prison != NULL);
238 }
239
240 /*
241 * Return the correct hostname for the passed credential.
242 */
243 void
244 getcredhostname(cred, buf, size)
245 struct ucred *cred;
246 char *buf;
247 size_t size;
248 {
249
250 if (jailed(cred)) {
251 mtx_lock(&cred->cr_prison->pr_mtx);
252 strlcpy(buf, cred->cr_prison->pr_host, size);
253 mtx_unlock(&cred->cr_prison->pr_mtx);
254 }
255 else
256 strlcpy(buf, hostname, size);
257 }
Cache object: 53d56a901a1285e2c19e26c4ac99cbd0
|