Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 16 Jun 2020 17:02:56 +0000 (UTC)
From:      "Simon J. Gerraty" <sjg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r362231 - head/sys/kern
Message-ID:  <202006161702.05GH2uI8028119@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <abkulkarni@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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202006161702.05GH2uI8028119>