about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/modules/virtualisation/virtualbox-host.nix51
-rw-r--r--nixos/tests/virtualbox.nix47
-rw-r--r--pkgs/applications/virtualization/virtualbox/default.nix27
-rw-r--r--pkgs/top-level/all-packages.nix4
4 files changed, 110 insertions, 19 deletions
diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix
index 50a8f8189590..0ecf7f490cf6 100644
--- a/nixos/modules/virtualisation/virtualbox-host.nix
+++ b/nixos/modules/virtualisation/virtualbox-host.nix
@@ -6,7 +6,7 @@ let
   cfg = config.virtualisation.virtualbox.host;
 
   virtualbox = cfg.package.override {
-    inherit (cfg) enableHardening headless enableWebService;
+    inherit (cfg) enableHardening headless enableWebService enableKvm;
     extensionPack = if cfg.enableExtensionPack then pkgs.virtualboxExtpack else null;
   };
 
@@ -81,13 +81,24 @@ in
         Build VirtualBox web service tool (vboxwebsrv) to allow managing VMs via other webpage frontend tools. Useful for headless servers.
       '';
     };
+
+    enableKvm = mkOption {
+      type = types.bool;
+      default = false;
+      description = lib.mdDoc ''
+        Enable KVM support for VirtualBox. This increases compatibility with Linux kernel versions, because the VirtualBox kernel modules
+        are not required.
+
+        This option is incompatible with `enableHardening` and `addNetworkInterface`.
+
+        Note: This is experimental. Please check https://github.com/cyberus-technology/virtualbox-kvm/issues.
+      '';
+    };
   };
 
   config = mkIf cfg.enable (mkMerge [{
     warnings = mkIf (pkgs.config.virtualbox.enableExtensionPack or false)
       ["'nixpkgs.virtualbox.enableExtensionPack' has no effect, please use 'virtualisation.virtualbox.host.enableExtensionPack'"];
-    boot.kernelModules = [ "vboxdrv" "vboxnetadp" "vboxnetflt" ];
-    boot.extraModulePackages = [ kernelModules ];
     environment.systemPackages = [ virtualbox ];
 
     security.wrappers = let
@@ -114,17 +125,43 @@ in
 
     services.udev.extraRules =
       ''
-        KERNEL=="vboxdrv",    OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
-        KERNEL=="vboxdrvu",   OWNER="root", GROUP="root",      MODE="0666", TAG+="systemd"
-        KERNEL=="vboxnetctl", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
         SUBSYSTEM=="usb_device", ACTION=="add", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}"
         SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}"
         SUBSYSTEM=="usb_device", ACTION=="remove", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"
         SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"
       '';
+  } (mkIf cfg.enableKvm {
+    assertions = [
+      {
+        assertion = !cfg.addNetworkInterface;
+        message = "VirtualBox KVM only supports standard NAT networking for VMs. Please turn off virtualisation.virtualbox.host.addNetworkInferface.";
+      }
+
+      {
+        assertion = !cfg.enableHardening;
+        message = "VirtualBox KVM is not compatible with hardening: Please turn off virtualisation.virtualbox.host.enableHardening.";
+      }
+    ];
+
+    warnings = [
+      ''
+        KVM support in VirtualBox is experimental. Not all security features are available yet.
+        See: https://github.com/cyberus-technology/virtualbox-kvm/issues/12
+      ''
+    ];
+  }) (mkIf (!cfg.enableKvm) {
+    boot.kernelModules = [ "vboxdrv" "vboxnetadp" "vboxnetflt" ];
+    boot.extraModulePackages = [ kernelModules ];
+
+    services.udev.extraRules =
+      ''
+        KERNEL=="vboxdrv",    OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
+        KERNEL=="vboxdrvu",   OWNER="root", GROUP="root",      MODE="0666", TAG+="systemd"
+        KERNEL=="vboxnetctl", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
+     '';
 
     # Since we lack the right setuid/setcap binaries, set up a host-only network by default.
-  } (mkIf cfg.addNetworkInterface {
+  }) (mkIf cfg.addNetworkInterface {
     systemd.services.vboxnet0 =
       { description = "VirtualBox vboxnet0 Interface";
         requires = [ "dev-vboxnetctl.device" ];
diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix
index e522d0679e15..3c2a391233db 100644
--- a/nixos/tests/virtualbox.nix
+++ b/nixos/tests/virtualbox.nix
@@ -3,6 +3,7 @@
   pkgs ? import ../.. { inherit system config; },
   debug ? false,
   enableUnfree ? false,
+  enableKvm ? false,
   use64bitGuest ? true
 }:
 
@@ -340,7 +341,7 @@ let
     testExtensionPack.vmFlags = enableExtensionPackVMFlags;
   };
 
-  mkVBoxTest = useExtensionPack: vms: name: testScript: makeTest {
+  mkVBoxTest = vboxHostConfig: vms: name: testScript: makeTest {
     name = "virtualbox-${name}";
 
     nodes.machine = { lib, config, ... }: {
@@ -349,14 +350,23 @@ let
         vmConfigs = mapAttrsToList mkVMConf vms;
       in [ ./common/user-account.nix ./common/x11.nix ] ++ vmConfigs;
       virtualisation.memorySize = 2048;
-      virtualisation.qemu.options = ["-cpu" "kvm64,svm=on,vmx=on"];
-      virtualisation.virtualbox.host.enable = true;
+
+      virtualisation.qemu.options = let
+        # IvyBridge is reasonably ancient to be compatible with recent
+        # Intel/AMD hosts and sufficient for the KVM flavor.
+        guestCpu = if config.virtualisation.virtualbox.host.enableKvm then "IvyBridge" else "kvm64";
+      in ["-cpu" "${guestCpu},svm=on,vmx=on"];
+
       test-support.displayManager.auto.user = "alice";
       users.users.alice.extraGroups = let
         inherit (config.virtualisation.virtualbox.host) enableHardening;
-      in lib.mkIf enableHardening (lib.singleton "vboxusers");
-      virtualisation.virtualbox.host.enableExtensionPack = useExtensionPack;
-      nixpkgs.config.allowUnfree = useExtensionPack;
+      in lib.mkIf enableHardening [ "vboxusers" ];
+
+      virtualisation.virtualbox.host = {
+        enable = true;
+      } // vboxHostConfig;
+
+      nixpkgs.config.allowUnfree = config.virtualisation.virtualbox.host.enableExtensionPack;
     };
 
     testScript = ''
@@ -390,7 +400,7 @@ let
     };
   };
 
-  unfreeTests = mapAttrs (mkVBoxTest true vboxVMsWithExtpack) {
+  unfreeTests = mapAttrs (mkVBoxTest { enableExtensionPack = true; } vboxVMsWithExtpack) {
     enable-extension-pack = ''
       create_vm_testExtensionPack()
       vbm("startvm testExtensionPack")
@@ -409,7 +419,24 @@ let
     '';
   };
 
-in mapAttrs (mkVBoxTest false vboxVMs) {
+  kvmTests = mapAttrs (mkVBoxTest {
+    enableKvm = true;
+
+    # Once the KVM version supports these, we can enable them.
+    addNetworkInterface = false;
+    enableHardening = false;
+  } vboxVMs) {
+    kvm-headless = ''
+      create_vm_headless()
+      machine.succeed(ru("VBoxHeadless --startvm headless >&2 & disown %1"))
+      wait_for_startup_headless()
+      wait_for_vm_boot_headless()
+      shutdown_vm_headless()
+      destroy_vm_headless()
+    '';
+  };
+
+in mapAttrs (mkVBoxTest {} vboxVMs) {
   simple-gui = ''
     # Home to select Tools, down to move to the VM, enter to start it.
     def send_vm_startup():
@@ -519,4 +546,6 @@ in mapAttrs (mkVBoxTest false vboxVMs) {
     destroy_vm_test1()
     destroy_vm_test2()
   '';
-} // (optionalAttrs enableUnfree unfreeTests)
+}
+// (optionalAttrs enableKvm kvmTests)
+// (optionalAttrs enableUnfree unfreeTests)
diff --git a/pkgs/applications/virtualization/virtualbox/default.nix b/pkgs/applications/virtualization/virtualbox/default.nix
index ebea2b78f50d..f226a32596d3 100644
--- a/pkgs/applications/virtualization/virtualbox/default.nix
+++ b/pkgs/applications/virtualization/virtualbox/default.nix
@@ -17,9 +17,13 @@
 , headless ? false
 , enable32bitGuests ? true
 , enableWebService ? false
+, enableKvm ? false
 , extraConfigureFlags ? ""
 }:
 
+# See https://github.com/cyberus-technology/virtualbox-kvm/issues/12
+assert enableKvm -> !enableHardening;
+
 with lib;
 
 let
@@ -27,6 +31,10 @@ let
   # Use maintainers/scripts/update.nix to update the version and all related hashes or
   # change the hashes in extpack.nix and guest-additions/default.nix as well manually.
   version = "7.0.14";
+
+  # The KVM build is not compatible to VirtualBox's kernel modules. So don't export
+  # modsrc at all.
+  withModsrc = !enableKvm;
 in stdenv.mkDerivation {
   pname = "virtualbox";
   inherit version;
@@ -36,7 +44,7 @@ in stdenv.mkDerivation {
     sha256 = "45860d834804a24a163c1bb264a6b1cb802a5bc7ce7e01128072f8d6a4617ca9";
   };
 
-  outputs = [ "out" "modsrc" ];
+  outputs = [ "out" ] ++ optional withModsrc "modsrc";
 
   nativeBuildInputs = [ pkg-config which docbook_xsl docbook_xml_dtd_43 yasm glslang ]
     ++ optional (!headless) wrapQtAppsHook;
@@ -103,7 +111,17 @@ in stdenv.mkDerivation {
   ++ optional (!headless && enableHardening) (substituteAll {
       src = ./qt-env-vars.patch;
       qtPluginPath = "${qtbase.bin}/${qtbase.qtPluginPrefix}:${qtsvg.bin}/${qtbase.qtPluginPrefix}:${qtwayland.bin}/${qtbase.qtPluginPrefix}";
-    })
+  })
+     # While the KVM patch should not break any other behavior if --with-kvm is not specified,
+     # we don't take any chances and only apply it if people actually want to use KVM support.
+  ++ optional enableKvm (fetchpatch
+    (let
+      patchVersion = "20240226";
+    in {
+      name = "virtualbox-${version}-kvm-dev-${patchVersion}.patch";
+      url = "https://github.com/cyberus-technology/virtualbox-kvm/releases/download/dev-${patchVersion}/virtualbox-${version}-kvm-dev-${patchVersion}.patch";
+      hash = "sha256-3YT1ZN/TwoNWNb2eqOcPF8GTrVGfOPaPb8vpGoPNISY=";
+    }))
   ++ [
     ./qt-dependency-paths.patch
     # https://github.com/NixOS/nixpkgs/issues/123851
@@ -165,6 +183,7 @@ in stdenv.mkDerivation {
       ${optionalString (!enable32bitGuests) "--disable-vmmraw"} \
       ${optionalString enableWebService "--enable-webservice"} \
       ${optionalString (open-watcom-bin != null) "--with-ow-dir=${open-watcom-bin}"} \
+      ${optionalString (enableKvm) "--with-kvm"} \
       ${extraConfigureFlags} \
       --disable-kmods
     sed -e 's@PKG_CONFIG_PATH=.*@PKG_CONFIG_PATH=${libIDL}/lib/pkgconfig:${glib.dev}/lib/pkgconfig ${libIDL}/bin/libIDL-config-2@' \
@@ -224,7 +243,9 @@ in stdenv.mkDerivation {
       ln -sv $libexec/nls "$out/share/virtualbox"
     ''}
 
-    cp -rv out/linux.*/${buildType}/bin/src "$modsrc"
+    ${optionalString withModsrc ''
+      cp -rv out/linux.*/${buildType}/bin/src "$modsrc"
+    ''}
 
     mkdir -p "$out/share/virtualbox"
     cp -rv src/VBox/Main/UnattendedTemplates "$out/share/virtualbox"
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 5a5033fd9c80..601526b67083 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -35866,6 +35866,10 @@ with pkgs;
     inherit (gnome2) libIDL;
   };
 
+  virtualboxKvm = lowPrio (virtualbox.override {
+    enableKvm = true;
+  });
+
   virtualboxHardened = lowPrio (virtualbox.override {
     enableHardening = true;
   });