Index: sys/kern/kern_environment.c =================================================================== --- sys/kern/kern_environment.c +++ sys/kern/kern_environment.c @@ -359,11 +359,33 @@ } } +/* Maximum suffix number appended for duplicate environment variable names. */ +#define MAXSUFFIX 9999 +#define SUFFIXLEN strlen("_" __XSTRING(MAXSUFFIX)) + +static void +getfreesuffix(char *cp, size_t *n) +{ + size_t len = strlen(cp); + char * ncp; + + ncp = malloc(len + SUFFIXLEN + 1, M_KENV, M_WAITOK); + memcpy(ncp, cp, len); + for (*n = 1; *n <= MAXSUFFIX; (*n)++) { + sprintf(&ncp[len], "_%zu", *n); + if (!_getenv_dynamic_locked(ncp, NULL)) + break; + } + free(ncp, M_KENV); + if (*n > MAXSUFFIX) + panic("Too many duplicate kernel environment values: %s", cp); +} + static void init_dynamic_kenv_from(char *init_env, int *curpos) { char *cp, *cpnext, *eqpos, *found; - size_t len; + size_t len, n; int i; if (init_env && *init_env != '\0') { @@ -372,6 +394,12 @@ for (cp = init_env; cp != NULL; cp = cpnext) { cpnext = kernenv_next(cp); len = strlen(cp) + 1; + if (i > KENV_SIZE) { + printf( + "WARNING: too many kenv strings, ignoring %s\n", + cp); + goto sanitize; + } if (len > KENV_MNAMELEN + 1 + kenv_mvallen + 1) { printf( "WARNING: too long kenv string, ignoring %s\n", @@ -387,25 +415,31 @@ } *eqpos = 0; /* - * De-dupe the environment as we go. We don't add the - * duplicated assignments because config(8) will flip - * the order of the static environment around to make - * kernel processing match the order of specification - * in the kernel config. + * Handle duplicates in the environment as we go; we + * add the duplicated assignments with _N suffixes. + * This ensures that (a) if a variable is set in the + * static environment and in the "loader" environement + * provided by MD code, the value from the loader will + * have the expected variable name and the value from + * the static environment will have the suffix; and (b) + * if the "loader" environment has the same variable + * set multiple times (as is possible with values being + * passed via the kernel "command line") the extra + * values are visible to code which knows where to look + * for them. */ found = _getenv_dynamic_locked(cp, NULL); - *eqpos = '='; - if (found != NULL) - goto sanitize; - if (i > KENV_SIZE) { - printf( - "WARNING: too many kenv strings, ignoring %s\n", - cp); - goto sanitize; + if (found != NULL) { + getfreesuffix(cp, &n); + kenvp[i] = malloc(len + SUFFIXLEN, + M_KENV, M_WAITOK); + sprintf(kenvp[i++], "%s_%zu=%s", cp, n, + &eqpos[1]); + } else { + kenvp[i] = malloc(len, M_KENV, M_WAITOK); + *eqpos = '='; + strcpy(kenvp[i++], cp); } - - kenvp[i] = malloc(len, M_KENV, M_WAITOK); - strcpy(kenvp[i++], cp); sanitize: #ifdef PRESERVE_EARLY_KENV continue;