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