Merge pull request #288579 from blitz/vbox-kvm-2

virtualboxKvm: init
This commit is contained in:
adisbladis 2024-03-05 18:58:57 +13:00 committed by GitHub
commit 5cdb38bb16
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 110 additions and 19 deletions

View file

@ -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" ];

View file

@ -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)

View file

@ -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"

View file

@ -35866,6 +35866,10 @@ with pkgs;
inherit (gnome2) libIDL;
};
virtualboxKvm = lowPrio (virtualbox.override {
enableKvm = true;
});
virtualboxHardened = lowPrio (virtualbox.override {
enableHardening = true;
});