git: a371b008d13f - main - Add boot_setenv
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 07 Apr 2026 16:30:00 UTC
The branch main has been updated by sjg:
URL: https://cgit.FreeBSD.org/src/commit/?id=a371b008d13f84cf4448bf6d700641ecc15c206b
commit a371b008d13f84cf4448bf6d700641ecc15c206b
Author: Simon J. Gerraty <sjg@FreeBSD.org>
AuthorDate: 2026-04-07 16:29:07 +0000
Commit: Simon J. Gerraty <sjg@FreeBSD.org>
CommitDate: 2026-04-07 16:29:07 +0000
Add boot_setenv
Move is_restricted_var() to libsa/environment.c so it can be leveraged
by boot_setenv called from subr_boot with not truted input.
Also, allow for local tuning via ENV_IS_RESTRICTED_ALLOWED_LIST and
ENV_IS_RESTRICTED_LIST
Sponsored by: Hewlett Packard Enterprise Development LP.
Reviewed by: kevans, imp
Differential Revision: https://reviews.freebsd.org/D56287
---
stand/common/commands.c | 60 ++-----------------------------------
stand/efi/loader/main.c | 5 ++++
stand/libsa/environment.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++
stand/libsa/stand.h | 3 ++
sys/kern/subr_boot.c | 2 +-
5 files changed, 88 insertions(+), 58 deletions(-)
diff --git a/stand/common/commands.c b/stand/common/commands.c
index 19452047a0ca..41687ece42fd 100644
--- a/stand/common/commands.c
+++ b/stand/common/commands.c
@@ -291,63 +291,6 @@ command_show(int argc, char *argv[])
return (CMD_OK);
}
-#ifdef LOADER_VERIEXEC
-static int
-is_restricted_var(const char *var)
-{
- /*
- * We impose restrictions if input is not verified
- * allowing for exceptions.
- * These entries should include the '='
- */
- const char *allowed[] = {
- "boot_function=",
- "boot_phase=",
- "boot_recover_cli=",
- "boot_recover_volume=",
- "boot_safe=",
- "boot_set=",
- "boot_single=",
- "boot_verbose=",
- NULL,
- };
- const char *restricted[] = {
- "boot",
- "init",
- "loader.ve.",
- "rootfs",
- "secur",
- "vfs.",
- NULL,
- };
- const char **cp;
- int ok = -1;
-
-#ifdef LOADER_VERIEXEC_TESTING
- printf("Checking: %s\n", var);
-#endif
- for (cp = restricted; *cp; cp++) {
- if (strncmp(var, *cp, strlen(*cp)) == 0) {
- ok = 0;
- break;
- }
- }
- if (!ok) {
- /*
- * Check for exceptions.
- * These should match up to '='.
- */
- for (cp = allowed; *cp; cp++) {
- if (strncmp(var, *cp, strlen(*cp)) == 0) {
- ok = 1;
- break;
- }
- }
- }
- return (ok == 0);
-}
-#endif
-
COMMAND_SET(set, "set", "set a variable", command_set);
static int
@@ -364,6 +307,9 @@ command_set(int argc, char *argv[])
ves = ve_status_get(-1);
if (ves == VE_UNVERIFIED_OK) {
+#ifdef LOADER_VERIEXEC_TESTING
+ printf("Checking: %s\n", var);
+#endif
if (is_restricted_var(argv[1])) {
printf("Ignoring restricted variable: %s\n",
argv[1]);
diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c
index 1fd6c8d74195..e54f3e1f9f35 100644
--- a/stand/efi/loader/main.c
+++ b/stand/efi/loader/main.c
@@ -1242,6 +1242,11 @@ main(int argc, CHAR16 *argv[])
/* Report the RSDP early. */
acpi_detect();
+#ifdef LOADER_VERIEXEC
+ /* tell boot_setenv to be careful */
+ set_check_restricted(true);
+#endif
+
/*
* Chicken-and-egg problem; we want to have console output early, but
* some console attributes may depend on reading from eg. the boot
diff --git a/stand/libsa/environment.c b/stand/libsa/environment.c
index d139249a8e84..3882db6ee9e1 100644
--- a/stand/libsa/environment.c
+++ b/stand/libsa/environment.c
@@ -222,6 +222,82 @@ env_noset(struct env_var *ev __unused, int flags __unused,
return (EPERM);
}
+bool
+is_restricted_var(const char *name)
+{
+ /*
+ * We impose restrictions if input is not verified/trusted
+ * allowing for exceptions.
+ * These entries should probably include the '='
+ */
+ const char *allowed[] = {
+ "boot_function=",
+ "boot_phase=",
+ "boot_recover_cli=",
+ "boot_recover_volume=",
+ "boot_safe=",
+ "boot_set=",
+ "boot_single=",
+ "boot_verbose=",
+#ifdef ENV_IS_RESTRICTED_ALLOWED_LIST
+ ENV_IS_RESTRICTED_ALLOWED_LIST,
+#endif
+ NULL,
+ };
+ /*
+ * These are prefixes we want to be careful with.
+ */
+ const char *restricted[] = {
+ "boot",
+ "init",
+ "loader.ve.",
+ "rootfs",
+ "secur",
+ "vfs.",
+#ifdef ENV_IS_RESTRICTED_LIST
+ ENV_IS_RESTRICTED_LIST,
+#endif
+ NULL,
+ };
+ const char **cp;
+ int ok = -1;
+
+ for (cp = restricted; *cp; cp++) {
+ if (strncmp(name, *cp, strlen(*cp)) == 0) {
+ ok = 0;
+ break;
+ }
+ }
+ if (!ok) {
+ for (cp = allowed; *cp; cp++) {
+ if (strncmp(name, *cp, strlen(*cp)) == 0) {
+ ok = 1;
+ break;
+ }
+ }
+ }
+ return (ok == 0);
+}
+
+static bool check_restricted = false;
+
+void
+set_check_restricted(bool b)
+{
+ check_restricted = b;
+}
+
+/* called from subr_boot with not quite trusted input */
+int
+boot_setenv(const char *name, const char *value)
+{
+ if (check_restricted && is_restricted_var(name)) {
+ errno = EPERM;
+ return -1;
+ }
+ return setenv(name, value, 1);
+}
+
int
env_nounset(struct env_var *ev __unused)
{
diff --git a/stand/libsa/stand.h b/stand/libsa/stand.h
index aaba0aa7fb39..4f7f21867cea 100644
--- a/stand/libsa/stand.h
+++ b/stand/libsa/stand.h
@@ -381,6 +381,9 @@ extern int setenv(const char *name, const char *value,
int overwrite);
extern int putenv(char *string);
extern int unsetenv(const char *name);
+extern bool is_restricted_var(const char *name);
+extern void set_check_restricted(bool);
+extern int boot_setenv(const char *name, const char *value);
extern ev_sethook_t env_noset; /* refuse set operation */
extern ev_unsethook_t env_nounset; /* refuse unset operation */
diff --git a/sys/kern/subr_boot.c b/sys/kern/subr_boot.c
index b721abf7013c..00c8e66617b8 100644
--- a/sys/kern/subr_boot.c
+++ b/sys/kern/subr_boot.c
@@ -53,7 +53,7 @@
#define GETENV(k) kern_getenv(k)
#define FREE(v) freeenv(v)
#else /* Boot loader */
-#define SETENV(k, v) setenv(k, v, 1)
+#define SETENV(k, v) boot_setenv(k, v)
#define GETENV(k) getenv(k)
#define FREE(v)
#endif