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