at 17.09-beta 4.5 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.virtualisation.virtualbox.host; 7 8 virtualbox = pkgs.virtualbox.override { 9 inherit (cfg) enableHardening headless; 10 }; 11 12 kernelModules = config.boot.kernelPackages.virtualbox.override { 13 inherit virtualbox; 14 }; 15 16in 17 18{ 19 options.virtualisation.virtualbox.host = { 20 enable = mkOption { 21 type = types.bool; 22 default = false; 23 description = '' 24 Whether to enable VirtualBox. 25 26 <note><para> 27 In order to pass USB devices from the host to the guests, the user 28 needs to be in the <literal>vboxusers</literal> group. 29 </para></note> 30 ''; 31 }; 32 33 addNetworkInterface = mkOption { 34 type = types.bool; 35 default = true; 36 description = '' 37 Automatically set up a vboxnet0 host-only network interface. 38 ''; 39 }; 40 41 enableHardening = mkOption { 42 type = types.bool; 43 default = true; 44 description = '' 45 Enable hardened VirtualBox, which ensures that only the binaries in the 46 system path get access to the devices exposed by the kernel modules 47 instead of all users in the vboxusers group. 48 49 <important><para> 50 Disabling this can put your system's security at risk, as local users 51 in the vboxusers group can tamper with the VirtualBox device files. 52 </para></important> 53 ''; 54 }; 55 56 headless = mkOption { 57 type = types.bool; 58 default = false; 59 description = '' 60 Use VirtualBox installation without GUI and Qt dependency. Useful to enable on servers 61 and when virtual machines are controlled only via SSH. 62 ''; 63 }; 64 }; 65 66 config = mkIf cfg.enable (mkMerge [{ 67 boot.kernelModules = [ "vboxdrv" "vboxnetadp" "vboxnetflt" ]; 68 boot.extraModulePackages = [ kernelModules ]; 69 environment.systemPackages = [ virtualbox ]; 70 71 security.wrappers = let 72 mkSuid = program: { 73 source = "${virtualbox}/libexec/virtualbox/${program}"; 74 owner = "root"; 75 group = "vboxusers"; 76 setuid = true; 77 }; 78 in mkIf cfg.enableHardening 79 (builtins.listToAttrs (map (x: { name = x; value = mkSuid x; }) [ 80 "VBoxHeadless" 81 "VBoxNetAdpCtl" 82 "VBoxNetDHCP" 83 "VBoxNetNAT" 84 "VBoxSDL" 85 "VBoxVolInfo" 86 "VirtualBox" 87 ])); 88 89 users.extraGroups.vboxusers.gid = config.ids.gids.vboxusers; 90 91 services.udev.extraRules = 92 '' 93 KERNEL=="vboxdrv", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd" 94 KERNEL=="vboxdrvu", OWNER="root", GROUP="root", MODE="0666", TAG+="systemd" 95 KERNEL=="vboxnetctl", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd" 96 SUBSYSTEM=="usb_device", ACTION=="add", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}" 97 SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}" 98 SUBSYSTEM=="usb_device", ACTION=="remove", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor" 99 SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor" 100 ''; 101 102 # Since we lack the right setuid/setcap binaries, set up a host-only network by default. 103 } (mkIf cfg.addNetworkInterface { 104 systemd.services."vboxnet0" = 105 { description = "VirtualBox vboxnet0 Interface"; 106 requires = [ "dev-vboxnetctl.device" ]; 107 after = [ "dev-vboxnetctl.device" ]; 108 wantedBy = [ "network.target" "sys-subsystem-net-devices-vboxnet0.device" ]; 109 path = [ virtualbox ]; 110 serviceConfig.RemainAfterExit = true; 111 serviceConfig.Type = "oneshot"; 112 serviceConfig.PrivateTmp = true; 113 environment.VBOX_USER_HOME = "/tmp"; 114 script = 115 '' 116 if ! [ -e /sys/class/net/vboxnet0 ]; then 117 VBoxManage hostonlyif create 118 cat /tmp/VBoxSVC.log >&2 119 fi 120 ''; 121 postStop = 122 '' 123 VBoxManage hostonlyif remove vboxnet0 124 ''; 125 }; 126 127 networking.interfaces.vboxnet0.ip4 = [ { address = "192.168.56.1"; prefixLength = 24; } ]; 128 # Make sure NetworkManager won't assume this interface being up 129 # means we have internet access. 130 networking.networkmanager.unmanaged = ["vboxnet0"]; 131 })]); 132}