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