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