xref: /freebsd/usr.sbin/jail/state.c (revision d8a0fe102c0cfdfcd5b818f850eff09d8536c9bc)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2011 James Gritton
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/uio.h>
33 
34 #include <err.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "jailp.h"
39 
40 struct cfjails ready = TAILQ_HEAD_INITIALIZER(ready);
41 struct cfjails depend = TAILQ_HEAD_INITIALIZER(depend);
42 
43 static void dep_add(struct cfjail *from, struct cfjail *to, unsigned flags);
44 static int cmp_jailptr(const void *a, const void *b);
45 static int cmp_jailptr_name(const void *a, const void *b);
46 static struct cfjail *find_jail(const char *name);
47 static int running_jid(const char *name, int flags);
48 
49 static struct cfjail **jails_byname;
50 static size_t njails;
51 
52 /*
53  * Set up jail dependency lists.
54  */
55 void
56 dep_setup(int docf)
57 {
58 	struct cfjail *j, *dj;
59 	struct cfparam *p;
60 	struct cfstring *s;
61 	struct cfdepend *d;
62 	const char *cs;
63 	char *pname;
64 	size_t plen;
65 	int deps, ldeps;
66 
67 	if (!docf) {
68 		/*
69 		 * With no config file, let "depend" for a single jail
70 		 * look at currently running jails.
71 		 */
72 		if ((j = TAILQ_FIRST(&cfjails)) &&
73 		    (p = j->intparams[IP_DEPEND])) {
74 			TAILQ_FOREACH(s, &p->val, tq) {
75 				if (running_jid(s->s, 0) < 0) {
76 					warnx("depends on nonexistent jail "
77 					    "\"%s\"", s->s);
78 					j->flags |= JF_FAILED;
79 				}
80 			}
81 		}
82 		return;
83 	}
84 
85 	njails = 0;
86 	TAILQ_FOREACH(j, &cfjails, tq)
87 		njails++;
88 	jails_byname = emalloc(njails * sizeof(struct cfjail *));
89 	njails = 0;
90 	TAILQ_FOREACH(j, &cfjails, tq)
91 		jails_byname[njails++] = j;
92 	qsort(jails_byname, njails, sizeof(struct cfjail *), cmp_jailptr);
93 	deps = 0;
94 	ldeps = 0;
95 	plen = 0;
96 	pname = NULL;
97 	TAILQ_FOREACH(j, &cfjails, tq) {
98 		if (j->flags & JF_FAILED)
99 			continue;
100 		if ((p = j->intparams[IP_DEPEND])) {
101 			TAILQ_FOREACH(s, &p->val, tq) {
102 				dj = find_jail(s->s);
103 				if (dj != NULL) {
104 					deps++;
105 					dep_add(j, dj, 0);
106 				} else {
107 					jail_warnx(j,
108 					    "depends on undefined jail \"%s\"",
109 					    s->s);
110 					j->flags |= JF_FAILED;
111 				}
112 			}
113 		}
114 		/* A jail has an implied dependency on its parent. */
115 		if ((cs = strrchr(j->name, '.')))
116 		{
117 			if (plen < (size_t)(cs - j->name + 1)) {
118 				plen = (cs - j->name) + 1;
119 				pname = erealloc(pname, plen);
120 			}
121 			strlcpy(pname, j->name, plen);
122 			dj = find_jail(pname);
123 			if (dj != NULL) {
124 				ldeps++;
125 				dep_add(j, dj, DF_LIGHT);
126 			}
127 		}
128 	}
129 
130 	/* Look for dependency loops. */
131 	if (deps && (deps > 1 || ldeps)) {
132 		(void)start_state(NULL, 0, 0, 0);
133 		while ((j = TAILQ_FIRST(&ready))) {
134 			requeue(j, &cfjails);
135 			dep_done(j, DF_NOFAIL);
136 		}
137 		while ((j = TAILQ_FIRST(&depend)) != NULL) {
138 			jail_warnx(j, "dependency loop");
139 			j->flags |= JF_FAILED;
140 			do {
141 				requeue(j, &cfjails);
142 				dep_done(j, DF_NOFAIL);
143 			} while ((j = TAILQ_FIRST(&ready)));
144 		}
145 		TAILQ_FOREACH(j, &cfjails, tq)
146 			STAILQ_FOREACH(d, &j->dep[DEP_FROM], tq[DEP_FROM])
147 				d->flags &= ~DF_SEEN;
148 	}
149 	if (pname != NULL)
150 		free(pname);
151 }
152 
153 /*
154  * Return if a jail has dependencies.
155  */
156 int
157 dep_check(struct cfjail *j)
158 {
159 	int reset, depfrom, depto, ndeps, rev;
160 	struct cfjail *dj;
161 	struct cfdepend *d;
162 
163 	static int bits[] = { 0, 1, 1, 2, 1, 2, 2, 3 };
164 
165 	if (j->ndeps == 0)
166 		return 0;
167 	ndeps = 0;
168 	if ((rev = JF_DO_STOP(j->flags))) {
169 		depfrom = DEP_TO;
170 		depto = DEP_FROM;
171 	} else {
172 		depfrom = DEP_FROM;
173 		depto = DEP_TO;
174 	}
175 	STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom]) {
176 		if (d->flags & DF_SEEN)
177 			continue;
178 		dj = d->j[depto];
179 		if (dj->flags & JF_FAILED) {
180 			if (!(j->flags & (JF_DEPEND | JF_FAILED)) &&
181 			    verbose >= 0)
182 				jail_warnx(j, "skipped");
183 			j->flags |= JF_FAILED;
184 			continue;
185 		}
186 		/*
187 		 * The dependee's state may be set (or changed) as a result of
188 		 * being in a dependency it wasn't in earlier.
189 		 */
190 		reset = 0;
191 		if (bits[dj->flags & JF_OP_MASK] <= 1) {
192 			if (!(dj->flags & JF_OP_MASK)) {
193 				reset = 1;
194 				dj->flags |= JF_DEPEND;
195 				requeue(dj, &ready);
196 			}
197 			/* Set or change the dependee's state. */
198 			switch (j->flags & JF_OP_MASK) {
199 			case JF_START:
200 				dj->flags |= JF_START;
201 				break;
202 			case JF_SET:
203 				if (!(dj->flags & JF_OP_MASK))
204 					dj->flags |= JF_SET;
205 				else if (dj->flags & JF_STOP)
206 					dj->flags |= JF_START;
207 				break;
208 			case JF_STOP:
209 			case JF_RESTART:
210 				if (!(dj->flags & JF_STOP))
211 					reset = 1;
212 				dj->flags |= JF_STOP;
213 				if (dj->flags & JF_SET)
214 					dj->flags ^= (JF_START | JF_SET);
215 				break;
216 			}
217 		}
218 		if (reset)
219 			dep_reset(dj);
220 		if (!((d->flags & DF_LIGHT) &&
221 		    (rev ? dj->jid < 0 : dj->jid > 0)))
222 			ndeps++;
223 	}
224 	if (ndeps == 0)
225 		return 0;
226 	requeue(j, &depend);
227 	return 1;
228 }
229 
230 /*
231  * Resolve any dependencies from a finished jail.
232  */
233 void
234 dep_done(struct cfjail *j, unsigned flags)
235 {
236 	struct cfjail *dj;
237 	struct cfdepend *d;
238 	int depfrom, depto;
239 
240 	if (JF_DO_STOP(j->flags)) {
241 		depfrom = DEP_TO;
242 		depto = DEP_FROM;
243 	} else {
244 		depfrom = DEP_FROM;
245 		depto = DEP_TO;
246 	}
247 	STAILQ_FOREACH(d, &j->dep[depto], tq[depto]) {
248 		if ((d->flags & DF_SEEN) | (flags & ~d->flags & DF_LIGHT))
249 			continue;
250 		d->flags |= DF_SEEN;
251 		dj = d->j[depfrom];
252 		if (!(flags & DF_NOFAIL) && (j->flags & JF_FAILED) &&
253 		    (j->flags & (JF_OP_MASK | JF_DEPEND)) !=
254 		    (JF_SET | JF_DEPEND)) {
255 			if (!(dj->flags & (JF_DEPEND | JF_FAILED)) &&
256 			    verbose >= 0)
257 				jail_warnx(dj, "skipped");
258 			dj->flags |= JF_FAILED;
259 		}
260 		if (!--dj->ndeps && dj->queue == &depend)
261 			requeue(dj, &ready);
262 	}
263 }
264 
265 /*
266  * Count a jail's dependencies and mark them as unseen.
267  */
268 void
269 dep_reset(struct cfjail *j)
270 {
271 	int depfrom;
272 	struct cfdepend *d;
273 
274 	depfrom = JF_DO_STOP(j->flags) ? DEP_TO : DEP_FROM;
275 	j->ndeps = 0;
276 	STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom])
277 		j->ndeps++;
278 }
279 
280 /*
281  * Find the next jail ready to do something.
282  */
283 struct cfjail *
284 next_jail(void)
285 {
286 	struct cfjail *j;
287 
288 	if (!(j = next_proc(!TAILQ_EMPTY(&ready))) &&
289 	    (j = TAILQ_FIRST(&ready)) && JF_DO_STOP(j->flags) &&
290 	    (j = TAILQ_LAST(&ready, cfjails)) && !JF_DO_STOP(j->flags)) {
291 		TAILQ_FOREACH_REVERSE(j, &ready, cfjails, tq)
292 			if (JF_DO_STOP(j->flags))
293 				break;
294 	}
295 	if (j != NULL)
296 		requeue(j, &cfjails);
297 	return j;
298 }
299 
300 /*
301  * Set jails to the proper start state.
302  */
303 int
304 start_state(const char *target, int docf, unsigned state, int running)
305 {
306 	struct iovec jiov[6];
307 	struct cfjail *j, *tj;
308 	int jid;
309 	char namebuf[MAXHOSTNAMELEN];
310 
311 	if (!target || (!docf && state != JF_STOP) ||
312 	    (!running && !strcmp(target, "*"))) {
313 		/*
314 		 * For a global wildcard (including no target specified),
315 		 * set the state on all jails and start with those that
316 		 * have no dependencies.
317 		 */
318 		TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
319 			j->flags = (j->flags & JF_FAILED) | state |
320 			    (docf ? JF_WILD : 0);
321 			dep_reset(j);
322 			requeue(j, j->ndeps ? &depend : &ready);
323 		}
324 	} else if (wild_jail_name(target)) {
325 		/*
326 		 * For targets specified singly, or with a non-global wildcard,
327 		 * set their state and call them ready (even if there are
328 		 * dependencies).  Leave everything else unqueued for now.
329 		 */
330 		if (running) {
331 			/*
332 			 * -R matches its wildcards against currently running
333 			 * jails, not against the config file.
334 			 */
335 			jiov[0].iov_base = __DECONST(char *, "lastjid");
336 			jiov[0].iov_len = sizeof("lastjid");
337 			jiov[1].iov_base = &jid;
338 			jiov[1].iov_len = sizeof(jid);
339 			jiov[2].iov_base = __DECONST(char *, "jid");
340 			jiov[2].iov_len = sizeof("jid");
341 			jiov[3].iov_base = &jid;
342 			jiov[3].iov_len = sizeof(jid);
343 			jiov[4].iov_base = __DECONST(char *, "name");
344 			jiov[4].iov_len = sizeof("name");
345 			jiov[5].iov_base = &namebuf;
346 			jiov[5].iov_len = sizeof(namebuf);
347 			for (jid = 0; jail_get(jiov, 6, 0) > 0; ) {
348 				if (wild_jail_match(namebuf, target)) {
349 					j = add_jail();
350 					j->name = estrdup(namebuf);
351 					j->jid = jid;
352 					j->flags = (j->flags & JF_FAILED) |
353 					    state | JF_WILD;
354 					dep_reset(j);
355 					requeue(j, &ready);
356 				}
357 			}
358 		} else {
359 			TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
360 				if (wild_jail_match(j->name, target)) {
361 					j->flags = (j->flags & JF_FAILED) |
362 					    state | JF_WILD;
363 					dep_reset(j);
364 					requeue(j, &ready);
365 				}
366 			}
367 		}
368 	} else {
369 		j = find_jail(target);
370 		if (j == NULL && state == JF_STOP) {
371 			/* Allow -[rR] to specify a currently running jail. */
372 			if ((jid = running_jid(target, JAIL_DYING)) > 0) {
373 				j = add_jail();
374 				j->name = estrdup(target);
375 				j->jid = jid;
376 			}
377 		}
378 		if (j == NULL) {
379 			warnx("\"%s\" not found", target);
380 			return -1;
381 		}
382 		j->flags = (j->flags & JF_FAILED) | state;
383 		dep_reset(j);
384 		requeue(j, &ready);
385 	}
386 	return 0;
387 }
388 
389 /*
390  * Move a jail to a new list.
391  */
392 void
393 requeue(struct cfjail *j, struct cfjails *queue)
394 {
395 	if (j->queue != queue) {
396 		TAILQ_REMOVE(j->queue, j, tq);
397 		TAILQ_INSERT_TAIL(queue, j, tq);
398 		j->queue = queue;
399 	}
400 }
401 
402 void
403 requeue_head(struct cfjail *j, struct cfjails *queue)
404 {
405     TAILQ_REMOVE(j->queue, j, tq);
406     TAILQ_INSERT_HEAD(queue, j, tq);
407     j->queue = queue;
408 }
409 
410 /*
411  * Add a dependency edge between two jails.
412  */
413 static void
414 dep_add(struct cfjail *from, struct cfjail *to, unsigned flags)
415 {
416 	struct cfdepend *d;
417 
418 	d = emalloc(sizeof(struct cfdepend));
419 	d->flags = flags;
420 	d->j[DEP_FROM] = from;
421 	d->j[DEP_TO] = to;
422 	STAILQ_INSERT_TAIL(&from->dep[DEP_FROM], d, tq[DEP_FROM]);
423 	STAILQ_INSERT_TAIL(&to->dep[DEP_TO], d, tq[DEP_TO]);
424 }
425 
426 /*
427  * Compare jail pointers for qsort/bsearch.
428  */
429 static int
430 cmp_jailptr(const void *a, const void *b)
431 {
432 	return strcmp((*((struct cfjail * const *)a))->name,
433 	    ((*(struct cfjail * const *)b))->name);
434 }
435 
436 static int
437 cmp_jailptr_name(const void *a, const void *b)
438 {
439 	return strcmp((const char *)a, ((*(struct cfjail * const *)b))->name);
440 }
441 
442 /*
443  * Find a jail object by name.
444  */
445 static struct cfjail *
446 find_jail(const char *name)
447 {
448 	struct cfjail **jp;
449 
450 	jp = bsearch(name, jails_byname, njails, sizeof(struct cfjail *),
451 	    cmp_jailptr_name);
452 	return jp ? *jp : NULL;
453 }
454 
455 /*
456  * Return the named jail's jid if it is running, and -1 if it isn't.
457  */
458 static int
459 running_jid(const char *name, int flags)
460 {
461 	struct iovec jiov[2];
462 	char *ep;
463 	int jid;
464 
465 	if ((jid = strtol(name, &ep, 10)) && !*ep) {
466 		jiov[0].iov_base = __DECONST(char *, "jid");
467 		jiov[0].iov_len = sizeof("jid");
468 		jiov[1].iov_base = &jid;
469 		jiov[1].iov_len = sizeof(jid);
470 	} else {
471 		jiov[0].iov_base = __DECONST(char *, "name");
472 		jiov[0].iov_len = sizeof("name");
473 		jiov[1].iov_len = strlen(name) + 1;
474 		jiov[1].iov_base = alloca(jiov[1].iov_len);
475 		strcpy(jiov[1].iov_base, name);
476 	}
477 	return jail_get(jiov, 2, flags);
478 }
479