diff options
| author | Kyle Evans <kevans@FreeBSD.org> | 2026-06-22 20:22:25 +0000 |
|---|---|---|
| committer | Kyle Evans <kevans@FreeBSD.org> | 2026-06-22 20:22:25 +0000 |
| commit | 4fd518fcb2bbee4c8c41215d6993b923ef57a0e5 (patch) | |
| tree | 8e0ce3cb444cec3910f99cf664b9f9c1e924b120 /sys | |
| parent | 88deb1cff92cb3620c248f32fa6e7bdbc5301213 (diff) | |
kern: add a security knob to disable unprivileged access to kenv
We sometimes store sensitive things in the kenv that get zapped, but we
really shouldn't rely on that zapping to actually happen. Most
unprivileged processes don't really need to read from the kernel
environment in the first place, so add a knob that allows it to be
disabled.
Note that we consider jailed root to be unprivileged from this
perspective; they have their own meta/env concepts and we should
encourage users to take advantage of those for passing information to
jails.
"Hey we should do something about that": dch
Reviewed by: imp, ziaee, zlei (all slightly previous version)
Differential Revision: https://reviews.freebsd.org/D57697
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/kern/kern_environment.c | 46 | ||||
| -rw-r--r-- | sys/sys/priv.h | 1 |
2 files changed, 41 insertions, 6 deletions
diff --git a/sys/kern/kern_environment.c b/sys/kern/kern_environment.c index 7c0654769581..72c7544b4bac 100644 --- a/sys/kern/kern_environment.c +++ b/sys/kern/kern_environment.c @@ -49,6 +49,7 @@ #include <sys/priv.h> #include <sys/proc.h> #include <sys/queue.h> +#include <sys/sysctl.h> #include <sys/sysent.h> #include <sys/sysproto.h> @@ -91,6 +92,11 @@ bool dynamic_kenv; #define KENV_CHECK if (!dynamic_kenv) \ panic("%s: called before SI_SUB_KMEM", __func__) +static int unprivileged_kenv_read = 1; +SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_kenv_read, CTLFLAG_RW, + &unprivileged_kenv_read, 1, + "Unprivileged processes can read the kernel environment"); + static int kenv_dump(struct thread *td, char **envp, int what, char *value, int len) { @@ -155,6 +161,33 @@ kenv_dump(struct thread *td, char **envp, int what, char *value, int len) return (error); } +static int +kenv_read_allowed(struct thread *td, int which) +{ + int error; + + if (!unprivileged_kenv_read) { + error = priv_check(td, PRIV_KENV_READ); + if (error) + return (error); + } + + switch (which) { + case KENV_DUMP: + case KENV_DUMP_LOADER: + case KENV_DUMP_STATIC: +#ifdef MAC + error = mac_kenv_check_dump(td->td_ucred); +#endif + break; + default: + error = 0; + break; + } + + return (error); +} + int sys_kenv(struct thread *td, struct kenv_args *uap) { @@ -168,19 +201,15 @@ sys_kenv(struct thread *td, struct kenv_args *uap) switch (uap->what) { case KENV_DUMP: -#ifdef MAC - error = mac_kenv_check_dump(td->td_ucred); + error = kenv_read_allowed(td, uap->what); 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); + error = kenv_read_allowed(td, uap->what); if (error) return (error); -#endif #ifdef PRESERVE_EARLY_KENV return (kenv_dump(td, uap->what == KENV_DUMP_LOADER ? (char **)md_envp : @@ -199,6 +228,11 @@ sys_kenv(struct thread *td, struct kenv_args *uap) if (error) return (error); break; + case KENV_GET: + error = kenv_read_allowed(td, uap->what); + if (error) + return (error); + break; } name = malloc(KENV_MNAMELEN + 1, M_TEMP, M_WAITOK); diff --git a/sys/sys/priv.h b/sys/sys/priv.h index 148f2191c6e0..87775632f8a8 100644 --- a/sys/sys/priv.h +++ b/sys/sys/priv.h @@ -141,6 +141,7 @@ */ #define PRIV_KENV_SET 120 /* Set kernel env. variables. */ #define PRIV_KENV_UNSET 121 /* Unset kernel env. variables. */ +#define PRIV_KENV_READ 122 /* Get/dump kernel env. variables. */ /* * Loadable kernel module privileges. |
