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