Page MenuHomeFreeBSD

D61163.1794469230.diff
No OneTemporary

Authored By
Unknown
Size
14 KB
Referenced Files
None
Subscribers
None

D61163.1794469230.diff

diff --git a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c
--- a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c
+++ b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c
@@ -57,6 +57,8 @@
#include "uart_emul.h"
static const struct config_option config_options_machdep[] = {
+ { "acpi_tables", CONFIG_OPTION_BOOL },
+ { "acpi_tables_in_memory", CONFIG_OPTION_BOOL },
{ "gdb.address", CONFIG_OPTION_STRING },
{ "gdb.port", CONFIG_OPTION_INTEGER },
{ "gdb.wait", CONFIG_OPTION_BOOL },
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -78,6 +78,7 @@
#include "bhyverun.h"
#include "bootrom.h"
#include "config.h"
+#include "config_schema.h"
#include "debug.h"
#ifdef BHYVE_GDB
#include "gdb.h"
@@ -869,6 +870,7 @@
#endif
bhyve_init_config();
+ set_config_path_validator(config_schema_path_valid);
bhyve_optparse(argc, argv);
argc -= optind;
argv += optind;
diff --git a/usr.sbin/bhyve/config.h b/usr.sbin/bhyve/config.h
--- a/usr.sbin/bhyve/config.h
+++ b/usr.sbin/bhyve/config.h
@@ -54,6 +54,12 @@
int walk_config_nodes(const char *, const nvlist_t *, void *,
int (*cb)(const char *, const nvlist_t *, const char *, int, void *));
+/*
+ * Installs a callback used to validate configuration variables fetched by
+ * bhyve. Raw lookups used to expand variable references are not validated.
+ */
+void set_config_path_validator(bool (*)(const char *));
+
/*
* Fetches the value of a configuration variable. If the "raw" value
* contains references to other configuration variables, this function
@@ -64,6 +70,8 @@
* If no node is found, returns NULL.
*
* If 'parent' is NULL, 'name' is assumed to be a top-level variable.
+ * Configuration consumers must use these accessors rather than reading
+ * string values directly from the backing nvlist so that reads are validated.
*/
const char *get_config_value_node(const nvlist_t *parent, const char *name);
diff --git a/usr.sbin/bhyve/config.c b/usr.sbin/bhyve/config.c
--- a/usr.sbin/bhyve/config.c
+++ b/usr.sbin/bhyve/config.c
@@ -27,6 +27,7 @@
*/
#include <sys/cdefs.h>
+#include <sys/queue.h>
#include <assert.h>
#include <err.h>
#include <stdio.h>
@@ -36,14 +37,90 @@
#include "config.h"
static nvlist_t *config_root;
+static bool (*config_path_validator)(const char *);
+
+struct config_node_path {
+ SLIST_ENTRY(config_node_path) link;
+ const nvlist_t *node;
+ char *path;
+};
+static SLIST_HEAD(, config_node_path) config_node_paths;
+
+static const char *
+config_node_path(const nvlist_t *node)
+{
+ struct config_node_path *entry;
+
+ SLIST_FOREACH(entry, &config_node_paths, link) {
+ if (entry->node == node)
+ return (entry->path);
+ }
+ return (NULL);
+}
+
+static void
+register_config_node(const nvlist_t *node, const char *path)
+{
+ struct config_node_path *entry;
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL)
+ err(4, "Failed to allocate memory");
+ entry->path = strdup(path);
+ if (entry->path == NULL)
+ err(4, "Failed to allocate memory");
+ entry->node = node;
+ SLIST_INSERT_HEAD(&config_node_paths, entry, link);
+}
+
+static void
+register_config_child(const nvlist_t *parent, const nvlist_t *child,
+ const char *name)
+{
+ const char *parent_path;
+ char *path;
+
+ parent_path = config_node_path(parent);
+ if (parent_path == NULL) {
+ if (config_path_validator != NULL)
+ errx(4,
+ "cannot register child of unregistered configuration node");
+ return;
+ }
+ if (*parent_path == '\0') {
+ if (asprintf(&path, "%s", name) == -1)
+ err(4, "Failed to allocate memory");
+ } else if (asprintf(&path, "%s.%s", parent_path, name) == -1)
+ err(4, "Failed to allocate memory");
+ register_config_node(child, path);
+ free(path);
+}
+
+void
+set_config_path_validator(bool (*validator)(const char *))
+{
+
+ config_path_validator = validator;
+}
+
+static void
+validate_config_path(const char *path)
+{
+
+ if (config_path_validator != NULL && !config_path_validator(path))
+ errx(4, "unsupported configuration variable '%s'", path);
+}
void
init_config(void)
{
+ SLIST_INIT(&config_node_paths);
+ config_path_validator = NULL;
config_root = nvlist_create(0);
if (config_root == NULL)
err(4, "Failed to create configuration root nvlist");
+ register_config_node(config_root, "");
}
static nvlist_t *
@@ -93,6 +170,7 @@
if (new_nvl == NULL)
errx(4, "Failed to allocate memory");
nvlist_move_nvlist(nvl, name, new_nvl);
+ register_config_child(nvl, new_nvl, name);
nvl = new_nvl;
} else {
nvl = NULL;
@@ -336,6 +414,7 @@
{
const char *value;
+ validate_config_path(path);
value = get_raw_config_value(path);
if (value == NULL)
return (NULL);
@@ -345,11 +424,26 @@
const char *
get_config_value_node(const nvlist_t *parent, const char *name)
{
+ const char *parent_path;
+ char *path;
if (strchr(name, '.') != NULL)
errx(4, "Invalid config node name %s", name);
if (parent == NULL)
parent = config_root;
+ if (config_path_validator != NULL) {
+ parent_path = config_node_path(parent);
+ if (parent_path == NULL)
+ errx(4,
+ "cannot validate unregistered configuration node");
+ if (*parent_path == '\0') {
+ if (asprintf(&path, "%s", name) == -1)
+ err(4, "Failed to allocate memory");
+ } else if (asprintf(&path, "%s.%s", parent_path, name) == -1)
+ err(4, "Failed to allocate memory");
+ validate_config_path(path);
+ free(path);
+ }
if (nvlist_exists_nvlist(parent, name))
warnx("Attempt to fetch value of node %s of list %p", name,
parent);
diff --git a/usr.sbin/bhyve/config_schema.h b/usr.sbin/bhyve/config_schema.h
--- a/usr.sbin/bhyve/config_schema.h
+++ b/usr.sbin/bhyve/config_schema.h
@@ -10,6 +10,8 @@
#include <sys/linker_set.h>
#include <sys/types.h>
+#include <stdbool.h>
+
enum config_option_type {
CONFIG_OPTION_BOOL,
CONFIG_OPTION_INTEGER,
@@ -35,6 +37,9 @@
void config_schema_merge_options(struct config_schema *, const char *,
const struct config_option *, size_t);
void config_schema_merge_options_machdep(struct config_schema *);
+/* Look up an exact option name or a concrete instance of a schema pattern. */
+bool config_schema_lookup(const char *, enum config_option_type *);
+bool config_schema_path_valid(const char *);
void print_config_options(void);
#endif /* !__CONFIG_SCHEMA_H__ */
diff --git a/usr.sbin/bhyve/config_schema.c b/usr.sbin/bhyve/config_schema.c
--- a/usr.sbin/bhyve/config_schema.c
+++ b/usr.sbin/bhyve/config_schema.c
@@ -8,6 +8,7 @@
#include <sys/param.h>
#include <sys/tree.h>
+#include <ctype.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
@@ -18,10 +19,13 @@
SET_DECLARE(config_option_set, struct config_option_set);
+#define CONFIG_OPTION_HIDDEN (1 << 0)
+
struct config_schema_option {
RB_ENTRY(config_schema_option) entry;
char *name;
enum config_option_type type;
+ unsigned int flags;
};
RB_HEAD(config_schema, config_schema_option);
@@ -107,6 +111,15 @@
{ "pci.B.S.F.slot.N.device", CONFIG_OPTION_STRING },
};
+static const struct config_option config_compat_options[] = {
+#ifdef __amd64__
+ { "lpc.bootrom", CONFIG_OPTION_STRING },
+ { "lpc.bootvars", CONFIG_OPTION_STRING },
+#endif
+ { "virtio_msix", CONFIG_OPTION_BOOL },
+ { "monitor", CONFIG_OPTION_BOOL },
+};
+
static const char *
config_option_type_name(enum config_option_type type)
{
@@ -122,9 +135,10 @@
errx(EX_SOFTWARE, "invalid configuration option type");
}
-void
-config_schema_merge_options(struct config_schema *schema, const char *prefix,
- const struct config_option *options, size_t count)
+static void
+config_schema_merge_options_flags(struct config_schema *schema,
+ const char *prefix, const struct config_option *options, size_t count,
+ unsigned int flags)
{
struct config_schema_option *existing, *option;
char *name;
@@ -140,6 +154,7 @@
err(EX_OSERR, "malloc");
option->name = name;
option->type = options[i].type;
+ option->flags = flags;
existing = RB_INSERT(config_schema, schema, option);
if (existing == NULL)
@@ -151,11 +166,24 @@
config_option_type_name(existing->type),
config_option_type_name(option->type));
}
+ if (existing->flags != option->flags) {
+ errx(EX_SOFTWARE,
+ "conflicting flags for configuration option '%s'",
+ option->name);
+ }
free(option->name);
free(option);
}
}
+void
+config_schema_merge_options(struct config_schema *schema, const char *prefix,
+ const struct config_option *options, size_t count)
+{
+
+ config_schema_merge_options_flags(schema, prefix, options, count, 0);
+}
+
static void
config_schema_merge_option_set(struct config_schema *schema,
const struct config_option_set *set, const char *inherited_prefix)
@@ -168,35 +196,115 @@
config_schema_merge_options(schema, prefix, set->options, set->count);
}
-static void
-config_schema_destroy(struct config_schema *schema)
+static struct config_schema *
+config_schema_get(void)
{
- struct config_schema_option *option, *tmp;
+ static struct config_schema schema;
+ static bool initialized;
+ struct config_option_set **setp;
- RB_FOREACH_SAFE(option, config_schema, schema, tmp) {
- RB_REMOVE(config_schema, schema, option);
- free(option->name);
- free(option);
+ if (!initialized) {
+ RB_INIT(&schema);
+ config_schema_merge_options(&schema, NULL, config_options,
+ nitems(config_options));
+ config_schema_merge_options_flags(&schema, NULL,
+ config_compat_options, nitems(config_compat_options),
+ CONFIG_OPTION_HIDDEN);
+ SET_FOREACH(setp, config_option_set) {
+ config_schema_merge_option_set(&schema, *setp, NULL);
+ }
+ config_schema_merge_options_machdep(&schema);
+ initialized = true;
+ }
+ return (&schema);
+}
+
+static bool
+config_schema_component_matches(const char *pattern, size_t pattern_len,
+ const char *value, size_t value_len)
+{
+ size_t i;
+
+ /* '*' matches one component; N, B, S, and F match decimal numbers. */
+ if (pattern_len == 1 && pattern[0] == '*')
+ return (value_len != 0);
+ if (pattern_len == 1 && strchr("NBSF", pattern[0]) != NULL) {
+ if (value_len == 0)
+ return (false);
+ for (i = 0; i < value_len; i++) {
+ if (!isdigit((unsigned char)value[i]))
+ return (false);
+ }
+ return (true);
+ }
+ return (pattern_len == value_len &&
+ strncmp(pattern, value, pattern_len) == 0);
+}
+
+static bool
+config_schema_path_matches(const char *pattern, const char *path)
+{
+ const char *pattern_end, *path_end;
+ size_t pattern_len, path_len;
+
+ for (;;) {
+ pattern_end = strchr(pattern, '.');
+ path_end = strchr(path, '.');
+ pattern_len = pattern_end != NULL ?
+ (size_t)(pattern_end - pattern) : strlen(pattern);
+ path_len = path_end != NULL ? (size_t)(path_end - path) :
+ strlen(path);
+ if (!config_schema_component_matches(pattern, pattern_len, path,
+ path_len))
+ return (false);
+ if (pattern_end == NULL || path_end == NULL)
+ return (pattern_end == NULL && path_end == NULL);
+ pattern = pattern_end + 1;
+ path = path_end + 1;
+ }
+}
+
+bool
+config_schema_lookup(const char *path, enum config_option_type *type)
+{
+ struct config_schema_option key, *option;
+ struct config_schema *schema;
+
+ schema = config_schema_get();
+ key.name = __DECONST(char *, path);
+ option = RB_FIND(config_schema, schema, &key);
+ if (option != NULL) {
+ if (type != NULL)
+ *type = option->type;
+ return (true);
+ }
+
+ RB_FOREACH(option, config_schema, schema) {
+ if (config_schema_path_matches(option->name, path)) {
+ if (type != NULL)
+ *type = option->type;
+ return (true);
+ }
}
+ return (false);
+}
+
+bool
+config_schema_path_valid(const char *path)
+{
+
+ return (config_schema_lookup(path, NULL));
}
void
print_config_options(void)
{
struct config_schema_option *option;
- struct config_option_set **setp;
- struct config_schema schema;
-
- RB_INIT(&schema);
- config_schema_merge_options(&schema, NULL, config_options,
- nitems(config_options));
- SET_FOREACH(setp, config_option_set) {
- config_schema_merge_option_set(&schema, *setp, NULL);
- }
- config_schema_merge_options_machdep(&schema);
+ struct config_schema *schema;
- RB_FOREACH(option, config_schema, &schema) {
- printf("%s\n", option->name);
+ schema = config_schema_get();
+ RB_FOREACH(option, config_schema, schema) {
+ if ((option->flags & CONFIG_OPTION_HIDDEN) == 0)
+ printf("%s\n", option->name);
}
- config_schema_destroy(&schema);
}
diff --git a/usr.sbin/bhyve/net_backend_slirp.c b/usr.sbin/bhyve/net_backend_slirp.c
--- a/usr.sbin/bhyve/net_backend_slirp.c
+++ b/usr.sbin/bhyve/net_backend_slirp.c
@@ -124,13 +124,7 @@
goto err;
}
- config = nvlist_clone(nvl);
- if (config == NULL) {
- EPRINTLN("nvlist_clone");
- goto err;
- }
-
- mtu_value = get_config_value_node(config, "mtu");
+ mtu_value = get_config_value_node(nvl, "mtu");
if (mtu_value != NULL) {
if (net_parsemtu(mtu_value, &mtu)) {
EPRINTLN("Could not parse MTU");
@@ -139,6 +133,12 @@
} else {
mtu = DEFAULT_MTU;
}
+
+ config = nvlist_clone(nvl);
+ if (config == NULL) {
+ EPRINTLN("nvlist_clone");
+ goto err;
+ }
nvlist_add_number(config, "mtui", mtu);
priv->mtu = mtu;
diff --git a/usr.sbin/bhyve/pci_virtio_scsi.c b/usr.sbin/bhyve/pci_virtio_scsi.c
--- a/usr.sbin/bhyve/pci_virtio_scsi.c
+++ b/usr.sbin/bhyve/pci_virtio_scsi.c
@@ -1230,7 +1230,8 @@
/*
* 'value' contains the backend path. Call the backend to open it.
*/
- value = nvlist_get_string(parent, name);
+ value = get_config_value_node(parent, name);
+ assert(value != NULL);
ret = sc->vss_backend->vsb_open(sc, value, target);
if (ret != 0)
EPRINTLN("cannot open target %lu at %s: %s", target, value,
diff --git a/usr.sbin/bhyve/riscv/bhyverun_machdep.c b/usr.sbin/bhyve/riscv/bhyverun_machdep.c
--- a/usr.sbin/bhyve/riscv/bhyverun_machdep.c
+++ b/usr.sbin/bhyve/riscv/bhyverun_machdep.c
@@ -60,6 +60,8 @@
#include "riscv.h"
static const struct config_option config_options_machdep[] = {
+ { "acpi_tables", CONFIG_OPTION_BOOL },
+ { "acpi_tables_in_memory", CONFIG_OPTION_BOOL },
{ "console", CONFIG_OPTION_STRING },
{ "fdt.bootargs", CONFIG_OPTION_STRING },
};
diff --git a/usr.sbin/bhyve/smbiostbl.c b/usr.sbin/bhyve/smbiostbl.c
--- a/usr.sbin/bhyve/smbiostbl.c
+++ b/usr.sbin/bhyve/smbiostbl.c
@@ -836,7 +836,7 @@
snprintf(keystr, sizeof(keystr), "%d", key);
if (nvlist_exists(node, keystr))
- vp = nvlist_get_string(node, keystr);
+ vp = get_config_value_node(node, keystr);
else
vp = na;
strings[key - 1].value = strdup(vp);

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 12, 7:40 AM (16 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41661158
Default Alt Text
D61163.1794469230.diff (14 KB)

Event Timeline