2014-11-27 18:24:57 +01:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
2015-08-13 12:17:32 +02:00
|
|
|
cfg = config.virtualisation.virtualbox.host;
|
2016-09-13 03:42:16 +02:00
|
|
|
|
|
|
|
virtualbox = pkgs.virtualbox.override {
|
2016-09-01 20:54:58 +02:00
|
|
|
inherit (cfg) enableHardening headless;
|
2014-12-15 07:08:56 +01:00
|
|
|
};
|
|
|
|
|
2016-09-13 03:42:16 +02:00
|
|
|
kernelModules = config.boot.kernelPackages.virtualbox.override {
|
|
|
|
inherit virtualbox;
|
|
|
|
};
|
|
|
|
|
2014-11-27 18:24:57 +01:00
|
|
|
in
|
|
|
|
|
|
|
|
{
|
2015-08-13 12:17:32 +02:00
|
|
|
options.virtualisation.virtualbox.host = {
|
2014-12-15 07:33:56 +01:00
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = ''
|
2015-08-12 14:11:03 +02:00
|
|
|
Whether to enable VirtualBox.
|
2014-12-15 07:33:56 +01:00
|
|
|
|
|
|
|
<note><para>
|
|
|
|
In order to pass USB devices from the host to the guests, the user
|
|
|
|
needs to be in the <literal>vboxusers</literal> group.
|
|
|
|
</para></note>
|
|
|
|
'';
|
|
|
|
};
|
2014-12-15 07:08:56 +01:00
|
|
|
|
|
|
|
addNetworkInterface = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = ''
|
|
|
|
Automatically set up a vboxnet0 host-only network interface.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
enableHardening = mkOption {
|
2014-12-11 23:28:09 +01:00
|
|
|
type = types.bool;
|
2014-12-18 18:12:25 +01:00
|
|
|
default = true;
|
2014-12-15 07:08:56 +01:00
|
|
|
description = ''
|
|
|
|
Enable hardened VirtualBox, which ensures that only the binaries in the
|
|
|
|
system path get access to the devices exposed by the kernel modules
|
|
|
|
instead of all users in the vboxusers group.
|
|
|
|
|
|
|
|
<important><para>
|
|
|
|
Disabling this can put your system's security at risk, as local users
|
|
|
|
in the vboxusers group can tamper with the VirtualBox device files.
|
|
|
|
</para></important>
|
|
|
|
'';
|
2014-12-11 23:28:09 +01:00
|
|
|
};
|
2016-09-01 20:54:58 +02:00
|
|
|
|
|
|
|
headless = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = ''
|
|
|
|
Use VirtualBox installation without GUI and Qt dependency. Useful to enable on servers
|
|
|
|
and when virtual machines are controlled only via SSH.
|
|
|
|
'';
|
|
|
|
};
|
2014-11-27 18:24:57 +01:00
|
|
|
};
|
|
|
|
|
2014-12-15 07:08:56 +01:00
|
|
|
config = mkIf cfg.enable (mkMerge [{
|
2014-11-27 18:24:57 +01:00
|
|
|
boot.kernelModules = [ "vboxdrv" "vboxnetadp" "vboxnetflt" ];
|
2016-09-13 03:42:16 +02:00
|
|
|
boot.extraModulePackages = [ kernelModules ];
|
2014-11-27 18:24:57 +01:00
|
|
|
environment.systemPackages = [ virtualbox ];
|
|
|
|
|
2017-01-29 08:58:12 +01:00
|
|
|
security.wrappers = let
|
2017-02-14 22:56:37 +01:00
|
|
|
mkSuid = program: {
|
2014-12-18 11:37:32 +01:00
|
|
|
source = "${virtualbox}/libexec/virtualbox/${program}";
|
2014-11-29 08:09:50 +01:00
|
|
|
owner = "root";
|
|
|
|
group = "vboxusers";
|
|
|
|
setuid = true;
|
2017-02-14 22:56:37 +01:00
|
|
|
};
|
|
|
|
in mkIf cfg.enableHardening
|
|
|
|
(builtins.listToAttrs (map (x: { name = x; value = mkSuid x; }) [
|
2014-11-29 08:09:50 +01:00
|
|
|
"VBoxHeadless"
|
2014-12-18 11:37:32 +01:00
|
|
|
"VBoxNetAdpCtl"
|
|
|
|
"VBoxNetDHCP"
|
|
|
|
"VBoxNetNAT"
|
2014-11-29 08:09:50 +01:00
|
|
|
"VBoxSDL"
|
2014-12-18 11:37:32 +01:00
|
|
|
"VBoxVolInfo"
|
2014-11-29 08:09:50 +01:00
|
|
|
"VirtualBox"
|
2017-02-14 22:56:37 +01:00
|
|
|
]));
|
2014-11-29 08:09:50 +01:00
|
|
|
|
2014-11-27 18:24:57 +01:00
|
|
|
users.extraGroups.vboxusers.gid = config.ids.gids.vboxusers;
|
|
|
|
|
|
|
|
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"
|
|
|
|
'';
|
|
|
|
|
2017-01-29 05:48:03 +01:00
|
|
|
# Since we lack the right setuid/setcap binaries, set up a host-only network by default.
|
2014-12-15 07:08:56 +01:00
|
|
|
} (mkIf cfg.addNetworkInterface {
|
2014-11-27 18:24:57 +01:00
|
|
|
systemd.services."vboxnet0" =
|
|
|
|
{ description = "VirtualBox vboxnet0 Interface";
|
|
|
|
requires = [ "dev-vboxnetctl.device" ];
|
|
|
|
after = [ "dev-vboxnetctl.device" ];
|
|
|
|
wantedBy = [ "network.target" "sys-subsystem-net-devices-vboxnet0.device" ];
|
|
|
|
path = [ virtualbox ];
|
|
|
|
serviceConfig.RemainAfterExit = true;
|
|
|
|
serviceConfig.Type = "oneshot";
|
2014-12-15 19:12:58 +01:00
|
|
|
serviceConfig.PrivateTmp = true;
|
|
|
|
environment.VBOX_USER_HOME = "/tmp";
|
2014-11-27 18:24:57 +01:00
|
|
|
script =
|
|
|
|
''
|
|
|
|
if ! [ -e /sys/class/net/vboxnet0 ]; then
|
|
|
|
VBoxManage hostonlyif create
|
2014-12-15 19:12:58 +01:00
|
|
|
cat /tmp/VBoxSVC.log >&2
|
2014-11-27 18:24:57 +01:00
|
|
|
fi
|
|
|
|
'';
|
|
|
|
postStop =
|
|
|
|
''
|
|
|
|
VBoxManage hostonlyif remove vboxnet0
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
networking.interfaces.vboxnet0.ip4 = [ { address = "192.168.56.1"; prefixLength = 24; } ];
|
2015-11-07 14:07:11 +01:00
|
|
|
# Make sure NetworkManager won't assume this interface being up
|
|
|
|
# means we have internet access.
|
|
|
|
networking.networkmanager.unmanaged = ["vboxnet0"];
|
2014-12-12 00:15:28 +01:00
|
|
|
})]);
|
2014-11-27 18:24:57 +01:00
|
|
|
}
|