git: ed7e0ebfa20e - main - bhyve: allow overriding snapshot socket directory

From: Roman Bogorodskiy <novel_at_FreeBSD.org>
Date: Wed, 08 Jul 2026 16:16:18 UTC
The branch main has been updated by novel:

URL: https://cgit.FreeBSD.org/src/commit/?id=ed7e0ebfa20e7e798d2e4e20623d452f1c715aa5

commit ed7e0ebfa20e7e798d2e4e20623d452f1c715aa5
Author:     Roman Bogorodskiy <novel@FreeBSD.org>
AuthorDate: 2026-06-07 07:31:30 +0000
Commit:     Roman Bogorodskiy <novel@FreeBSD.org>
CommitDate: 2026-07-08 16:10:14 +0000

    bhyve: allow overriding snapshot socket directory
    
    By default bhyve(8) creates a snapshot socket in
    "/var/run/bhyve/" (BHYVE_RUN_DIR).
    As this is a system directory not writable by users,
    this does not work when bhyve(8) is being started
    as a non-root user.
    
    Address that by allowing to override this directory.
    In bhyve(8) it is done by setting 'rundir' option
    with '-o rundir=<path>'.
    
    In bhyvectl(8) it is done with '--rundir=<path>'.
    
    MFC after:              1 month
    Reviewed by:            bcr (manpages), bnovkov
    Sponsored by:           The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D57494
---
 usr.sbin/bhyve/amd64/bhyverun_machdep.c |  6 ++++++
 usr.sbin/bhyve/bhyve_config.5           |  9 ++++++++-
 usr.sbin/bhyve/bhyverun.c               |  2 +-
 usr.sbin/bhyve/snapshot.c               | 14 ++++++++++----
 usr.sbin/bhyve/snapshot.h               |  2 +-
 usr.sbin/bhyvectl/bhyvectl.8            |  8 +++++++-
 usr.sbin/bhyvectl/bhyvectl.c            | 32 +++++++++++++++++++++++++-------
 7 files changed, 58 insertions(+), 15 deletions(-)

diff --git a/usr.sbin/bhyve/amd64/bhyverun_machdep.c b/usr.sbin/bhyve/amd64/bhyverun_machdep.c
index 98a756551272..2c8f825b4a7c 100644
--- a/usr.sbin/bhyve/amd64/bhyverun_machdep.c
+++ b/usr.sbin/bhyve/amd64/bhyverun_machdep.c
@@ -37,6 +37,9 @@
 #include "acpi.h"
 #include "atkbdc.h"
 #include "bhyverun.h"
+#ifdef BHYVE_SNAPSHOT
+#include "snapshot.h"
+#endif
 #include "bootrom.h"
 #include "config.h"
 #include "debug.h"
@@ -65,6 +68,9 @@ bhyve_init_config(void)
 	set_config_bool("x86.strictmsr", true);
 	set_config_bool("x86.verbosemsr", false);
 	set_config_value("lpc.fwcfg", "bhyve");
+#ifdef BHYVE_SNAPSHOT
+	set_config_value("rundir", BHYVE_RUN_DIR);
+#endif
 }
 
 void
diff --git a/usr.sbin/bhyve/bhyve_config.5 b/usr.sbin/bhyve/bhyve_config.5
index 8bfe9afd0b24..dd82bea61d20 100644
--- a/usr.sbin/bhyve/bhyve_config.5
+++ b/usr.sbin/bhyve/bhyve_config.5
@@ -24,7 +24,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd December 26, 2025
+.Dd July 8, 2026
 .Dt BHYVE_CONFIG 5
 .Os
 .Sh NAME
@@ -226,6 +226,13 @@ This value is used for the guest's System Management BIOS System Information str
 Stock keeping unit of the chassis.
 It's also called product ID or purchase order number.
 This value is used for the guest's System Management BIOS System Information structure.
