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