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