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