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