1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2020, Ryan Moeller <freqlabs@FreeBSD.org>
5 * Copyright (c) 2020, Kyle Evans <kevans@FreeBSD.org>
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 REGENTS 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 REGENTS 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/param.h>
30 #include <sys/jail.h>
31 #include <errno.h>
32 #include <jail.h>
33 #include <stdbool.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <lua.h>
38 #include <lauxlib.h>
39 #include <lualib.h>
40
41 #include "bootstrap.h"
42
43 #define JAIL_METATABLE "jail iterator metatable"
44
45 /*
46 * Taken from RhodiumToad's lspawn implementation, let static analyzers make
47 * better decisions about the behavior after we raise an error.
48 */
49 #if defined(LUA_VERSION_NUM) && defined(LUA_API)
50 LUA_API int (lua_error) (lua_State *L) __dead2;
51 #endif
52 #if defined(LUA_ERRFILE) && defined(LUALIB_API)
53 LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg) __dead2;
54 LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname) __dead2;
55 LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...) __dead2;
56 #endif
57
58 int luaopen_jail(lua_State *);
59
60 typedef bool (*getparam_filter)(const char *, void *);
61
62 static void getparam_table(lua_State *L, int paramindex,
63 struct jailparam *params, size_t paramoff, size_t *params_countp,
64 getparam_filter keyfilt, void *udata);
65
66 struct l_jail_iter {
67 struct jailparam *params;
68 size_t params_count;
69 int jid;
70 };
71
72 static bool
l_jail_filter(const char * param_name,void * data __unused)73 l_jail_filter(const char *param_name, void *data __unused)
74 {
75
76 /*
77 * Allowing lastjid will mess up our iteration over all jails on the
78 * system, as this is a special parameter that indicates where the search
79 * starts from. We'll always add jid and name, so just silently remove
80 * these.
81 */
82 return (strcmp(param_name, "lastjid") != 0 &&
83 strcmp(param_name, "jid") != 0 &&
84 strcmp(param_name, "name") != 0);
85 }
86
87 static int
l_jail_iter_next(lua_State * L)88 l_jail_iter_next(lua_State *L)
89 {
90 struct l_jail_iter *iter, **iterp;
91 struct jailparam *jp;
92 int serrno;
93
94 iterp = (struct l_jail_iter **)luaL_checkudata(L, 1, JAIL_METATABLE);
95 iter = *iterp;
96 luaL_argcheck(L, iter != NULL, 1, "closed jail iterator");
97
98 jp = iter->params;
99 /* Populate lastjid; we must keep it in params[0] for our sake. */
100 if (jailparam_import_raw(&jp[0], &iter->jid, sizeof(iter->jid))) {
101 jailparam_free(jp, iter->params_count);
102 free(jp);
103 free(iter);
104 *iterp = NULL;
105 return (luaL_error(L, "jailparam_import_raw: %s", jail_errmsg));
106 }
107
108 /* The list of requested params was populated back in l_list(). */
109 iter->jid = jailparam_get(jp, iter->params_count, 0);
110 if (iter->jid == -1) {
111 /*
112 * We probably got an ENOENT to signify the end of the jail
113 * listing, but just in case we didn't; stash it off and start
114 * cleaning up. We'll handle non-ENOENT errors later.
115 */
116 serrno = errno;
117 jailparam_free(jp, iter->params_count);
118 free(iter->params);
119 free(iter);
120 *iterp = NULL;
121 if (serrno != ENOENT)
122 return (luaL_error(L, "jailparam_get: %s",
123 strerror(serrno)));
124 return (0);
125 }
126
127 /*
128 * Finally, we'll fill in the return table with whatever parameters the
129 * user requested, in addition to the ones we forced with exception to
130 * lastjid.
131 */
132 lua_newtable(L);
133 for (size_t i = 0; i < iter->params_count; ++i) {
134 char *value;
135
136 jp = &iter->params[i];
137 if (strcmp(jp->jp_name, "lastjid") == 0)
138 continue;
139 value = jailparam_export(jp);
140 lua_pushstring(L, value);
141 lua_setfield(L, -2, jp->jp_name);
142 free(value);
143 }
144
145 return (1);
146 }
147
148 static int
l_jail_iter_close(lua_State * L)149 l_jail_iter_close(lua_State *L)
150 {
151 struct l_jail_iter *iter, **iterp;
152
153 /*
154 * Since we're using this as the __gc method as well, there's a good
155 * chance that it's already been cleaned up by iterating to the end of
156 * the list.
157 */
158 iterp = (struct l_jail_iter **)lua_touserdata(L, 1);
159 iter = *iterp;
160 if (iter == NULL)
161 return (0);
162
163 jailparam_free(iter->params, iter->params_count);
164 free(iter->params);
165 free(iter);
166 *iterp = NULL;
167 return (0);
168 }
169
170 static int
l_list(lua_State * L)171 l_list(lua_State *L)
172 {
173 struct l_jail_iter *iter;
174 int nargs;
175
176 nargs = lua_gettop(L);
177 if (nargs >= 1)
178 luaL_checktype(L, 1, LUA_TTABLE);
179
180 iter = malloc(sizeof(*iter));
181 if (iter == NULL)
182 return (luaL_error(L, "malloc: %s", strerror(errno)));
183
184 /*
185 * lastjid, jid, name + length of the table. This may be too much if
186 * we have duplicated one of those fixed parameters.
187 */
188 iter->params_count = 3 + (nargs != 0 ? lua_rawlen(L, 1) : 0);
189 iter->params = malloc(iter->params_count * sizeof(*iter->params));
190 if (iter->params == NULL) {
191 free(iter);
192 return (luaL_error(L, "malloc params: %s", strerror(errno)));
193 }
194
195 /* The :next() method will populate lastjid before jail_getparam(). */
196 if (jailparam_init(&iter->params[0], "lastjid") == -1) {
197 free(iter->params);
198 free(iter);
199 return (luaL_error(L, "jailparam_init: %s", jail_errmsg));
200 }
201 /* These two will get populated by jail_getparam(). */
202 if (jailparam_init(&iter->params[1], "jid") == -1) {
203 jailparam_free(iter->params, 1);
204 free(iter->params);
205 free(iter);
206 return (luaL_error(L, "jailparam_init: %s",
207 jail_errmsg));
208 }
209 if (jailparam_init(&iter->params[2], "name") == -1) {
210 jailparam_free(iter->params, 2);
211 free(iter->params);
212 free(iter);
213 return (luaL_error(L, "jailparam_init: %s",
214 jail_errmsg));
215 }
216
217 /*
218 * We only need to process additional arguments if we were given any.
219 * That is, we don't descend into getparam_table if we're passed nothing
220 * or an empty table.
221 */
222 iter->jid = 0;
223 if (iter->params_count != 3)
224 getparam_table(L, 1, iter->params, 2, &iter->params_count,
225 l_jail_filter, NULL);
226
227 /*
228 * Part of the iterator magic. We give it an iterator function with a
229 * metatable defining next() and close() that can be used for manual
230 * iteration. iter->jid is how we track which jail we last iterated, to
231 * be supplied as "lastjid".
232 */
233 lua_pushcfunction(L, l_jail_iter_next);
234 *(struct l_jail_iter **)lua_newuserdata(L,
235 sizeof(struct l_jail_iter **)) = iter;
236 luaL_getmetatable(L, JAIL_METATABLE);
237 lua_setmetatable(L, -2);
238 return (2);
239 }
240
241 static void
register_jail_metatable(lua_State * L)242 register_jail_metatable(lua_State *L)
243 {
244 luaL_newmetatable(L, JAIL_METATABLE);
245 lua_newtable(L);
246 lua_pushcfunction(L, l_jail_iter_next);
247 lua_setfield(L, -2, "next");
248 lua_pushcfunction(L, l_jail_iter_close);
249 lua_setfield(L, -2, "close");
250
251 lua_setfield(L, -2, "__index");
252
253 lua_pushcfunction(L, l_jail_iter_close);
254 lua_setfield(L, -2, "__gc");
255
256 lua_pop(L, 1);
257 }
258
259 static int
l_getid(lua_State * L)260 l_getid(lua_State *L)
261 {
262 const char *name;
263 int jid;
264
265 name = luaL_checkstring(L, 1);
266 jid = jail_getid(name);
267 if (jid == -1) {
268 lua_pushnil(L);
269 lua_pushstring(L, jail_errmsg);
270 return (2);
271 }
272 lua_pushinteger(L, jid);
273 return (1);
274 }
275
276 static int
l_getname(lua_State * L)277 l_getname(lua_State *L)
278 {
279 char *name;
280 int jid;
281
282 jid = luaL_checkinteger(L, 1);
283 name = jail_getname(jid);
284 if (name == NULL) {
285 lua_pushnil(L);
286 lua_pushstring(L, jail_errmsg);
287 return (2);
288 }
289 lua_pushstring(L, name);
290 free(name);
291 return (1);
292 }
293
294 static int
l_allparams(lua_State * L)295 l_allparams(lua_State *L)
296 {
297 struct jailparam *params;
298 int params_count;
299
300 params_count = jailparam_all(¶ms);
301 if (params_count == -1) {
302 lua_pushnil(L);
303 lua_pushstring(L, jail_errmsg);
304 return (2);
305 }
306 lua_newtable(L);
307 for (int i = 0; i < params_count; ++i) {
308 lua_pushstring(L, params[i].jp_name);
309 lua_rawseti(L, -2, i + 1);
310 }
311 jailparam_free(params, params_count);
312 free(params);
313 return (1);
314 }
315
316 static void
getparam_table(lua_State * L,int paramindex,struct jailparam * params,size_t params_off,size_t * params_countp,getparam_filter keyfilt,void * udata)317 getparam_table(lua_State *L, int paramindex, struct jailparam *params,
318 size_t params_off, size_t *params_countp, getparam_filter keyfilt,
319 void *udata)
320 {
321 size_t params_count;
322 int skipped;
323
324 params_count = *params_countp;
325 skipped = 0;
326 for (size_t i = 1 + params_off; i < params_count; ++i) {
327 const char *param_name;
328
329 lua_rawgeti(L, -1, i - params_off);
330 param_name = lua_tostring(L, -1);
331 if (param_name == NULL) {
332 jailparam_free(params, i - skipped);
333 free(params);
334 luaL_argerror(L, paramindex,
335 "param names must be strings");
336 }
337 lua_pop(L, 1);
338 if (keyfilt != NULL && !keyfilt(param_name, udata)) {
339 ++skipped;
340 continue;
341 }
342 if (jailparam_init(¶ms[i - skipped], param_name) == -1) {
343 jailparam_free(params, i - skipped);
344 free(params);
345 luaL_error(L, "jailparam_init: %s", jail_errmsg);
346 }
347 }
348 *params_countp -= skipped;
349 }
350
351 struct getparams_filter_args {
352 int filter_type;
353 };
354
355 static bool
l_getparams_filter(const char * param_name,void * udata)356 l_getparams_filter(const char *param_name, void *udata)
357 {
358 struct getparams_filter_args *gpa;
359
360 gpa = udata;
361
362 /* Skip name or jid, whichever was given. */
363 if (gpa->filter_type == LUA_TSTRING) {
364 if (strcmp(param_name, "name") == 0)
365 return (false);
366 } else /* type == LUA_TNUMBER */ {
367 if (strcmp(param_name, "jid") == 0)
368 return (false);
369 }
370
371 return (true);
372 }
373
374 static int
l_getparams(lua_State * L)375 l_getparams(lua_State *L)
376 {
377 const char *name;
378 struct jailparam *params;
379 size_t params_count;
380 struct getparams_filter_args gpa;
381 int flags, jid, type;
382
383 type = lua_type(L, 1);
384 luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
385 "expected a jail name (string) or id (integer)");
386 luaL_checktype(L, 2, LUA_TTABLE);
387 params_count = 1 + lua_rawlen(L, 2);
388 flags = luaL_optinteger(L, 3, 0);
389
390 params = malloc(params_count * sizeof(struct jailparam));
391 if (params == NULL)
392 return (luaL_error(L, "malloc: %s", strerror(errno)));
393
394 /*
395 * Set the jail name or id param as determined by the first arg.
396 */
397
398 if (type == LUA_TSTRING) {
399 if (jailparam_init(¶ms[0], "name") == -1) {
400 free(params);
401 return (luaL_error(L, "jailparam_init: %s",
402 jail_errmsg));
403 }
404 name = lua_tostring(L, 1);
405 if (jailparam_import(¶ms[0], name) == -1) {
406 jailparam_free(params, 1);
407 free(params);
408 return (luaL_error(L, "jailparam_import: %s",
409 jail_errmsg));
410 }
411 } else /* type == LUA_TNUMBER */ {
412 if (jailparam_init(¶ms[0], "jid") == -1) {
413 free(params);
414 return (luaL_error(L, "jailparam_init: %s",
415 jail_errmsg));
416 }
417 jid = lua_tointeger(L, 1);
418 if (jailparam_import_raw(¶ms[0], &jid, sizeof(jid)) == -1) {
419 jailparam_free(params, 1);
420 free(params);
421 return (luaL_error(L, "jailparam_import_raw: %s",
422 jail_errmsg));
423 }
424 }
425
426 /*
427 * Set the remaining param names being requested.
428 */
429 gpa.filter_type = type;
430 getparam_table(L, 2, params, 0, ¶ms_count, l_getparams_filter, &gpa);
431
432 /*
433 * Get the values and convert to a table.
434 */
435
436 jid = jailparam_get(params, params_count, flags);
437 if (jid == -1) {
438 jailparam_free(params, params_count);
439 free(params);
440 lua_pushnil(L);
441 lua_pushstring(L, jail_errmsg);
442 return (2);
443 }
444 lua_pushinteger(L, jid);
445
446 lua_newtable(L);
447 for (size_t i = 0; i < params_count; ++i) {
448 char *value;
449
450 if (params[i].jp_flags & JP_KEYVALUE &&
451 params[i].jp_valuelen == 0) {
452 /* Communicate back a missing key. */
453 lua_pushnil(L);
454 } else {
455 value = jailparam_export(¶ms[i]);
456 lua_pushstring(L, value);
457 free(value);
458 }
459
460 lua_setfield(L, -2, params[i].jp_name);
461 }
462
463 jailparam_free(params, params_count);
464 free(params);
465
466 return (2);
467 }
468
469 static int
l_setparams(lua_State * L)470 l_setparams(lua_State *L)
471 {
472 const char *name;
473 struct jailparam *params;
474 size_t params_count;
475 int flags, jid, type;
476
477 type = lua_type(L, 1);
478 luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
479 "expected a jail name (string) or id (integer)");
480 luaL_checktype(L, 2, LUA_TTABLE);
481
482 lua_pushnil(L);
483 for (params_count = 1; lua_next(L, 2) != 0; ++params_count)
484 lua_pop(L, 1);
485
486 flags = luaL_optinteger(L, 3, 0);
487
488 params = malloc(params_count * sizeof(struct jailparam));
489 if (params == NULL)
490 return (luaL_error(L, "malloc: %s", strerror(errno)));
491
492 /*
493 * Set the jail name or id param as determined by the first arg.
494 */
495
496 if (type == LUA_TSTRING) {
497 if (jailparam_init(¶ms[0], "name") == -1) {
498 free(params);
499 return (luaL_error(L, "jailparam_init: %s",
500 jail_errmsg));
501 }
502 name = lua_tostring(L, 1);
503 if (jailparam_import(¶ms[0], name) == -1) {
504 jailparam_free(params, 1);
505 free(params);
506 return (luaL_error(L, "jailparam_import: %s",
507 jail_errmsg));
508 }
509 } else /* type == LUA_TNUMBER */ {
510 if (jailparam_init(¶ms[0], "jid") == -1) {
511 free(params);
512 return (luaL_error(L, "jailparam_init: %s",
513 jail_errmsg));
514 }
515 jid = lua_tointeger(L, 1);
516 if (jailparam_import_raw(¶ms[0], &jid, sizeof(jid)) == -1) {
517 jailparam_free(params, 1);
518 free(params);
519 return (luaL_error(L, "jailparam_import_raw: %s",
520 jail_errmsg));
521 }
522 }
523
524 /*
525 * Set the rest of the provided params.
526 */
527
528 lua_pushnil(L);
529 for (size_t i = 1; i < params_count && lua_next(L, 2) != 0; ++i) {
530 const char *value;
531
532 name = lua_tostring(L, -2);
533 if (name == NULL) {
534 jailparam_free(params, i);
535 free(params);
536 return (luaL_argerror(L, 2,
537 "param names must be strings"));
538 }
539 if (jailparam_init(¶ms[i], name) == -1) {
540 jailparam_free(params, i);
541 free(params);
542 return (luaL_error(L, "jailparam_init: %s",
543 jail_errmsg));
544 }
545
546 value = lua_tostring(L, -1);
547 /* Allow passing NULL for key removal. */
548 if (value == NULL && !(params[i].jp_flags & JP_KEYVALUE)) {
549 jailparam_free(params, i + 1);
550 free(params);
551 return (luaL_argerror(L, 2,
552 "param values must be strings"));
553 }
554 if (jailparam_import(¶ms[i], value) == -1) {
555 jailparam_free(params, i + 1);
556 free(params);
557 return (luaL_error(L, "jailparam_import: %s",
558 jail_errmsg));
559 }
560
561 lua_pop(L, 1);
562 }
563
564 /*
565 * Attempt to set the params.
566 */
567
568 jid = jailparam_set(params, params_count, flags);
569 if (jid == -1) {
570 jailparam_free(params, params_count);
571 free(params);
572 lua_pushnil(L);
573 lua_pushstring(L, jail_errmsg);
574 return (2);
575 }
576 lua_pushinteger(L, jid);
577
578 jailparam_free(params, params_count);
579 free(params);
580 return (1);
581 }
582
583 static int
l_attach(lua_State * L)584 l_attach(lua_State *L)
585 {
586 int jid, type;
587
588 type = lua_type(L, 1);
589 luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
590 "expected a jail name (string) or id (integer)");
591
592 if (lua_isstring(L, 1)) {
593 /* Resolve it to a jid. */
594 jid = jail_getid(lua_tostring(L, 1));
595 if (jid == -1) {
596 lua_pushnil(L);
597 lua_pushstring(L, jail_errmsg);
598 return (2);
599 }
600 } else {
601 jid = lua_tointeger(L, 1);
602 }
603
604 if (jail_attach(jid) == -1) {
605 lua_pushnil(L);
606 lua_pushstring(L, strerror(errno));
607 return (2);
608 }
609
610 lua_pushboolean(L, 1);
611 return (1);
612 }
613
614 static int
l_remove(lua_State * L)615 l_remove(lua_State *L)
616 {
617 int jid, type;
618
619 type = lua_type(L, 1);
620 luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
621 "expected a jail name (string) or id (integer)");
622
623 if (lua_isstring(L, 1)) {
624 /* Resolve it to a jid. */
625 jid = jail_getid(lua_tostring(L, 1));
626 if (jid == -1) {
627 lua_pushnil(L);
628 lua_pushstring(L, jail_errmsg);
629 return (2);
630 }
631 } else {
632 jid = lua_tointeger(L, 1);
633 }
634
635 if (jail_remove(jid) == -1) {
636 lua_pushnil(L);
637 lua_pushstring(L, strerror(errno));
638 return (2);
639 }
640
641 lua_pushboolean(L, 1);
642 return (1);
643 }
644
645 static const struct luaL_Reg l_jail[] = {
646 /** Get id of a jail by name.
647 * @param name jail name (string)
648 * @return jail id (integer)
649 * or nil, error (string) on error
650 */
651 {"getid", l_getid},
652 /** Get name of a jail by id.
653 * @param jid jail id (integer)
654 * @return jail name (string)
655 * or nil, error (string) on error
656 */
657 {"getname", l_getname},
658 /** Get a list of all known jail parameters.
659 * @return list of jail parameter names (table of strings)
660 * or nil, error (string) on error
661 */
662 {"allparams", l_allparams},
663 /** Get the listed params for a given jail.
664 * @param jail jail name (string) or id (integer)
665 * @param params list of parameter names (table of strings)
666 * @param flags optional flags (integer)
667 * @return jid (integer), params (table of [string] = string)
668 * or nil, error (string) on error
669 */
670 {"getparams", l_getparams},
671 /** Set params for a given jail.
672 * @param jail jail name (string) or id (integer)
673 * @param params params and values (table of [string] = string)
674 * @param flags optional flags (integer)
675 * @return jid (integer)
676 * or nil, error (string) on error
677 */
678 {"setparams", l_setparams},
679 /** Get a list of jail parameters for running jails on the system.
680 * @param params optional list of parameter names (table of
681 * strings)
682 * @return iterator (function), jail_obj (object) with next and
683 * close methods
684 */
685 {"list", l_list},
686 /** Attach to a running jail.
687 * @param jail jail name (string) or id (integer)
688 * @return true (boolean)
689 * or nil, error (string) on error
690 */
691 {"attach", l_attach},
692 /** Remove a running jail.
693 * @param jail jail name (string) or id (integer)
694 * @return true (boolean)
695 * or nil, error (string) on error
696 */
697 {"remove", l_remove},
698 {NULL, NULL}
699 };
700
701 int
luaopen_jail(lua_State * L)702 luaopen_jail(lua_State *L)
703 {
704 lua_newtable(L);
705
706 luaL_setfuncs(L, l_jail, 0);
707
708 lua_pushinteger(L, JAIL_CREATE);
709 lua_setfield(L, -2, "CREATE");
710 lua_pushinteger(L, JAIL_UPDATE);
711 lua_setfield(L, -2, "UPDATE");
712 lua_pushinteger(L, JAIL_ATTACH);
713 lua_setfield(L, -2, "ATTACH");
714 lua_pushinteger(L, JAIL_DYING);
715 lua_setfield(L, -2, "DYING");
716
717 register_jail_metatable(L);
718
719 return (1);
720 }
721
722 FLUA_MODULE(jail);
723