+.It Va rundir Ta String Ta Pa /var/run/bhyve/ Ta
+Path to the runtime directory for
+.Xr bhyve 8
+to store its service files, such as the checkpoint socket.
+Overriding this path is useful when running
+.Xr bhyve 8
+as an unprivileged user.
 .El
 .Ss x86-Specific Settings
 .Bl -column "x86.vmexit_on_pause" "integer" "Default"
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index 8cbc19fcfef8..ace631594544 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -1068,7 +1068,7 @@ main(int argc, char *argv[])
 	/*
 	 * checkpointing thread for communication with bhyvectl
 	 */
-	if (init_checkpoint_thread(ctx) != 0)
+	if (init_checkpoint_thread(ctx, get_config_value("rundir")) != 0)
 		errx(EX_OSERR, "Failed to start checkpoint thread");
 #endif
 
diff --git a/usr.sbin/bhyve/snapshot.c b/usr.sbin/bhyve/snapshot.c
index 5b941984c0c0..fdb5941bf1d0 100644
--- a/usr.sbin/bhyve/snapshot.c
+++ b/usr.sbin/bhyve/snapshot.c
@@ -1399,13 +1399,13 @@ IPC_COMMAND(ipc_cmd_set, checkpoint, vm_do_checkpoint);
  * Create the listening socket for IPC with bhyvectl
  */
 int
-init_checkpoint_thread(struct vmctx *ctx)
+init_checkpoint_thread(struct vmctx *ctx, const char *bhyve_run_dir)
 {
 	struct checkpoint_thread_info *checkpoint_info = NULL;
 	struct sockaddr_un addr;
 	int socket_fd;
 	pthread_t checkpoint_pthread;
-	int err;
+	int err, ret;
 #ifndef WITHOUT_CAPSICUM
 	cap_rights_t rights;
 #endif
@@ -1421,8 +1421,14 @@ init_checkpoint_thread(struct vmctx *ctx)
 
 	addr.sun_family = AF_UNIX;
 
-	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s%s",
-		 BHYVE_RUN_DIR, vm_get_name(ctx));
+	ret = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+	    bhyve_run_dir, vm_get_name(ctx));
+	if ((ret < 0) || ((size_t)ret >= sizeof(addr.sun_path))) {
+		EPRINTLN("%s: error setting socket path (%d)", __func__, ret);
+		err = -1;
+		goto fail;
+	}
+
 	addr.sun_len = SUN_LEN(&addr);
 	unlink(addr.sun_path);
 
diff --git a/usr.sbin/bhyve/snapshot.h b/usr.sbin/bhyve/snapshot.h
index 8bebdafd6117..5c71640f3f09 100644
--- a/usr.sbin/bhyve/snapshot.h
+++ b/usr.sbin/bhyve/snapshot.h
@@ -99,7 +99,7 @@ int vm_resume_devices(void);
 
 int get_checkpoint_msg(int conn_fd, struct vmctx *ctx);
 void *checkpoint_thread(void *param);
-int init_checkpoint_thread(struct vmctx *ctx);
+int init_checkpoint_thread(struct vmctx *ctx, const char *bhyve_run_dir);
 
 int load_restore_file(const char *filename, struct restore_state *rstate);
 
diff --git a/usr.sbin/bhyvectl/bhyvectl.8 b/usr.sbin/bhyvectl/bhyvectl.8
index 550c4f10d8e6..b999230cfd73 100644
--- a/usr.sbin/bhyvectl/bhyvectl.8
+++ b/usr.sbin/bhyvectl/bhyvectl.8
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd May 8, 2025
+.Dd July 8, 2026
 .Dt BHYVECTL 8
 .Os
 .Sh NAME
@@ -41,6 +41,7 @@
 .Op Fl -force-reset
 .Op Fl -force-poweroff
 .Op Fl -checkpoint= Ns Ar <file>
+.Op Fl -rundir= Ns Ar <path>
 .Op Fl -suspend= Ns Ar <file>
 .Sh DESCRIPTION
 The
@@ -77,6 +78,11 @@ Save a snapshot of a virtual machine similar to
 .Fl -checkpoint .
 The virtual machine will terminate after the snapshot has been
 saved.
+.It Fl -rundir= Ns Ar <path>
+Specify path to the directory containing the checkpoint socket.
+If not specified,
+.Pa /var/run/bhyve
+is used.
 .El
 .Pp
 .Em Note :
diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c
index 96768383d4ca..b63cd5dc8c6e 100644
--- a/usr.sbin/bhyvectl/bhyvectl.c
+++ b/usr.sbin/bhyvectl/bhyvectl.c
@@ -86,6 +86,7 @@ enum {
 #ifdef BHYVE_SNAPSHOT
 	SET_CHECKPOINT_FILE,
 	SET_SUSPEND_FILE,
+	SET_RUNDIR,
 #endif
 	OPT_LAST,
 };
@@ -138,6 +139,7 @@ setup_options(void)
 #ifdef BHYVE_SNAPSHOT
 		{ "checkpoint", 	REQ_ARG, 0,	SET_CHECKPOINT_FILE},
 		{ "suspend", 		REQ_ARG, 0,	SET_SUSPEND_FILE},
+		{ "rundir", 		REQ_ARG, 0,	SET_RUNDIR},
 #endif
 	};
 
@@ -155,6 +157,7 @@ usage(const struct option *opts)
 #ifdef BHYVE_SNAPSHOT
 	    [SET_CHECKPOINT_FILE] = "filename",
 	    [SET_SUSPEND_FILE] = "filename",
+	    [SET_RUNDIR] = "path",
 #endif
 	};
 	(void)fprintf(stderr, "Usage: %s --vm=<vmname>\n", progname);
@@ -252,10 +255,10 @@ show_memseg(struct vmctx *ctx)
 
 #ifdef BHYVE_SNAPSHOT
 static int
-send_message(const char *vmname, nvlist_t *nvl)
+send_message(const char *vmname, nvlist_t *nvl, const char *rundir)
 {
 	struct sockaddr_un addr;
-	int err = 0, socket_fd;
+	int err = 0, ret, socket_fd;
 
 	socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
 	if (socket_fd < 0) {
@@ -265,8 +268,15 @@ send_message(const char *vmname, nvlist_t *nvl)
 	}
 
 	memset(&addr, 0, sizeof(struct sockaddr_un));
-	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s%s",
-	    BHYVE_RUN_DIR, vmname);
+	ret = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+	    rundir, vmname);
+	if ((ret < 0) || ((size_t)ret >= sizeof(addr.sun_path))) {
+		fprintf(stderr, "%s: error setting socket path (%d)",
+		    __func__, ret);
+		err = 1;
+		goto done;
+	}
+
 	addr.sun_family = AF_UNIX;
 	addr.sun_len = SUN_LEN(&addr);
 
@@ -305,7 +315,7 @@ open_directory(const char *file)
 }
 
 static int
-snapshot_request(const char *vmname, char *file, bool suspend)
+snapshot_request(const char *vmname, char *file, bool suspend, const char *rundir)
 {
 	nvlist_t *nvl;
 	int fd;
@@ -319,7 +329,7 @@ snapshot_request(const char *vmname, char *file, bool suspend)
 	nvlist_add_bool(nvl, "suspend", suspend);
 	nvlist_move_descriptor(nvl, "fddir", fd);
 
-	return (send_message(vmname, nvl));
+	return (send_message(vmname, nvl, rundir));
 }
 #endif
 
@@ -335,6 +345,7 @@ main(int argc, char *argv[])
 	struct option *opts;
 #ifdef BHYVE_SNAPSHOT
 	char *checkpoint_file = NULL;
+	char *rundir = NULL;
 #endif
 
 	opts = setup_options();
@@ -379,6 +390,11 @@ main(int argc, char *argv[])
 			checkpoint_file = optarg;
 			vm_suspend_opt = (ch == SET_SUSPEND_FILE);
 			break;
+
+		case SET_RUNDIR:
+			rundir = optarg;
+			break;
+
 #endif
 		default:
 			usage(opts);
@@ -528,7 +544,9 @@ main(int argc, char *argv[])
 
 #ifdef BHYVE_SNAPSHOT
 	if (!error && checkpoint_file)
-		error = snapshot_request(vmname, checkpoint_file, vm_suspend_opt);
+		error = snapshot_request(vmname, checkpoint_file,
+				vm_suspend_opt,
+				rundir ? rundir : BHYVE_RUN_DIR);
 #endif
 
 	if (error)