diff --git a/sys/kern/kern_environment.c b/sys/kern/kern_environment.c index 7c36a24ff75c..f2d7dcb1de4d 100644 --- a/sys/kern/kern_environment.c +++ b/sys/kern/kern_environment.c @@ -63,6 +63,9 @@ static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment"); #define KENV_SIZE 512 /* Maximum number of environment strings */ +static uma_zone_t kenv_zone; +static int kenv_mvallen = KENV_MVALLEN; + /* pointer to the config-generated static environment */ char *kern_envp; @@ -85,6 +88,8 @@ bool dynamic_kenv; #define KENV_CHECK if (!dynamic_kenv) \ panic("%s: called before SI_SUB_KMEM", __func__) +static char *getenv_string_buffer(const char *); + int sys_kenv(td, uap) struct thread *td; @@ -110,9 +115,9 @@ sys_kenv(td, uap) #endif done = needed = 0; buflen = uap->len; - if (buflen > KENV_SIZE * (KENV_MNAMELEN + KENV_MVALLEN + 2)) + if (buflen > KENV_SIZE * (KENV_MNAMELEN + kenv_mvallen + 2)) buflen = KENV_SIZE * (KENV_MNAMELEN + - KENV_MVALLEN + 2); + kenv_mvallen + 2); if (uap->len > 0 && uap->value != NULL) buffer = malloc(buflen, M_TEMP, M_WAITOK|M_ZERO); mtx_lock(&kenv_lock); @@ -185,8 +190,8 @@ sys_kenv(td, uap) error = EINVAL; goto done; } - if (len > KENV_MVALLEN + 1) - len = KENV_MVALLEN + 1; + if (len > kenv_mvallen + 1) + len = kenv_mvallen + 1; value = malloc(len, M_TEMP, M_WAITOK); error = copyinstr(uap->value, value, len, NULL); if (error) { @@ -327,7 +332,7 @@ init_dynamic_kenv_from(char *init_env, int *curpos) for (cp = init_env; cp != NULL; cp = cpnext) { cpnext = kernenv_next(cp); len = strlen(cp) + 1; - if (len > KENV_MNAMELEN + 1 + KENV_MVALLEN + 1) { + if (len > KENV_MNAMELEN + 1 + kenv_mvallen + 1) { printf( "WARNING: too long kenv string, ignoring %s\n", cp); @@ -375,6 +380,13 @@ static void init_dynamic_kenv(void *data __unused) { int dynamic_envpos; + int size; + + TUNABLE_INT_FETCH("kenv_mvallen", &kenv_mvallen); + size = KENV_MNAMELEN + 1 + kenv_mvallen + 1; + + kenv_zone = uma_zcreate("kenv", size, NULL, NULL, NULL, NULL, + UMA_ALIGN_PTR, 0); kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV, M_WAITOK | M_ZERO); @@ -395,7 +407,7 @@ freeenv(char *env) if (dynamic_kenv && env != NULL) { explicit_bzero(env, strlen(env)); - free(env, M_KENV); + uma_zfree(kenv_zone, env); } } @@ -470,14 +482,11 @@ _getenv_static(const char *name) char * kern_getenv(const char *name) { - char buf[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1]; char *ret; if (dynamic_kenv) { - if (getenv_string(name, buf, sizeof(buf))) { - ret = strdup(buf, M_KENV); - } else { - ret = NULL; + ret = getenv_string_buffer(name); + if (ret == NULL) { WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "getenv"); } @@ -548,7 +557,7 @@ kern_setenv(const char *name, const char *value) if (namelen > KENV_MNAMELEN + 1) return (-1); vallen = strlen(value) + 1; - if (vallen > KENV_MVALLEN + 1) + if (vallen > kenv_mvallen + 1) return (-1); buf = malloc(namelen + vallen, M_KENV, M_WAITOK); sprintf(buf, "%s=%s", name, value); @@ -606,6 +615,33 @@ kern_unsetenv(const char *name) return (-1); } +/* + * Return a buffer containing the string value from an environment variable + */ +static char * +getenv_string_buffer(const char *name) +{ + char *cp, *ret; + int len; + + if (dynamic_kenv) { + len = KENV_MNAMELEN + 1 + kenv_mvallen + 1; + ret = uma_zalloc(kenv_zone, M_WAITOK | M_ZERO); + mtx_lock(&kenv_lock); + cp = _getenv_dynamic(name, NULL); + if (cp != NULL) + strlcpy(ret, cp, len); + mtx_unlock(&kenv_lock); + if (cp == NULL) { + uma_zfree(kenv_zone, ret); + ret = NULL; + } + } else + ret = _getenv_static(name); + + return (ret); +} + /* * Return a string value from an environment variable. */ @@ -635,17 +671,19 @@ int getenv_array(const char *name, void *pdata, int size, int *psize, int type_size, bool allow_signed) { - char buf[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1]; uint8_t shift; int64_t value; int64_t old; + char *buf; char *end; char *ptr; int n; + int rc; - if (getenv_string(name, buf, sizeof(buf)) == 0) + if ((buf = getenv_string_buffer(name)) == NULL) return (0); + rc = 0; /* assume failure */ /* get maximum number of elements */ size /= type_size; @@ -758,9 +796,11 @@ getenv_array(const char *name, void *pdata, int size, int *psize, *psize = n * type_size; if (n != 0) - return (1); /* success */ + rc = 1; /* success */ error: - return (0); /* failure */ + if (dynamic_kenv) + uma_zfree(kenv_zone, buf); + return (rc); } /* @@ -859,15 +899,17 @@ getenv_ulong(const char *name, unsigned long *data) int getenv_quad(const char *name, quad_t *data) { - char value[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1]; - char *vtp; + char *value, *vtp; quad_t iv; - if (!getenv_string(name, value, sizeof(value))) + value = getenv_string_buffer(name); + if (value == NULL) return (0); iv = strtoq(value, &vtp, 0); - if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) + if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) { + freeenv(value); return (0); + } switch (vtp[0]) { case 't': case 'T': iv *= 1024; @@ -883,8 +925,10 @@ getenv_quad(const char *name, quad_t *data) case '\0': break; default: + freeenv(value); return (0); } + freeenv(value); *data = iv; return (1); }