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/mac.h> 33 #include <sys/socket.h> 34 #include <sys/sysctl.h> 35 36 #include <arpa/inet.h> 37 #include <netinet/in.h> 38 39 #include <assert.h> 40 #include <errno.h> 41 #include <inttypes.h> 42 #include <stdio.h> 43 #include <stdarg.h> 44 #include <stdlib.h> 45 #include <string.h> 46 47 #include "jail.h" 48 49 #define SJPARAM "security.jail.param" 50 51 #define JPSDEF_OF(jp) \ 52 ((jp)->jp_structtype >= 0 ? &jp_structdefs[(jp)->jp_structtype] : NULL) 53 54 static int jps_get(struct jailparam *, struct iovec *); 55 static int jps_set(const struct jailparam *, struct iovec *); 56 static void jps_free(struct jailparam *); 57 58 typedef int (jps_import_t)(const struct jailparam *, int, const char *); 59 typedef char *(jps_export_t)(const struct jailparam *, int); 60 typedef int (jps_get_t)(struct jailparam *, struct iovec *); 61 typedef int (jps_set_t)(const struct jailparam *, struct iovec *); 62 typedef void (jps_free_t)(struct jailparam *); 63 64 static jps_import_t jps_import_in_addr; 65 static jps_import_t jps_import_in6_addr; 66 static jps_import_t jps_import_mac_label; 67 68 static jps_export_t jps_export_in_addr; 69 static jps_export_t jps_export_in6_addr; 70 static jps_export_t jps_export_mac_label; 71 72 static jps_get_t jps_get_mac_label; 73 74 static jps_set_t jps_set_mac_label; 75 76 static jps_free_t jps_free_mac_label; 77 78 static const struct jp_structdef { 79 const char *jps_type; /* sysctl type */ 80 size_t jps_valuelen; /* value size */ 81 jps_import_t *jps_import; /* jailparam_import() */ 82 jps_export_t *jps_export; /* jailparam_export() */ 83 jps_get_t *jps_get; /* jailparam_get() */ 84 jps_set_t *jps_set; /* jailparam_set() */ 85 jps_free_t *jps_free; /* jailparam_free() */ 86 } jp_structdefs[] = { 87 { 88 .jps_type = "S,in_addr", 89 .jps_valuelen = sizeof(struct in_addr), 90 .jps_import = jps_import_in_addr, 91 .jps_export = jps_export_in_addr, 92 }, 93 { 94 .jps_type = "S,in6_addr", 95 .jps_valuelen = sizeof(struct in6_addr), 96 .jps_import = jps_import_in6_addr, 97 .jps_export = jps_export_in6_addr, 98 }, 99 { 100 .jps_type = "S,mac", 101 .jps_valuelen = sizeof(mac_t *), 102 .jps_import = jps_import_mac_label, 103 .jps_export = jps_export_mac_label, 104 .jps_get = jps_get_mac_label, 105 .jps_set = jps_set_mac_label, 106 .jps_free = jps_free_mac_label, 107 }, 108 }; 109 110 _Static_assert(nitems(jp_structdefs) <= INT_MAX, 111 "Too many struct definitions requires an ABI break in struct jailparam"); 112 113 #define ARRAY_SANITY 5 114 #define ARRAY_SLOP 5 115 116 static const struct jp_structdef *jp_structinfo(const char *type, int *); 117 118 static int jailparam_import_enum(const char **values, int nvalues, 119 const char *valstr, size_t valsize, int *value); 120 static int jailparam_type(struct jailparam *jp); 121 static int kldload_param(const char *name); 122 static char *noname(const char *name); 123 static char *nononame(const char *name); 124 static char *kvname(const char *name); 125 126 char jail_errmsg[JAIL_ERRMSGLEN]; 127 128 static const char *bool_values[] = { "false", "true" }; 129 static const char *jailsys_values[] = { "disable", "new", "inherit" }; 130 131 static const struct jp_structdef * 132 jp_structinfo(const char *type, int *oidx) 133 { 134 const struct jp_structdef *jpsdef; 135 136 for (size_t idx = 0; idx < nitems(jp_structdefs); idx++) { 137 jpsdef = &jp_structdefs[idx]; 138 139 if (strcmp(jpsdef->jps_type, type) == 0) { 140 *oidx = (int)idx; 141 return (jpsdef); 142 } 143 } 144 145 *oidx = -1; 146 return (NULL); 147 } 148 149 /* 150 * Import a null-terminated parameter list and set a jail with the flags 151 * and parameters. 152 */ 153 int 154 jail_setv(int flags, ...) 155 { 156 va_list ap, tap; 157 struct jailparam *jp, *jp_desc; 158 const char *name; 159 char *value, *desc_value; 160 int njp, jid; 161 162 /* Create the parameter list and import the parameters. */ 163 va_start(ap, flags); 164 va_copy(tap, ap); 165 for (njp = 0; va_arg(tap, char *) != NULL; njp++) 166 (void)va_arg(tap, char *); 167 va_end(tap); 168 jp = alloca(njp * sizeof(struct jailparam)); 169 jp_desc = NULL; 170 desc_value = NULL; 171 for (njp = 0; (name = va_arg(ap, char *)) != NULL; njp++) { 172 value = va_arg(ap, char *); 173 if (jailparam_init(jp + njp, name) < 0) 174 goto error; 175 if (jailparam_import(jp + njp, value) < 0) 176 goto error; 177 if (!strcmp(name, JAIL_PARAM_DESC) && 178 (flags & (JAIL_GET_DESC | JAIL_OWN_DESC))) { 179 jp_desc = jp + njp; 180 desc_value = value; 181 } 182 } 183 va_end(ap); 184 jid = jailparam_set(jp, njp, flags); 185 if (jid > 0 && jp_desc != NULL) 186 sprintf(desc_value, "%d", *(int *)jp_desc->jp_value); 187 jailparam_free(jp, njp); 188 return (jid); 189 190 error: 191 jailparam_free(jp, njp); 192 va_end(ap); 193 return (-1); 194 } 195 196 /* 197 * Read a null-terminated parameter list, get the referenced jail, and export 198 * the parameters to the list. 199 */ 200 int 201 jail_getv(int flags, ...) 202 { 203 va_list ap, tap; 204 struct jailparam *jp, *jp_desc, *jp_lastjid, *jp_jid, *jp_name, *jp_key; 205 char *valarg, *value; 206 const char *name, *key_value, *desc_value, *lastjid_value, *jid_value; 207 const char *name_value; 208 int njp, i, jid; 209 210 /* Create the parameter list and find the key. */ 211 va_start(ap, flags); 212 va_copy(tap, ap); 213 for (njp = 0; va_arg(tap, char *) != NULL; njp++) 214 (void)va_arg(tap, char *); 215 va_end(tap); 216 217 jp = alloca(njp * sizeof(struct jailparam)); 218 va_copy(tap, ap); 219 jp_desc = jp_lastjid = jp_jid = jp_name = NULL; 220 desc_value = lastjid_value = jid_value = name_value = NULL; 221 for (njp = 0; (name = va_arg(tap, char *)) != NULL; njp++) { 222 value = va_arg(tap, char *); 223 if (jailparam_init(jp + njp, name) < 0) { 224 va_end(tap); 225 goto error; 226 } 227 if (!strcmp(jp[njp].jp_name, JAIL_PARAM_DESC) && 228 (flags & (JAIL_USE_DESC | JAIL_AT_DESC))) { 229 jp_desc = jp + njp; 230 desc_value = value; 231 } else if (!strcmp(jp[njp].jp_name, JAIL_PARAM_LASTJID)) { 232 jp_lastjid = jp + njp; 233 lastjid_value = value; 234 } else if (!strcmp(jp[njp].jp_name, JAIL_PARAM_JID)) { 235 jp_jid = jp + njp; 236 jid_value = value; 237 } if (!strcmp(jp[njp].jp_name, JAIL_PARAM_NAME)) { 238 jp_name = jp + njp; 239 name_value = value; 240 } 241 } 242 va_end(tap); 243 /* Import the key parameter. */ 244 if (jp_desc != NULL && (flags & JAIL_USE_DESC)) { 245 jp_key = jp_desc; 246 key_value = desc_value; 247 } else if (jp_lastjid != NULL) { 248 jp_key = jp_lastjid; 249 key_value = lastjid_value; 250 } else if (jp_jid != NULL && strtol(jid_value, NULL, 10) != 0) { 251 jp_key = jp_jid; 252 key_value = jid_value; 253 } else if (jp_name != NULL) { 254 jp_key = jp_name; 255 key_value = name_value; 256 } else { 257 strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN); 258 errno = ENOENT; 259 goto error; 260 } 261 if (jailparam_import(jp_key, key_value) < 0) 262 goto error; 263 if (jp_desc != NULL && jp_desc != jp_key && 264 jailparam_import(jp_desc, desc_value) < 0) 265 goto error; 266 /* Get the jail and export the parameters. */ 267 jid = jailparam_get(jp, njp, flags); 268 if (jid < 0) 269 goto error; 270 for (i = 0; i < njp; i++) { 271 (void)va_arg(ap, char *); 272 valarg = va_arg(ap, char *); 273 if (jp + i != jp_key) { 274 /* It's up to the caller to ensure there's room. */ 275 if ((jp[i].jp_ctltype & CTLTYPE) == CTLTYPE_STRING) 276 strcpy(valarg, jp[i].jp_value); 277 else { 278 value = jailparam_export(jp + i); 279 if (value == NULL) 280 goto error; 281 strcpy(valarg, value); 282 free(value); 283 } 284 } 285 } 286 jailparam_free(jp, njp); 287 va_end(ap); 288 return (jid); 289 290 error: 291 jailparam_free(jp, njp); 292 va_end(ap); 293 return (-1); 294 } 295 296 /* 297 * Return a list of all known parameters. 298 */ 299 int 300 jailparam_all(struct jailparam **jpp) 301 { 302 struct jailparam *jp, *tjp; 303 size_t mlen1, mlen2, buflen; 304 unsigned njp, nlist; 305 int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2]; 306 char buf[MAXPATHLEN]; 307 308 njp = 0; 309 nlist = 32; 310 jp = malloc(nlist * sizeof(*jp)); 311 if (jp == NULL) { 312 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 313 return (-1); 314 } 315 mib1[0] = 0; 316 mib1[1] = 2; 317 mlen1 = CTL_MAXNAME - 2; 318 if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0) { 319 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 320 "sysctlnametomib(" SJPARAM "): %s", strerror(errno)); 321 goto error; 322 } 323 for (;; njp++) { 324 /* Get the next parameter. */ 325 mlen2 = sizeof(mib2); 326 if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0) { 327 if (errno == ENOENT) { 328 /* No more entries. */ 329 break; 330 } 331 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 332 "sysctl(0.2): %s", strerror(errno)); 333 goto error; 334 } 335 if (mib2[0] != mib1[2] || 336 mib2[1] != mib1[3] || 337 mib2[2] != mib1[4]) 338 break; 339 /* Convert it to an ascii name. */ 340 memcpy(mib1 + 2, mib2, mlen2); 341 mlen1 = mlen2 / sizeof(int); 342 mib1[1] = 1; 343 buflen = sizeof(buf); 344 if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0) { 345 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 346 "sysctl(0.1): %s", strerror(errno)); 347 goto error; 348 } 349 if (buf[buflen - 2] == '.') 350 buf[buflen - 2] = '\0'; 351 /* Add the parameter to the list */ 352 if (njp >= nlist) { 353 nlist *= 2; 354 tjp = reallocarray(jp, nlist, sizeof(*jp)); 355 if (tjp == NULL) 356 goto error; 357 jp = tjp; 358 } 359 if (jailparam_init(jp + njp, buf + sizeof(SJPARAM)) < 0) 360 goto error; 361 mib1[1] = 2; 362 } 363 /* Just return the untrimmed buffer if reallocarray() somehow fails. */ 364 tjp = reallocarray(jp, njp, sizeof(*jp)); 365 if (tjp != NULL) 366 jp = tjp; 367 *jpp = jp; 368 return (njp); 369 370 error: 371 jailparam_free(jp, njp); 372 free(jp); 373 return (-1); 374 } 375 376 /* 377 * Clear a jail parameter and copy in its name. 378 */ 379 int 380 jailparam_init(struct jailparam *jp, const char *name) 381 { 382 383 memset(jp, 0, sizeof(*jp)); 384 jp->jp_name = strdup(name); 385 if (jp->jp_name == NULL) { 386 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 387 return (-1); 388 } 389 if (jailparam_type(jp) < 0) { 390 jailparam_free(jp, 1); 391 jp->jp_name = NULL; 392 jp->jp_value = NULL; 393 return (-1); 394 } 395 return (0); 396 } 397 398 /* 399 * Put a name and value into a jail parameter element, converting the value 400 * to internal form. 401 */ 402 int 403 jailparam_import(struct jailparam *jp, const char *value) 404 { 405 char *ep, *tvalue; 406 const char *avalue, *p; 407 const struct jp_structdef *jpsdef; 408 int i, nval, fw; 409 410 if (value == NULL) 411 return (0); 412 if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) { 413 jp->jp_value = strdup(value); 414 if (jp->jp_value == NULL) { 415 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 416 return (-1); 417 } 418 return (0); 419 } 420 nval = 1; 421 if (jp->jp_elemlen) { 422 if (value[0] == '\0' || (value[0] == '-' && value[1] == '\0')) { 423 jp->jp_value = strdup(""); 424 if (jp->jp_value == NULL) { 425 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 426 return (-1); 427 } 428 jp->jp_valuelen = 0; 429 return (0); 430 } 431 for (p = strchr(value, ','); p; p = strchr(p + 1, ',')) 432 nval++; 433 jp->jp_valuelen = jp->jp_elemlen * nval; 434 } 435 jp->jp_value = malloc(jp->jp_valuelen); 436 if (jp->jp_value == NULL) { 437 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 438 return (-1); 439 } 440 avalue = value; 441 for (i = 0; i < nval; i++) { 442 fw = nval == 1 ? strlen(avalue) : strcspn(avalue, ","); 443 switch (jp->jp_ctltype & CTLTYPE) { 444 case CTLTYPE_INT: 445 if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) { 446 if (!jailparam_import_enum(bool_values, 2, 447 avalue, fw, &((int *)jp->jp_value)[i])) { 448 snprintf(jail_errmsg, 449 JAIL_ERRMSGLEN, "%s: " 450 "unknown boolean value \"%.*s\"", 451 jp->jp_name, fw, avalue); 452 errno = EINVAL; 453 goto error; 454 } 455 break; 456 } 457 if (jp->jp_flags & JP_JAILSYS) { 458 /* 459 * Allow setting a jailsys parameter to "new" 460 * in a booleanesque fashion. 461 */ 462 if (value[0] == '\0') 463 ((int *)jp->jp_value)[i] = JAIL_SYS_NEW; 464 else if (!jailparam_import_enum(jailsys_values, 465 sizeof(jailsys_values) / 466 sizeof(jailsys_values[0]), avalue, fw, 467 &((int *)jp->jp_value)[i])) { 468 snprintf(jail_errmsg, 469 JAIL_ERRMSGLEN, "%s: " 470 "unknown jailsys value \"%.*s\"", 471 jp->jp_name, fw, avalue); 472 errno = EINVAL; 473 goto error; 474 } 475 break; 476 } 477 ((int *)jp->jp_value)[i] = strtol(avalue, &ep, 10); 478 integer_test: 479 if (ep != avalue + fw) { 480 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 481 "%s: non-integer value \"%.*s\"", 482 jp->jp_name, fw, avalue); 483 errno = EINVAL; 484 goto error; 485 } 486 break; 487 case CTLTYPE_UINT: 488 ((unsigned *)jp->jp_value)[i] = 489 strtoul(avalue, &ep, 10); 490 goto integer_test; 491 case CTLTYPE_LONG: 492 ((long *)jp->jp_value)[i] = strtol(avalue, &ep, 10); 493 goto integer_test; 494 case CTLTYPE_ULONG: 495 ((unsigned long *)jp->jp_value)[i] = 496 strtoul(avalue, &ep, 10); 497 goto integer_test; 498 case CTLTYPE_S64: 499 ((int64_t *)jp->jp_value)[i] = 500 strtoimax(avalue, &ep, 10); 501 goto integer_test; 502 case CTLTYPE_U64: 503 ((uint64_t *)jp->jp_value)[i] = 504 strtoumax(avalue, &ep, 10); 505 goto integer_test; 506 case CTLTYPE_STRUCT: 507 tvalue = alloca(fw + 1); 508 strlcpy(tvalue, avalue, fw + 1); 509 510 if (jp->jp_structtype == -1) 511 goto unknown_type; 512 513 jpsdef = &jp_structdefs[jp->jp_structtype]; 514 if ((*jpsdef->jps_import)(jp, i, tvalue) != 0) 515 goto error; 516 break; 517 default: 518 unknown_type: 519 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 520 "unknown type for %s", jp->jp_name); 521 errno = ENOENT; 522 goto error; 523 } 524 avalue += fw + 1; 525 } 526 return (0); 527 528 error: 529 free(jp->jp_value); 530 jp->jp_value = NULL; 531 return (-1); 532 } 533 534 static int 535 jailparam_import_enum(const char **values, int nvalues, const char *valstr, 536 size_t valsize, int *value) 537 { 538 char *ep; 539 int i; 540 541 for (i = 0; i < nvalues; i++) 542 if (valsize == strlen(values[i]) && 543 !strncasecmp(valstr, values[i], valsize)) { 544 *value = i; 545 return 1; 546 } 547 *value = strtol(valstr, &ep, 10); 548 return (ep == valstr + valsize); 549 } 550 551 /* 552 * Put a name and value into a jail parameter element, copying the value 553 * but not altering it. 554 */ 555 int 556 jailparam_import_raw(struct jailparam *jp, void *value, size_t valuelen) 557 { 558 559 jp->jp_value = value; 560 jp->jp_valuelen = valuelen; 561 jp->jp_flags |= JP_RAWVALUE; 562 return (0); 563 } 564 565 /* 566 * Run the jail_set and jail_get system calls on a parameter list. 567 */ 568 int 569 jailparam_set(struct jailparam *jp, unsigned njp, int flags) 570 { 571 struct iovec *jiov; 572 char *nname; 573 int i, jid, bool0; 574 unsigned j; 575 576 jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1)); 577 bool0 = 0; 578 for (i = j = 0; j < njp; j++) { 579 jiov[i].iov_base = jp[j].jp_name; 580 jiov[i].iov_len = strlen(jp[j].jp_name) + 1; 581 i++; 582 if (jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) { 583 /* 584 * Set booleans without values. If one has a value of 585 * zero, change it to (or from) its "no" counterpart. 586 */ 587 jiov[i].iov_base = NULL; 588 jiov[i].iov_len = 0; 589 if (jp[j].jp_value != NULL && 590 jp[j].jp_valuelen == sizeof(int) && 591 !*(int *)jp[j].jp_value) { 592 bool0 = 1; 593 nname = jp[j].jp_flags & JP_BOOL 594 ? noname(jp[j].jp_name) 595 : nononame(jp[j].jp_name); 596 if (nname == NULL) { 597 njp = j; 598 jid = -1; 599 goto done; 600 } 601 jiov[i - 1].iov_base = nname; 602 jiov[i - 1].iov_len = strlen(nname) + 1; 603 604 } 605 } else if (jp[j].jp_flags & JP_KEYVALUE && 606 jp[j].jp_value == NULL) { 607 /* No value means key removal. */ 608 jiov[i].iov_base = NULL; 609 jiov[i].iov_len = 0; 610 } else if (jps_set(&jp[j], &jiov[i]) != 0) { 611 /* 612 * Try to fill in missing values with an empty string. 613 */ 614 if (jp[j].jp_value == NULL && jp[j].jp_valuelen > 0 && 615 jailparam_import(jp + j, "") < 0) { 616 njp = j; 617 jid = -1; 618 goto done; 619 } 620 jiov[i].iov_base = jp[j].jp_value; 621 jiov[i].iov_len = 622 (jp[j].jp_ctltype & CTLTYPE) == CTLTYPE_STRING 623 ? strlen(jp[j].jp_value) + 1 624 : jp[j].jp_valuelen; 625 } 626 i++; 627 } 628 jiov[i].iov_base = __DECONST(char *, JAIL_PARAM_ERRMSG); 629 jiov[i].iov_len = sizeof(JAIL_PARAM_ERRMSG); 630 i++; 631 jiov[i].iov_base = jail_errmsg; 632 jiov[i].iov_len = JAIL_ERRMSGLEN; 633 i++; 634 jail_errmsg[0] = 0; 635 jid = jail_set(jiov, i, flags); 636 if (jid < 0 && !jail_errmsg[0]) 637 snprintf(jail_errmsg, sizeof(jail_errmsg), "jail_set: %s", 638 strerror(errno)); 639 done: 640 if (bool0) 641 for (j = 0; j < njp; j++) 642 if ((jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) && 643 jp[j].jp_value != NULL && 644 jp[j].jp_valuelen == sizeof(int) && 645 !*(int *)jp[j].jp_value) 646 free(jiov[j * 2].iov_base); 647 return (jid); 648 } 649 650 int 651 jailparam_get(struct jailparam *jp, unsigned njp, int flags) 652 { 653 struct iovec *jiov; 654 struct jailparam *jp_desc, *jp_lastjid, *jp_jid, *jp_name, *jp_key; 655 int i, ai, ki, jid, arrays, processed, sanity; 656 unsigned j; 657 658 /* 659 * Get the types for all parameters. 660 * Find the key and any array parameters. 661 */ 662 jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1)); 663 jp_desc = jp_lastjid = jp_jid = jp_name = NULL; 664 arrays = 0; 665 for (ai = j = 0; j < njp; j++) { 666 if (!strcmp(jp[j].jp_name, JAIL_PARAM_DESC) && 667 (flags & (JAIL_USE_DESC | JAIL_AT_DESC))) 668 jp_desc = jp + j; 669 else if (!strcmp(jp[j].jp_name, JAIL_PARAM_LASTJID)) 670 jp_lastjid = jp + j; 671 else if (!strcmp(jp[j].jp_name, JAIL_PARAM_JID)) 672 jp_jid = jp + j; 673 else if (!strcmp(jp[j].jp_name, JAIL_PARAM_NAME)) 674 jp_name = jp + j; 675 else if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 676 arrays = 1; 677 jiov[ai].iov_base = jp[j].jp_name; 678 jiov[ai].iov_len = strlen(jp[j].jp_name) + 1; 679 ai++; 680 jiov[ai].iov_base = NULL; 681 jiov[ai].iov_len = 0; 682 ai++; 683 } 684 } 685 jp_key = jp_desc && jp_desc->jp_valuelen == sizeof(int) && 686 jp_desc->jp_value && (flags & JAIL_USE_DESC) ? jp_desc : 687 jp_lastjid ? jp_lastjid : 688 jp_jid && jp_jid->jp_valuelen == sizeof(int) && 689 jp_jid->jp_value && *(int *)jp_jid->jp_value ? jp_jid : jp_name; 690 if (jp_key == NULL || jp_key->jp_value == NULL) { 691 strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN); 692 errno = ENOENT; 693 return (-1); 694 } 695 ki = ai; 696 jiov[ki].iov_base = jp_key->jp_name; 697 jiov[ki].iov_len = strlen(jp_key->jp_name) + 1; 698 ki++; 699 jiov[ki].iov_base = jp_key->jp_value; 700 jiov[ki].iov_len = (jp_key->jp_ctltype & CTLTYPE) == CTLTYPE_STRING 701 ? strlen(jp_key->jp_value) + 1 : jp_key->jp_valuelen; 702 ki++; 703 jiov[ki].iov_base = __DECONST(char *, JAIL_PARAM_ERRMSG); 704 jiov[ki].iov_len = sizeof(JAIL_PARAM_ERRMSG); 705 ki++; 706 jiov[ki].iov_base = jail_errmsg; 707 jiov[ki].iov_len = JAIL_ERRMSGLEN; 708 ki++; 709 jail_errmsg[0] = 0; 710 if (jp_desc != NULL && jp_desc != jp_key) { 711 jiov[ki].iov_base = jp_desc->jp_name; 712 jiov[ki].iov_len = strlen(jp_desc->jp_name) + 1; 713 ki++; 714 jiov[ki].iov_base = jp_desc->jp_value; 715 jiov[ki].iov_len = jp_desc->jp_valuelen; 716 ki++; 717 } 718 if (arrays && jail_get(jiov, ki, flags) < 0) { 719 if (!jail_errmsg[0]) 720 snprintf(jail_errmsg, sizeof(jail_errmsg), 721 "jail_get: %s", strerror(errno)); 722 return (-1); 723 } 724 /* Allocate storage for all parameters. */ 725 for (ai = j = 0, i = ki; j < njp; j++) { 726 if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 727 ai++; 728 jiov[ai].iov_len += jp[j].jp_elemlen * ARRAY_SLOP; 729 if (jp[j].jp_valuelen >= jiov[ai].iov_len) 730 jiov[ai].iov_len = jp[j].jp_valuelen; 731 else { 732 jp[j].jp_valuelen = jiov[ai].iov_len; 733 if (jp[j].jp_value != NULL) 734 free(jp[j].jp_value); 735 jp[j].jp_value = malloc(jp[j].jp_valuelen); 736 if (jp[j].jp_value == NULL) { 737 strerror_r(errno, jail_errmsg, 738 JAIL_ERRMSGLEN); 739 return (-1); 740 } 741 } 742 jiov[ai].iov_base = jp[j].jp_value; 743 memset(jiov[ai].iov_base, 0, jiov[ai].iov_len); 744 ai++; 745 } else if (jp + j != jp_key && jp + j != jp_desc) { 746 jiov[i].iov_base = jp[j].jp_name; 747 jiov[i].iov_len = strlen(jp[j].jp_name) + 1; 748 i++; 749 750 /* 751 * We give structured types' jps_get() implementations 752 * a chance to initialize the value. We'll guarantee 753 * that the initial value is zeroed out, but they should 754 * assume on every call that the value may be populated 755 * by a subsequent jailparam_get(). 756 */ 757 if (!(jp[j].jp_flags & JP_RAWVALUE)) { 758 if (jp[j].jp_value == NULL) { 759 jp[j].jp_value = calloc(1, 760 jp[j].jp_valuelen); 761 if (jp[j].jp_value == NULL) { 762 strerror_r(errno, jail_errmsg, 763 JAIL_ERRMSGLEN); 764 return (-1); 765 } 766 } 767 768 /* 769 * Returns -1 on error, or # index populated on 770 * success. 0 is perfectly valid for a type 771 * that may want to simply initialize the value 772 * as needed. 773 */ 774 processed = jps_get(&jp[j], &jiov[i]); 775 if (processed == -1) { 776 return (-1); 777 } else if (processed > 0) { 778 /* 779 * The above math for jiov sizing does 780 * not really account for one param 781 * expanding to multiple entries. 782 */ 783 assert(processed == 1); 784 i += processed; 785 continue; 786 } 787 } 788 jiov[i].iov_base = jp[j].jp_value; 789 jiov[i].iov_len = jp[j].jp_valuelen; 790 memset(jiov[i].iov_base, 0, jiov[i].iov_len); 791 i++; 792 } 793 } 794 /* 795 * Get the prison. If there are array elements, retry a few times 796 * in case their sizes changed from under us. 797 */ 798 for (sanity = 0;; sanity++) { 799 jid = jail_get(jiov, i, flags); 800 if (jid >= 0 || !arrays || sanity == ARRAY_SANITY || 801 errno != EINVAL || jail_errmsg[0]) 802 break; 803 for (ai = j = 0; j < njp; j++) { 804 if (jp[j].jp_elemlen && 805 !(jp[j].jp_flags & JP_RAWVALUE)) { 806 ai++; 807 jiov[ai].iov_base = NULL; 808 jiov[ai].iov_len = 0; 809 ai++; 810 } 811 } 812 if (jail_get(jiov, ki, flags) < 0) 813 break; 814 for (ai = j = 0; j < njp; j++) { 815 if (jp[j].jp_elemlen && 816 !(jp[j].jp_flags & JP_RAWVALUE)) { 817 ai++; 818 jiov[ai].iov_len += 819 jp[j].jp_elemlen * ARRAY_SLOP; 820 if (jp[j].jp_valuelen >= jiov[ai].iov_len) 821 jiov[ai].iov_len = jp[j].jp_valuelen; 822 else { 823 jp[j].jp_valuelen = jiov[ai].iov_len; 824 if (jp[j].jp_value != NULL) 825 free(jp[j].jp_value); 826 jp[j].jp_value = 827 malloc(jiov[ai].iov_len); 828 if (jp[j].jp_value == NULL) { 829 strerror_r(errno, jail_errmsg, 830 JAIL_ERRMSGLEN); 831 return (-1); 832 } 833 } 834 jiov[ai].iov_base = jp[j].jp_value; 835 memset(jiov[ai].iov_base, 0, jiov[ai].iov_len); 836 ai++; 837 } 838 } 839 } 840 if (jid < 0 && !jail_errmsg[0]) 841 snprintf(jail_errmsg, sizeof(jail_errmsg), 842 "jail_get: %s", strerror(errno)); 843 for (ai = j = 0, i = ki; j < njp; j++) { 844 if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 845 ai++; 846 jp[j].jp_valuelen = jiov[ai].iov_len; 847 ai++; 848 } else if (jp + j != jp_key) { 849 i++; 850 jp[j].jp_valuelen = jiov[i].iov_len; 851 i++; 852 } 853 } 854 return (jid); 855 } 856 857 /* 858 * Convert a jail parameter's value to external form. 859 */ 860 char * 861 jailparam_export(struct jailparam *jp) 862 { 863 size_t *valuelens; 864 char *value, *tvalue, **values; 865 const struct jp_structdef *jpsdef; 866 size_t valuelen; 867 int i, nval, ival; 868 char valbuf[INET6_ADDRSTRLEN]; 869 870 if (jp->jp_value == NULL) { 871 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 872 "parameter %s was not imported", jp->jp_name); 873 errno = EINVAL; 874 return (NULL); 875 } 876 if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) { 877 value = strdup(jp->jp_value); 878 if (value == NULL) 879 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 880 return (value); 881 } 882 nval = jp->jp_elemlen ? jp->jp_valuelen / jp->jp_elemlen : 1; 883 if (nval == 0) { 884 value = strdup(""); 885 if (value == NULL) 886 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 887 return (value); 888 } 889 values = alloca(nval * sizeof(char *)); 890 valuelens = alloca(nval * sizeof(size_t)); 891 valuelen = 0; 892 for (i = 0; i < nval; i++) { 893 switch (jp->jp_ctltype & CTLTYPE) { 894 case CTLTYPE_INT: 895 ival = ((int *)jp->jp_value)[i]; 896 if ((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) && 897 (unsigned)ival < 2) { 898 strlcpy(valbuf, bool_values[ival], 899 sizeof(valbuf)); 900 break; 901 } 902 if ((jp->jp_flags & JP_JAILSYS) && 903 (unsigned)ival < sizeof(jailsys_values) / 904 sizeof(jailsys_values[0])) { 905 strlcpy(valbuf, jailsys_values[ival], 906 sizeof(valbuf)); 907 break; 908 } 909 snprintf(valbuf, sizeof(valbuf), "%d", ival); 910 break; 911 case CTLTYPE_UINT: 912 snprintf(valbuf, sizeof(valbuf), "%u", 913 ((unsigned *)jp->jp_value)[i]); 914 break; 915 case CTLTYPE_LONG: 916 snprintf(valbuf, sizeof(valbuf), "%ld", 917 ((long *)jp->jp_value)[i]); 918 break; 919 case CTLTYPE_ULONG: 920 snprintf(valbuf, sizeof(valbuf), "%lu", 921 ((unsigned long *)jp->jp_value)[i]); 922 break; 923 case CTLTYPE_S64: 924 snprintf(valbuf, sizeof(valbuf), "%jd", 925 (intmax_t)((int64_t *)jp->jp_value)[i]); 926 break; 927 case CTLTYPE_U64: 928 snprintf(valbuf, sizeof(valbuf), "%ju", 929 (uintmax_t)((uint64_t *)jp->jp_value)[i]); 930 break; 931 case CTLTYPE_STRUCT: 932 if (jp->jp_structtype == -1) 933 goto unknown_type; 934 935 jpsdef = &jp_structdefs[jp->jp_structtype]; 936 value = (*jpsdef->jps_export)(jp, i); 937 if (value == NULL) { 938 strerror_r(errno, jail_errmsg, 939 JAIL_ERRMSGLEN); 940 return (NULL); 941 } 942 943 valuelens[i] = strlen(value) + 1; 944 valuelen += valuelens[i]; 945 values[i] = alloca(valuelens[i]); 946 strcpy(values[i], value); 947 948 free(value); 949 value = NULL; 950 continue; /* Value already added to values[] */ 951 default: 952 unknown_type: 953 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 954 "unknown type for %s", jp->jp_name); 955 errno = ENOENT; 956 return (NULL); 957 } 958 valuelens[i] = strlen(valbuf) + 1; 959 valuelen += valuelens[i]; 960 values[i] = alloca(valuelens[i]); 961 strcpy(values[i], valbuf); 962 } 963 value = malloc(valuelen); 964 if (value == NULL) 965 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 966 else { 967 tvalue = value; 968 for (i = 0; i < nval; i++) { 969 strcpy(tvalue, values[i]); 970 if (i < nval - 1) { 971 tvalue += valuelens[i]; 972 tvalue[-1] = ','; 973 } 974 } 975 } 976 return (value); 977 } 978 979 /* 980 * Free the contents of a jail parameter list (but not the list itself). 981 */ 982 void 983 jailparam_free(struct jailparam *jp, unsigned njp) 984 { 985 986 unsigned j; 987 988 for (j = 0; j < njp; j++) { 989 free(jp[j].jp_name); 990 if (!(jp[j].jp_flags & JP_RAWVALUE)) { 991 jps_free(&jp[j]); 992 free(jp[j].jp_value); 993 } 994 } 995 } 996 997 /* 998 * Find a parameter's type and size from its MIB. 999 */ 1000 static int 1001 jailparam_type(struct jailparam *jp) 1002 { 1003 char *p, *name, *nname; 1004 size_t miblen, desclen; 1005 int i, isarray; 1006 struct { 1007 int i; 1008 char s[MAXPATHLEN]; 1009 } desc; 1010 int mib[CTL_MAXNAME]; 1011 1012 /* 1013 * Some pseudo-parameters don't show up in the sysctl 1014 * parameter list. 1015 */ 1016 name = jp->jp_name; 1017 if (!strcmp(name, JAIL_PARAM_LASTJID)) { 1018 jp->jp_valuelen = sizeof(int); 1019 jp->jp_ctltype = CTLTYPE_INT | CTLFLAG_WR; 1020 return (0); 1021 } 1022 if (!strcmp(name, JAIL_PARAM_DESC)) { 1023 jp->jp_valuelen = sizeof(int); 1024 jp->jp_ctltype = CTLTYPE_INT | CTLFLAG_RW; 1025 return (0); 1026 } 1027 1028 /* Find the sysctl that describes the parameter. */ 1029 mib[0] = 0; 1030 mib[1] = 3; 1031 snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", name); 1032 miblen = sizeof(mib) - 2 * sizeof(int); 1033 if (sysctl(mib, 2, mib + 2, &miblen, desc.s, strlen(desc.s)) < 0) { 1034 if (errno != ENOENT) { 1035 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1036 "sysctl(0.3.%s): %s", name, strerror(errno)); 1037 return (-1); 1038 } 1039 if (kldload_param(name) >= 0 && sysctl(mib, 2, mib + 2, &miblen, 1040 desc.s, strlen(desc.s)) >= 0) 1041 goto mib_desc; 1042 /* 1043 * The parameter probably doesn't exist. But it might be 1044 * the "no" counterpart to a boolean. 1045 */ 1046 nname = nononame(name); 1047 if (nname != NULL) { 1048 snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname); 1049 miblen = sizeof(mib) - 2 * sizeof(int); 1050 if (sysctl(mib, 2, mib + 2, &miblen, desc.s, 1051 strlen(desc.s)) >= 0) { 1052 name = alloca(strlen(nname) + 1); 1053 strcpy(name, nname); 1054 free(nname); 1055 jp->jp_flags |= JP_NOBOOL; 1056 goto mib_desc; 1057 } 1058 free(nname); 1059 } 1060 /* 1061 * It might be an assumed sub-node of a fmt='A,keyvalue' sysctl. 1062 */ 1063 nname = kvname(name); 1064 if (nname != NULL) { 1065 snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname); 1066 miblen = sizeof(mib) - 2 * sizeof(int); 1067 if (sysctl(mib, 2, mib + 2, &miblen, desc.s, 1068 strlen(desc.s)) >= 0) { 1069 name = alloca(strlen(nname) + 1); 1070 strcpy(name, nname); 1071 free(nname); 1072 jp->jp_flags |= JP_KEYVALUE; 1073 goto mib_desc; 1074 } 1075 free(nname); 1076 } 1077 unknown_parameter: 1078 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1079 "unknown parameter: %s", jp->jp_name); 1080 errno = ENOENT; 1081 return (-1); 1082 } 1083 mib_desc: 1084 mib[1] = 4; 1085 desclen = sizeof(desc); 1086 if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen, 1087 NULL, 0) < 0) { 1088 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1089 "sysctl(0.4.%s): %s", name, strerror(errno)); 1090 return (-1); 1091 } 1092 jp->jp_ctltype = desc.i; 1093 /* If this came from removing a "no", it better be a boolean. */ 1094 if (jp->jp_flags & JP_NOBOOL) { 1095 if ((desc.i & CTLTYPE) == CTLTYPE_INT && desc.s[0] == 'B') { 1096 jp->jp_valuelen = sizeof(int); 1097 return (0); 1098 } 1099 else if ((desc.i & CTLTYPE) != CTLTYPE_NODE) 1100 goto unknown_parameter; 1101 } 1102 /* Make sure it is a valid keyvalue param. */ 1103 if (jp->jp_flags & JP_KEYVALUE) { 1104 if ((desc.i & CTLTYPE) != CTLTYPE_STRING || 1105 strcmp(desc.s, "A,keyvalue") != 0) 1106 goto unknown_parameter; 1107 } 1108 /* See if this is an array type. */ 1109 p = strchr(desc.s, '\0'); 1110 isarray = 0; 1111 if (p - 2 < desc.s || strcmp(p - 2, ",a")) 1112 isarray = 0; 1113 else { 1114 isarray = 1; 1115 p[-2] = 0; 1116 } 1117 /* Look for types we understand. */ 1118 switch (desc.i & CTLTYPE) { 1119 case CTLTYPE_INT: 1120 if (desc.s[0] == 'B') 1121 jp->jp_flags |= JP_BOOL; 1122 else if (!strcmp(desc.s, "E,jailsys")) 1123 jp->jp_flags |= JP_JAILSYS; 1124 case CTLTYPE_UINT: 1125 jp->jp_valuelen = sizeof(int); 1126 break; 1127 case CTLTYPE_LONG: 1128 case CTLTYPE_ULONG: 1129 jp->jp_valuelen = sizeof(long); 1130 break; 1131 case CTLTYPE_S64: 1132 case CTLTYPE_U64: 1133 jp->jp_valuelen = sizeof(int64_t); 1134 break; 1135 case CTLTYPE_STRING: 1136 desc.s[0] = 0; 1137 desclen = sizeof(desc.s); 1138 if (sysctl(mib + 2, miblen / sizeof(int), desc.s, &desclen, 1139 NULL, 0) < 0) { 1140 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1141 "sysctl(" SJPARAM ".%s): %s", name, 1142 strerror(errno)); 1143 return (-1); 1144 } 1145 jp->jp_valuelen = strtoul(desc.s, NULL, 10); 1146 break; 1147 case CTLTYPE_STRUCT: { 1148 const struct jp_structdef *jpsdef; 1149 1150 jpsdef = jp_structinfo(desc.s, &jp->jp_structtype); 1151 if (jpsdef != NULL) { 1152 assert(jp->jp_structtype >= 0); 1153 1154 jp->jp_valuelen = jpsdef->jps_valuelen; 1155 } else { 1156 assert(jp->jp_structtype == -1); 1157 1158 desclen = 0; 1159 if (sysctl(mib + 2, miblen / sizeof(int), 1160 NULL, &jp->jp_valuelen, NULL, 0) < 0) { 1161 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1162 "sysctl(" SJPARAM ".%s): %s", name, 1163 strerror(errno)); 1164 return (-1); 1165 } 1166 } 1167 break; 1168 } 1169 case CTLTYPE_NODE: 1170 /* 1171 * A node might be described by an empty-named child, 1172 * which would be immediately before or after the node itself. 1173 */ 1174 mib[1] = 1; 1175 miblen += sizeof(int); 1176 for (i = -1; i <= 1; i += 2) { 1177 mib[(miblen / sizeof(int)) + 1] = 1178 mib[(miblen / sizeof(int))] + i; 1179 desclen = sizeof(desc.s); 1180 if (sysctl(mib, (miblen / sizeof(int)) + 2, desc.s, 1181 &desclen, NULL, 0) < 0) { 1182 if (errno == ENOENT) 1183 continue; 1184 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1185 "sysctl(0.1): %s", strerror(errno)); 1186 return (-1); 1187 } 1188 if (desclen == sizeof(SJPARAM) + strlen(name) + 2 && 1189 memcmp(SJPARAM ".", desc.s, sizeof(SJPARAM)) == 0 && 1190 memcmp(name, desc.s + sizeof(SJPARAM), 1191 desclen - sizeof(SJPARAM) - 2) == 0 && 1192 desc.s[desclen - 2] == '.') 1193 goto mib_desc; 1194 } 1195 goto unknown_parameter; 1196 default: 1197 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1198 "unknown type for %s", jp->jp_name); 1199 errno = ENOENT; 1200 return (-1); 1201 } 1202 if (isarray) { 1203 jp->jp_elemlen = jp->jp_valuelen; 1204 jp->jp_valuelen = 0; 1205 } 1206 return (0); 1207 } 1208 1209 /* 1210 * Attempt to load a kernel module matching an otherwise nonexistent parameter. 1211 */ 1212 static int 1213 kldload_param(const char *name) 1214 { 1215 int kl; 1216 1217 if (strcmp(name, "linux") == 0 || strncmp(name, "linux.", 6) == 0) 1218 kl = kldload("linux"); 1219 else if (strcmp(name, "sysvmsg") == 0 || strcmp(name, "sysvsem") == 0 || 1220 strcmp(name, "sysvshm") == 0) 1221 kl = kldload(name); 1222 else if (strncmp(name, "allow.mount.", 12) == 0) { 1223 /* Load the matching filesystem */ 1224 const char *modname = name + 12; 1225 1226 kl = kldload(modname); 1227 if (kl < 0 && errno == ENOENT && 1228 strncmp(modname, "no", 2) == 0) 1229 kl = kldload(modname + 2); 1230 } else { 1231 errno = ENOENT; 1232 return (-1); 1233 } 1234 if (kl < 0 && errno == EEXIST) { 1235 /* 1236 * In the module is already loaded, then it must not contain 1237 * the parameter. 1238 */ 1239 errno = ENOENT; 1240 } 1241 return kl; 1242 } 1243 1244 /* 1245 * Change a boolean parameter name into its "no" counterpart or vice versa. 1246 */ 1247 static char * 1248 noname(const char *name) 1249 { 1250 char *nname; 1251 const char *p; 1252 1253 nname = malloc(strlen(name) + 3); 1254 if (nname == NULL) { 1255 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 1256 return (NULL); 1257 } 1258 p = strrchr(name, '.'); 1259 if (p != NULL) 1260 sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1); 1261 else 1262 sprintf(nname, "no%s", name); 1263 return (nname); 1264 } 1265 1266 static char * 1267 nononame(const char *name) 1268 { 1269 char *nname; 1270 const char *p; 1271 1272 p = strrchr(name, '.'); 1273 if (strncmp(p ? p + 1 : name, "no", 2)) { 1274 snprintf(jail_errmsg, sizeof(jail_errmsg), 1275 "mismatched boolean: %s", name); 1276 errno = EINVAL; 1277 return (NULL); 1278 } 1279 nname = malloc(strlen(name) - 1); 1280 if (nname == NULL) { 1281 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 1282 return (NULL); 1283 } 1284 if (p != NULL) 1285 sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3); 1286 else 1287 strcpy(nname, name + 2); 1288 return (nname); 1289 } 1290 1291 static char * 1292 kvname(const char *name) 1293 { 1294 const char *p; 1295 char *kvname; 1296 size_t len; 1297 1298 p = strchr(name, '.'); 1299 if (p == NULL) 1300 return (NULL); 1301 1302 len = p - name; 1303 kvname = malloc(len + 1); 1304 if (kvname == NULL) { 1305 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 1306 return (NULL); 1307 } 1308 strncpy(kvname, name, len); 1309 kvname[len] = '\0'; 1310 1311 return (kvname); 1312 } 1313 1314 static int 1315 jps_get(struct jailparam *jp, struct iovec *jiov) 1316 { 1317 const struct jp_structdef *jpsdef; 1318 1319 jpsdef = JPSDEF_OF(jp); 1320 if (jpsdef == NULL || jpsdef->jps_get == NULL) 1321 return (0); /* Nop, but not an error. */ 1322 1323 return ((jpsdef->jps_get)(jp, jiov)); 1324 } 1325 1326 static int 1327 jps_set(const struct jailparam *jp, struct iovec *jiov) 1328 { 1329 const struct jp_structdef *jpsdef; 1330 1331 jpsdef = JPSDEF_OF(jp); 1332 if (jpsdef == NULL || jpsdef->jps_set == NULL) 1333 return (EINVAL); /* Unhandled */ 1334 1335 return ((jpsdef->jps_set)(jp, jiov)); 1336 } 1337 1338 static void 1339 jps_free(struct jailparam *jp) 1340 { 1341 const struct jp_structdef *jpsdef; 1342 1343 jpsdef = JPSDEF_OF(jp); 1344 if (jpsdef == NULL) 1345 return; 1346 1347 if (jpsdef->jps_free != NULL) 1348 jpsdef->jps_free(jp); 1349 } 1350 1351 static int 1352 jps_import_in_addr(const struct jailparam *jp, int i, const char *value) 1353 { 1354 struct in_addr *addr; 1355 1356 addr = &((struct in_addr *)jp->jp_value)[i]; 1357 if (inet_pton(AF_INET, value, addr) != 1) { 1358 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1359 "%s: not an IPv4 address: %s", jp->jp_name, value); 1360 errno = EINVAL; 1361 return (-1); 1362 } 1363 1364 return (0); 1365 } 1366 1367 static int 1368 jps_import_in6_addr(const struct jailparam *jp, int i, const char *value) 1369 { 1370 struct in6_addr *addr6; 1371 1372 addr6 = &((struct in6_addr *)jp->jp_value)[i]; 1373 if (inet_pton(AF_INET6, value, addr6) != 1) { 1374 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1375 "%s: not an IPv6 address: %s", jp->jp_name, value); 1376 errno = EINVAL; 1377 return (-1); 1378 } 1379 1380 return (0); 1381 } 1382 1383 static int 1384 jps_import_mac_label(const struct jailparam *jp, int i, const char *value) 1385 { 1386 mac_t *pmac; 1387 1388 pmac = &((mac_t *)jp->jp_value)[i]; 1389 if (mac_from_text(pmac, value) != 0) { 1390 int serrno = errno; 1391 1392 snprintf(jail_errmsg, JAIL_ERRMSGLEN, "%s: mac_from_text: %s", 1393 jp->jp_name, strerror(errno)); 1394 errno = serrno; 1395 return (-1); 1396 } 1397 1398 return (0); 1399 } 1400 1401 static char * 1402 jps_export_in_addr(const struct jailparam *jp, int i) 1403 { 1404 struct in_addr *addr; 1405 char valbuf[INET_ADDRSTRLEN]; 1406 1407 addr = &((struct in_addr *)jp->jp_value)[i]; 1408 if (inet_ntop(AF_INET, addr, valbuf, sizeof(valbuf)) == NULL) 1409 return (NULL); 1410 1411 /* Error checked by caller. */ 1412 return (strdup(valbuf)); 1413 } 1414 1415 static char * 1416 jps_export_in6_addr(const struct jailparam *jp, int i) 1417 { 1418 struct in6_addr *addr6; 1419 char valbuf[INET6_ADDRSTRLEN]; 1420 1421 addr6 = &((struct in6_addr *)jp->jp_value)[i]; 1422 if (inet_ntop(AF_INET6, addr6, valbuf, sizeof(valbuf)) == NULL) 1423 return (NULL); 1424 1425 /* Error checked by caller. */ 1426 return (strdup(valbuf)); 1427 } 1428 1429 static char * 1430 jps_export_mac_label(const struct jailparam *jp, int i) 1431 { 1432 mac_t *macp; 1433 char *labelbuf; 1434 int error; 1435 1436 macp = &((mac_t *)jp->jp_value)[i]; 1437 error = mac_to_text(*macp, &labelbuf); 1438 if (error != 0) 1439 return (NULL); 1440 1441 return (labelbuf); 1442 } 1443 1444 static int 1445 jps_get_mac_label(struct jailparam *jp, struct iovec *jiov) 1446 { 1447 mac_t *pmac = jp->jp_value; 1448 int error; 1449 1450 /* 1451 * Our value is only allocated once and may be reused for many 1452 * jailparam_get() calls; avoid leaking. 1453 */ 1454 if (*pmac != NULL) { 1455 mac_free(*pmac); 1456 *pmac = NULL; 1457 } 1458 1459 error = mac_prepare_type(pmac, "jail"); 1460 if (error != 0 && errno == ENOENT) { 1461 /* 1462 * We special-case the scenario where a system has a custom 1463 * mac.conf(5) that doesn't include a jail entry -- just let 1464 * an empty label slide. 1465 */ 1466 error = mac_prepare(pmac, "?"); 1467 } 1468 if (error != 0) { 1469 int serrno = errno; 1470 1471 free(jp->jp_value); 1472 jp->jp_value = NULL; 1473 1474 strerror_r(serrno, jail_errmsg, JAIL_ERRMSGLEN); 1475 errno = serrno; 1476 return (-1); 1477 } 1478 1479 /* 1480 * MAC label gets special handling because libjail internally maintains 1481 * it as a pointer to a mac_t, but we actually want to pass the mac_t 1482 * itself. We don't want the jailparam_get() zeroing behavior, as it's 1483 * initialized by us. 1484 */ 1485 jiov->iov_base = *pmac; 1486 jiov->iov_len = sizeof(**pmac); 1487 return (1); 1488 } 1489 1490 static int 1491 jps_set_mac_label(const struct jailparam *jp, struct iovec *jiov) 1492 { 1493 mac_t *pmac; 1494 1495 /* 1496 * MAC label gets special handling because libjail internally 1497 * maintains it as a pointer to a mac_t, but we actually want to 1498 * pass the mac_t itself. 1499 */ 1500 pmac = jp->jp_value; 1501 if (pmac != NULL) { 1502 jiov->iov_base = *pmac; 1503 jiov->iov_len = sizeof(**pmac); 1504 } else { 1505 jiov->iov_base = NULL; 1506 jiov->iov_len = 0; 1507 } 1508 1509 return (0); 1510 } 1511 1512 static void 1513 jps_free_mac_label(struct jailparam *jp) 1514 { 1515 mac_t *pmac = jp->jp_value; 1516 1517 if (pmac != NULL) 1518 mac_free(*pmac); 1519 } 1520