kern_environment.c revision 221597
1229997Sken/*- 2229997Sken * Copyright (c) 1998 Michael Smith 3229997Sken * All rights reserved. 4229997Sken * 5229997Sken * Redistribution and use in source and binary forms, with or without 6229997Sken * modification, are permitted provided that the following conditions 7229997Sken * are met: 8229997Sken * 1. Redistributions of source code must retain the above copyright 9229997Sken * notice, this list of conditions and the following disclaimer. 10229997Sken * 2. Redistributions in binary form must reproduce the above copyright 11229997Sken * notice, this list of conditions and the following disclaimer in the 12229997Sken * documentation and/or other materials provided with the distribution. 13229997Sken * 14229997Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15229997Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16229997Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17229997Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18229997Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22229997Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23229997Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24229997Sken * SUCH DAMAGE. 25229997Sken */ 26229997Sken 27229997Sken/* 28229997Sken * The unified bootloader passes us a pointer to a preserved copy of 29229997Sken * bootstrap/kernel environment variables. We convert them to a 30229997Sken * dynamic array of strings later when the VM subsystem is up. 31229997Sken * 32229997Sken * We make these available through the kenv(2) syscall for userland 33229997Sken * and through getenv()/freeenv() setenv() unsetenv() testenv() for 34229997Sken * the kernel. 35229997Sken */ 36229997Sken 37229997Sken#include <sys/cdefs.h> 38229997Sken__FBSDID("$FreeBSD: head/sys/kern/kern_environment.c 221597 2011-05-07 11:10:58Z jh $"); 39229997Sken 40229997Sken#include <sys/types.h> 41229997Sken#include <sys/param.h> 42229997Sken#include <sys/proc.h> 43229997Sken#include <sys/queue.h> 44229997Sken#include <sys/lock.h> 45229997Sken#include <sys/malloc.h> 46229997Sken#include <sys/mutex.h> 47229997Sken#include <sys/priv.h> 48229997Sken#include <sys/kernel.h> 49229997Sken#include <sys/systm.h> 50229997Sken#include <sys/sysent.h> 51229997Sken#include <sys/sysproto.h> 52229997Sken#include <sys/libkern.h> 53229997Sken#include <sys/kenv.h> 54229997Sken 55229997Sken#include <security/mac/mac_framework.h> 56229997Sken 57229997Skenstatic MALLOC_DEFINE(M_KENV, "kenv", "kernel environment"); 58229997Sken 59229997Sken#define KENV_SIZE 512 /* Maximum number of environment strings */ 60229997Sken 61229997Sken/* pointer to the static environment */ 62229997Skenchar *kern_envp; 63229997Skenstatic int env_len; 64229997Skenstatic int env_pos; 65229997Skenstatic char *kernenv_next(char *); 66229997Sken 67229997Sken/* dynamic environment variables */ 68229997Skenchar **kenvp; 69229997Skenstruct mtx kenv_lock; 70229997Sken 71229997Sken/* 72229997Sken * No need to protect this with a mutex since SYSINITS are single threaded. 73229997Sken */ 74229997Skenint dynamic_kenv = 0; 75229997Sken 76229997Sken#define KENV_CHECK if (!dynamic_kenv) \ 77229997Sken panic("%s: called before SI_SUB_KMEM", __func__) 78229997Sken 79229997Skenint 80229997Skenkenv(td, uap) 81229997Sken struct thread *td; 82229997Sken struct kenv_args /* { 83229997Sken int what; 84229997Sken const char *name; 85229997Sken char *value; 86229997Sken int len; 87229997Sken } */ *uap; 88229997Sken{ 89229997Sken char *name, *value, *buffer = NULL; 90229997Sken size_t len, done, needed, buflen; 91229997Sken int error, i; 92229997Sken 93229997Sken KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = 0")); 94229997Sken 95229997Sken error = 0; 96229997Sken if (uap->what == KENV_DUMP) { 97229997Sken#ifdef MAC 98229997Sken error = mac_kenv_check_dump(td->td_ucred); 99229997Sken if (error) 100229997Sken return (error); 101229997Sken#endif 102229997Sken done = needed = 0; 103229997Sken buflen = uap->len; 104229997Sken if (buflen > KENV_SIZE * (KENV_MNAMELEN + KENV_MVALLEN + 2)) 105229997Sken buflen = KENV_SIZE * (KENV_MNAMELEN + 106229997Sken KENV_MVALLEN + 2); 107229997Sken if (uap->len > 0 && uap->value != NULL) 108229997Sken buffer = malloc(buflen, M_TEMP, M_WAITOK|M_ZERO); 109229997Sken mtx_lock(&kenv_lock); 110229997Sken for (i = 0; kenvp[i] != NULL; i++) { 111229997Sken len = strlen(kenvp[i]) + 1; 112229997Sken needed += len; 113229997Sken len = min(len, buflen - done); 114229997Sken /* 115229997Sken * If called with a NULL or insufficiently large 116229997Sken * buffer, just keep computing the required size. 117229997Sken */ 118229997Sken if (uap->value != NULL && buffer != NULL && len > 0) { 119229997Sken bcopy(kenvp[i], buffer + done, len); 120229997Sken done += len; 121229997Sken } 122229997Sken } 123229997Sken mtx_unlock(&kenv_lock); 124229997Sken if (buffer != NULL) { 125229997Sken error = copyout(buffer, uap->value, done); 126229997Sken free(buffer, M_TEMP); 127229997Sken } 128229997Sken td->td_retval[0] = ((done == needed) ? 0 : needed); 129229997Sken return (error); 130229997Sken } 131229997Sken 132229997Sken switch (uap->what) { 133229997Sken case KENV_SET: 134229997Sken error = priv_check(td, PRIV_KENV_SET); 135229997Sken if (error) 136229997Sken return (error); 137229997Sken break; 138229997Sken 139229997Sken case KENV_UNSET: 140229997Sken error = priv_check(td, PRIV_KENV_UNSET); 141229997Sken if (error) 142229997Sken return (error); 143229997Sken break; 144229997Sken } 145229997Sken 146229997Sken name = malloc(KENV_MNAMELEN, M_TEMP, M_WAITOK); 147229997Sken 148229997Sken error = copyinstr(uap->name, name, KENV_MNAMELEN, NULL); 149229997Sken if (error) 150229997Sken goto done; 151229997Sken 152229997Sken switch (uap->what) { 153229997Sken case KENV_GET: 154229997Sken#ifdef MAC 155229997Sken error = mac_kenv_check_get(td->td_ucred, name); 156229997Sken if (error) 157229997Sken goto done; 158229997Sken#endif 159229997Sken value = getenv(name); 160229997Sken if (value == NULL) { 161229997Sken error = ENOENT; 162229997Sken goto done; 163229997Sken } 164229997Sken len = strlen(value) + 1; 165229997Sken if (len > uap->len) 166229997Sken len = uap->len; 167229997Sken error = copyout(value, uap->value, len); 168229997Sken freeenv(value); 169229997Sken if (error) 170229997Sken goto done; 171229997Sken td->td_retval[0] = len; 172229997Sken break; 173229997Sken case KENV_SET: 174229997Sken len = uap->len; 175229997Sken if (len < 1) { 176254759Strasz error = EINVAL; 177254759Strasz goto done; 178254759Strasz } 179254759Strasz if (len > KENV_MVALLEN) 180254759Strasz len = KENV_MVALLEN; 181254759Strasz value = malloc(len, M_TEMP, M_WAITOK); 182229997Sken error = copyinstr(uap->value, value, len, NULL); 183229997Sken if (error) { 184229997Sken free(value, M_TEMP); 185229997Sken goto done; 186229997Sken } 187229997Sken#ifdef MAC 188229997Sken error = mac_kenv_check_set(td->td_ucred, name, value); 189229997Sken if (error == 0) 190229997Sken#endif 191229997Sken setenv(name, value); 192229997Sken free(value, M_TEMP); 193229997Sken break; 194229997Sken case KENV_UNSET: 195229997Sken#ifdef MAC 196254759Strasz error = mac_kenv_check_unset(td->td_ucred, name); 197229997Sken if (error) 198229997Sken goto done; 199229997Sken#endif 200229997Sken error = unsetenv(name); 201229997Sken if (error) 202229997Sken error = ENOENT; 203229997Sken break; 204229997Sken default: 205229997Sken error = EINVAL; 206229997Sken break; 207229997Sken } 208229997Skendone: 209229997Sken free(name, M_TEMP); 210229997Sken return (error); 211229997Sken} 212229997Sken 213229997Skenvoid 214229997Skeninit_static_kenv(char *buf, size_t len) 215229997Sken{ 216229997Sken kern_envp = buf; 217229997Sken env_len = len; 218229997Sken env_pos = 0; 219229997Sken} 220229997Sken 221229997Sken/* 222229997Sken * Setup the dynamic kernel environment. 223229997Sken */ 224229997Skenstatic void 225229997Skeninit_dynamic_kenv(void *data __unused) 226229997Sken{ 227229997Sken char *cp; 228229997Sken int len, i; 229229997Sken 230229997Sken kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV, 231229997Sken M_WAITOK | M_ZERO); 232229997Sken i = 0; 233229997Sken for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) { 234229997Sken len = strlen(cp) + 1; 235229997Sken if (i < KENV_SIZE) { 236229997Sken kenvp[i] = malloc(len, M_KENV, M_WAITOK); 237229997Sken strcpy(kenvp[i++], cp); 238229997Sken } else 239229997Sken printf( 240229997Sken "WARNING: too many kenv strings, ignoring %s\n", 241229997Sken cp); 242229997Sken } 243229997Sken kenvp[i] = NULL; 244229997Sken 245229997Sken mtx_init(&kenv_lock, "kernel environment", NULL, MTX_DEF); 246229997Sken dynamic_kenv = 1; 247229997Sken} 248229997SkenSYSINIT(kenv, SI_SUB_KMEM, SI_ORDER_ANY, init_dynamic_kenv, NULL); 249229997Sken 250229997Skenvoid 251229997Skenfreeenv(char *env) 252229997Sken{ 253229997Sken 254229997Sken if (dynamic_kenv) 255229997Sken free(env, M_KENV); 256229997Sken} 257229997Sken 258229997Sken/* 259229997Sken * Internal functions for string lookup. 260229997Sken */ 261229997Skenstatic char * 262229997Sken_getenv_dynamic(const char *name, int *idx) 263229997Sken{ 264229997Sken char *cp; 265229997Sken int len, i; 266229997Sken 267229997Sken mtx_assert(&kenv_lock, MA_OWNED); 268229997Sken len = strlen(name); 269229997Sken for (cp = kenvp[0], i = 0; cp != NULL; cp = kenvp[++i]) { 270229997Sken if ((strncmp(cp, name, len) == 0) && 271229997Sken (cp[len] == '=')) { 272229997Sken if (idx != NULL) 273229997Sken *idx = i; 274229997Sken return (cp + len + 1); 275229997Sken } 276229997Sken } 277229997Sken return (NULL); 278229997Sken} 279229997Sken 280229997Skenstatic char * 281229997Sken_getenv_static(const char *name) 282229997Sken{ 283229997Sken char *cp, *ep; 284229997Sken int len; 285229997Sken 286229997Sken for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) { 287229997Sken for (ep = cp; (*ep != '=') && (*ep != 0); ep++) 288229997Sken ; 289229997Sken if (*ep != '=') 290232604Strasz continue; 291232604Strasz len = ep - cp; 292232604Strasz ep++; 293232604Strasz if (!strncmp(name, cp, len) && name[len] == 0) 294232604Strasz return (ep); 295229997Sken } 296229997Sken return (NULL); 297229997Sken} 298229997Sken 299229997Sken/* 300229997Sken * Look up an environment variable by name. 301 * Return a pointer to the string if found. 302 * The pointer has to be freed with freeenv() 303 * after use. 304 */ 305char * 306getenv(const char *name) 307{ 308 char buf[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1]; 309 char *ret, *cp; 310 int len; 311 312 if (dynamic_kenv) { 313 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "getenv"); 314 mtx_lock(&kenv_lock); 315 cp = _getenv_dynamic(name, NULL); 316 if (cp != NULL) { 317 strcpy(buf, cp); 318 mtx_unlock(&kenv_lock); 319 len = strlen(buf) + 1; 320 ret = malloc(len, M_KENV, M_WAITOK); 321 strcpy(ret, buf); 322 } else { 323 mtx_unlock(&kenv_lock); 324 ret = NULL; 325 } 326 } else 327 ret = _getenv_static(name); 328 return (ret); 329} 330 331/* 332 * Test if an environment variable is defined. 333 */ 334int 335testenv(const char *name) 336{ 337 char *cp; 338 339 if (dynamic_kenv) { 340 mtx_lock(&kenv_lock); 341 cp = _getenv_dynamic(name, NULL); 342 mtx_unlock(&kenv_lock); 343 } else 344 cp = _getenv_static(name); 345 if (cp != NULL) 346 return (1); 347 return (0); 348} 349 350static int 351setenv_static(const char *name, const char *value) 352{ 353 int len; 354 355 if (env_pos >= env_len) 356 return (-1); 357 358 /* Check space for x=y and two nuls */ 359 len = strlen(name) + strlen(value); 360 if (len + 3 < env_len - env_pos) { 361 len = sprintf(&kern_envp[env_pos], "%s=%s", name, value); 362 env_pos += len+1; 363 kern_envp[env_pos] = '\0'; 364 return (0); 365 } else 366 return (-1); 367 368} 369 370/* 371 * Set an environment variable by name. 372 */ 373int 374setenv(const char *name, const char *value) 375{ 376 char *buf, *cp, *oldenv; 377 int namelen, vallen, i; 378 379 if (dynamic_kenv == 0 && env_len > 0) 380 return (setenv_static(name, value)); 381 382 KENV_CHECK; 383 384 namelen = strlen(name) + 1; 385 if (namelen > KENV_MNAMELEN) 386 return (-1); 387 vallen = strlen(value) + 1; 388 if (vallen > KENV_MVALLEN) 389 return (-1); 390 buf = malloc(namelen + vallen, M_KENV, M_WAITOK); 391 sprintf(buf, "%s=%s", name, value); 392 393 mtx_lock(&kenv_lock); 394 cp = _getenv_dynamic(name, &i); 395 if (cp != NULL) { 396 oldenv = kenvp[i]; 397 kenvp[i] = buf; 398 mtx_unlock(&kenv_lock); 399 free(oldenv, M_KENV); 400 } else { 401 /* We add the option if it wasn't found */ 402 for (i = 0; (cp = kenvp[i]) != NULL; i++) 403 ; 404 405 /* Bounds checking */ 406 if (i < 0 || i >= KENV_SIZE) { 407 free(buf, M_KENV); 408 mtx_unlock(&kenv_lock); 409 return (-1); 410 } 411 412 kenvp[i] = buf; 413 kenvp[i + 1] = NULL; 414 mtx_unlock(&kenv_lock); 415 } 416 return (0); 417} 418 419/* 420 * Unset an environment variable string. 421 */ 422int 423unsetenv(const char *name) 424{ 425 char *cp, *oldenv; 426 int i, j; 427 428 KENV_CHECK; 429 430 mtx_lock(&kenv_lock); 431 cp = _getenv_dynamic(name, &i); 432 if (cp != NULL) { 433 oldenv = kenvp[i]; 434 for (j = i + 1; kenvp[j] != NULL; j++) 435 kenvp[i++] = kenvp[j]; 436 kenvp[i] = NULL; 437 mtx_unlock(&kenv_lock); 438 free(oldenv, M_KENV); 439 return (0); 440 } 441 mtx_unlock(&kenv_lock); 442 return (-1); 443} 444 445/* 446 * Return a string value from an environment variable. 447 */ 448int 449getenv_string(const char *name, char *data, int size) 450{ 451 char *tmp; 452 453 tmp = getenv(name); 454 if (tmp != NULL) { 455 strlcpy(data, tmp, size); 456 freeenv(tmp); 457 return (1); 458 } else 459 return (0); 460} 461 462/* 463 * Return an integer value from an environment variable. 464 */ 465int 466getenv_int(const char *name, int *data) 467{ 468 quad_t tmp; 469 int rval; 470 471 rval = getenv_quad(name, &tmp); 472 if (rval) 473 *data = (int) tmp; 474 return (rval); 475} 476 477/* 478 * Return an unsigned integer value from an environment variable. 479 */ 480int 481getenv_uint(const char *name, unsigned int *data) 482{ 483 quad_t tmp; 484 int rval; 485 486 rval = getenv_quad(name, &tmp); 487 if (rval) 488 *data = (unsigned int) tmp; 489 return (rval); 490} 491 492/* 493 * Return a long value from an environment variable. 494 */ 495int 496getenv_long(const char *name, long *data) 497{ 498 quad_t tmp; 499 int rval; 500 501 rval = getenv_quad(name, &tmp); 502 if (rval) 503 *data = (long) tmp; 504 return (rval); 505} 506 507/* 508 * Return an unsigned long value from an environment variable. 509 */ 510int 511getenv_ulong(const char *name, unsigned long *data) 512{ 513 quad_t tmp; 514 int rval; 515 516 rval = getenv_quad(name, &tmp); 517 if (rval) 518 *data = (unsigned long) tmp; 519 return (rval); 520} 521 522/* 523 * Return a quad_t value from an environment variable. 524 */ 525int 526getenv_quad(const char *name, quad_t *data) 527{ 528 char *value; 529 char *vtp; 530 quad_t iv; 531 532 value = getenv(name); 533 if (value == NULL) 534 return (0); 535 iv = strtoq(value, &vtp, 0); 536 if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) { 537 freeenv(value); 538 return (0); 539 } 540 switch (vtp[0]) { 541 case 't': case 'T': 542 iv *= 1024; 543 case 'g': case 'G': 544 iv *= 1024; 545 case 'm': case 'M': 546 iv *= 1024; 547 case 'k': case 'K': 548 iv *= 1024; 549 case '\0': 550 break; 551 default: 552 freeenv(value); 553 return (0); 554 } 555 *data = iv; 556 freeenv(value); 557 return (1); 558} 559 560/* 561 * Find the next entry after the one which (cp) falls within, return a 562 * pointer to its start or NULL if there are no more. 563 */ 564static char * 565kernenv_next(char *cp) 566{ 567 568 if (cp != NULL) { 569 while (*cp != 0) 570 cp++; 571 cp++; 572 if (*cp == 0) 573 cp = NULL; 574 } 575 return (cp); 576} 577 578void 579tunable_int_init(void *data) 580{ 581 struct tunable_int *d = (struct tunable_int *)data; 582 583 TUNABLE_INT_FETCH(d->path, d->var); 584} 585 586void 587tunable_long_init(void *data) 588{ 589 struct tunable_long *d = (struct tunable_long *)data; 590 591 TUNABLE_LONG_FETCH(d->path, d->var); 592} 593 594void 595tunable_ulong_init(void *data) 596{ 597 struct tunable_ulong *d = (struct tunable_ulong *)data; 598 599 TUNABLE_ULONG_FETCH(d->path, d->var); 600} 601 602void 603tunable_quad_init(void *data) 604{ 605 struct tunable_quad *d = (struct tunable_quad *)data; 606 607 TUNABLE_QUAD_FETCH(d->path, d->var); 608} 609 610void 611tunable_str_init(void *data) 612{ 613 struct tunable_str *d = (struct tunable_str *)data; 614 615 TUNABLE_STR_FETCH(d->path, d->var, d->size); 616} 617