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