--- /dev/null
+Isolate NixOS QEMU VMs from each other and from the host by using a
+squashfs for the VM's /nix/store that contains only the VM's dependencies
+(like the installer has) rather than a virtio mount of the host's entire
+/nix/store.
--- /dev/null
+{ pkgs, ... }: {
+ name = "qemu-private-store-mount-grep";
+
+ nodes = {
+ shared = _: { };
+ private = _: { imports = [ ../modules/qemu-vm-isolation.nix ]; };
+ };
+
+ testScript = ''
+ start_all()
+ shared.wait_for_unit("multi-user.target")
+ private.wait_for_unit("multi-user.target")
+
+ shared.succeed("[[ $(mount | grep -c virt) -gt 0 ]]")
+ private.succeed("[[ $(mount | grep -c virt) -eq 0 ]]")
+ '';
+}
--- /dev/null
+{
+ "nodes": {
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1635141467,
+ "narHash": "sha256-H+TVE6tBSm4nAepm7HRfW7AcrndI5e4+TJwCQo4/z+s=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "38d21595b8fb0a744aa31c5794013bf42cf98fa9",
+ "type": "github"
+ },
+ "original": {
+ "id": "nixpkgs",
+ "type": "indirect"
+ }
+ },
+ "root": {
+ "inputs": {
+ "nixpkgs": "nixpkgs"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
--- /dev/null
+{
+ outputs = { self, nixpkgs, }:
+ let
+ inherit (nixpkgs.lib) genAttrs;
+
+ systems = nixpkgs.lib.systems.supported.tier1;
+
+ forAllSystems = genAttrs systems;
+
+ in {
+ nixosModules = {
+ qemu-vm-isolation = import ./modules/qemu-vm-isolation.nix;
+ };
+ checks = forAllSystems (system: {
+ mount-grep = nixpkgs.legacyPackages."${system}".nixosTest
+ (import ./checks/mount-grep.nix);
+ });
+ };
+}
--- /dev/null
+{ config, lib, modulesPath, pkgs, ... }:
+let
+ inherit (lib) findSingle mkForce mkVMOverride;
+
+ lookupDriveDeviceName = driveName: driveList:
+ (findSingle (drive: drive.name == driveName)
+ (throw "Drive ${driveName} not found")
+ (throw "Multiple drives named ${driveName}") driveList).device;
+
+ storeMountPath = if config.virtualisation.writableStore then
+ "/nix/.ro-store"
+ else
+ "/nix/store";
+
+in {
+
+ boot.initrd.availableKernelModules = [ "squashfs" ];
+
+ fileSystems = mkVMOverride {
+ "${storeMountPath}" = {
+ device =
+ lookupDriveDeviceName "nixstore" config.virtualisation.qemu.drives;
+ fsType = "squashfs";
+ options = [ "ro" ];
+ neededForBoot = true;
+ };
+ };
+
+ system.build.squashfsStore =
+ pkgs.callPackage (modulesPath + "/../lib/make-squashfs.nix") {
+ storeContents = config.virtualisation.pathsInNixDB;
+ };
+
+ virtualisation = {
+
+ # This should be the default.
+ bootDevice = lookupDriveDeviceName "root" config.virtualisation.qemu.drives;
+
+ sharedDirectories = mkForce { };
+
+ qemu.drives = [{
+ name = "nixstore";
+ file = "${config.system.build.squashfsStore}";
+ driveExtraOpts = {
+ format = "raw";
+ read-only = "on";
+ werror = "report";
+ };
+ }];
+
+ };
+}