state.c revision 330449
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: stable/11/usr.sbin/jail/state.c 330449 2018-03-05 07:26:05Z eadler $");
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
40struct cfjails ready = TAILQ_HEAD_INITIALIZER(ready);
41struct cfjails depend = TAILQ_HEAD_INITIALIZER(depend);
42
43static void dep_add(struct cfjail *from, struct cfjail *to, unsigned flags);
44static int cmp_jailptr(const void *a, const void *b);
45static int cmp_jailptr_name(const void *a, const void *b);
46static struct cfjail *find_jail(const char *name);
47static int running_jid(const char *name, int flags);
48
49static struct cfjail **jails_byname;
50static size_t njails;
51
52/*
53 * Set up jail dependency lists.
54 */
55void
56dep_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 */
156int
157dep_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 */
233void
234dep_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 */
268void
269dep_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 */
283struct cfjail *
284next_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 */
303int
304start_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 */
392void
393requeue(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
402void
403requeue_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 */
413static void
414dep_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 */
429static int
430cmp_jailptr(const void *a, const void *b)
431{
432	return strcmp((*((struct cfjail * const *)a))->name,
433	    ((*(struct cfjail * const *)b))->name);
434}
435
436static int
437cmp_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 */
445static struct cfjail *
446find_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 */
458static int
459running_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