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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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