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