- Add support for the 'bhyve:///session' connection URL
   for running in unprivileged mode.
 - Use bhyve monitor mode ('-M') and a per-user runtime directory.
 - Require monitor mode and VM PID query support for session mode.
 - Use user configuration directories instead of system-wide directories.

Signed-off-by: Roman Bogorodskiy <[email protected]>
---
 src/bhyve/bhyve_command.c |  7 ++++++
 src/bhyve/bhyve_conf.c    | 42 ++++++++++++++++++++++++++---------
 src/bhyve/bhyve_conf.h    |  2 +-
 src/bhyve/bhyve_domain.c  |  9 +++++++-
 src/bhyve/bhyve_driver.c  | 46 ++++++++++++++++++++++++++-------------
 src/bhyve/bhyve_process.c |  2 +-
 src/bhyve/bhyve_utils.h   |  2 ++
 tests/bhyvexml2argvtest.c |  4 +++-
 tests/bhyvexml2xmltest.c  |  2 +-
 9 files changed, 86 insertions(+), 30 deletions(-)

diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c
index f0a87cffea..41c3767c3e 100644
--- a/src/bhyve/bhyve_command.c
+++ b/src/bhyve/bhyve_command.c
@@ -1100,6 +1100,13 @@ virBhyveProcessBuildBhyveCmd(struct _bhyveConn *driver, 
virDomainDef *def,
     unsigned nvcpus = virDomainDefGetVcpus(def);
     size_t ncells = virDomainNumaGetNodeCount(def->numa);
 
+    /* Monitor mode */
+    if (!driver->privileged) {
+        virCommandAddArg(cmd, "-M");
+        virCommandAddArg(cmd, "-o");
+        virCommandAddArgFormat(cmd, "rundir=%s", driver->config->stateDir);
+    }
+
     /* CPUs */
     virCommandAddArg(cmd, "-c");
     if (def->cpu && def->cpu->sockets) {
diff --git a/src/bhyve/bhyve_conf.c b/src/bhyve/bhyve_conf.c
index e0439af6fa..182dd24a60 100644
--- a/src/bhyve/bhyve_conf.c
+++ b/src/bhyve/bhyve_conf.c
@@ -25,6 +25,7 @@
 #include "viralloc.h"
 #include "virlog.h"
 #include "virstring.h"
+#include "virutil.h"
 #include "bhyve_conf.h"
 #include "bhyve_domain.h"
 #include "configmake.h"
@@ -47,7 +48,7 @@ static int virBhyveConfigOnceInit(void)
 VIR_ONCE_GLOBAL_INIT(virBhyveConfig);
 
 struct _virBhyveDriverConfig *
-virBhyveDriverConfigNew(void)
+virBhyveDriverConfigNew(bool privileged)
 {
     struct _virBhyveDriverConfig *cfg;
 
@@ -57,18 +58,39 @@ virBhyveDriverConfigNew(void)
     if (!(cfg = virObjectNew(virBhyveDriverConfigClass)))
         return NULL;
 
-    cfg->configBaseDir = g_strdup(SYSCONFDIR "/libvirt");
+    if (privileged) {
+        cfg->configBaseDir = g_strdup(SYSCONFDIR "/libvirt");
 
-    cfg->firmwareDir = g_strdup(DATADIR "/uefi-firmware");
-    cfg->libDir = g_strdup_printf("%s/lib/libvirt/bhyve", LOCALSTATEDIR);
-    cfg->nvramDir = g_strdup_printf("%s/nvram", cfg->libDir);
+        cfg->firmwareDir = g_strdup(DATADIR "/uefi-firmware");
+        cfg->libDir = g_strdup_printf("%s/lib/libvirt/bhyve", LOCALSTATEDIR);
+        cfg->nvramDir = g_strdup_printf("%s/nvram", cfg->libDir);
 
-    cfg->ubootPath = g_strdup(DATADIR "/u-boot/u-boot-bhyve-arm64/u-boot.bin");
+        cfg->ubootPath = g_strdup(DATADIR 
"/u-boot/u-boot-bhyve-arm64/u-boot.bin");
 
-    cfg->configDir = g_strdup_printf("%s/bhyve", cfg->configBaseDir);
-    cfg->autostartDir = g_strdup_printf("%s/bhyve/autostart", 
cfg->configBaseDir);
-    cfg->stateDir = g_strdup_printf("%s/libvirt/bhyve", RUNSTATEDIR);
-    cfg->logDir = g_strdup_printf("%s/log/libvirt/bhyve", LOCALSTATEDIR);
+        cfg->configDir = g_strdup_printf("%s/bhyve", cfg->configBaseDir);
+        cfg->autostartDir = g_strdup_printf("%s/bhyve/autostart", 
cfg->configBaseDir);
+        cfg->stateDir = g_strdup_printf("%s/libvirt/bhyve", RUNSTATEDIR);
+        cfg->logDir = g_strdup_printf("%s/log/libvirt/bhyve", LOCALSTATEDIR);
+    } else {
+        g_autofree char *rundir = NULL;
+        g_autofree char *cachedir = NULL;
+
+        cfg->configBaseDir = virGetUserConfigDirectory();
+
+        cachedir = virGetUserCacheDirectory();
+        rundir = virGetUserRuntimeDirectory();
+
+        cfg->firmwareDir = g_strdup(DATADIR "/uefi-firmware");
+        cfg->libDir = g_strdup_printf("%s/bhyve/lib", cfg->configBaseDir);
+        cfg->nvramDir = g_strdup_printf("%s/bhyve/nvram", cfg->configBaseDir);
+
+        cfg->ubootPath = g_strdup(DATADIR 
"/u-boot/u-boot-bhyve-arm64/u-boot.bin");
+
+        cfg->configDir = g_strdup_printf("%s/bhyve", cfg->configBaseDir);
+        cfg->autostartDir = g_strdup_printf("%s/bhyve/autostart", 
cfg->configBaseDir);
+        cfg->stateDir = g_strdup_printf("%s/bhyve/run", rundir);
+        cfg->logDir = g_strdup_printf("%s/bhyve/log", cachedir);
+    }
 
     cfg->bhyveloadTimeout = 300;
     cfg->bhyveloadTimeoutKill = 15;
diff --git a/src/bhyve/bhyve_conf.h b/src/bhyve/bhyve_conf.h
index d895f66bb7..70c6b1f6ed 100644
--- a/src/bhyve/bhyve_conf.h
+++ b/src/bhyve/bhyve_conf.h
@@ -23,7 +23,7 @@
 
 #include "bhyve_utils.h"
 
-struct _virBhyveDriverConfig *virBhyveDriverConfigNew(void);
+struct _virBhyveDriverConfig *virBhyveDriverConfigNew(bool privileged);
 struct _virBhyveDriverConfig *virBhyveDriverGetConfig(struct _bhyveConn 
*driver);
 int virBhyveLoadDriverConfig(struct _virBhyveDriverConfig *cfg,
                              const char *filename);
diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c
index 3588557979..2513573e98 100644
--- a/src/bhyve/bhyve_domain.c
+++ b/src/bhyve/bhyve_domain.c
@@ -555,9 +555,10 @@ bhyveValidateDomainLifecycleAction(const virDomainDef *def)
 
 static int
 bhyveDomainDefValidate(const virDomainDef *def,
-                       void *opaque G_GNUC_UNUSED,
+                       void *opaque,
                        void *parseOpaque G_GNUC_UNUSED)
 {
+    struct _bhyveConn *driver = opaque;
     size_t i;
     size_t ncells;
     virStorageSource *src = NULL;
@@ -640,6 +641,12 @@ bhyveDomainDefValidate(const virDomainDef *def,
             return -1;
     }
 
+    if (!driver->privileged && !def->os.loader) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("only UEFI boot is supported in unprivileged mode"));
+        return -1;
+    }
+
     if (bhyveValidateDomainLifecycleAction(def) < 0)
         return -1;
 
diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c
index 7e8cc572e4..f48543e205 100644
--- a/src/bhyve/bhyve_driver.c
+++ b/src/bhyve/bhyve_driver.c
@@ -211,7 +211,8 @@ bhyveConnectURIProbe(char **uri)
     if (bhyve_driver == NULL)
         return 0;
 
-    *uri = g_strdup("bhyve:///system");
+    *uri = g_strdup(bhyve_driver->privileged ?
+                    "bhyve:///system" : "bhyve:///session");
     return 1;
 }
 
@@ -224,19 +225,17 @@ bhyveConnectOpen(virConnectPtr conn,
 {
     virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
 
-    if (STRNEQ(conn->uri->path, "/system")) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Unexpected bhyve URI path '%1$s', try 
bhyve:///system"),
-                       conn->uri->path);
-        return VIR_DRV_OPEN_ERROR;
-    }
-
     if (bhyve_driver == NULL) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("bhyve state driver is not active"));
         return VIR_DRV_OPEN_ERROR;
     }
 
