Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153246866
D30835.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D30835.id.diff
View Options
diff --git a/bin/kenv/kenv.1 b/bin/kenv/kenv.1
--- a/bin/kenv/kenv.1
+++ b/bin/kenv/kenv.1
@@ -32,6 +32,7 @@
.Nd list or modify the kernel environment
.Sh SYNOPSIS
.Nm
+.Op Fl l | s
.Op Fl hNq
.Nm
.Op Fl qv
@@ -45,6 +46,23 @@
.Nm
utility will list all variables in the kernel environment if
invoked without arguments.
+.Pp
+If the
+.Fl l
+option is specified, then the static environment provided by
+.Xr loader 8
+will be listed instead.
+Similarly, the
+.Fl s
+option will list the static environment defined by the kernel config.
+Both of the
+.Fl l
+and
+.Fl s
+options are dependent on the kernel being configured to preserve early kernel
+environments.
+The default kernel configuration does not preserve these environments.
+.Pp
If the
.Fl h
option is specified, it will limit the report to kernel probe hints.
diff --git a/bin/kenv/kenv.c b/bin/kenv/kenv.c
--- a/bin/kenv/kenv.c
+++ b/bin/kenv/kenv.c
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <sys/sysctl.h>
#include <err.h>
+#include <errno.h>
#include <kenv.h>
#include <stdio.h>
#include <stdlib.h>
@@ -36,14 +37,16 @@
#include <unistd.h>
static void usage(void);
-static int kdumpenv(void);
+static int kdumpenv(int dump_type);
static int kgetenv(const char *);
static int ksetenv(const char *, char *);
static int kunsetenv(const char *);
static int hflag = 0;
+static int lflag = 0;
static int Nflag = 0;
static int qflag = 0;
+static int sflag = 0;
static int uflag = 0;
static int vflag = 0;
@@ -51,7 +54,7 @@
usage(void)
{
(void)fprintf(stderr, "%s\n%s\n%s\n",
- "usage: kenv [-hNq]",
+ "usage: kenv [-l|-s] [-hNq]",
" kenv [-qv] variable[=value]",
" kenv [-q] -u variable");
exit(1);
@@ -65,17 +68,23 @@
val = NULL;
env = NULL;
- while ((ch = getopt(argc, argv, "hNquv")) != -1) {
+ while ((ch = getopt(argc, argv, "hlNqsuv")) != -1) {
switch (ch) {
case 'h':
hflag++;
break;
+ case 'l':
+ lflag++;
+ break;
case 'N':
Nflag++;
break;
case 'q':
qflag++;
break;
+ case 's':
+ sflag++;
+ break;
case 'u':
uflag++;
break;
@@ -100,12 +109,23 @@
}
if ((hflag || Nflag) && env != NULL)
usage();
+ if (lflag && sflag)
+ usage();
if (argc > 0 || ((uflag || vflag) && env == NULL))
usage();
if (env == NULL) {
- error = kdumpenv();
- if (error && !qflag)
- warn("kdumpenv");
+ if (lflag)
+ error = kdumpenv(KENV_DUMP_LOADER);
+ else if (sflag)
+ error = kdumpenv(KENV_DUMP_STATIC);
+ else
+ error = kdumpenv(KENV_DUMP);
+ if (error && !qflag) {
+ if (errno == ENOENT)
+ warnx("requested environment is unavailable");
+ else
+ warn("kdumpenv");
+ }
} else if (val == NULL) {
if (uflag) {
error = kunsetenv(env);
@@ -125,12 +145,12 @@
}
static int
-kdumpenv(void)
+kdumpenv(int dump_type)
{
char *buf, *bp, *cp;
int buflen, envlen;
- envlen = kenv(KENV_DUMP, NULL, NULL, 0);
+ envlen = kenv(dump_type, NULL, NULL, 0);
if (envlen < 0)
return (-1);
for (;;) {
@@ -138,7 +158,7 @@
buf = calloc(1, buflen + 1);
if (buf == NULL)
return (-1);
- envlen = kenv(KENV_DUMP, NULL, buf, buflen);
+ envlen = kenv(dump_type, NULL, buf, buflen);
if (envlen < 0) {
free(buf);
return (-1);
diff --git a/lib/libc/sys/kenv.2 b/lib/libc/sys/kenv.2
--- a/lib/libc/sys/kenv.2
+++ b/lib/libc/sys/kenv.2
@@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 20, 2017
+.Dd June 20, 2021
.Dt KENV 2
.Os
.Sh NAME
@@ -49,7 +49,7 @@
The
.Fa action
argument can be one of the following:
-.Bl -tag -width ".Dv KENV_UNSET"
+.Bl -tag -width ".Dv KENV_DUMP_LOADER"
.It Dv KENV_GET
Get the
.Fa value
@@ -90,7 +90,7 @@
arguments are ignored.
This option is only available to the superuser.
.It Dv KENV_DUMP
-Dump as much of the kernel environment as will fit in
+Dump as much of the dynamic kernel environment as will fit in
.Fa value ,
whose size is given in
.Fa len .
@@ -103,6 +103,18 @@
The
.Fa name
is ignored.
+.It Dv KENV_DUMP_LOADER
+Dump the static environment provided by
+.Xr loader 8 ,
+with semantics identical to
+.Dv KENV_DUMP .
+Duplicate and malformed variables originally present in this environment are
+discarded by the kernel and will not appear in the output.
+.It Dv KENV_DUMP_STATIC
+Dump the static environment defined by the kernel
+.Xr config 5 .
+The semantics are identical to
+.Dv KENV_DUMP_LOADER .
.El
.Sh RETURN VALUES
The
@@ -142,6 +154,12 @@
.Dv KENV_GET
or
.Dv KENV_UNSET .
+.It Bq Er ENOENT
+The requested environment is not available for a
+.Dv KENV_DUMP_LOADER
+or
+.Dv KENV_DUMP_STATIC .
+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.
diff --git a/sys/kern/kern_environment.c b/sys/kern/kern_environment.c
--- a/sys/kern/kern_environment.c
+++ b/sys/kern/kern_environment.c
@@ -92,60 +92,103 @@
#define KENV_CHECK if (!dynamic_kenv) \
panic("%s: called before SI_SUB_KMEM", __func__)
+static int
+kenv_dump(struct thread *td, char **envp, int what, char *value, int len)
+{
+ char *buffer, *senv;
+ size_t done, needed, buflen;
+ int error;
+
+ error = 0;
+ buffer = NULL;
+ done = needed = 0;
+
+ 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))
+ buflen = KENV_SIZE * (KENV_MNAMELEN +
+ kenv_mvallen + 2);
+ if (len > 0 && value != NULL)
+ 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);
+ while (*envp != NULL) {
+ len = strlen(*envp) + 1;
+ needed += len;
+ len = min(len, buflen - done);
+ /*
+ * If called with a NULL or insufficiently large
+ * buffer, just keep computing the required size.
+ */
+ if (value != NULL && buffer != NULL && len > 0) {
+ bcopy(*envp, buffer + 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);
+ if (buffer != NULL) {
+ error = copyout(buffer, value, done);
+ free(buffer, M_TEMP);
+ }
+ td->td_retval[0] = ((done == needed) ? 0 : needed);
+ return (error);
+}
+
int
-sys_kenv(td, uap)
- struct thread *td;
- struct kenv_args /* {
- int what;
- const char *name;
- char *value;
- int len;
- } */ *uap;
+sys_kenv(struct thread *td, struct kenv_args *uap)
{
- char *name, *value, *buffer = NULL;
- size_t len, done, needed, buflen;
- int error, i;
+ char *name, *value;
+ size_t len;
+ int error;
KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = false"));
error = 0;
- if (uap->what == KENV_DUMP) {
+
+ switch (uap->what) {
+ case KENV_DUMP:
#ifdef MAC
error = mac_kenv_check_dump(td->td_ucred);
if (error)
return (error);
#endif
- done = needed = 0;
- buflen = uap->len;
- if (buflen > KENV_SIZE * (KENV_MNAMELEN + kenv_mvallen + 2))
- buflen = KENV_SIZE * (KENV_MNAMELEN +
- kenv_mvallen + 2);
- if (uap->len > 0 && uap->value != NULL)
- buffer = malloc(buflen, M_TEMP, M_WAITOK|M_ZERO);
- mtx_lock(&kenv_lock);
- for (i = 0; kenvp[i] != NULL; i++) {
- len = strlen(kenvp[i]) + 1;
- needed += len;
- len = min(len, buflen - done);
- /*
- * If called with a NULL or insufficiently large
- * buffer, just keep computing the required size.
- */
- if (uap->value != NULL && buffer != NULL && len > 0) {
- bcopy(kenvp[i], buffer + done, len);
- done += len;
- }
- }
- mtx_unlock(&kenv_lock);
- if (buffer != NULL) {
- error = copyout(buffer, uap->value, done);
- free(buffer, M_TEMP);
- }
- td->td_retval[0] = ((done == needed) ? 0 : needed);
- return (error);
- }
-
- switch (uap->what) {
+ 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)
+ 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:
error = priv_check(td, PRIV_KENV_SET);
if (error)
diff --git a/sys/sys/kenv.h b/sys/sys/kenv.h
--- a/sys/sys/kenv.h
+++ b/sys/sys/kenv.h
@@ -34,10 +34,12 @@
/*
* Constants for the kenv(2) syscall
*/
-#define KENV_GET 0
-#define KENV_SET 1
-#define KENV_UNSET 2
-#define KENV_DUMP 3
+#define KENV_GET 0
+#define KENV_SET 1
+#define KENV_UNSET 2
+#define KENV_DUMP 3
+#define KENV_DUMP_LOADER 4
+#define KENV_DUMP_STATIC 5
#define KENV_MNAMELEN 128 /* Maximum name length (for the syscall) */
#define KENV_MVALLEN 128 /* Maximum value length (for the syscall) */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Apr 21, 1:20 AM (15 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31876986
Default Alt Text
D30835.id.diff (9 KB)
Attached To
Mode
D30835: kenv: allow listing of static kernel environments
Attached
Detach File
Event Timeline
Log In to Comment