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