+    if (!virConnectValidateURIPath(conn->uri->path,
+                                   "bhyve",
+                                   bhyve_driver->privileged))
+        return VIR_DRV_OPEN_ERROR;
+
     if (virConnectOpenEnsureACL(conn) < 0)
         return VIR_DRV_OPEN_ERROR;
 
@@ -1398,6 +1397,7 @@ bhyveStateInitialize(bool privileged,
                      void *opaque G_GNUC_UNUSED)
 {
     virDomainDriverAutoStartConfig autostartCfg;
+    g_autofree char *configFile = NULL;
     virBhyveDriverConfig *cfg;
 
     if (root != NULL) {
@@ -1406,13 +1406,9 @@ bhyveStateInitialize(bool privileged,
         return -1;
     }
 
-    if (!privileged) {
-        VIR_INFO("Not running privileged, disabling driver");
-        return VIR_DRV_STATE_INIT_SKIPPED;
-    }
-
     bhyve_driver = g_new0(bhyveConn, 1);
 
+    bhyve_driver->privileged = privileged;
     bhyve_driver->lockFD = -1;
     if (virMutexInit(&bhyve_driver->lock) < 0) {
         VIR_FREE(bhyve_driver);
@@ -1425,6 +1421,18 @@ bhyveStateInitialize(bool privileged,
     if (virBhyveProbeCaps(&bhyve_driver->bhyvecaps) < 0)
         goto cleanup;
 
+    if (!privileged && !(bhyveDriverGetBhyveCaps(bhyve_driver) & 
BHYVE_CAP_MONITOR)) {
+        virReportError(VIR_ERR_INVALID_ARG, "%s",
+                       _("bhyve does not support monitor mode, cannot run 
unprivileged"));
+        goto cleanup;
+    }
+
+    if (!privileged && !(bhyveDriverGetBhyveCaps(bhyve_driver) & 
BHYVE_CAP_GET_VMPID)) {
+        virReportError(VIR_ERR_INVALID_ARG, "%s",
+                       _("bhyvectl does not support querying the VM PID, 
cannot run unprivileged"));
+        goto cleanup;
+    }
+
     if (virBhyveProbeGrubCaps(&bhyve_driver->grubcaps) < 0)
         goto cleanup;
 
@@ -1443,10 +1451,11 @@ bhyveStateInitialize(bool privileged,
 
     bhyve_driver->hostsysinfo = virSysinfoRead();
 
-    if (!(bhyve_driver->config = cfg = virBhyveDriverConfigNew()))
+    if (!(bhyve_driver->config = cfg = virBhyveDriverConfigNew(privileged)))
         goto cleanup;
 
-    if (virBhyveLoadDriverConfig(bhyve_driver->config, SYSCONFDIR 
"/libvirt/bhyve.conf") < 0)
+    configFile = g_build_filename(cfg->configBaseDir, "bhyve.conf", NULL);
+    if (virBhyveLoadDriverConfig(cfg, configFile) < 0)
         goto cleanup;
 
     if (g_mkdir_with_parents(cfg->logDir, 0777) < 0) {
@@ -1463,6 +1472,13 @@ bhyveStateInitialize(bool privileged,
         goto cleanup;
     }
 
+    if (g_mkdir_with_parents(cfg->nvramDir, 0777) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to mkdir %1$s"),
+                             cfg->nvramDir);
+        goto cleanup;
+    }
+
     if ((bhyve_driver->lockFD =
          virPidFileAcquire(cfg->stateDir, "driver", getpid())) < 0)
         goto cleanup;
diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c
index 4144f8230e..c42d9ec092 100644
--- a/src/bhyve/bhyve_process.c
+++ b/src/bhyve/bhyve_process.c
@@ -537,7 +537,7 @@ bhyvePrepareNVRAMFile(bhyveConn *driver G_GNUC_UNUSED,
 
     if (virFileRewrite(loader->nvram->path,
                        S_IRUSR | S_IWUSR,
-                       0, 0,
+                       -1, -1,
                        bhyvePrepareNVRAMHelper,
                        &data) < 0) {
         return -1;
diff --git a/src/bhyve/bhyve_utils.h b/src/bhyve/bhyve_utils.h
index 5d04b42195..8a6ca25b47 100644
--- a/src/bhyve/bhyve_utils.h
+++ b/src/bhyve/bhyve_utils.h
@@ -70,6 +70,8 @@ struct _bhyveConn {
 
     unsigned bhyvecaps;
     unsigned grubcaps;
+
+    bool privileged;
 };
 
 typedef struct _bhyveConn bhyveConn;
diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c
index 95969a641b..06af9dec8a 100644
--- a/tests/bhyvexml2argvtest.c
+++ b/tests/bhyvexml2argvtest.c
@@ -162,7 +162,7 @@ mymain(void)
     if (!(driver.remotePorts = virPortAllocatorRangeNew("display", 5900, 
65535)))
         return EXIT_FAILURE;
 
-    if (!(driver.config = virBhyveDriverConfigNew()))
+    if (!(driver.config = virBhyveDriverConfigNew(true)))
         return EXIT_FAILURE;
 
     VIR_FREE(driver.config->firmwareDir);
@@ -174,6 +174,8 @@ mymain(void)
     driver.config->bhyveloadTimeout = 0;
     driver.config->bhyveloadTimeoutKill = 0;
 
+    driver.privileged = true;
+
 # define DO_TEST_FULL(name, flags) \
     do { \
         static struct testInfo info = { \
diff --git a/tests/bhyvexml2xmltest.c b/tests/bhyvexml2xmltest.c
index 336278ce1c..92710b3f0f 100644
--- a/tests/bhyvexml2xmltest.c
+++ b/tests/bhyvexml2xmltest.c
@@ -67,7 +67,7 @@ mymain(void)
     if ((driver.xmlopt = virBhyveDriverCreateXMLConf(&driver)) == NULL)
         return EXIT_FAILURE;
 
-    if (!(driver.config = virBhyveDriverConfigNew()))
+    if (!(driver.config = virBhyveDriverConfigNew(true)))
         return EXIT_FAILURE;
 
     VIR_FREE(driver.config->firmwareDir);
-- 
2.55.0

Reply via email to