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
This commit is contained in:
Kyle Evans committed 2026-06-22 15:22:25 -05:00
1 parent 88deb1cff9
commit 4fd518fcb2
5 files changed
+59 -9

No files matched your search

+9 -1
View File
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd June 20, 2021
.Dd June 22, 2026
.Dt KENV 1
.Os
.Sh NAME
@@ -166,3 +166,11 @@ The
.Nm
utility appeared in
.Fx 4.1.1 .
.Sh SECURITY CONSIDERATIONS
Note that unprivileged users are allowed to read from the kernel environment,
unless the
.Va security.bsd.unprivileged_kenv_read
sysctl is set to 0.
This includes both listing the kernel environment, as well as getting a specific
.Va variable
from the environment.
+6 -1
View File
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
.\" DAMAGE.
.\"
.Dd June 20, 2021
.Dd June 22, 2026
.Dt KENV 2
.Os
.Sh NAME
@@ -161,6 +161,11 @@ The kernel is configured to destroy these environments by default.
.It Bq Er EPERM
A user other than the superuser attempted to set or unset a kernel
environment variable.
.It Bq Er EPERM
A user other than the superuser attempted to get a variable from or dump the
kernel environment, and the
.Va security.bsd.unprivileged_kenv_read
sysctl is set to 0.
.It Bq Er EFAULT
A bad address was encountered while attempting to copy in user arguments
or copy out value(s).
+3 -1
View File
@@ -26,7 +26,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd March 22, 2026
.Dd June 22, 2026
.Dt SECURITY 7
.Os
.Sh NAME
@@ -987,6 +987,8 @@ and usual termination signals like
and
.Dv SIGTERM ,
to the processes executing programs with changed uids.
.It Va security.bsd.unprivileged_kenv_read
Controls availability of kernel environment variables to non-root users.
.It Va security.bsd.unprivileged_proc_debug
Controls availability of the process debugging facilities to non-root users.
See also
+40 -6
View File
@@ -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);
+1
View File
@@ -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.