Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_environment.c
Show First 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* No need to protect this with a mutex since SYSINITS are single threaded. | * No need to protect this with a mutex since SYSINITS are single threaded. | ||||
*/ | */ | ||||
bool dynamic_kenv; | bool dynamic_kenv; | ||||
#define KENV_CHECK if (!dynamic_kenv) \ | #define KENV_CHECK if (!dynamic_kenv) \ | ||||
panic("%s: called before SI_SUB_KMEM", __func__) | panic("%s: called before SI_SUB_KMEM", __func__) | ||||
int | static int | ||||
sys_kenv(td, uap) | kenv_dump(struct thread *td, char **envp, int what, char *value, int len) | ||||
struct thread *td; | |||||
struct kenv_args /* { | |||||
int what; | |||||
const char *name; | |||||
char *value; | |||||
int len; | |||||
} */ *uap; | |||||
{ | { | ||||
char *name, *value, *buffer = NULL; | char *buffer, *senv; | ||||
size_t len, done, needed, buflen; | size_t done, needed, buflen; | ||||
int error, i; | int error; | ||||
KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = false")); | |||||
error = 0; | error = 0; | ||||
if (uap->what == KENV_DUMP) { | buffer = NULL; | ||||
#ifdef MAC | |||||
error = mac_kenv_check_dump(td->td_ucred); | |||||
if (error) | |||||
return (error); | |||||
#endif | |||||
done = needed = 0; | done = needed = 0; | ||||
buflen = uap->len; | |||||
MPASS(what == KENV_DUMP || what == KENV_DUMP_LOADER || | |||||
what == KENV_DUMP_STATIC); | |||||
/* | |||||
* For non-dynamic kernel environment, we pass in either md_envp or | |||||
* kern_envp and we must traverse with kernenv_next(). This shuffling | |||||
* of pointers simplifies the below loop by only differing in how envp | |||||
* is modified. | |||||
*/ | |||||
if (what != KENV_DUMP) { | |||||
senv = (char *)envp; | |||||
envp = &senv; | |||||
} | |||||
buflen = len; | |||||
if (buflen > KENV_SIZE * (KENV_MNAMELEN + kenv_mvallen + 2)) | if (buflen > KENV_SIZE * (KENV_MNAMELEN + kenv_mvallen + 2)) | ||||
buflen = KENV_SIZE * (KENV_MNAMELEN + | buflen = KENV_SIZE * (KENV_MNAMELEN + | ||||
kenv_mvallen + 2); | kenv_mvallen + 2); | ||||
if (uap->len > 0 && uap->value != NULL) | if (len > 0 && value != NULL) | ||||
buffer = malloc(buflen, M_TEMP, M_WAITOK|M_ZERO); | buffer = malloc(buflen, M_TEMP, M_WAITOK|M_ZERO); | ||||
/* Only take the lock for the dynamic kenv. */ | |||||
if (what == KENV_DUMP) | |||||
mtx_lock(&kenv_lock); | mtx_lock(&kenv_lock); | ||||
for (i = 0; kenvp[i] != NULL; i++) { | while (*envp != NULL) { | ||||
len = strlen(kenvp[i]) + 1; | len = strlen(*envp) + 1; | ||||
needed += len; | needed += len; | ||||
len = min(len, buflen - done); | len = min(len, buflen - done); | ||||
/* | /* | ||||
* If called with a NULL or insufficiently large | * If called with a NULL or insufficiently large | ||||
* buffer, just keep computing the required size. | * buffer, just keep computing the required size. | ||||
*/ | */ | ||||
if (uap->value != NULL && buffer != NULL && len > 0) { | if (value != NULL && buffer != NULL && len > 0) { | ||||
bcopy(kenvp[i], buffer + done, len); | bcopy(*envp, buffer + done, len); | ||||
done += len; | done += len; | ||||
} | } | ||||
/* Advance the pointer depending on the kenv format. */ | |||||
if (what == KENV_DUMP) | |||||
envp++; | |||||
else | |||||
senv = kernenv_next(senv); | |||||
} | } | ||||
if (what == KENV_DUMP) | |||||
mtx_unlock(&kenv_lock); | mtx_unlock(&kenv_lock); | ||||
if (buffer != NULL) { | if (buffer != NULL) { | ||||
error = copyout(buffer, uap->value, done); | error = copyout(buffer, value, done); | ||||
free(buffer, M_TEMP); | free(buffer, M_TEMP); | ||||
} | } | ||||
td->td_retval[0] = ((done == needed) ? 0 : needed); | td->td_retval[0] = ((done == needed) ? 0 : needed); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | |||||
sys_kenv(struct thread *td, struct kenv_args *uap) | |||||
{ | |||||
char *name, *value; | |||||
size_t len; | |||||
int error; | |||||
KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = false")); | |||||
error = 0; | |||||
switch (uap->what) { | switch (uap->what) { | ||||
case KENV_DUMP: | |||||
#ifdef MAC | |||||
error = mac_kenv_check_dump(td->td_ucred); | |||||
if (error) | |||||
return (error); | |||||
#endif | |||||
return (kenv_dump(td, kenvp, uap->what, uap->value, uap->len)); | |||||
case KENV_DUMP_LOADER: | |||||
case KENV_DUMP_STATIC: | |||||
#ifdef MAC | |||||
error = mac_kenv_check_dump(td->td_ucred); | |||||
if (error) | |||||
jhb: I think it might be a bit clearer to rewrite this as a switch on the what. I think it's then… | |||||
return (error); | |||||
#endif | |||||
#ifdef PRESERVE_EARLY_KENV | |||||
return (kenv_dump(td, | |||||
uap->what == KENV_DUMP_LOADER ? (char **)md_envp : | |||||
(char **)kern_envp, uap->what, uap->value, uap->len)); | |||||
#else | |||||
return (ENOENT); | |||||
#endif | |||||
case KENV_SET: | case KENV_SET: | ||||
error = priv_check(td, PRIV_KENV_SET); | error = priv_check(td, PRIV_KENV_SET); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
break; | break; | ||||
case KENV_UNSET: | case KENV_UNSET: | ||||
error = priv_check(td, PRIV_KENV_UNSET); | error = priv_check(td, PRIV_KENV_UNSET); | ||||
▲ Show 20 Lines • Show All 928 Lines • Show Last 20 Lines |
I think it might be a bit clearer to rewrite this as a switch on the what. I think it's then more obvious that your MPASS is really an '_assert_unreachable()'. Looking at this even further though, I think I'd really like to just split out this early section into a helper function:
And then in sys_kenv() you add this to the start of the switch statement below: