From 7dd125e9a0da6f5cdf10e58206bbeb4e1d356dd6 Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Thu, 8 Feb 2024 20:19:41 +0100 Subject: [PATCH 1/5] virtualboxKvm: init at 20240226 --- .../virtualization/virtualbox/default.nix | 26 ++++++++++++++++--- pkgs/top-level/all-packages.nix | 4 +++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/pkgs/applications/virtualization/virtualbox/default.nix b/pkgs/applications/virtualization/virtualbox/default.nix index 948a8da2da7b..a52a3cec15e5 100644 --- a/pkgs/applications/virtualization/virtualbox/default.nix +++ b/pkgs/applications/virtualization/virtualbox/default.nix @@ -1,4 +1,4 @@ -{ config, stdenv, fetchurl, lib, acpica-tools, dev86, pam, libxslt, libxml2, wrapQtAppsHook +{ config, stdenv, fetchurl, fetchpatch, lib, acpica-tools, dev86, pam, libxslt, libxml2, wrapQtAppsHook , libX11, xorgproto, libXext, libXcursor, libXmu, libIDL, SDL2, libcap, libGL, libGLU , libpng, glib, lvm2, libXrandr, libXinerama, libopus, libtpms, qtbase, qtx11extras , qttools, qtsvg, qtwayland, pkg-config, which, docbook_xsl, docbook_xml_dtd_43 @@ -17,6 +17,7 @@ , headless ? false , enable32bitGuests ? true , enableWebService ? false +, enableKvm ? false , extraConfigureFlags ? "" }: @@ -27,6 +28,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 +41,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; @@ -97,7 +102,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 @@ -159,6 +174,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@' \ @@ -218,7 +234,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 47143e74f4ad..d8451bd1923e 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -35924,6 +35924,10 @@ with pkgs; inherit (gnome2) libIDL; }); + virtualboxKvm = lowPrio (virtualbox.override { + enableKvm = true; + }); + virtualboxHardened = lowPrio (virtualbox.override { enableHardening = true; }); From a9822fa200f3976986698ba37adc856d50349bf3 Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Tue, 13 Feb 2024 15:53:54 +0100 Subject: [PATCH 2/5] nixos/virtualbox-host: expose option to run with KVM --- .../virtualisation/virtualbox-host.nix | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 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" ]; From 77c7ac6c357c43342642efc62119fc58ad11031e Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Wed, 14 Feb 2024 17:29:06 +0100 Subject: [PATCH 3/5] nixosTests.virtualbox: allow additional parameters for tests --- nixos/tests/virtualbox.nix | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix index e522d0679e15..878d60c33f47 100644 --- a/nixos/tests/virtualbox.nix +++ b/nixos/tests/virtualbox.nix @@ -340,7 +340,7 @@ let testExtensionPack.vmFlags = enableExtensionPackVMFlags; }; - mkVBoxTest = useExtensionPack: vms: name: testScript: makeTest { + mkVBoxTest = vboxHostConfig: vms: name: testScript: makeTest { name = "virtualbox-${name}"; nodes.machine = { lib, config, ... }: { @@ -350,13 +350,16 @@ let 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; 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 +393,7 @@ let }; }; - unfreeTests = mapAttrs (mkVBoxTest true vboxVMsWithExtpack) { + unfreeTests = mapAttrs (mkVBoxTest { enableExtensionPack = true; } vboxVMsWithExtpack) { enable-extension-pack = '' create_vm_testExtensionPack() vbm("startvm testExtensionPack") @@ -409,7 +412,7 @@ let ''; }; -in mapAttrs (mkVBoxTest false vboxVMs) { +in mapAttrs (mkVBoxTest {} vboxVMs) { simple-gui = '' # Home to select Tools, down to move to the VM, enter to start it. def send_vm_startup(): From 3661b3ee536fdfbe031ada573de61d920da3268e Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Wed, 14 Feb 2024 18:40:46 +0100 Subject: [PATCH 4/5] nixosTests.virtualbox: add happy path KVM test The KVM support is still new and experimental. There is no point in doing extensive testing. Just check whether it works in general. --- nixos/tests/virtualbox.nix | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix index 878d60c33f47..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 }: @@ -349,7 +350,13 @@ 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.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; @@ -412,6 +419,23 @@ let ''; }; + 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. @@ -522,4 +546,6 @@ in mapAttrs (mkVBoxTest {} vboxVMs) { destroy_vm_test1() destroy_vm_test2() ''; -} // (optionalAttrs enableUnfree unfreeTests) +} +// (optionalAttrs enableKvm kvmTests) +// (optionalAttrs enableUnfree unfreeTests) From c9f940be782d44fea9a51358f3e7e124d7bb00a9 Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Mon, 4 Mar 2024 22:19:48 +0100 Subject: [PATCH 5/5] virtualboxKvm: assert KVM variant incompatibilities --- pkgs/applications/virtualization/virtualbox/default.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkgs/applications/virtualization/virtualbox/default.nix b/pkgs/applications/virtualization/virtualbox/default.nix index a52a3cec15e5..98c161f6b4e3 100644 --- a/pkgs/applications/virtualization/virtualbox/default.nix +++ b/pkgs/applications/virtualization/virtualbox/default.nix @@ -21,6 +21,9 @@ , extraConfigureFlags ? "" }: +# See https://github.com/cyberus-technology/virtualbox-kvm/issues/12 +assert enableKvm -> !enableHardening; + with lib; let