Author: sjg
Date: Tue Jun 16 17:02:56 2020
New Revision: 362231
URL: https://svnweb.freebsd.org/changeset/base/362231

Log:
  Make KENV_MVALLEN tunable
  
  When doing secure boot, loader wants to export loader.ve.hashed
  the value of which typically exceeds KENV_MVALLEN.
  
  Replace use of KENV_MVALLEN with tunable kenv_mvallen.
  
  Add getenv_string_buffer() for the case where a stack buffer cannot be
  created and use uma_zone_t kenv_zone for suitably sized buffers.
  
  Reviewed by:  stevek, kevans
  Obtained from:        Abhishek Kulkarni <abkulka...@juniper.net>
  MFC after:    1 week
  Sponsored by: Juniper Networks
  Differential Revision: https://reviews.freebsd.org//D25259

Modified:
  head/sys/kern/kern_environment.c

Modified: head/sys/kern/kern_environment.c
==============================================================================
--- head/sys/kern/kern_environment.c    Tue Jun 16 16:48:52 2020        
(r362230)
+++ head/sys/kern/kern_environment.c    Tue Jun 16 17:02:56 2020        
(r362231)
@@ -63,6 +63,9 @@ static MALLOC_DEFINE(M_KENV, "kenv", "kernel environme
 
 #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,7 +380,14 @@ 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);
@@ -607,6 +616,33 @@ kern_unsetenv(const char *name)
 }
 
 /*
+ * 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.
  */
 int
@@ -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, 
        *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);
 }
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to