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 value = jailparam_export(¶ms[i]); 449 lua_pushstring(L, value); 450 free(value); 451 lua_setfield(L, -2, params[i].jp_name); 452 } 453 454 jailparam_free(params, params_count); 455 free(params); 456 457 return (2); 458 } 459 460 static int 461 l_setparams(lua_State *L) 462 { 463 const char *name; 464 struct jailparam *params; 465 size_t params_count; 466 int flags, jid, type; 467 468 type = lua_type(L, 1); 469 luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1, 470 "expected a jail name (string) or id (integer)"); 471 luaL_checktype(L, 2, LUA_TTABLE); 472 473 lua_pushnil(L); 474 for (params_count = 1; lua_next(L, 2) != 0; ++params_count) 475 lua_pop(L, 1); 476 477 flags = luaL_optinteger(L, 3, 0); 478 479 params = malloc(params_count * sizeof(struct jailparam)); 480 if (params == NULL) 481 return (luaL_error(L, "malloc: %s", strerror(errno))); 482 483 /* 484 * Set the jail name or id param as determined by the first arg. 485 */ 486 487 if (type == LUA_TSTRING) { 488 if (jailparam_init(¶ms[0], "name") == -1) { 489 free(params); 490 return (luaL_error(L, "jailparam_init: %s", 491 jail_errmsg)); 492 } 493 name = lua_tostring(L, 1); 494 if (jailparam_import(¶ms[0], name) == -1) { 495 jailparam_free(params, 1); 496 free(params); 497 return (luaL_error(L, "jailparam_import: %s", 498 jail_errmsg)); 499 } 500 } else /* type == LUA_TNUMBER */ { 501 if (jailparam_init(¶ms[0], "jid") == -1) { 502 free(params); 503 return (luaL_error(L, "jailparam_init: %s", 504 jail_errmsg)); 505 } 506 jid = lua_tointeger(L, 1); 507 if (jailparam_import_raw(¶ms[0], &jid, sizeof(jid)) == -1) { 508 jailparam_free(params, 1); 509 free(params); 510 return (luaL_error(L, "jailparam_import_raw: %s", 511 jail_errmsg)); 512 } 513 } 514 515 /* 516 * Set the rest of the provided params. 517 */ 518 519 lua_pushnil(L); 520 for (size_t i = 1; i < params_count && lua_next(L, 2) != 0; ++i) { 521 const char *value; 522 523 name = lua_tostring(L, -2); 524 if (name == NULL) { 525 jailparam_free(params, i); 526 free(params); 527 return (luaL_argerror(L, 2, 528 "param names must be strings")); 529 } 530 if (jailparam_init(¶ms[i], name) == -1) { 531 jailparam_free(params, i); 532 free(params); 533 return (luaL_error(L, "jailparam_init: %s", 534 jail_errmsg)); 535 } 536 537 value = lua_tostring(L, -1); 538 if (value == NULL) { 539 jailparam_free(params, i + 1); 540 free(params); 541 return (luaL_argerror(L, 2, 542 "param values must be strings")); 543 } 544 if (jailparam_import(¶ms[i], value) == -1) { 545 jailparam_free(params, i + 1); 546 free(params); 547 return (luaL_error(L, "jailparam_import: %s", 548 jail_errmsg)); 549 } 550 551 lua_pop(L, 1); 552 } 553 554 /* 555 * Attempt to set the params. 556 */ 557 558 jid = jailparam_set(params, params_count, flags); 559 if (jid == -1) { 560 jailparam_free(params, params_count); 561 free(params); 562 lua_pushnil(L); 563 lua_pushstring(L, jail_errmsg); 564 return (2); 565 } 566 lua_pushinteger(L, jid); 567 568 jailparam_free(params, params_count); 569 free(params); 570 return (1); 571 } 572 573 static int 574 l_attach(lua_State *L) 575 { 576 int jid, type; 577 578 type = lua_type(L, 1); 579 luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1, 580 "expected a jail name (string) or id (integer)"); 581 582 if (lua_isstring(L, 1)) { 583 /* Resolve it to a jid. */ 584 jid = jail_getid(lua_tostring(L, 1)); 585 if (jid == -1) { 586 lua_pushnil(L); 587 lua_pushstring(L, jail_errmsg); 588 return (2); 589 } 590 } else { 591 jid = lua_tointeger(L, 1); 592 } 593 594 if (jail_attach(jid) == -1) { 595 lua_pushnil(L); 596 lua_pushstring(L, strerror(errno)); 597 return (2); 598 } 599 600 lua_pushboolean(L, 1); 601 return (1); 602 } 603 604 static int 605 l_remove(lua_State *L) 606 { 607 int jid, type; 608 609 type = lua_type(L, 1); 610 luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1, 611 "expected a jail name (string) or id (integer)"); 612 613 if (lua_isstring(L, 1)) { 614 /* Resolve it to a jid. */ 615 jid = jail_getid(lua_tostring(L, 1)); 616 if (jid == -1) { 617 lua_pushnil(L); 618 lua_pushstring(L, jail_errmsg); 619 return (2); 620 } 621 } else { 622 jid = lua_tointeger(L, 1); 623 } 624 625 if (jail_remove(jid) == -1) { 626 lua_pushnil(L); 627 lua_pushstring(L, strerror(errno)); 628 return (2); 629 } 630 631 lua_pushboolean(L, 1); 632 return (1); 633 } 634 635 static const struct luaL_Reg l_jail[] = { 636 /** Get id of a jail by name. 637 * @param name jail name (string) 638 * @return jail id (integer) 639 * or nil, error (string) on error 640 */ 641 {"getid", l_getid}, 642 /** Get name of a jail by id. 643 * @param jid jail id (integer) 644 * @return jail name (string) 645 * or nil, error (string) on error 646 */ 647 {"getname", l_getname}, 648 /** Get a list of all known jail parameters. 649 * @return list of jail parameter names (table of strings) 650 * or nil, error (string) on error 651 */ 652 {"allparams", l_allparams}, 653 /** Get the listed params for a given jail. 654 * @param jail jail name (string) or id (integer) 655 * @param params list of parameter names (table of strings) 656 * @param flags optional flags (integer) 657 * @return jid (integer), params (table of [string] = string) 658 * or nil, error (string) on error 659 */ 660 {"getparams", l_getparams}, 661 /** Set params for a given jail. 662 * @param jail jail name (string) or id (integer) 663 * @param params params and values (table of [string] = string) 664 * @param flags optional flags (integer) 665 * @return jid (integer) 666 * or nil, error (string) on error 667 */ 668 {"setparams", l_setparams}, 669 /** Get a list of jail parameters for running jails on the system. 670 * @param params optional list of parameter names (table of 671 * strings) 672 * @return iterator (function), jail_obj (object) with next and 673 * close methods 674 */ 675 {"list", l_list}, 676 /** Attach to a running jail. 677 * @param jail jail name (string) or id (integer) 678 * @return true (boolean) 679 * or nil, error (string) on error 680 */ 681 {"attach", l_attach}, 682 /** Remove a running jail. 683 * @param jail jail name (string) or id (integer) 684 * @return true (boolean) 685 * or nil, error (string) on error 686 */ 687 {"remove", l_remove}, 688 {NULL, NULL} 689 }; 690 691 int 692 luaopen_jail(lua_State *L) 693 { 694 lua_newtable(L); 695 696 luaL_setfuncs(L, l_jail, 0); 697 698 lua_pushinteger(L, JAIL_CREATE); 699 lua_setfield(L, -2, "CREATE"); 700 lua_pushinteger(L, JAIL_UPDATE); 701 lua_setfield(L, -2, "UPDATE"); 702 lua_pushinteger(L, JAIL_ATTACH); 703 lua_setfield(L, -2, "ATTACH"); 704 lua_pushinteger(L, JAIL_DYING); 705 lua_setfield(L, -2, "DYING"); 706 707 register_jail_metatable(L); 708 709 return (1); 710 } 711