1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2009 James Gritton. 5 * All rights reserved. 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 AUTHOR 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 AUTHOR 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/types.h> 34#include <sys/jail.h> 35#include <sys/linker.h> 36#include <sys/socket.h> 37#include <sys/sysctl.h> 38 39#include <arpa/inet.h> 40#include <netinet/in.h> 41 42#include <errno.h> 43#include <inttypes.h> 44#include <stdio.h> 45#include <stdarg.h> 46#include <stdlib.h> 47#include <string.h> 48 49#include "jail.h" 50 51#define SJPARAM "security.jail.param" 52 53#define JPS_IN_ADDR 1 54#define JPS_IN6_ADDR 2 55 56#define ARRAY_SANITY 5 57#define ARRAY_SLOP 5 58 59 60static int jailparam_import_enum(const char **values, int nvalues, 61 const char *valstr, size_t valsize, int *value); 62static int jailparam_type(struct jailparam *jp); 63static int kldload_param(const char *name); 64static char *noname(const char *name); 65static char *nononame(const char *name); 66 67char jail_errmsg[JAIL_ERRMSGLEN]; 68 69static const char *bool_values[] = { "false", "true" }; 70static const char *jailsys_values[] = { "disable", "new", "inherit" }; 71 72 73/* 74 * Import a null-terminated parameter list and set a jail with the flags 75 * and parameters. 76 */ 77int 78jail_setv(int flags, ...) 79{ 80 va_list ap, tap; 81 struct jailparam *jp; 82 const char *name, *value; 83 int njp, jid; 84 85 /* Create the parameter list and import the parameters. */ 86 va_start(ap, flags); 87 va_copy(tap, ap); 88 for (njp = 0; va_arg(tap, char *) != NULL; njp++) 89 (void)va_arg(tap, char *); 90 va_end(tap); 91 jp = alloca(njp * sizeof(struct jailparam)); 92 for (njp = 0; (name = va_arg(ap, char *)) != NULL;) { 93 value = va_arg(ap, char *); 94 if (jailparam_init(jp + njp, name) < 0) 95 goto error; 96 if (jailparam_import(jp + njp++, value) < 0) 97 goto error; 98 } 99 va_end(ap); 100 jid = jailparam_set(jp, njp, flags); 101 jailparam_free(jp, njp); 102 return (jid); 103 104 error: 105 jailparam_free(jp, njp); 106 va_end(ap); 107 return (-1); 108} 109 110/* 111 * Read a null-terminated parameter list, get the referenced jail, and export 112 * the parameters to the list. 113 */ 114int 115jail_getv(int flags, ...) 116{ 117 va_list ap, tap; 118 struct jailparam *jp, *jp_lastjid, *jp_jid, *jp_name, *jp_key; 119 char *valarg, *value; 120 const char *name, *key_value, *lastjid_value, *jid_value, *name_value; 121 int njp, i, jid; 122 123 /* Create the parameter list and find the key. */ 124 va_start(ap, flags); 125 va_copy(tap, ap); 126 for (njp = 0; va_arg(tap, char *) != NULL; njp++) 127 (void)va_arg(tap, char *); 128 va_end(tap); 129 130 jp = alloca(njp * sizeof(struct jailparam)); 131 va_copy(tap, ap); 132 jp_lastjid = jp_jid = jp_name = NULL; 133 lastjid_value = jid_value = name_value = NULL; 134 for (njp = 0; (name = va_arg(tap, char *)) != NULL; njp++) { 135 value = va_arg(tap, char *); 136 if (jailparam_init(jp + njp, name) < 0) { 137 va_end(tap); 138 goto error; 139 } 140 if (!strcmp(jp[njp].jp_name, "lastjid")) { 141 jp_lastjid = jp + njp; 142 lastjid_value = value; 143 } else if (!strcmp(jp[njp].jp_name, "jid")) { 144 jp_jid = jp + njp; 145 jid_value = value; 146 } if (!strcmp(jp[njp].jp_name, "name")) { 147 jp_name = jp + njp; 148 name_value = value; 149 } 150 } 151 va_end(tap); 152 /* Import the key parameter. */ 153 if (jp_lastjid != NULL) { 154 jp_key = jp_lastjid; 155 key_value = lastjid_value; 156 } else if (jp_jid != NULL && strtol(jid_value, NULL, 10) != 0) { 157 jp_key = jp_jid; 158 key_value = jid_value; 159 } else if (jp_name != NULL) { 160 jp_key = jp_name; 161 key_value = name_value; 162 } else { 163 strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN); 164 errno = ENOENT; 165 goto error; 166 } 167 if (jailparam_import(jp_key, key_value) < 0) 168 goto error; 169 /* Get the jail and export the parameters. */ 170 jid = jailparam_get(jp, njp, flags); 171 if (jid < 0) 172 goto error; 173 for (i = 0; i < njp; i++) { 174 (void)va_arg(ap, char *); 175 valarg = va_arg(ap, char *); 176 if (jp + i != jp_key) { 177 /* It's up to the caller to ensure there's room. */ 178 if ((jp[i].jp_ctltype & CTLTYPE) == CTLTYPE_STRING) 179 strcpy(valarg, jp[i].jp_value); 180 else { 181 value = jailparam_export(jp + i); 182 if (value == NULL) 183 goto error; 184 strcpy(valarg, value); 185 free(value); 186 } 187 } 188 } 189 jailparam_free(jp, njp); 190 va_end(ap); 191 return (jid); 192 193 error: 194 jailparam_free(jp, njp); 195 va_end(ap); 196 return (-1); 197} 198 199/* 200 * Return a list of all known parameters. 201 */ 202int 203jailparam_all(struct jailparam **jpp) 204{ 205 struct jailparam *jp, *tjp; 206 size_t mlen1, mlen2, buflen; 207 unsigned njp, nlist; 208 int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2]; 209 char buf[MAXPATHLEN]; 210 211 njp = 0; 212 nlist = 32; 213 jp = malloc(nlist * sizeof(*jp)); 214 if (jp == NULL) { 215 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 216 return (-1); 217 } 218 mib1[0] = 0; 219 mib1[1] = 2; 220 mlen1 = CTL_MAXNAME - 2; 221 if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0) { 222 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 223 "sysctlnametomib(" SJPARAM "): %s", strerror(errno)); 224 goto error; 225 } 226 for (;; njp++) { 227 /* Get the next parameter. */ 228 mlen2 = sizeof(mib2); 229 if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0) { 230 if (errno == ENOENT) { 231 /* No more entries. */ 232 break; 233 } 234 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 235 "sysctl(0.2): %s", strerror(errno)); 236 goto error; 237 } 238 if (mib2[0] != mib1[2] || 239 mib2[1] != mib1[3] || 240 mib2[2] != mib1[4]) 241 break; 242 /* Convert it to an ascii name. */ 243 memcpy(mib1 + 2, mib2, mlen2); 244 mlen1 = mlen2 / sizeof(int); 245 mib1[1] = 1; 246 buflen = sizeof(buf); 247 if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0) { 248 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 249 "sysctl(0.1): %s", strerror(errno)); 250 goto error; 251 } 252 if (buf[buflen - 2] == '.') 253 buf[buflen - 2] = '\0'; 254 /* Add the parameter to the list */ 255 if (njp >= nlist) { 256 nlist *= 2; 257 tjp = reallocarray(jp, nlist, sizeof(*jp)); 258 if (tjp == NULL) 259 goto error; 260 jp = tjp; 261 } 262 if (jailparam_init(jp + njp, buf + sizeof(SJPARAM)) < 0) 263 goto error; 264 mib1[1] = 2; 265 } 266 /* Just return the untrimmed buffer if reallocarray() somehow fails. */ 267 tjp = reallocarray(jp, njp, sizeof(*jp)); 268 if (tjp != NULL) 269 jp = tjp; 270 *jpp = jp; 271 return (njp); 272 273 error: 274 jailparam_free(jp, njp); 275 free(jp); 276 return (-1); 277} 278 279/* 280 * Clear a jail parameter and copy in its name. 281 */ 282int 283jailparam_init(struct jailparam *jp, const char *name) 284{ 285 286 memset(jp, 0, sizeof(*jp)); 287 jp->jp_name = strdup(name); 288 if (jp->jp_name == NULL) { 289 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 290 return (-1); 291 } 292 if (jailparam_type(jp) < 0) { 293 jailparam_free(jp, 1); 294 jp->jp_name = NULL; 295 jp->jp_value = NULL; 296 return (-1); 297 } 298 return (0); 299} 300 301/* 302 * Put a name and value into a jail parameter element, converting the value 303 * to internal form. 304 */ 305int 306jailparam_import(struct jailparam *jp, const char *value) 307{ 308 char *p, *ep, *tvalue; 309 const char *avalue; 310 int i, nval, fw; 311 312 if (value == NULL) 313 return (0); 314 if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) { 315 jp->jp_value = strdup(value); 316 if (jp->jp_value == NULL) { 317 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 318 return (-1); 319 } 320 return (0); 321 } 322 nval = 1; 323 if (jp->jp_elemlen) { 324 if (value[0] == '\0' || (value[0] == '-' && value[1] == '\0')) { 325 jp->jp_value = strdup(""); 326 if (jp->jp_value == NULL) { 327 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 328 return (-1); 329 } 330 jp->jp_valuelen = 0; 331 return (0); 332 } 333 for (p = strchr(value, ','); p; p = strchr(p + 1, ',')) 334 nval++; 335 jp->jp_valuelen = jp->jp_elemlen * nval; 336 } 337 jp->jp_value = malloc(jp->jp_valuelen); 338 if (jp->jp_value == NULL) { 339 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 340 return (-1); 341 } 342 avalue = value; 343 for (i = 0; i < nval; i++) { 344 fw = nval == 1 ? strlen(avalue) : strcspn(avalue, ","); 345 switch (jp->jp_ctltype & CTLTYPE) { 346 case CTLTYPE_INT: 347 if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) { 348 if (!jailparam_import_enum(bool_values, 2, 349 avalue, fw, &((int *)jp->jp_value)[i])) { 350 snprintf(jail_errmsg, 351 JAIL_ERRMSGLEN, "%s: " 352 "unknown boolean value \"%.*s\"", 353 jp->jp_name, fw, avalue); 354 errno = EINVAL; 355 goto error; 356 } 357 break; 358 } 359 if (jp->jp_flags & JP_JAILSYS) { 360 /* 361 * Allow setting a jailsys parameter to "new" 362 * in a booleanesque fashion. 363 */ 364 if (value[0] == '\0') 365 ((int *)jp->jp_value)[i] = JAIL_SYS_NEW; 366 else if (!jailparam_import_enum(jailsys_values, 367 sizeof(jailsys_values) / 368 sizeof(jailsys_values[0]), avalue, fw, 369 &((int *)jp->jp_value)[i])) { 370 snprintf(jail_errmsg, 371 JAIL_ERRMSGLEN, "%s: " 372 "unknown jailsys value \"%.*s\"", 373 jp->jp_name, fw, avalue); 374 errno = EINVAL; 375 goto error; 376 } 377 break; 378 } 379 ((int *)jp->jp_value)[i] = strtol(avalue, &ep, 10); 380 integer_test: 381 if (ep != avalue + fw) { 382 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 383 "%s: non-integer value \"%.*s\"", 384 jp->jp_name, fw, avalue); 385 errno = EINVAL; 386 goto error; 387 } 388 break; 389 case CTLTYPE_UINT: 390 ((unsigned *)jp->jp_value)[i] = 391 strtoul(avalue, &ep, 10); 392 goto integer_test; 393 case CTLTYPE_LONG: 394 ((long *)jp->jp_value)[i] = strtol(avalue, &ep, 10); 395 goto integer_test; 396 case CTLTYPE_ULONG: 397 ((unsigned long *)jp->jp_value)[i] = 398 strtoul(avalue, &ep, 10); 399 goto integer_test; 400 case CTLTYPE_S64: 401 ((int64_t *)jp->jp_value)[i] = 402 strtoimax(avalue, &ep, 10); 403 goto integer_test; 404 case CTLTYPE_U64: 405 ((uint64_t *)jp->jp_value)[i] = 406 strtoumax(avalue, &ep, 10); 407 goto integer_test; 408 case CTLTYPE_STRUCT: 409 tvalue = alloca(fw + 1); 410 strlcpy(tvalue, avalue, fw + 1); 411 switch (jp->jp_structtype) { 412 case JPS_IN_ADDR: 413 if (inet_pton(AF_INET, tvalue, 414 &((struct in_addr *)jp->jp_value)[i]) != 1) 415 { 416 snprintf(jail_errmsg, 417 JAIL_ERRMSGLEN, 418 "%s: not an IPv4 address: %s", 419 jp->jp_name, tvalue); 420 errno = EINVAL; 421 goto error; 422 } 423 break; 424 case JPS_IN6_ADDR: 425 if (inet_pton(AF_INET6, tvalue, 426 &((struct in6_addr *)jp->jp_value)[i]) != 1) 427 { 428 snprintf(jail_errmsg, 429 JAIL_ERRMSGLEN, 430 "%s: not an IPv6 address: %s", 431 jp->jp_name, tvalue); 432 errno = EINVAL; 433 goto error; 434 } 435 break; 436 default: 437 goto unknown_type; 438 } 439 break; 440 default: 441 unknown_type: 442 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 443 "unknown type for %s", jp->jp_name); 444 errno = ENOENT; 445 goto error; 446 } 447 avalue += fw + 1; 448 } 449 return (0); 450 451 error: 452 free(jp->jp_value); 453 jp->jp_value = NULL; 454 return (-1); 455} 456 457static int 458jailparam_import_enum(const char **values, int nvalues, const char *valstr, 459 size_t valsize, int *value) 460{ 461 char *ep; 462 int i; 463 464 for (i = 0; i < nvalues; i++) 465 if (valsize == strlen(values[i]) && 466 !strncasecmp(valstr, values[i], valsize)) { 467 *value = i; 468 return 1; 469 } 470 *value = strtol(valstr, &ep, 10); 471 return (ep == valstr + valsize); 472} 473 474/* 475 * Put a name and value into a jail parameter element, copying the value 476 * but not altering it. 477 */ 478int 479jailparam_import_raw(struct jailparam *jp, void *value, size_t valuelen) 480{ 481 482 jp->jp_value = value; 483 jp->jp_valuelen = valuelen; 484 jp->jp_flags |= JP_RAWVALUE; 485 return (0); 486} 487 488/* 489 * Run the jail_set and jail_get system calls on a parameter list. 490 */ 491int 492jailparam_set(struct jailparam *jp, unsigned njp, int flags) 493{ 494 struct iovec *jiov; 495 char *nname; 496 int i, jid, bool0; 497 unsigned j; 498 499 jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1)); 500 bool0 = 0; 501 for (i = j = 0; j < njp; j++) { 502 jiov[i].iov_base = jp[j].jp_name; 503 jiov[i].iov_len = strlen(jp[j].jp_name) + 1; 504 i++; 505 if (jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) { 506 /* 507 * Set booleans without values. If one has a value of 508 * zero, change it to (or from) its "no" counterpart. 509 */ 510 jiov[i].iov_base = NULL; 511 jiov[i].iov_len = 0; 512 if (jp[j].jp_value != NULL && 513 jp[j].jp_valuelen == sizeof(int) && 514 !*(int *)jp[j].jp_value) { 515 bool0 = 1; 516 nname = jp[j].jp_flags & JP_BOOL 517 ? noname(jp[j].jp_name) 518 : nononame(jp[j].jp_name); 519 if (nname == NULL) { 520 njp = j; 521 jid = -1; 522 goto done; 523 } 524 jiov[i - 1].iov_base = nname; 525 jiov[i - 1].iov_len = strlen(nname) + 1; 526 527 } 528 } else { 529 /* 530 * Try to fill in missing values with an empty string. 531 */ 532 if (jp[j].jp_value == NULL && jp[j].jp_valuelen > 0 && 533 jailparam_import(jp + j, "") < 0) { 534 njp = j; 535 jid = -1; 536 goto done; 537 } 538 jiov[i].iov_base = jp[j].jp_value; 539 jiov[i].iov_len = 540 (jp[j].jp_ctltype & CTLTYPE) == CTLTYPE_STRING 541 ? strlen(jp[j].jp_value) + 1 542 : jp[j].jp_valuelen; 543 } 544 i++; 545 } 546 jiov[i].iov_base = __DECONST(char *, "errmsg"); 547 jiov[i].iov_len = sizeof("errmsg"); 548 i++; 549 jiov[i].iov_base = jail_errmsg; 550 jiov[i].iov_len = JAIL_ERRMSGLEN; 551 i++; 552 jail_errmsg[0] = 0; 553 jid = jail_set(jiov, i, flags); 554 if (jid < 0 && !jail_errmsg[0]) 555 snprintf(jail_errmsg, sizeof(jail_errmsg), "jail_set: %s", 556 strerror(errno)); 557 done: 558 if (bool0) 559 for (j = 0; j < njp; j++) 560 if ((jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) && 561 jp[j].jp_value != NULL && 562 jp[j].jp_valuelen == sizeof(int) && 563 !*(int *)jp[j].jp_value) 564 free(jiov[j * 2].iov_base); 565 return (jid); 566} 567 568int 569jailparam_get(struct jailparam *jp, unsigned njp, int flags) 570{ 571 struct iovec *jiov; 572 struct jailparam *jp_lastjid, *jp_jid, *jp_name, *jp_key; 573 int i, ai, ki, jid, arrays, sanity; 574 unsigned j; 575 576 /* 577 * Get the types for all parameters. 578 * Find the key and any array parameters. 579 */ 580 jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1)); 581 jp_lastjid = jp_jid = jp_name = NULL; 582 arrays = 0; 583 for (ai = j = 0; j < njp; j++) { 584 if (!strcmp(jp[j].jp_name, "lastjid")) 585 jp_lastjid = jp + j; 586 else if (!strcmp(jp[j].jp_name, "jid")) 587 jp_jid = jp + j; 588 else if (!strcmp(jp[j].jp_name, "name")) 589 jp_name = jp + j; 590 else if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 591 arrays = 1; 592 jiov[ai].iov_base = jp[j].jp_name; 593 jiov[ai].iov_len = strlen(jp[j].jp_name) + 1; 594 ai++; 595 jiov[ai].iov_base = NULL; 596 jiov[ai].iov_len = 0; 597 ai++; 598 } 599 } 600 jp_key = jp_lastjid ? jp_lastjid : 601 jp_jid && jp_jid->jp_valuelen == sizeof(int) && 602 jp_jid->jp_value && *(int *)jp_jid->jp_value ? jp_jid : jp_name; 603 if (jp_key == NULL || jp_key->jp_value == NULL) { 604 strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN); 605 errno = ENOENT; 606 return (-1); 607 } 608 ki = ai; 609 jiov[ki].iov_base = jp_key->jp_name; 610 jiov[ki].iov_len = strlen(jp_key->jp_name) + 1; 611 ki++; 612 jiov[ki].iov_base = jp_key->jp_value; 613 jiov[ki].iov_len = (jp_key->jp_ctltype & CTLTYPE) == CTLTYPE_STRING 614 ? strlen(jp_key->jp_value) + 1 : jp_key->jp_valuelen; 615 ki++; 616 jiov[ki].iov_base = __DECONST(char *, "errmsg"); 617 jiov[ki].iov_len = sizeof("errmsg"); 618 ki++; 619 jiov[ki].iov_base = jail_errmsg; 620 jiov[ki].iov_len = JAIL_ERRMSGLEN; 621 ki++; 622 jail_errmsg[0] = 0; 623 if (arrays && jail_get(jiov, ki, flags) < 0) { 624 if (!jail_errmsg[0]) 625 snprintf(jail_errmsg, sizeof(jail_errmsg), 626 "jail_get: %s", strerror(errno)); 627 return (-1); 628 } 629 /* Allocate storage for all parameters. */ 630 for (ai = j = 0, i = ki; j < njp; j++) { 631 if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 632 ai++; 633 jiov[ai].iov_len += jp[j].jp_elemlen * ARRAY_SLOP; 634 if (jp[j].jp_valuelen >= jiov[ai].iov_len) 635 jiov[ai].iov_len = jp[j].jp_valuelen; 636 else { 637 jp[j].jp_valuelen = jiov[ai].iov_len; 638 if (jp[j].jp_value != NULL) 639 free(jp[j].jp_value); 640 jp[j].jp_value = malloc(jp[j].jp_valuelen); 641 if (jp[j].jp_value == NULL) { 642 strerror_r(errno, jail_errmsg, 643 JAIL_ERRMSGLEN); 644 return (-1); 645 } 646 } 647 jiov[ai].iov_base = jp[j].jp_value; 648 memset(jiov[ai].iov_base, 0, jiov[ai].iov_len); 649 ai++; 650 } else if (jp + j != jp_key) { 651 jiov[i].iov_base = jp[j].jp_name; 652 jiov[i].iov_len = strlen(jp[j].jp_name) + 1; 653 i++; 654 if (jp[j].jp_value == NULL && 655 !(jp[j].jp_flags & JP_RAWVALUE)) { 656 jp[j].jp_value = malloc(jp[j].jp_valuelen); 657 if (jp[j].jp_value == NULL) { 658 strerror_r(errno, jail_errmsg, 659 JAIL_ERRMSGLEN); 660 return (-1); 661 } 662 } 663 jiov[i].iov_base = jp[j].jp_value; 664 jiov[i].iov_len = jp[j].jp_valuelen; 665 memset(jiov[i].iov_base, 0, jiov[i].iov_len); 666 i++; 667 } 668 } 669 /* 670 * Get the prison. If there are array elements, retry a few times 671 * in case their sizes changed from under us. 672 */ 673 for (sanity = 0;; sanity++) { 674 jid = jail_get(jiov, i, flags); 675 if (jid >= 0 || !arrays || sanity == ARRAY_SANITY || 676 errno != EINVAL || jail_errmsg[0]) 677 break; 678 for (ai = j = 0; j < njp; j++) { 679 if (jp[j].jp_elemlen && 680 !(jp[j].jp_flags & JP_RAWVALUE)) { 681 ai++; 682 jiov[ai].iov_base = NULL; 683 jiov[ai].iov_len = 0; 684 ai++; 685 } 686 } 687 if (jail_get(jiov, ki, flags) < 0) 688 break; 689 for (ai = j = 0; j < njp; j++) { 690 if (jp[j].jp_elemlen && 691 !(jp[j].jp_flags & JP_RAWVALUE)) { 692 ai++; 693 jiov[ai].iov_len += 694 jp[j].jp_elemlen * ARRAY_SLOP; 695 if (jp[j].jp_valuelen >= jiov[ai].iov_len) 696 jiov[ai].iov_len = jp[j].jp_valuelen; 697 else { 698 jp[j].jp_valuelen = jiov[ai].iov_len; 699 if (jp[j].jp_value != NULL) 700 free(jp[j].jp_value); 701 jp[j].jp_value = 702 malloc(jiov[ai].iov_len); 703 if (jp[j].jp_value == NULL) { 704 strerror_r(errno, jail_errmsg, 705 JAIL_ERRMSGLEN); 706 return (-1); 707 } 708 } 709 jiov[ai].iov_base = jp[j].jp_value; 710 memset(jiov[ai].iov_base, 0, jiov[ai].iov_len); 711 ai++; 712 } 713 } 714 } 715 if (jid < 0 && !jail_errmsg[0]) 716 snprintf(jail_errmsg, sizeof(jail_errmsg), 717 "jail_get: %s", strerror(errno)); 718 for (ai = j = 0, i = ki; j < njp; j++) { 719 if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 720 ai++; 721 jp[j].jp_valuelen = jiov[ai].iov_len; 722 ai++; 723 } else if (jp + j != jp_key) { 724 i++; 725 jp[j].jp_valuelen = jiov[i].iov_len; 726 i++; 727 } 728 } 729 return (jid); 730} 731 732/* 733 * Convert a jail parameter's value to external form. 734 */ 735char * 736jailparam_export(struct jailparam *jp) 737{ 738 size_t *valuelens; 739 char *value, *tvalue, **values; 740 size_t valuelen; 741 int i, nval, ival; 742 char valbuf[INET6_ADDRSTRLEN]; 743 744 if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) { 745 value = strdup(jp->jp_value); 746 if (value == NULL) 747 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 748 return (value); 749 } 750 nval = jp->jp_elemlen ? jp->jp_valuelen / jp->jp_elemlen : 1; 751 if (nval == 0) { 752 value = strdup(""); 753 if (value == NULL) 754 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 755 return (value); 756 } 757 values = alloca(nval * sizeof(char *)); 758 valuelens = alloca(nval * sizeof(size_t)); 759 valuelen = 0; 760 for (i = 0; i < nval; i++) { 761 switch (jp->jp_ctltype & CTLTYPE) { 762 case CTLTYPE_INT: 763 ival = ((int *)jp->jp_value)[i]; 764 if ((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) && 765 (unsigned)ival < 2) { 766 strlcpy(valbuf, bool_values[ival], 767 sizeof(valbuf)); 768 break; 769 } 770 if ((jp->jp_flags & JP_JAILSYS) && 771 (unsigned)ival < sizeof(jailsys_values) / 772 sizeof(jailsys_values[0])) { 773 strlcpy(valbuf, jailsys_values[ival], 774 sizeof(valbuf)); 775 break; 776 } 777 snprintf(valbuf, sizeof(valbuf), "%d", ival); 778 break; 779 case CTLTYPE_UINT: 780 snprintf(valbuf, sizeof(valbuf), "%u", 781 ((unsigned *)jp->jp_value)[i]); 782 break; 783 case CTLTYPE_LONG: 784 snprintf(valbuf, sizeof(valbuf), "%ld", 785 ((long *)jp->jp_value)[i]); 786 break; 787 case CTLTYPE_ULONG: 788 snprintf(valbuf, sizeof(valbuf), "%lu", 789 ((unsigned long *)jp->jp_value)[i]); 790 break; 791 case CTLTYPE_S64: 792 snprintf(valbuf, sizeof(valbuf), "%jd", 793 (intmax_t)((int64_t *)jp->jp_value)[i]); 794 break; 795 case CTLTYPE_U64: 796 snprintf(valbuf, sizeof(valbuf), "%ju", 797 (uintmax_t)((uint64_t *)jp->jp_value)[i]); 798 break; 799 case CTLTYPE_STRUCT: 800 switch (jp->jp_structtype) { 801 case JPS_IN_ADDR: 802 if (inet_ntop(AF_INET, 803 &((struct in_addr *)jp->jp_value)[i], 804 valbuf, sizeof(valbuf)) == NULL) { 805 strerror_r(errno, jail_errmsg, 806 JAIL_ERRMSGLEN); 807 return (NULL); 808 } 809 break; 810 case JPS_IN6_ADDR: 811 if (inet_ntop(AF_INET6, 812 &((struct in6_addr *)jp->jp_value)[i], 813 valbuf, sizeof(valbuf)) == NULL) { 814 strerror_r(errno, jail_errmsg, 815 JAIL_ERRMSGLEN); 816 return (NULL); 817 } 818 break; 819 default: 820 goto unknown_type; 821 } 822 break; 823 default: 824 unknown_type: 825 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 826 "unknown type for %s", jp->jp_name); 827 errno = ENOENT; 828 return (NULL); 829 } 830 valuelens[i] = strlen(valbuf) + 1; 831 valuelen += valuelens[i]; 832 values[i] = alloca(valuelens[i]); 833 strcpy(values[i], valbuf); 834 } 835 value = malloc(valuelen); 836 if (value == NULL) 837 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 838 else { 839 tvalue = value; 840 for (i = 0; i < nval; i++) { 841 strcpy(tvalue, values[i]); 842 if (i < nval - 1) { 843 tvalue += valuelens[i]; 844 tvalue[-1] = ','; 845 } 846 } 847 } 848 return (value); 849} 850 851/* 852 * Free the contents of a jail parameter list (but not the list itself). 853 */ 854void 855jailparam_free(struct jailparam *jp, unsigned njp) 856{ 857 unsigned j; 858 859 for (j = 0; j < njp; j++) { 860 free(jp[j].jp_name); 861 if (!(jp[j].jp_flags & JP_RAWVALUE)) 862 free(jp[j].jp_value); 863 } 864} 865 866/* 867 * Find a parameter's type and size from its MIB. 868 */ 869static int 870jailparam_type(struct jailparam *jp) 871{ 872 char *p, *name, *nname; 873 size_t miblen, desclen; 874 int i, isarray; 875 struct { 876 int i; 877 char s[MAXPATHLEN]; 878 } desc; 879 int mib[CTL_MAXNAME]; 880 881 /* The "lastjid" parameter isn't real. */ 882 name = jp->jp_name; 883 if (!strcmp(name, "lastjid")) { 884 jp->jp_valuelen = sizeof(int); 885 jp->jp_ctltype = CTLTYPE_INT | CTLFLAG_WR; 886 return (0); 887 } 888 889 /* Find the sysctl that describes the parameter. */ 890 mib[0] = 0; 891 mib[1] = 3; 892 snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", name); 893 miblen = sizeof(mib) - 2 * sizeof(int); 894 if (sysctl(mib, 2, mib + 2, &miblen, desc.s, strlen(desc.s)) < 0) { 895 if (errno != ENOENT) { 896 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 897 "sysctl(0.3.%s): %s", name, strerror(errno)); 898 return (-1); 899 } 900 if (kldload_param(name) >= 0 && sysctl(mib, 2, mib + 2, &miblen, 901 desc.s, strlen(desc.s)) >= 0) 902 goto mib_desc; 903 /* 904 * The parameter probably doesn't exist. But it might be 905 * the "no" counterpart to a boolean. 906 */ 907 nname = nononame(name); 908 if (nname == NULL) { 909 unknown_parameter: 910 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 911 "unknown parameter: %s", jp->jp_name); 912 errno = ENOENT; 913 return (-1); 914 } 915 name = alloca(strlen(nname) + 1); 916 strcpy(name, nname); 917 free(nname); 918 snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", name); 919 miblen = sizeof(mib) - 2 * sizeof(int); 920 if (sysctl(mib, 2, mib + 2, &miblen, desc.s, 921 strlen(desc.s)) < 0) 922 goto unknown_parameter; 923 jp->jp_flags |= JP_NOBOOL; 924 } 925 mib_desc: 926 mib[1] = 4; 927 desclen = sizeof(desc); 928 if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen, 929 NULL, 0) < 0) { 930 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 931 "sysctl(0.4.%s): %s", name, strerror(errno)); 932 return (-1); 933 } 934 jp->jp_ctltype = desc.i; 935 /* If this came from removing a "no", it better be a boolean. */ 936 if (jp->jp_flags & JP_NOBOOL) { 937 if ((desc.i & CTLTYPE) == CTLTYPE_INT && desc.s[0] == 'B') { 938 jp->jp_valuelen = sizeof(int); 939 return (0); 940 } 941 else if ((desc.i & CTLTYPE) != CTLTYPE_NODE) 942 goto unknown_parameter; 943 } 944 /* See if this is an array type. */ 945 p = strchr(desc.s, '\0'); 946 isarray = 0; 947 if (p - 2 < desc.s || strcmp(p - 2, ",a")) 948 isarray = 0; 949 else { 950 isarray = 1; 951 p[-2] = 0; 952 } 953 /* Look for types we understand. */ 954 switch (desc.i & CTLTYPE) { 955 case CTLTYPE_INT: 956 if (desc.s[0] == 'B') 957 jp->jp_flags |= JP_BOOL; 958 else if (!strcmp(desc.s, "E,jailsys")) 959 jp->jp_flags |= JP_JAILSYS; 960 case CTLTYPE_UINT: 961 jp->jp_valuelen = sizeof(int); 962 break; 963 case CTLTYPE_LONG: 964 case CTLTYPE_ULONG: 965 jp->jp_valuelen = sizeof(long); 966 break; 967 case CTLTYPE_S64: 968 case CTLTYPE_U64: 969 jp->jp_valuelen = sizeof(int64_t); 970 break; 971 case CTLTYPE_STRING: 972 desc.s[0] = 0; 973 desclen = sizeof(desc.s); 974 if (sysctl(mib + 2, miblen / sizeof(int), desc.s, &desclen, 975 NULL, 0) < 0) { 976 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 977 "sysctl(" SJPARAM ".%s): %s", name, 978 strerror(errno)); 979 return (-1); 980 } 981 jp->jp_valuelen = strtoul(desc.s, NULL, 10); 982 break; 983 case CTLTYPE_STRUCT: 984 if (!strcmp(desc.s, "S,in_addr")) { 985 jp->jp_structtype = JPS_IN_ADDR; 986 jp->jp_valuelen = sizeof(struct in_addr); 987 } else if (!strcmp(desc.s, "S,in6_addr")) { 988 jp->jp_structtype = JPS_IN6_ADDR; 989 jp->jp_valuelen = sizeof(struct in6_addr); 990 } else { 991 desclen = 0; 992 if (sysctl(mib + 2, miblen / sizeof(int), 993 NULL, &jp->jp_valuelen, NULL, 0) < 0) { 994 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 995 "sysctl(" SJPARAM ".%s): %s", name, 996 strerror(errno)); 997 return (-1); 998 } 999 } 1000 break; 1001 case CTLTYPE_NODE: 1002 /* 1003 * A node might be described by an empty-named child, 1004 * which would be immediately before or after the node itself. 1005 */ 1006 mib[1] = 1; 1007 miblen += sizeof(int); 1008 for (i = -1; i <= 1; i += 2) { 1009 mib[(miblen / sizeof(int)) + 1] = 1010 mib[(miblen / sizeof(int))] + i; 1011 desclen = sizeof(desc.s); 1012 if (sysctl(mib, (miblen / sizeof(int)) + 2, desc.s, 1013 &desclen, NULL, 0) < 0) { 1014 if (errno == ENOENT) 1015 continue; 1016 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1017 "sysctl(0.1): %s", strerror(errno)); 1018 return (-1); 1019 } 1020 if (desclen == sizeof(SJPARAM) + strlen(name) + 2 && 1021 memcmp(SJPARAM ".", desc.s, sizeof(SJPARAM)) == 0 && 1022 memcmp(name, desc.s + sizeof(SJPARAM), 1023 desclen - sizeof(SJPARAM) - 2) == 0 && 1024 desc.s[desclen - 2] == '.') 1025 goto mib_desc; 1026 } 1027 goto unknown_parameter; 1028 default: 1029 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1030 "unknown type for %s", jp->jp_name); 1031 errno = ENOENT; 1032 return (-1); 1033 } 1034 if (isarray) { 1035 jp->jp_elemlen = jp->jp_valuelen; 1036 jp->jp_valuelen = 0; 1037 } 1038 return (0); 1039} 1040 1041/* 1042 * Attempt to load a kernel module matching an otherwise nonexistent parameter. 1043 */ 1044static int 1045kldload_param(const char *name) 1046{ 1047 int kl; 1048 1049 if (strcmp(name, "linux") == 0 || strncmp(name, "linux.", 6) == 0) 1050 kl = kldload("linux"); 1051 else if (strcmp(name, "sysvmsg") == 0 || strcmp(name, "sysvsem") == 0 || 1052 strcmp(name, "sysvshm") == 0) 1053 kl = kldload(name); 1054 else if (strncmp(name, "allow.mount.", 12) == 0) { 1055 /* Load the matching filesystem */ 1056 const char *modname = name + 12; 1057 1058 kl = kldload(modname); 1059 if (kl < 0 && errno == ENOENT && 1060 strncmp(modname, "no", 2) == 0) 1061 kl = kldload(modname + 2); 1062 } else { 1063 errno = ENOENT; 1064 return (-1); 1065 } 1066 if (kl < 0 && errno == EEXIST) { 1067 /* 1068 * In the module is already loaded, then it must not contain 1069 * the parameter. 1070 */ 1071 errno = ENOENT; 1072 } 1073 return kl; 1074} 1075 1076/* 1077 * Change a boolean parameter name into its "no" counterpart or vice versa. 1078 */ 1079static char * 1080noname(const char *name) 1081{ 1082 char *nname, *p; 1083 1084 nname = malloc(strlen(name) + 3); 1085 if (nname == NULL) { 1086 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 1087 return (NULL); 1088 } 1089 p = strrchr(name, '.'); 1090 if (p != NULL) 1091 sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1); 1092 else 1093 sprintf(nname, "no%s", name); 1094 return (nname); 1095} 1096 1097static char * 1098nononame(const char *name) 1099{ 1100 char *p, *nname; 1101 1102 p = strrchr(name, '.'); 1103 if (strncmp(p ? p + 1 : name, "no", 2)) { 1104 snprintf(jail_errmsg, sizeof(jail_errmsg), 1105 "mismatched boolean: %s", name); 1106 errno = EINVAL; 1107 return (NULL); 1108 } 1109 nname = malloc(strlen(name) - 1); 1110 if (nname == NULL) { 1111 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 1112 return (NULL); 1113 } 1114 if (p != NULL) 1115 sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3); 1116 else 1117 strcpy(nname, name + 2); 1118 return (nname); 1119} 1120