diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 1bdaf713ab5dc..da4346b3ec1cf 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -689,6 +689,8 @@ in # References: # https://www.debian.org/doc/debian-policy/ch-opersys.html#uid-and-gid-classes + qubes = 999; # Qubes dom0 expects gid 999 + onepassword = 31001; # 1Password requires that its GID be larger than 1000 onepassword-cli = 31002; # 1Password requires that its GID be larger than 1000 diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 7f6fa1c8e73b0..cf7be2567796c 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1716,6 +1716,7 @@ ./virtualisation/parallels-guest.nix ./virtualisation/podman/default.nix ./virtualisation/qemu-guest-agent.nix + ./virtualisation/qubes-dom0.nix ./virtualisation/rosetta.nix ./virtualisation/spice-usb-redirection.nix ./virtualisation/virtualbox-guest.nix diff --git a/nixos/modules/services/desktop-managers/plasma6.nix b/nixos/modules/services/desktop-managers/plasma6.nix index a7f71f13fbbd2..6056ff99e3cc6 100644 --- a/nixos/modules/services/desktop-managers/plasma6.nix +++ b/nixos/modules/services/desktop-managers/plasma6.nix @@ -58,6 +58,7 @@ in { ]; qt.enable = true; + programs.xwayland.enable = true; environment.systemPackages = with kdePackages; let requiredPackages = [ qtwayland # Hack? To make everything run on Wayland @@ -87,7 +88,6 @@ in { # Core Plasma parts kwin - pkgs.xwayland kscreen libkscreen kscreenlocker diff --git a/nixos/modules/services/security/usbguard.nix b/nixos/modules/services/security/usbguard.nix index 17bffa57ef3ad..3a267aeeb9a20 100644 --- a/nixos/modules/services/security/usbguard.nix +++ b/nixos/modules/services/security/usbguard.nix @@ -13,6 +13,8 @@ let daemonConf = '' # generated by nixos/modules/services/security/usbguard.nix RuleFile=${ruleFile} + # usual configuration + RuleFolder=/etc/usbguard/rules.d ImplicitPolicyTarget=${cfg.implicitPolicyTarget} PresentDevicePolicy=${cfg.presentDevicePolicy} PresentControllerPolicy=${cfg.presentControllerPolicy} @@ -24,6 +26,7 @@ let IPCAllowedGroups=${concatStringsSep " " cfg.IPCAllowedGroups} IPCAccessControlFiles=/var/lib/usbguard/IPCAccessControl.d/ DeviceRulesWithPort=${boolToString cfg.deviceRulesWithPort} + AuditBackend=${cfg.AuditBackend} # HACK: that way audit logs still land in the journal AuditFilePath=/dev/null ''; @@ -149,6 +152,15 @@ in ''; }; + AuditBackend = mkOption { + type = types.enum ["FileAudit" "LinuxAudit"]; + default = "FileAudit"; + example = "LinuxAudit"; + description = '' + USBGuard audit events log backend. + ''; + }; + deviceRulesWithPort = mkOption { type = types.bool; default = false; @@ -157,6 +169,14 @@ in ''; }; + packages = mkOption { + type = types.listOf types.package; + default = [ ]; + description = '' + Packages containing USBGuard rules in `/etc/usbguard/rules.d` + ''; + }; + dbus.enable = mkEnableOption "USBGuard dbus daemon"; }; }; @@ -252,6 +272,12 @@ in } }); ''; + + environment.etc."usbguard/rules.d".source = pkgs.symlinkJoin { + name = "rules.d"; + paths = cfg.packages; + stripPrefix = "/etc/usbguard/rules.d"; + }; }; imports = [ (mkRemovedOptionModule [ "services" "usbguard" "IPCAccessControlFiles" ] "The usbguard module now hardcodes IPCAccessControlFiles to /var/lib/usbguard/IPCAccessControl.d.") diff --git a/nixos/modules/virtualisation/qubes-dom0.nix b/nixos/modules/virtualisation/qubes-dom0.nix new file mode 100644 index 0000000000000..75c64f89f8b51 --- /dev/null +++ b/nixos/modules/virtualisation/qubes-dom0.nix @@ -0,0 +1,494 @@ +{ + lib, + pkgs, + config, + ... +}: let + inherit (lib) mkEnableOption mkIf optional mkOption stringAfter optionalAttrs optionals; + inherit (lib.types) listOf path str enum; + inherit (pkgs) qubes-linux-utils qubes-core-qubesdb qubes-core-libvirt qubes-gui-daemon qubes-vmm-xen qubes-artwork qubes-desktop-linux-kde qemu_qubes qubes-manager runCommand symlinkJoin qubes-core-admin-linux; + inherit (pkgs.python3Packages) qubes-core-admin qubes-core-qrexec qubes-desktop-linux-common qubes-core-admin-client qubes-app-linux-usb-proxy; + + cfg = config.virtualisation.qubes; + + anyEnabled = cfg.dom0.enable || cfg.sys-net.enable || cfg.sys-usb.enable || cfg.sys-gui.enable; + isDom0 = cfg.dom0.enable; + isDomU = anyEnabled && !isDom0; + + optOutFlags = [ + # Configure networkmanager to use random MAC + "randomise-mac" + # It is possible to run qubes securely with SMT enabled, however + # neither qubes nixos module nor QubesOS itself is not configured + # out of the box for that. + "disable-smt" + # qubes expects adminvm to have hostname dom0. + "hostname-dom0" + # sys-gui is considered advanced. + "dom0-is-gui" + # Qubes disables most of USB in dom0 by default. + # This might be problematic for PC + "dom0-restricted-usb" + # when disabled - dom0 has ability to be sys-net/sys-usb + "dedicated-sys-net" + "dedicated-sys-usb" + ]; + + # Is recommended option enabled? + recommended = flag: + assert (builtins.elem flag optOutFlags); + !(builtins.elem flag cfg.optOutRecommendedConfiguration); +in { + # Bug: + # Loopback vchan connection not supported + # FATAL: vchan initialization failed + # Solution: Xenstore has no set domid + # It can be set manually using + # `run0 xenstore-write "/domid" 0` + # However it should always be set by default by something, + # and I am not sure how/where. + # FIXME: Is this still relevant? I don't remember where I have encountered this error, + # but I no longer have this problem. + + # Bug: + # Not enough memory during start of VM + # Solution: + # Qubes memory manager overrides max memory of dom0 with + # total memory available, you need to set memory limit for it. + # I have no idea what writes this memory limit in QubesOS, but + # it can be set manually: + # `run0 xenstore-write /local/domain/0/memory/static-max 100000000` + # Note that the standard `xl mem-set` doesn't work for that, as it + # uses /vm/uuid/memory field instead. + # FIXME: Permanent solution needed. + + # Current security policy. + # QubesOS assumes there is only one user of the machine, and he is trusted + # to do anything. QubesOS disables sudo password/grants everything via polkit + + options.virtualisation.qubes = { + dom0.enable = mkEnableOption "Qubes"; + secure = + (mkEnableOption '' + Follow QubesOS security model as close as possible. + + Do not disable unles you absolutely know what're you doing. + '') + // { + default = true; + visible = false; + }; + optOutRecommendedConfiguration = mkOption { + description = '' + Opt-out of recommended QubesOS configuration options. + + Do not use unless you know what're you doing. + ''; + type = listOf (enum optOutFlags); + default = []; + }; + user = mkOption { + description = '' + Which user will have to QubesOS + + QubesOS is fundamentally bound to single user. It is possible to + have multiple users on machine and give access to qubes only to one, + but it probably won't work well, many Qubes services assume there + is one and only one user in "qubes" group. + ''; + type = str; + }; + # Shared with domU + sys-net.enable = mkEnableOption "Install sys-net components into dom0"; + sys-usb.enable = mkEnableOption "Install sys-usb components into dom0"; + sys-gui.enable = mkEnableOption "Install sys-gui components into dom0"; + # Can be shared with domU, I think? + packages = mkOption { + description = '' + Packages providing qubes configuration files. + + They might contain: + - /etc/qubes-rpc + - /etc/qubes/policy.d + - /etc/qubes/suspend-pre.d - TODO + - /etc/qubes/rpc-config - TODO + ''; + type = listOf path; + default = []; + }; + # policy.mutablePolicy = mkEnableOption? + }; + config = mkIf cfg.dom0.enable { + assertions = [ + { + assertion = isDom0 -> !(recommended "dedicated-sys-net") && !(recommended "dedicated-sys-usb"); + message = "Do not rely exclusively dedicated sys-net/sys-usb, they're not ready yet"; + } + { + # Is there not recommended options which don't conflict with Qubes security model? + # For now assume there is not, secure is not possible to enable anyway. + assertion = cfg.secure -> (cfg.optOutRecommendedConfiguration == []); + message = "QubesOS security model depends on some of recommended configuration options."; + } + { + # Require user to explicitly opt-out of QubesOS security model, which is not implemented + # and partially not applicable for NixOS-Qubes module deployment right now. + assertion = !cfg.secure; + message = "QubesOS security model is not implemented yet."; + } + ]; + + virtualisation.qubes = { + sys-gui.enable = mkIf (isDom0 && recommended "dom0-is-gui") true; + sys-net.enable = mkIf (isDom0 && !(recommended "dedicated-sys-net")) true; + sys-usb.enable = mkIf (isDom0 && !(recommended "dedicated-sys-usb")) true; + }; + + # Some of Qubes apps require host name to match domain name. + # There is a bypass implemented in qubesd-dom0 service, but it might + # not work for everyone. + networking.hostName = mkIf (isDom0 && recommended "hostname-dom0") "dom0"; + + users.groups.qubes.gid = config.ids.gids.qubes; + users.users.${cfg.user}.extraGroups = ["qubes"]; + # xl create needs to allocate and mlock all VM memory + security.pam.loginLimits = [ + { + domain = "@qubes"; + type = "soft"; + item = "memlock"; + value = "unlimited"; + } + { + domain = "@qubes"; + type = "hard"; + item = "memlock"; + value = "unlimited"; + } + ]; + + systemd.tmpfiles.packages = [ + qubes-core-admin + qubes-linux-utils + ]; + systemd.tmpfiles.settings."10-qubes" = + { + # Qubes daemons are configured to install qube autostart units here + "/etc/systemd-mutable/system/multi-user.target.wants".d = {}; + # Idk what is supposed to make this directory + "/var/log/qubes".d = { + user = "root"; + group = "qubes"; + mode = "770"; + }; + } + // optionalAttrs cfg.dom0.enable { + # Used to recognize if current system is qubes dom0. + # https://github.com/QubesOS/qubes-core-admin-client/blob/d9db37fdae9aaf91dec993b5dd111e02e66f782d/qubesadmin/__init__.py#L31 + "/etc/qubes-release".f = {}; + # Created by qubes-core-admin during installation + "/var/log/qubes".d = { + user = "root"; + group = "qubes"; + mode = "770"; + }; + "/var/lib/qubes/appvms".d = { + user = "root"; + group = "qubes"; + mode = "700"; + }; + "/var/lib/qubes/backup".d = { + user = "root"; + group = "qubes"; + mode = "700"; + }; + "/var/lib/qubes/vm-kernels".d = { + user = "root"; + group = "qubes"; + mode = "700"; + }; + "/var/lib/qubes/vm-templates".d = { + user = "root"; + group = "qubes"; + mode = "700"; + }; + }; + + # Conflicting with libxl according to qubes + systemd.services.xend.enable = false; + systemd.services.xendomains.enable = false; + + systemd.services.qubes-db = { + enable = isDomU; + wantedBy = ["multi-user.target"]; + after = ["systemd-tmpfiles-setup.service"]; + }; + systemd.services.qubes-db-dom0 = { + enable = isDom0; + wantedBy = ["multi-user.target"]; + after = ["systemd-tmpfiles-setup.service"]; + # Some of Qubes utilities have two ways of receiving hostname: reading uname, and reading qubesdb /name key. + # + # They also assume hostname matches domain name, and dom0 name can't be changed. + # Either networking.hostName needs to be forced in this module, or there be added a workaround for domain name. + # This is an implementation of second fix, it might not work somewhere. + # Works for me, though. + serviceConfig.ExecStartPost = "${qubes-core-qubesdb}/bin/qubesdb-write /name dom0"; + }; + systemd.services.qubesd = { + enable = isDom0; + wantedBy = ["multi-user.target"]; + before = ["systemd-user-sessions.service"]; + }; + systemd.services.qubes-qmemman = { + enable = isDom0; + wantedBy = ["multi-user.target"]; + }; + systemd.services.qubes-meminfo-writer = { + enable = isDomU; + wantedBy = ["multi-user.target"]; + before = ["systemd-user-sessions.service"]; + }; + systemd.services.qubes-meminfo-writer-dom0 = { + enable = isDom0; + wantedBy = ["multi-user.target"]; + before = ["systemd-user-sessions.service"]; + after = ["qubes-core.service" "qubes-qmemman.service"]; + }; + systemd.services.qubes-core = { + enable = isDom0; + wantedBy = ["multi-user.target"]; + aliases = ["qubes_core.service"]; + }; + systemd.services."qubes-vm@" = { + enable = isDom0; + after = ["qubesd.service" "qubes-meminfo-writer-dom0.service"]; + }; + systemd.services."qubes-reload-firewall@" = { + # FIXME: I don't fully understand how it is supposed to work in NixOS + }; + + systemd.services.qubes-qrexec-agent = { + enable = isDomU; + wantedBy = ["multi-user.target"]; + aliases = ["qubes-core-agent.service"]; + after = ["xendriverdomain.service" "systemd-user-sessions.service"]; + }; + systemd.services.qubes-qrexec-policy-daemon = { + enable = isDom0; + wantedBy = ["multi-user.target"]; + after = ["qubesd.service"]; + }; + + virtualisation.libvirtd = mkIf isDom0 { + enable = true; + package = qubes-core-libvirt; + }; + environment.etc = { + # "/*" at the end to make qubes-rpc directory writable. + # Unfortunately, services like policy.Eval{Gui,Simple} are creating rpc socket + # only when they actually started. TODO: Patch patckages to work with immutable qubes-rpc directory + "qubes-rpc".source = "${symlinkJoin { + name = "etc-qubes-rpc"; + paths = cfg.packages; + stripPrefix = "/etc/qubes-rpc"; + postBuild = "mv $out/policy $out/policy.static"; + }}/*"; + # We might want to drop policy.d/include directory from + # every package, and then declare it using NixOS config? + "qubes/policy.d".source = symlinkJoin { + name = "etc-qubes-policy-d"; + paths = cfg.packages; + stripPrefix = "/etc/qubes/policy.d"; + }; + "xen/scripts-qubes" = { + source = "${qubes-linux-utils}/etc/xen/scripts/*"; + target = "xen/scripts"; + }; + # This file describes itself as "not used", and "only here for reference", but guid is actually + # using it... + "qubes/guid.conf" = mkIf isDom0 { + source = "${qubes-gui-daemon}/etc/qubes/guid.conf"; + }; + }; + + # Some qubes daemons write to legacy policy directory at runtime. + system.etc.overlay.mutable = true; + # FIXME: When package is removed, its old policy will remain in etc. + # TODO: Test with etc overlays. setup-etc preserves old files, but with overlays + # it might require to evacuate runtime policy - install etc - move runtime policy back. + system.activationScripts.etc-qubes-rpc = stringAfter ["etc"] '' + echo "setting up qubes rpc..." + mkdir -p /etc/qubes-rpc/policy + cp -rf /etc/qubes-rpc/policy.static/* /etc/qubes-rpc/policy + ''; + + systemd.packages = + [ + qubes-core-qubesdb.daemon # both domU and dom0 + qubes-linux-utils + ] + ++ optional isDomU [ + qubes-core-qrexec.domU + ] + ++ optionals isDom0 [ + qubes-core-admin + qubes-core-qrexec.dom0 + ]; + + virtualisation.qubes.packages = + [ + qubes-core-qrexec + qubes-desktop-linux-common + # Legacy policy directory, wanted by qrexec. + (runCommand "legacy-policy-stub" {} '' + mkdir -p $out/etc/qubes-rpc/policy + '') + ] + ++ optionals isDom0 [ + qubes-core-admin + qubes-app-linux-usb-proxy + qubes-core-qrexec.dom0 + ] + ++ optionals isDomU [ + qubes-core-qrexec.domU + ] + # clipboard/window icons access; + ++ optional cfg.sys-gui.enable qubes-gui-daemon + # FIXME: also has qubes/suspend-pre.d + ++ optional cfg.sys-usb.enable qubes-app-linux-usb-proxy.sys-usb; + + services.udev.packages = + [ + qubes-linux-utils + ] + ++ optional isDom0 qubes-core-admin-linux + ++ optional cfg.sys-usb.enable qubes-app-linux-usb-proxy.sys-usb; + + virtualisation.xen = mkIf isDom0 { + enable = true; + package = qubes-vmm-xen; + store.path = "${qubes-vmm-xen}/bin/xenstored"; + qemu.package = qemu_qubes; + + bootParams = + [ + "gnttab_max_frames=2048" + "gnttab_max_maptrack_frames=4096" + ] + ++ optional (recommended "disable-smt") "smt=off"; + + # TODO: Add declarative xl.conf + # settings = { + # autoballoon = "0"; + # lockfile = "/var/run/qubes/xl-lock"; + # }; + }; + + # FIXME: Similar wrapping wanted for xserver + # I don't use xorg, and have no easy way to test that. + # FIXME: Some of desktop-managers don't use xwayland.package option, + # instead adding xwayland directly to systemPackages, they need to be fixed. + programs.xwayland.package = mkIf cfg.sys-gui.enable qubes-gui-daemon.xwayland; + + # TODO: qrexec-domU pam.d + + environment.systemPackages = + [ + qubes-core-qubesdb # qubesdb-read, qubesdb-write, ... + qubes-core-qrexec + + # Those are not technically optional, but might be disabled for non-gui nixos? + # qvm-appmenus - expected in $PATH by some tools, TODO: patch/wrap packages instead? + qubes-desktop-linux-common + qubes-linux-utils # contains icons + qubes-core-admin-client # qvm-* CLI tools, xdg-autostart + ] + ++ optionals isDom0 [ + qubes-manager # qubes-qube-manager + qubes-core-admin # qvm-console-dispvm + qubes-artwork # qubes icons/wallpapers + qubes-gui-daemon # xdg-autostart + qubes-core-qrexec.dom0 + qubes-core-admin-linux # qvm-copy + ] + ++ optionals isDomU [ + qubes-core-qrexec.domU + ] + # I'm too lazy to do plasma support, but not enough lazy to not write this message. + ++ optionals (isDom0 && config.services.desktopManager.plasma6.enable) [ + qubes-desktop-linux-kde + pkgs.kdePackages.kdialog + ] + # qrexec-base contains both xdg-autostart gui agent and utilities for dom0. + ++ optional (isDom0 || cfg.sys-gui.enable) qubes-core-qrexec; + + # qubes-core-agent-linux also configures NM to use rc-manager=file, + # but it should work with rc-manager=resolvconf too, if resolvconf will call hooks, + # which are originally called by dhclient. Oh boy + # TODO: share with domU, make optional for non-networked vm + networking.networkmanager.settings = mkIf (cfg.sys-net.enable && recommended "randomise-mac") { + device."wifi.scan-rand-mac-address" = "yes"; + connection = { + "wifi.cloned-mac-address" = "stable"; + "connection.stable-id" = "\${CONNECTION}/\${BOOT}"; + "ipv6.ipv6-privacy" = "2"; + }; + }; + + services.usbguard = mkIf (isDom0 && recommended "dom0-restricted-usb") { + enable = true; + IPCAllowedGroups = ["qubes"]; + AuditBackend = "LinuxAudit"; + # HidePII? + + # Use the port number in generated rules. The port number is unstable, + # but this is due to a bug in Qubes OS, and everything else is spoofable :( + # https://github.com/QubesOS/qubes-core-admin-linux/blob/fc9e5a13b123d90e43ffeaf274484df2394d7554/system-config/qubes-usbguard.conf#L26-L28 + deviceRulesWithPort = true; + implicitPolicyTarget = "block"; + presentDevicePolicy = "apply-policy"; + presentControllerPolicy = "apply-policy"; + insertedDevicePolicy = "apply-policy"; + restoreControllerDeviceState = false; + + packages = [ + qubes-core-admin-linux # allows usb hubs/hid devices + ]; + }; + + services.pipewire.extraConfig.pipewire."10-qubes" = { + # In dom0, PipeWire doesn't realize it is running in a VM. + # Therefore, it chooses low quantum values and xruns due + # to Xen descheduling dom0. + "context.properties" = { + "default.clock.min-quantum" = 1024; + }; + }; + + # Qubes uses mutable services for some tasks, e.g vm autostart, + # packages are patched to use this directory for it. + boot.extraSystemdUnitPaths = ["/etc/systemd-mutable/system"]; + + # TODO: Some modules might be moved around depending on role. + boot.kernelModules = + [ + "xen-evtchn" + "xen-gntalloc" + "xen-gntdev" + "xen-privcmd" + + "cpufreq-xen" + "xen-acpi-processor" + ] + ++ optionals isDom0 [ + "xen-pciback" + ] + ++ optional cfg.sys-usb.enable "xen-blkback"; + + # It is possible to have VMs backed by filesystem, but lets assume configuration preferred by + # QubesOS - VM thin pool. + # I haven't figured out why it is required, but manual vgchange -a y qubes-pool is required if only dm-thin-pool module is present. + services.lvm.boot.thin.enable = mkIf isDom0 true; + }; +} diff --git a/pkgs/applications/qubes/qubes-core-vchan-xen/default.nix b/pkgs/applications/qubes/qubes-core-vchan-xen/default.nix index 7def14890300d..54a6001c64ef2 100644 --- a/pkgs/applications/qubes/qubes-core-vchan-xen/default.nix +++ b/pkgs/applications/qubes/qubes-core-vchan-xen/default.nix @@ -1,36 +1,39 @@ { lib, stdenv , fetchFromGitHub -, xen +, qubes-vmm-xen }: - -stdenv.mkDerivation rec { - pname = "qubes-core-vchan-xen"; - version = "4.1.4"; - +let + version = "4.2.4"; src = fetchFromGitHub { owner = "QubesOS"; - repo = pname; - rev = "v${version}"; - hash = "sha256:02l1vs5c2jfw22gxvl2fb66m0d99n8ya1i7rphsb5cxsljvxary0"; + repo = "qubes-core-vchan-xen"; + rev = "refs/tags/v${version}"; + hash = "sha256-O7i5zK7S+d/O8oPMvm6szNR1Xq6qSBNE2+uFI/1mDEg="; }; +in +stdenv.mkDerivation { + inherit version src; + pname = "qubes-core-vchan-xen"; + + buildInputs = [ qubes-vmm-xen.dev ]; - buildInputs = [ xen ]; + buildFlags = [ "all" ]; - buildPhase = '' - make all PREFIX=/ LIBDIR="$out/lib" INCLUDEDIR="$out/include" - ''; + makeFlags = [ + "DESTDIR=/" + "PREFIX=/" + "LIBDIR=$(out)/lib" + "INCLUDEDIR=$(out)/include" + ]; - installPhase = '' - make install DESTDIR=$out PREFIX=/ - ''; + # This flag needs to be enabled for Xen > 1.18. + env.CFLAGS = "-DHAVE_XC_DOMAIN_GETINFO_SINGLE"; meta = with lib; { description = "Libraries required for the higher-level Qubes daemons and tools"; homepage = "https://qubes-os.org"; license = licenses.gpl2Plus; - maintainers = [ ]; + maintainers = with maintainers; [ lach sigmasquadron ]; platforms = platforms.linux; - broken = true; }; - } diff --git a/pkgs/applications/virtualization/xen/generic/default.nix b/pkgs/applications/virtualization/xen/generic/default.nix index 250e5a41bfc1f..b64a37aa08b1f 100644 --- a/pkgs/applications/virtualization/xen/generic/default.nix +++ b/pkgs/applications/virtualization/xen/generic/default.nix @@ -25,7 +25,7 @@ versionDefinition: ncurses, ocamlPackages, perl, - python311Packages, + python3, systemdMinimal, xz, yajl, @@ -323,6 +323,7 @@ stdenv.mkDerivation (finalAttrs: { "doc" # The full Xen documentation in HTML format. "dev" # Development headers. "boot" # xen.gz kernel, policy file if Flask is enabled, xen.efi if EFI is enabled. + # TODO: Python package to be in separate output/package. ]; # Main Xen source. @@ -345,10 +346,11 @@ stdenv.mkDerivation (finalAttrs: { flex pandoc pkg-config + python3.pkgs.setuptools ] ++ lib.lists.optionals withInternalQEMU [ ninja - python311Packages.sphinx + python3.pkgs.sphinx ]; buildInputs = [ @@ -362,7 +364,7 @@ stdenv.mkDerivation (finalAttrs: { lzo ncurses perl - python311Packages.python + python3 xz yajl zlib @@ -373,7 +375,7 @@ stdenv.mkDerivation (finalAttrs: { ocamlPackages.ocaml # Python Fixes - python311Packages.wrapPython + python3.pkgs.wrapPython ] ++ lib.lists.optionals withInternalQEMU [ glib @@ -390,7 +392,7 @@ stdenv.mkDerivation (finalAttrs: { ] ++ lib.lists.optional (!withInternalQEMU) "--with-system-qemu" - ++ lib.lists.optional withSeaBIOS "--with-system-seabios=${seabios}/share/seabios" + ++ lib.lists.optional withSeaBIOS "--with-system-seabios=${seabios.firmware}" ++ lib.lists.optional (!withInternalSeaBIOS && !withSeaBIOS) "--disable-seabios" ++ lib.lists.optional withOVMF "--with-system-ovmf=${OVMF.firmware}" diff --git a/pkgs/applications/virtualization/xen/packages.nix b/pkgs/applications/virtualization/xen/packages.nix index 7402edc8bc70f..a3e4447c8a86d 100644 --- a/pkgs/applications/virtualization/xen/packages.nix +++ b/pkgs/applications/virtualization/xen/packages.nix @@ -1,4 +1,4 @@ -{ callPackage }: +{ python311, callPackage }: let standard = { meta = { @@ -24,10 +24,12 @@ let ''; }; }; + # FIXME: Broken with python 3.12+ due to https://github.com/NixOS/nixpkgs/issues/253751 + python = python311; in # TODO: generalise this to automatically generate both Xen variants for each .//default.nix. rec { - xen_4_19 = callPackage ./4.19/default.nix { inherit (standard) meta; }; + xen_4_19 = callPackage ./4.19/default.nix { inherit (standard) meta; inherit python; }; xen_4_19-slim = xen_4_19.override { withInternalQEMU = false; withInternalSeaBIOS = false; @@ -36,7 +38,7 @@ rec { inherit (slim) meta; }; - xen_4_18 = callPackage ./4.18/default.nix { inherit (standard) meta; }; + xen_4_18 = callPackage ./4.18/default.nix { inherit (standard) meta; inherit python; }; xen_4_18-slim = xen_4_18.override { withInternalQEMU = false; withInternalSeaBIOS = false; @@ -45,7 +47,7 @@ rec { inherit (slim) meta; }; - xen_4_17 = callPackage ./4.17/default.nix { inherit (standard) meta; }; + xen_4_17 = callPackage ./4.17/default.nix { inherit (standard) meta; inherit python; }; xen_4_17-slim = xen_4_17.override { withInternalQEMU = false; withInternalSeaBIOS = false; diff --git a/pkgs/build-support/trivial-builders/default.nix b/pkgs/build-support/trivial-builders/default.nix index a02fe1fd6d0a1..877ebabb14510 100644 --- a/pkgs/build-support/trivial-builders/default.nix +++ b/pkgs/build-support/trivial-builders/default.nix @@ -3,7 +3,11 @@ let inherit (lib) optionalAttrs + optionalString + hasPrefix warn + map + isList ; in @@ -471,23 +475,35 @@ rec { symlinkJoin = args_@{ name , paths + , stripPrefix ? "" , preferLocalBuild ? true , allowSubstitutes ? false , postBuild ? "" , ... }: + # Ensure no partial paths used, it will be confusing considering + # most of the time symlinkJoin is used with packages. + assert (stripPrefix == "" || (hasPrefix "/" stripPrefix) && stripPrefix != "/"); let - args = removeAttrs args_ [ "name" "postBuild" ] + mapPaths = f: paths: map (path: + if path == null then null + else if isList path then mapPaths f path + else f path + ) paths; + args = removeAttrs args_ [ "name" "postBuild" "stripPrefix" "paths" ] // { inherit preferLocalBuild allowSubstitutes; + paths = mapPaths (path: "${path}${stripPrefix}") paths; passAsFile = [ "paths" ]; }; # pass the defaults + ignoreMissing = optionalString (stripPrefix != "") "test -d $i && "; + ignoreError = optionalString (stripPrefix != "") " || true"; in runCommand name args '' mkdir -p $out for i in $(cat $pathsPath); do - ${lndir}/bin/lndir -silent $i $out + ${ignoreMissing}${lndir}/bin/lndir -silent $i $out${ignoreError} done ${postBuild} ''; diff --git a/pkgs/by-name/qu/qubes-artwork/package.nix b/pkgs/by-name/qu/qubes-artwork/package.nix new file mode 100644 index 0000000000000..7318da22fa421 --- /dev/null +++ b/pkgs/by-name/qu/qubes-artwork/package.nix @@ -0,0 +1,51 @@ +{ + lib, + stdenv, + fetchFromGitHub, + graphicsmagick, + inkscape, + python3, +}: +let + version = "4.3.2-1"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-artwork"; + rev = "refs/tags/v${version}"; + hash = "sha256-FIBby9mB/Q6vdGCNJGf17p3ZB7H5Hy4N9XDfaPUEjgs="; + }; + +in +stdenv.mkDerivation { + inherit version src; + pname = "qubes-artwork"; + + postPatch = '' + substituteInPlace bin/mkpadlock.py \ + --replace-fail "/usr/bin/python3" "${python3.withPackages (p: [p.qubes-imgconverter])}/bin/python3" + ''; + + nativeBuildInputs = [ + graphicsmagick + inkscape + ]; + + postInstall = '' + mv $out/usr/* $out/ + rm -d $out/usr + ''; + + makeFlags = [ + "DESTDIR=$(out)" + ]; + + # TODO: Carefully study license. As far as I can see there is no problems with + # redistribution, but I think to needs what counts as modification here. + meta = { + description = "QubesOS icons/wallpapers"; + homepage = "https://qubes-os.org"; + license = with lib.licenses; [ cc-by-nc-sa-40 gpl2Plus ]; + maintainers = with lib.maintainers; [ lach sigmasquadron ]; + platforms = lib.platforms.all; + }; +} diff --git a/pkgs/by-name/qu/qubes-core-admin-linux/package.nix b/pkgs/by-name/qu/qubes-core-admin-linux/package.nix new file mode 100644 index 0000000000000..42b1be0223bd5 --- /dev/null +++ b/pkgs/by-name/qu/qubes-core-admin-linux/package.nix @@ -0,0 +1,115 @@ +{ + python3, + fetchFromGitHub, + qubes-linux-utils, + pandoc, + bash, + patsh, +}: let + inherit + (python3.pkgs) + buildPythonApplication + setuptools + distutils + wrapPython + qubes-core-admin-client + ; + + version = "4.3.2"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-core-admin-linux"; + rev = "refs/tags/v${version}"; + hash = "sha256-duaH+T8ZbP/c0r2YABF3Pv9DnxI3n9sTO6Py2obeETQ="; + }; +in + # FIXME: qfile-dom0-agent tries to call kdialog by absolute path + buildPythonApplication { + inherit version src; + pname = "qubes-core-admin-linux"; + format = "custom"; + + postPatch = '' + substituteInPlace Makefile \ + --replace-fail "setup.py install" "setup.py install --prefix=." + ''; + + nativeBuildInputs = [ + setuptools + distutils + wrapPython + pandoc + patsh + ]; + + buildInputs = [ + qubes-linux-utils + bash + ]; + + propagatedBuildInputs = [ + qubes-core-admin-client + ]; + + buildPhase = '' + make -C dom0-updates $makeFlags + make -C file-copy-vm $makeFlags + make -C doc manpages $makeFlags + make all $makeFlags + ''; + + dontUsePypaInstall = true; + installPhase = '' + runHook preInstall + + make install $makeFlags + + ### pm-utils + mkdir -p $out/lib/pm-utils/sleep.d + cp pm-utils/52qubes-pause-vms $out/lib/pm-utils/sleep.d/ + mkdir -p $out/lib/systemd/system + cp pm-utils/qubes-suspend.service $out/lib/systemd/system/ + + udevrulesdir=$out/etc/udev/rules.d + install -d $udevrulesdir + install -m 644 system-config/00-qubes-ignore-devices.rules $udevrulesdir + install -m 644 system-config/12-qubes-ignore-lvm-devices.rules $udevrulesdir + install -m 644 system-config/11-qubes-ignore-zvol-devices.rules $udevrulesdir + install -m 644 system-config/99z-qubes-mark-ready.rules $udevrulesdir + install -m 755 -D system-config/zvol_is_qubes_volume $out/lib/udev/zvol_is_qubes_volume + # USBguard and PCIe device handling + install -m 0755 -d -- "$out/etc/usbguard" "$out/etc/usbguard/rules.d" + install -m 0644 -- system-config/qubes-usb-rules.conf "$out/etc/usbguard/rules.d/02-qubes.conf" + + # file copy to VM + mkdir -p $out/lib/qubes/ + install -m 755 file-copy-vm/qfile-dom0-agent $out/lib/qubes/ + install -m 755 file-copy-vm/qvm-copy-to-vm $out/bin/ + install -m 755 file-copy-vm/qvm-copy $out/bin/ + ln -s qvm-copy-to-vm $out/bin/qvm-move-to-vm + ln -s qvm-copy $out/bin/qvm-move + + runHook postInstall + ''; + postInstall = '' + wrapPythonProgramsIn $out/bin + + for i in $out/bin/{qvm-copy,qvm-copy-to-vm}; do + substituteInPlace $i \ + --replace-fail "#!/bin/bash" "#!/usr/bin/env bash" + patsh -f $i -s ${builtins.storeDir} + done + substituteInPlace $out/bin/qvm-copy-to-vm \ + --replace-fail "/usr/lib/qubes/" "$out/lib/qubes/" + + substituteInPlace $out/etc/udev/rules.d/11-qubes-ignore-zvol-devices.rules \ + --replace-fail "/usr/lib/udev/" "$out/lib/udev/" + ''; + + env.NIX_CFLAGS_COMPILE = "-Wno-error=unused-result"; + + makeFlags = [ + "DESTDIR=$(out)" + "BACKEND_VMM=xen" + ]; + } diff --git a/pkgs/by-name/qu/qubes-core-agent-linux/package.nix b/pkgs/by-name/qu/qubes-core-agent-linux/package.nix new file mode 100644 index 0000000000000..52c4acfb9dd0c --- /dev/null +++ b/pkgs/by-name/qu/qubes-core-agent-linux/package.nix @@ -0,0 +1,119 @@ +{ + python3, + fetchFromGitHub, + desktop-file-utils, + shared-mime-info, + qubes-linux-utils, + pandoc, + bash, + patsh, +}: +let + inherit (python3.pkgs) buildPythonApplication setuptools distutils qubes-core-qubesdb; + version = "4.2.37"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-core-agent-linux"; + rev = "refs/tags/v${version}"; + hash = "sha256-BPIlym08pOer6IzdsJj2p5AChTSRsoIvjuMTaJSdvMs="; + }; +in +buildPythonApplication { + inherit version src; + pname = "qubes-core-agent-linux"; + format = "custom"; + + nativeBuildInputs = [ + desktop-file-utils + shared-mime-info + pandoc + setuptools + distutils + patsh + ]; + + propagatedBuildInputs = [ + qubes-linux-utils + qubes-core-qubesdb + bash + ]; + + buildFlags = ["all"]; + + dontUsePypaInstall = true; + # TODO: netvm wants everything, but most of those things need to be removed for NixOS. + # It might make sense to drop default Makefile and copy everything we need only. + installTargets = [ + "install-systemd-dropins" + "install-systemd-networking-dropins" + "install-init" + "install-systemd" + "install-common" + "install-networking" + "install-netvm" + ]; + + outputs = ["out" "man"]; + + # Many things needs to be dropped from package, because they are heavily dependent on QubesOS infra. + postInstall = '' + mv $out/usr/bin $out/ + mkdir -p $man + mv $out/usr/share $man/ + + # NetworkManager doesn't accept such dropins on NixOS, they are rewritten + # in qubes-dom0 module instead. As for non-nixos nix users... Its complicated, TODO. + rm $out/usr/lib/NetworkManager/conf.d/{30-qubes.conf,31-randomize-mac.conf} + mv $out/usr/lib/tmpfiles.d $out/lib/ + rm -d $out/usr/lib/{NetworkManager/{conf.d,},} + + rm -d $out/usr/ + + # Symlink to /lib/qubes/qubes-setup-dnat-to-ns, needs to be either recreated (because it is broken), + # or completely ignored (as it is now), as NixOS doesn't use dhclient, something else might call this hook. + # qubes-dnat-to-ns hook setups dns dnat in sys-net. + rm -rf $out/etc/dhclient.d + + # part of xen-domU setup + rm $out/etc/systemd/system/xendriverdomain.service + rm -d $out/etc/systemd/{system,} + + rm $out/lib/modules-load.d/qubes-core.conf + rm -d $out/lib/modules-load.d + + patsh -f $out/etc/xen/scripts/vif-route-qubes -s ${builtins.storeDir} + patsh -f $out/etc/xen/scripts/vif-qubes-nat.sh -s ${builtins.storeDir} + + # Many of those needs to be remade for NixOS, I doubt they work, but it is not required for dom0 + for name in bind-dirs.sh control-printer-icon.sh functions misc-post.sh misc-post-stop.sh mount-dirs.sh \ + network-proxy-setup.sh network-proxy-stop.sh network-uplink-wait.sh qubes-early-vm-config.sh \ + qubes-iptables qubes-random-seed.sh qubes-sysinit.sh resize-rootfs-if-needed.sh setup-rwdev.sh setup-rw.sh; do + patsh -f $out/lib/qubes/init/$name -s ${builtins.storeDir} + substituteInPlace $out/lib/qubes/init/$name \ + --replace-quiet "/usr/lib/qubes" "$out/lib/qubes" + done + for name in network-manager-prepare-conf-dir qubes-fix-nm-conf.sh qubes-setup-dnat-to-ns show-hide-nm-applet.sh; do + patsh -f $out/lib/qubes/$name -s ${builtins.storeDir} + substituteInPlace $out/lib/qubes/$name \ + --replace-quiet "/usr/lib/qubes" "$out/lib/qubes" + done + + rm $out/lib/systemd/system-preset/75-qubes-vm.preset + rm -d $out/lib/systemd/system-preset + rm $out/lib/systemd/resolved.conf.d/30_resolved-no-mdns-or-llmnr.conf + rm -d $out/lib/systemd/resolved.conf.d + + # Too many dropins which I don't use and have no ide how to make them work. + rm -rf $out/lib/systemd/user/{evolution-*,tracker-*} + rm -d $out/lib/systemd/user + + ''; + + makeFlags = [ + "DESTDIR=$(out)" + "LIBDIR=/lib" + "USER_DROPIN_DIR=/lib/systemd/user" + "PYTHON=${python3}/bin/python" + "PYTHON_PREFIX_ARG=--prefix=." + ]; +} diff --git a/pkgs/by-name/qu/qubes-core-libvirt/package.nix b/pkgs/by-name/qu/qubes-core-libvirt/package.nix new file mode 100644 index 0000000000000..cfb7c1ba4681e --- /dev/null +++ b/pkgs/by-name/qu/qubes-core-libvirt/package.nix @@ -0,0 +1,58 @@ +{ + lib, + libvirt, + fetchFromGitHub, + mountPath ? "/run/wrappers/bin/mount", + qubes-vmm-xen, +}: +let + inherit (lib) optionalString; + versionPatches = "10.5.0"; + versionSuffix = "1"; + patches = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-core-libvirt"; + rev = "refs/tags/v${versionPatches}-${versionSuffix}"; + hash = "sha256-6c7H2ulsMXoc8U3EbZyVONEptaoAdW5VEhetqQ2DskY="; + }; + patchSeries = '' + 0001-conf-add-script-attribute-to-disk-specification.patch + 0002-libxl-use-disk-script-attribute.patch + 0003-libxl-Stubdom-emulator-type.patch + 0004-libxl-support-domain-config-modification-in-virDomai.patch + 0005-Add-nostrictreset-attribute-to-PCI-host-devices.patch + 0006-libxl-pause-also-stubdomain-if-any-while-pausing-a-d.patch + 0007-libxl-plug-workaround-for-missing-pcidev-group-assig.patch + 0008-libxl-add-linux-stubdom-support.patch + 0009-libxl-add-support-for-qubes-graphic-device.patch + 0010-libxl-add-support-for-stubdom_mem-option.patch + 0011-libxl-add-support-for-emulator-kernel-and-ramdisk-pa.patch + 0012-libxl-Fix-setting-invtsc-in-Xen-4.14.patch + 0013-libxl-fail-with-distinct-error-on-unsupported-PM-sus.patch + 0014-libxl-add-support-for-xengt-video-device.patch + 0015-libxl-set-net-disk-trusted-parameter-based-on-backen.patch + 0016-libxl-setup-shadow-memory-according-to-max-hotplug-m.patch + 0017-Add-powerManagementFiltering-for-PCI-PM-control.patch + 0018-libxl-don-t-create-vkb-device-for-qubes-graphics-out.patch + ''; +in + +assert libvirt.version == versionPatches; + +(libvirt.override { + enableXen = true; + xen = qubes-vmm-xen; +}).overrideAttrs (oldAttrs: { + pname = "qubes-core-libvirt"; + version = "${versionPatches}-${versionSuffix}"; + + # I am too lazy to list patches using patches & fetchpatch, we need some ready to use + # updater script for that. + postPatch = '' + # series-qubes.conf in patches repo is outdated! + echo "${patchSeries}" > series-qubes.conf + ${patches}/apply-patches series-qubes.conf ${patches} + '' + optionalString (oldAttrs ? postPatch) oldAttrs.postPatch; + + # FIXME: Override maintainers +}) diff --git a/pkgs/by-name/qu/qubes-core-qubesdb/0001-fix-cmd-name-parsing.patch b/pkgs/by-name/qu/qubes-core-qubesdb/0001-fix-cmd-name-parsing.patch new file mode 100644 index 0000000000000..5344077ebcc68 --- /dev/null +++ b/pkgs/by-name/qu/qubes-core-qubesdb/0001-fix-cmd-name-parsing.patch @@ -0,0 +1,36 @@ +From 08b26522e48dfd7b645b90f03b744d92f1a3c29f Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Wed, 11 Sep 2024 23:04:11 +0200 +Subject: [PATCH] fix: cmd name parsing + +--- + qubesdb-cmd.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/qubesdb-cmd.c b/qubesdb-cmd.c +index fc2c961..0c6d909 100644 +--- a/qubesdb-cmd.c ++++ b/qubesdb-cmd.c +@@ -287,7 +287,18 @@ int main(int argc, char **argv) { + int last_optind; + qdb_handle_t h; + +- if ((cmd_argv0=strchr(argv[0], '-'))) { ++ char *cmd_argv0_tmp; ++ ++ // qubesdb-cmd tries to parse first argument by removing part before first -, and then taking the rest ++ // in QubesOS that works well: /bin/qubesdb-read => read, however in nixos, path before can contain a -: ++ // /nix/store/aaaaaa-qubesdb/qubesdb-read => qubesdb/qubesdb-read, which is not a valid qubesdb command. ++ // Fix it by first taking a filename (=removing all components ending in /) of a path. ++ cmd_argv0 = argv[0]; ++ while ((cmd_argv0_tmp=strchr(cmd_argv0, '/'))) { ++ cmd_argv0 = cmd_argv0_tmp + 1; ++ } ++ ++ if ((cmd_argv0=strchr(cmd_argv0, '-'))) { + cmd_argv0++; + do_cmd = parse_cmd(cmd_argv0); + } +-- +2.45.2 + diff --git a/pkgs/by-name/qu/qubes-core-qubesdb/package.nix b/pkgs/by-name/qu/qubes-core-qubesdb/package.nix new file mode 100644 index 0000000000000..a788a8a8bbb12 --- /dev/null +++ b/pkgs/by-name/qu/qubes-core-qubesdb/package.nix @@ -0,0 +1,123 @@ +{ + lib, + stdenv, + fetchFromGitHub, + qubes-core-vchan-xen, + pkg-config, + systemd, + withPython ? false, + python ? null, +}: +let + inherit (lib) optionalString optionals optional optionalAttrs; + + version = "4.2.6"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-core-qubesdb"; + rev = "refs/tags/v${version}"; + hash = "sha256-vPv74tBD7elYNqpgKLFKAanMH8D18OdDj0xhmw8aWwM="; + }; + + daemon = stdenv.mkDerivation { + inherit src version; + pname = "qubes-core-qubesdb-daemon"; + + sourceRoot = "${src.name}/daemon"; + + postPatch = '' + # vchan module needs to be loaded using system-specific means. + substituteInPlace qubes-db.service \ + --replace-fail " fedora-loadmodules.service" "" + substituteInPlace *.service \ + --replace-fail "ExecStart=/usr/sbin/qubesdb-daemon" "ExecStart=$out/bin/qubesdb-daemon" + ''; + + nativeBuildInputs = [ + pkg-config + ]; + buildInputs = [ + qubes-core-vchan-xen + systemd.dev + ]; + + postInstall = '' + install -D -m0444 -t $out/lib/systemd/system *.service + ''; + + makeFlags = [ "DESTDIR=$(out)" "SBINDIR=/bin" "LIBDIR=/lib" ]; + + inherit meta; + }; + + pythonModule = python.pkgs.buildPythonPackage { + inherit src version; + pname = "qubes-core-qubesdb-daemon-python"; + + sourceRoot = "${src.name}/python"; + + nativeBuildInputs = [ + pkg-config + ]; + + build-system = [ + python.pkgs.setuptools + ]; + + buildInputs = [ + client + ]; + + makeFlags = [ "DESTDIR=$(out)" "LIBDIR=/lib" "PYTHON_PREFIX_ARG=--prefix=." ]; + + pythonImportsCheck = ["qubesdb"]; + + inherit meta; + }; + + client = stdenv.mkDerivation { + inherit src version; + pname = "qubes-core-qubesdb-client"; + + sourceRoot = "${src.name}/client"; + + patches = [ + ./0001-fix-cmd-name-parsing.patch + ]; + + # binaries in client take around 20K of space, not worth splitting those. + postInstall = '' + make -C ../include install $makeFlags + ''; + + nativeBuildInputs = [ + pkg-config + ] ++ optionals withPython [ + python + python.pkgs.setuptools + ]; + + buildInputs = [ + qubes-core-vchan-xen + ]; + + makeFlags = [ "DESTDIR=$(out)" "BINDIR=/bin" "LIBDIR=/lib" "INCLUDEDIR=/include" ]; + + inherit meta; + }; + + meta = { + description = "Qubes VM configuration interface."; + homepage = "https://qubes-os.org"; + license = lib.licenses.gpl2Plus; + maintainers = with lib.maintainers; [ lach sigmasquadron ]; + # daemon can also work on windows, ignoring for now. + platforms = lib.platforms.linux; + }; +in client.overrideAttrs { + passthru = { + inherit daemon; + } // optionalAttrs withPython { + inherit pythonModule; + }; +} diff --git a/pkgs/by-name/qu/qubes-desktop-linux-kde/package.nix b/pkgs/by-name/qu/qubes-desktop-linux-kde/package.nix new file mode 100644 index 0000000000000..fc80ed9f1c425 --- /dev/null +++ b/pkgs/by-name/qu/qubes-desktop-linux-kde/package.nix @@ -0,0 +1,42 @@ +{ + lib, + stdenv, + fetchFromGitHub, + python3, +}: +let + inherit (python3.pkgs) qubes-core-admin-client; + version = "4.2.0"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-desktop-linux-kde"; + rev = "refs/tags/R${version}"; + hash = "sha256-25j3aii64wAGjm/orMMPGO08Dx/adOufr0Lcbn8A848="; + }; +in +# NOTE: Only window colorschema generator is packaged here, original +# also has such things as changing default panel configuration, which is not wanted. +stdenv.mkDerivation { + inherit version src; + pname = "qubes-desktop-linux-kde"; + + postPatch = '' + substituteInPlace qubes-generate-color-palette.desktop \ + --replace-fail "Exec=" "Exec=$out/libexec/" + substituteInPlace qubes-generate-color-palette \ + --replace-fail "#!/usr/bin/python3" "Exec=#!/usr/bin/env python3" + ''; + + nativeBuildInputs = [ + python3.pkgs.wrapPython + ]; + + buildPhase = "true"; + + installPhase = '' + mkdir -p $out/{libexec,etc/xdg/autostart} + cp qubes-generate-color-palette $out/libexec/ + cp qubes-generate-color-palette.desktop $out/etc/xdg/autostart/ + wrapPythonProgramsIn $out/libexec ${qubes-core-admin-client} + ''; +} diff --git a/pkgs/by-name/qu/qubes-gui-common/package.nix b/pkgs/by-name/qu/qubes-gui-common/package.nix new file mode 100644 index 0000000000000..017bfd1584f92 --- /dev/null +++ b/pkgs/by-name/qu/qubes-gui-common/package.nix @@ -0,0 +1,25 @@ +{ + lib, + stdenvNoCC, + fetchFromGitHub, +}: +let + version = "4.2.5"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-gui-common"; + rev = "refs/tags/v${version}"; + hash = "sha256-rv80X/wecXRtJ3HhHgksJd43AKvLQTHyX8e1EJPwEO0="; + }; +in +stdenvNoCC.mkDerivation { + inherit version src; + name = "qubes-gui-common"; + + buildPhase = "true"; + + installPhase = '' + mkdir -p $out + cp -r include $out/ + ''; +} diff --git a/pkgs/by-name/qu/qubes-gui-daemon/0001-fix-make-shmoverride-initfirst.patch b/pkgs/by-name/qu/qubes-gui-daemon/0001-fix-make-shmoverride-initfirst.patch new file mode 100644 index 0000000000000..edb97fd44fbd6 --- /dev/null +++ b/pkgs/by-name/qu/qubes-gui-daemon/0001-fix-make-shmoverride-initfirst.patch @@ -0,0 +1,95 @@ +From a1b6626aed57028af0e24fd220be38a6caabcb0f Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Wed, 25 Sep 2024 23:34:35 +0200 +Subject: [PATCH] fix: make shmoverride initfirst + +--- + shmoverride/shmoverride.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +diff --git a/shmoverride/shmoverride.c b/shmoverride/shmoverride.c +index d399905..3cd9536 100644 +--- a/shmoverride/shmoverride.c ++++ b/shmoverride/shmoverride.c +@@ -72,6 +72,8 @@ static int (*real_munmap) (void *shmaddr, size_t len); + static int (*real_fstat64) (VER_ARG int fd, struct stat64 *buf); + static int (*real_fstat)(VER_ARG int fd, struct stat *buf); + ++static int try_init(void); ++ + static struct stat global_buf; + static int gntdev_fd = -1; + +@@ -84,7 +86,7 @@ static int xc_hnd; + static xengnttab_handle *xgt; + static char __shmid_filename[SHMID_FILENAME_LEN]; + static char *shmid_filename = NULL; +-static int idfd = -1, display = -1; ++static int idfd = -1, display = -1, init_called = 0; + + static uint8_t *mmap_mfns(struct shm_args_hdr *shm_args) { + uint8_t *map; +@@ -151,6 +153,8 @@ ASM_DEF(void *, mmap, + real_fstat = FSTAT; + } + ++ try_init(); ++ + #if defined MAP_ANON && defined MAP_ANONYMOUS && (MAP_ANONYMOUS) != (MAP_ANON) + # error header bug (def mismatch) + #endif +@@ -217,6 +221,9 @@ ASM_DEF(int, munmap, void *addr, size_t len) + { + if (len > SIZE_MAX - XC_PAGE_SIZE) + abort(); ++ ++ try_init(); ++ + const uintptr_t addr_int = (uintptr_t)addr; + const uintptr_t rounded_addr = addr_int & ~(uintptr_t)(XC_PAGE_SIZE - 1); + return real_munmap((void *)rounded_addr, len + (addr_int - rounded_addr)); +@@ -438,6 +445,7 @@ static int assign_off(off_t *off) { + + #define STAT(id) \ + ASM_DEF(int, f ## id, int filedes, struct id *buf) { \ ++ try_init(); \ + int res = real_f ## id(VER filedes, buf); \ + if (res || \ + !S_ISCHR(buf->st_mode) || \ +@@ -454,6 +462,7 @@ STAT(stat64) + #ifdef _STAT_VER + #define STAT(id) \ + ASM_DEF(int, __fx ## id, int ver, int filedes, struct id *buf) { \ ++ try_init(); \ + if (ver != _STAT_VER) { \ + fprintf(stderr, \ + "Wrong _STAT_VER: got %d, expected %d, libc has incompatibly changed\n", \ +@@ -467,8 +476,13 @@ STAT(stat64) + #undef STAT + #endif + +-int __attribute__ ((constructor)) initfunc(void) ++static int try_init(void) + { ++ // Ideally it is being called in constructor, if something is calling this before ++ // constructor - we're assuming it is not multi-threaded code. ++ if (__builtin_expect(init_called, 1)) return 0; ++ init_called = 1; ++ + unsetenv("LD_PRELOAD"); + fprintf(stderr, "shmoverride constructor running\n"); + dlerror(); +@@ -581,6 +595,10 @@ cleanup: + shm_args = NULL; + return 0; + } ++int __attribute__ ((constructor)) initfunc(void) ++{ ++ return try_init(); ++} + + int __attribute__ ((destructor)) descfunc(void) + { +-- +2.46.0 + diff --git a/pkgs/by-name/qu/qubes-gui-daemon/package.nix b/pkgs/by-name/qu/qubes-gui-daemon/package.nix new file mode 100644 index 0000000000000..07a3c7b85a34d --- /dev/null +++ b/pkgs/by-name/qu/qubes-gui-daemon/package.nix @@ -0,0 +1,117 @@ +{ + lib, + stdenv, + fetchFromGitHub, + pkg-config, + xorg, + libconfig, + libnotify, + glib, + qubes-core-vchan-xen, + qubes-gui-common, + qubes-linux-utils, + qubes-vmm-xen, + help2man, + pulseaudio, + qubes-core-qubesdb, + python3Packages, + runCommand, + xwayland, + makeWrapper, +}: +let + inherit (python3Packages) wrapPython xcffib qubes-imgconverter; + + version = "4.3.3"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-gui-daemon"; + rev = "refs/tags/v${version}"; + hash = "sha256-m/a/JrDd3na7pKuYW+p+J/FoDx0bLeKHtO/QB+c88q0="; + }; + daemon = stdenv.mkDerivation { + inherit version src; + name = "qubes-gui-daemon"; + + patches = [ + # Daemon crashes on NixOS without this patch. Submitted to upstream + # https://github.com/QubesOS/qubes-gui-daemon/pull/148 + ./0001-fix-make-shmoverride-initfirst.patch + ]; + + nativeBuildInputs = [ + pkg-config + help2man + wrapPython + ]; + + buildInputs = [ + xorg.libX11.dev + xorg.libxcb.dev + xorg.xcbutil.dev + xorg.libXrandr.dev + libnotify.dev + glib + libconfig + qubes-core-vchan-xen + qubes-gui-common + qubes-linux-utils + qubes-core-qubesdb + qubes-vmm-xen.dev + pulseaudio + ]; + + buildFlags = [ "all" ]; + + postInstall = '' + mv $out/usr/* $out/ + mv $out/lib64/* $out/lib + rm -d $out/{usr,lib64} + + substituteInPlace $out/etc/xdg/autostart/qubes-{icon-receiver,screen-layout-watches}.desktop \ + --replace-fail "Exec=/usr/" "$out/" + substituteInPlace $out/lib/qubes/icon-receiver \ + --replace-fail "#!/usr/bin/python3" "#!/usr/bin/env python3" + wrapPythonProgramsIn $out/lib/qubes "${qubes-imgconverter}" "${xcffib}" + ''; + + # Package setups fortification by itself, nixos flags cause "_FORTIFY_SOURCE redefined" error + hardeningDisable = [ "fortify" ]; + + makeFlags = [ "DESTDIR=$(out)" ]; + }; + # TODO: Patch xwayland derivation instead, and pass wrapper flags here? + xwayland-patched = + runCommand "xwayland-qubes" + { + nativeBuildInputs = [ + makeWrapper + ]; + } + '' + mkdir -p $out + cp -r ${xwayland}/* $out/ + chmod -R a+w $out/bin + + wrapProgram $out/bin/Xwayland \ + --prefix LD_PRELOAD : ${daemon}/lib/qubes-gui-daemon/shmoverride.so + substituteInPlace $out/share/applications/org.freedesktop.Xwayland.desktop \ + --replace-fail "Exec=${xwayland}/bin/Xwayland" "Exec=$out/bin/Xwayland" + ''; +in +daemon.overrideAttrs { + passthru = { + xwayland = xwayland-patched; + }; + + meta = { + description = "Qubes GUID and Xorg LD_PRELOAD payload"; + homepage = "https://qubes-os.org"; + license = lib.licenses.gpl2Plus; + maintainers = with lib.maintainers; [ + lach + sigmasquadron + ]; + platforms = lib.platforms.linux; + }; +} diff --git a/pkgs/by-name/qu/qubes-linux-utils/package.nix b/pkgs/by-name/qu/qubes-linux-utils/package.nix new file mode 100644 index 0000000000000..ab6fdd15a5631 --- /dev/null +++ b/pkgs/by-name/qu/qubes-linux-utils/package.nix @@ -0,0 +1,102 @@ +{ + lib, + stdenv, + fetchFromGitHub, + icu, + pkg-config, + qubes-vmm-xen, + patsh, + qubes-core-qubesdb, + kmod, + graphicsmagick, + + withPython ? false, + python ? null, +}: +let + inherit (lib) optionalAttrs; + + version = "4.3.4"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-linux-utils"; + rev = "refs/tags/v${version}"; + hash = "sha256-h1e+M7h3GUkQQKJWYAkhJ/kLPNc+LUIEp8THItmyers="; + }; + + imgconverter = python.pkgs.buildPythonPackage { + inherit src version; + pname = "qubes-linux-utils-imgconverter"; + + sourceRoot = "${src.name}/imgconverter"; + + nativeBuildInputs = [ + pkg-config + ]; + + build-system = [ + python.pkgs.setuptools + ]; + + propagatedBuildInputs = [ + python.pkgs.pilkit + python.pkgs.numpy + python.pkgs.pycairo + graphicsmagick + ]; + + makeFlags = [ "DESTDIR=$(out)" "LIBDIR=/lib" "PYTHON_PREFIX_ARG=--prefix=." ]; + + pythonImportsCheck = ["qubesimgconverter"]; + }; +in +stdenv.mkDerivation { + inherit version src; + pname = "qubes-linux-utils"; + + # imgconverter is built in separate derivation + postPatch = '' + substituteInPlace Makefile \ + --replace-fail "\$(MAKE) -C imgconverter all" "" \ + --replace-fail "\$(MAKE) -C imgconverter install" "" + substituteInPlace qmemman/*.service \ + --replace-fail "ExecStart=/usr/sbin/meminfo-writer" "ExecStart=$out/bin/meminfo-writer" + ''; + + nativeBuildInputs = [ + pkg-config + patsh + ]; + + buildInputs = [ + icu.dev + qubes-vmm-xen.dev + + qubes-core-qubesdb + kmod + ]; + + postInstall = '' + mv $out/usr/lib/systemd $out/lib/ + rm -d $out/usr/{lib,} + + substituteInPlace $out/lib/udev/rules.d/99-qubes-{usb,block}.rules \ + --replace-fail '/usr/lib/qubes/' "$out/libexec/qubes/" + + for hook in block-add-change block-remove usb-add-change usb-remove; do + substituteInPlace $out/libexec/qubes/udev-$hook \ + --replace-quiet "/sbin/modprobe" "/bin/modprobe" + patsh -f $out/libexec/qubes/udev-$hook -s ${builtins.storeDir} + done + ''; + + makeFlags = [ + "DESTDIR=$(out)" "LIBDIR=/lib" "SCRIPTSDIR=/libexec/qubes" + "SYSLIBDIR=/lib" "INCLUDEDIR=/include" "SBINDIR=/bin" + "CFLAGS=-DUSE_XENSTORE_H" + ]; + + passthru = optionalAttrs withPython { + inherit imgconverter; + }; +} diff --git a/pkgs/by-name/qu/qubes-manager/package.nix b/pkgs/by-name/qu/qubes-manager/package.nix new file mode 100644 index 0000000000000..625abd6b4bc4d --- /dev/null +++ b/pkgs/by-name/qu/qubes-manager/package.nix @@ -0,0 +1,75 @@ +{ + lib, + fetchFromGitHub, + python3Packages, + qt5, +}: +let + inherit (python3Packages) + buildPythonApplication + pyqt5 + setuptools + qubes-core-admin-client + qasync + pyaml + lxml + ; + + version = "4.3.4-1"; + + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-manager"; + rev = "refs/tags/v${version}"; + hash = "sha256-XcegcVjyb1JoXFFIX5Sj/QlZAn1H4bONwPpX/Yd+Njc="; + }; +in +buildPythonApplication { + inherit version src; + pname = "qubes-manager"; + + nativeBuildInputs = [ + setuptools + pyqt5 + qt5.qttools + qt5.wrapQtAppsHook + ]; + + dependencies = [ + pyqt5 + qubes-core-admin-client + qasync + pyaml + lxml + qt5.qtwayland + ]; + + preBuild = '' + make ui res translations python $makeFlags + ''; + + installTargets = [ "python_install" ]; + + postInstall = '' + make install $makeFlags + mv $out/usr/* $out + rm -d $out/usr + ''; + + makeFlags = [ + "DESTDIR=$(out)" + "LRELEASE_QT5=lrelease" + ]; + pythonImportsCheck = [ "qubesmanager" ]; + + meta = { + description = "Qubes management UI"; + homepage = "https://qubes-os.org"; + license = lib.licenses.gpl2Plus; + maintainers = with lib.maintainers; [ + lach + sigmasquadron + ]; + platforms = lib.platforms.linux; + }; +} diff --git a/pkgs/by-name/qu/qubes-seabios/package.nix b/pkgs/by-name/qu/qubes-seabios/package.nix new file mode 100644 index 0000000000000..f5256e8b536c6 --- /dev/null +++ b/pkgs/by-name/qu/qubes-seabios/package.nix @@ -0,0 +1,70 @@ +{ + lib, + stdenv, + stdenvNoCC, + fetchFromGitHub, + python3, + seabios, +}: +let + inherit (lib) concatStringsSep map; + + version = "4.2.0"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-seabios"; + rev = "refs/tags/R${version}"; + hash = "sha256-KEvdQ0VLJSnLRNuzMBWY0LFp9CN1EKq3K2v8Ud/vojc="; + }; + mkBios = { + config, + target ? "", + outBin, + name, + }: stdenv.mkDerivation { + inherit version; + src = seabios.src; + pname = "qubes-seabios-${name}"; + + nativeBuildInputs = [ + python3 + ]; + buildPhase = '' + mkdir binaries + + cp ${src}/${config} .config + make oldnoconfig + make V=1 ${target} + ''; + installPhase = '' + mkdir $out + ls out + cp out/${outBin} $out/${name} + ''; + }; + mkVgaBios = name: mkBios {config="config.vga-${name}"; outBin = "vgabios.bin"; name = "vgabios-${name}.bin"; target = "out/vgabios.bin";}; + # For me the build is breaking if trying to build all packages in the same derivation, + # they are conflicting somehow. Building everything by itself, and then combining into a single dir. + seabioses = concatStringsSep "," [ + (mkBios {config = "config.seabios-128k"; outBin = "bios.bin"; name = "bios.bin";}) + (mkBios {config = "config.seabios-256k"; outBin = "bios.bin"; name = "bios-256k.bin";}) + (mkBios {config = "config.csm"; outBin = "Csm16.bin"; name = "bios-csm.bin";}) + (mkBios {config = "config.coreboot"; outBin = "bios.bin.elf"; name = "bios-coreboot.bin";}) + (mkBios {config = "config.seabios-microvm"; outBin = "bios.bin"; name = "bios-microvm.bin";}) + ]; + # Probably we don't need all of those... Building for completeness. + seavgabioses = concatStringsSep "," (map mkVgaBios ["bochs-display" "cirrus" "isavga" "qxl" "stdvga" "ramfb" "vmware" "virtio" "ati"]); + +in +stdenvNoCC.mkDerivation (finalAttrs: { + name = "qubes-seabios"; + inherit version; + unpackPhase = "true"; + installPhase = '' + mkdir -p $out/share/{seabios,seavgabios} + cp {${seabioses}}/*.bin $out/share/seabios + cp {${seavgabioses}}/*.bin $out/share/seavgabios + ''; + + passthru.firmware = "${finalAttrs.finalPackage}/share/seabios/bios-256k.bin"; +}) diff --git a/pkgs/by-name/qu/qubes-vmm-stubdom-linux/package.nix b/pkgs/by-name/qu/qubes-vmm-stubdom-linux/package.nix new file mode 100644 index 0000000000000..889faab52a7b2 --- /dev/null +++ b/pkgs/by-name/qu/qubes-vmm-stubdom-linux/package.nix @@ -0,0 +1,29 @@ +# Qubes standard stubdom is too hard to build using nix infrastructure. +# In the future, it will be better to replace it with NixOS based stubdom, or maybe based on dockerTools build system? +{fetchurl, stdenv, rpmextract}: +let + version = "4.3.0-1"; + stubdom = fetchurl { + url = "https://ftp.qubes-os.org/repo/yum/r4.3/current-testing/dom0/fc41/rpm/xen-hvm-stubdom-linux-${version}.fc41.x86_64.rpm"; + hash = "sha256-iVMOuZmqgXIrlKFL+ftoBA3qntKjwB3dmz5KEfra26E="; + }; + stubdom-full = fetchurl { + url = "https://ftp.qubes-os.org/repo/yum/r4.3/current-testing/dom0/fc41/rpm/xen-hvm-stubdom-linux-full-${version}.fc41.x86_64.rpm"; + hash = "sha256-wRHnc9dM5NEIHsiSEjQ1aasD73xdpKEq1IFbfjpn7ag="; + }; +in +stdenv.mkDerivation { + name = "qubes-vmm-stubdom-linux"; + src = null; + unpackPhase = "true"; + buildPhase = "true"; + + nativeBuildInputs = [rpmextract]; + + installPhase = '' + mkdir $out + rpmextract ${stubdom} + rpmextract ${stubdom-full} + mv usr/libexec $out/ + ''; +} diff --git a/pkgs/by-name/qu/qubes-vmm-xen/package.nix b/pkgs/by-name/qu/qubes-vmm-xen/package.nix new file mode 100644 index 0000000000000..6f9d922444a75 --- /dev/null +++ b/pkgs/by-name/qu/qubes-vmm-xen/package.nix @@ -0,0 +1,122 @@ +{ + lib, + fetchpatch, + callPackage, + ocaml-ng, + xen, + python3, + qubes-seabios, + qubes-vmm-stubdom-linux, + ... +}@genericDefinition: + +let + pname = "qubes-vmm-xen"; + branch = "4.19"; + versionPatches = "4.19.0"; + versionSuffix = "3"; + version = "${versionPatches}-${versionSuffix}"; + latest = true; + + xenPatches = import ../../../applications/virtualization/xen/generic/patches.nix { + inherit lib fetchpatch; + }; + xenPatchList = lib.lists.flatten ( + with xenPatches; + [ + XSA_460 + XSA_461 + ] + ); + + qubesPatches = import ./patches.nix { + inherit fetchpatch version; + }; + qubesPatchList = lib.lists.flatten ( + with qubesPatches; + [ + EFI_WORKAROUNDS + BACKPORTS + UPSTREAMABLE_PATCHES + QUBES_SPECIFIC_PATCHES + OTHERS + ] + ); +in + +(callPackage + (import ../../../applications/virtualization/xen/generic/default.nix { + inherit + pname + branch + version + latest + ; + pkg = { + xen = { + rev = "026c9fa29716b0ff0f8b7c687908e71ba29cf239"; + hash = "sha256-Q6x+2fZ4ITBz6sKICI0NHGx773Rc919cl+wzI89UY+Q="; + patches = [ ] ++ xenPatchList ++ qubesPatchList; + }; + qemu = { + rev = "0df9387c8983e1b1e72d8c574356f572342c03e6"; + hash = "sha256-BX+LXfNzwdUMALwwI1ZDW12dJ357oynjnrboLHREDGQ="; + patches = [ ]; + }; + seaBIOS = { + rev = "a6ed6b701f0a57db0569ab98b0661c12a6ec3ff8"; + hash = "sha256-hWemj83cxdY8p+Jhkh5GcPvI0Sy5aKYZJCsKDjHTUUk="; + patches = [ ]; + }; + ovmf = { + rev = "ba91d0292e593df8528b66f99c1b0b14fadc8e16"; + hash = "sha256-htOvV43Hw5K05g0SF3po69HncLyma3BtgpqYSdzRG4s="; + patches = [ ]; + }; + ipxe = { + rev = "1d1cf74a5e58811822bee4b3da3cff7282fcdfca"; + hash = "sha256-8pwoPrmkpL6jIM+Y/C0xSvyrBM/Uv0D1GuBwNm+0DHU="; + patches = [ ]; + }; + }; + + meta = { + inherit branch; + description = "Qubes component: vmm-xen"; + longDescription = '' + Qubes OS' modified version of the Xen Hypervisor. + Contains dozens of Qubes-specific patches, and is intended to power a Qubes OS Domain 0. + + This is effectively a `xen-slim` build. Use with `qemu_qubes`. + ''; + homepage = "https://qubes-os.org"; + downloadPage = "https://github.com/QubesOS/qubes-vmm-xen"; + license = xen.meta.license; + mainProgram = "xl"; + platforms = lib.lists.intersectLists lib.platforms.linux lib.platforms.x86_64; + maintainers = with lib.maintainers; [ sigmasquadron ]; + }; + }) + ( + { + python = python3; + withInternalQEMU = false; + withInternalSeaBIOS = false; + seabios = qubes-seabios; + withInternalIPXE = false; + withInternalOVMF = false; + withFlask = false; + ocamlPackages = ocaml-ng.ocamlPackages_4_14; + } + // genericDefinition + ) +).overrideAttrs (oldAttrs: { + # FIXME: Drop after rebasing to latest changes in https://github.com/NixOS/nixpkgs/pull/341429 + passthru = oldAttrs.passthru // { + efi = "boot/xen-${versionPatches}.efi"; + }; + postInstall = oldAttrs.postInstall + '' + ln -sf ${qubes-vmm-stubdom-linux}/libexec/xen/boot/qemu-stubdom-linux{-full,}-{kernel,rootfs} \ + $out/libexec/xen/boot/ + ''; +}) diff --git a/pkgs/by-name/qu/qubes-vmm-xen/patches.nix b/pkgs/by-name/qu/qubes-vmm-xen/patches.nix new file mode 100644 index 0000000000000..31d710cd7c1d7 --- /dev/null +++ b/pkgs/by-name/qu/qubes-vmm-xen/patches.nix @@ -0,0 +1,309 @@ +{ fetchpatch, version }: + +let + qubesPatch = + { + name, + tag ? version, + type ? "qubes", + hash ? "", + }: + (fetchpatch { + inherit name; + url = "https://raw.githubusercontent.com/QubesOS/qubes-vmm-xen/v${tag}/${name}.patch"; + inherit hash; + passthru.type = type; + }); +in +{ + # We obviously don't need Fedora-specific patches, so this is only included here for completeness. + FEDORA = [ ]; + EFI_WORKAROUNDS = [ + (qubesPatch { + name = "0200-EFI-early-Add-noexit-to-inhibit-calling-ExitBootServ"; + hash = "sha256-77PNyzpUaNG/wi5jjWtJy3SOdCc0+MbrcVrEywWBaok="; + }) + (qubesPatch { + name = "0201-efi-Ensure-incorrectly-typed-runtime-services-get-ma"; + hash = "sha256-wihn9o0IrCAMRpWL+Fbjmyhs0d27n3pCHmECCA5hp9s="; + }) + (qubesPatch { + name = "0202-Add-xen.cfg-options-for-mapbs-and-noexitboot"; + hash = "sha256-ydQgH3aMZO4/Wb8VNaU7/DZF/Hhti15zWGVYTa5PKmk="; + }) + (qubesPatch { + name = "0203-xen.efi.build"; + hash = "sha256-/uWEh/QuHHYuqm4pxFJBRQIXb0jTErGQk0Kiwpy4CeY="; + }) + ]; + BACKPORTS = [ + (qubesPatch { + name = "0300-xen-list-add-LIST_HEAD_RO_AFTER_INIT"; + hash = "sha256-q2lWcFTT7xq2lFjmBFq/5mYdvkKW81/3H2jEwRA/+aQ="; + }) + (qubesPatch { + name = "0301-x86-mm-add-API-for-marking-only-part-of-a-MMIO-page-"; + hash = "sha256-qX82j6ELrQTmrlzjz5/T9BHQnV/MuNTrjwl771DYLas="; + }) + # Identical to 0319, for some reason. + (qubesPatch { + name = "0302-drivers-char-Use-sub-page-ro-API-to-make-just-xhci-d"; + hash = "sha256-DeQx+g/jEYEzUDzLtIX5rVU1DFIu1mTRMbmQEiTF6Qc="; + }) + ]; + # We already get XSA patches from Xen, so this is only included here for completeness. + SECURITY_FIXES = [ + (qubesPatch { + name = "0500-xsa458"; + hash = "sha256-yHI9Sp/7Ed40iIYQ/HOOIULlfzAzL0c0MGqdF+GR+AQ="; + }) + ]; + UPSTREAMABLE_PATCHES = [ + (qubesPatch { + name = "0600-libxl-create-writable-error-xenstore-dir"; + hash = "sha256-yhGIDJGN+JYV0zJeNJvfNx5ju8IFQL8Zl+Ol0HZGKCc="; + }) + (qubesPatch { + name = "0601-libxl-do-not-wait-for-backend-on-PCI-remove-when-bac"; + hash = "sha256-tbudNDBFK/NS7oa9SsM6xcOBwOjbxciCkEjqG/QVkn0="; + }) + (qubesPatch { + name = "0602-libxl-do-not-fail-device-removal-if-backend-domain-i"; + hash = "sha256-s6vmNVWtajYnpClpNMt9c12hQ/r7a+Q/5g/8Fafv7f0="; + }) + (qubesPatch { + name = "0603-libvchan-use-xengntshr_unshare-instead-of-munmap-dir"; + hash = "sha256-IDXsXmofLW6+Vamwdxywprt1IrO3C5EDssgxugcYc4Q="; + }) + (qubesPatch { + name = "0604-x86-time-Don-t-use-EFI-s-GetTime-call-by-default"; + hash = "sha256-rUVWHu64HHNfjcRCMMEUF9y9UtMMrkxqFDLUc3BenGM="; + }) + (qubesPatch { + name = "0605-libxl-automatically-enable-gfx_passthru-if-IGD-is-as"; + hash = "sha256-R5jsBSx8nCrve0FW/Fw70zD4GnHBRymFlHx5CPkyWVs="; + }) + (qubesPatch { + name = "0606-autoconf-fix-handling-absolute-PYTHON-path"; + hash = "sha256-8OUOxMB6FI12NtWQBNegF2c6x1pKF0KfGwMV08cSz5s="; + }) + (qubesPatch { + name = "0607-libxl-do-not-require-filling-backend_domid-to-remove"; + hash = "sha256-9eg2PIs+NJgmAJa7piIIMfIt7lVZqx+Aa6FSdZc6M9o="; + }) + (qubesPatch { + name = "0608-libxl-add-pcidevs-to-stubdomain-earlier"; + hash = "sha256-I/C5Cq1+vG2WEIfm7kxX5DntvjGcLrU2sTmHcoF69do="; + }) + (qubesPatch { + name = "0609-Fix-buildid-alignment"; + hash = "sha256-vwqibkhezWa8STghaUZ+d80w/qudjyc665l/kO/tnvs="; + }) + (qubesPatch { + name = "0610-vchan-socket-proxy-add-reconnect-marker-support"; + hash = "sha256-Z4EbS4bqAKC7/3D4t710HJdhwfHu6vGiPospUlyT7vM="; + }) + (qubesPatch { + name = "0611-tools-libxl-enable-in-band-reconnect-marker-for-stub"; + hash = "sha256-sQKycDr2w6P6dw6KAS/g3pOmb8u6bimOQk2k6Ist/3Y="; + }) + (qubesPatch { + name = "0612-libxl-Add-a-utility-function-for-domain-resume"; + hash = "sha256-/Tj1eIUvTNhyHIJ0wUyQwxQO04YWnJzaQ46PFPd5UAc="; + }) + (qubesPatch { + name = "0613-libxl-Properly-suspend-stubdomains"; + hash = "sha256-MXvnjABA/WyM26D/gR8T2XV1idQyK3pc/1C1pbj2gW4="; + }) + (qubesPatch { + name = "0614-libxl-Fix-race-condition-in-domain-suspension"; + hash = "sha256-paNCg7rpaBiDHFM2LAkDcID3UiUZ0XtjJOCpPsLz0hA="; + }) + (qubesPatch { + name = "0615-libxl-Add-additional-domain-suspend-resume-logs"; + hash = "sha256-6iNcHlirlqEHuOxwslG0dDHa2lPZqTuCrLSpRr2s0L0="; + }) + (qubesPatch { + name = "0616-libxl-workaround-for-Windows-PV-drivers-removing-con"; + hash = "sha256-8zDDw78bjz4oGbYaUNoSuMO6eWOoj+gfXZ0l2xHNLqQ="; + }) + (qubesPatch { + name = "0617-libxl-check-control-feature-before-issuing-pvcontrol"; + hash = "sha256-9nVim2eRxG/HsuulWtkUxbXPWd2LV82QGr4WpM7FlgQ="; + }) + (qubesPatch { + name = "0618-tools-kdd-mute-spurious-gcc-warning"; + hash = "sha256-1ODg5Q+sciLT4OYIEfDWaPXblxxxJaiR7naNBKBPwV8="; + }) + (qubesPatch { + name = "0619-libxl-do-not-start-qemu-in-dom0-just-for-extra-conso"; + hash = "sha256-A72XOJjNxxYevJq5QyrRWvWQrrJapmZ/syAai146RJ0="; + }) + (qubesPatch { + name = "0620-libxl-Allow-stubdomain-to-control-interupts-of-PCI-d"; + hash = "sha256-RpWQlMu9S7Y2h98U4+6Lxumbv7KTje9imEhAls4rN4E="; + }) + (qubesPatch { + name = "0621-Validate-EFI-memory-descriptors"; + hash = "sha256-gXJj7f9ZDc5gZ2H3fG8SSamQObldkY/Pmag2/RMNkKk="; + }) + (qubesPatch { + name = "0622-x86-mm-make-code-robust-to-future-PAT-changes"; + hash = "sha256-v62CaJOSeIiCOn2oeoRcKi93VLu9zVGOeWIFDI6ViX8="; + }) + (qubesPatch { + name = "0623-Drop-ELF-notes-from-non-EFI-binary-too"; + hash = "sha256-PLTr7oZ7BffIGSGtgqJgpAIB1/n87M64UJSoES0h2D8="; + }) + (qubesPatch { + name = "0624-xenpm-Factor-out-a-non-fatal-cpuid_parse-variant"; + hash = "sha256-JkAaDDaXAikuaXL3vP1aqfpIBdxvFr132WjB+M2JdNY="; + }) + (qubesPatch { + name = "0625-x86-idle-Get-PC-8.10-counters-for-Tiger-and-Alder-La"; + hash = "sha256-pxLu9DYuA+7mtRTLdWc+5T4Pegl1ovdjtjpOIUXQZUY="; + }) + (qubesPatch { + name = "0626-x86-ACPI-Ignore-entries-marked-as-unusable-when-pars"; + hash = "sha256-Nz3qVXma0CSyoSqlhXqw+b1/Pn4l/IIJxq9akRJ/PqU="; + }) + (qubesPatch { + name = "0627-x86-msr-Allow-hardware-domain-to-read-package-C-stat"; + hash = "sha256-FD5iON3v4LvEL965WizuVY5l8Xcvj2ZdGlkN7YXP+Nk="; + }) + (qubesPatch { + name = "0628-x86-mwait-idle-Use-ACPI-for-CPUs-without-hardcoded-C"; + hash = "sha256-39zprrOQbd3kkPGilT0FkoQKWjkXULkNaHKyP4gbHwA="; + }) + (qubesPatch { + name = "0629-libxl_pci-Pass-power_mgmt-via-QMP"; + hash = "sha256-RXzoxDADWe+Gr2O6Vch+iCInye+0V4S+n5fQgcReskI="; + }) + (qubesPatch { + name = "0653-python-avoid-conflicting-_FORTIFY_SOURCE-values"; + hash = "sha256-OeyNaBtqpqoCsVv85sYgaAEzz8jYcv32BnnvYKHbsqA="; + }) + ]; + QUBES_SPECIFIC_PATCHES = [ + (qubesPatch { + name = "1000-Do-not-access-network-during-the-build"; + hash = "sha256-lb/8vKZOcl+kT8lbr6ycneve7i+B6tV3PnvRcPV18bo="; + }) + (qubesPatch { + name = "1001-hotplug-store-block-params-for-cleanup"; + hash = "sha256-exumEe3L7q+yVT7GR4D1mprFe7NRpTCOjo/Qx8XVtAQ="; + }) + (qubesPatch { + name = "1002-libxl-do-not-start-dom0-qemu-when-not-needed"; + hash = "sha256-nu/trIFKABlK8JwoPJ32Ni9zuJJM924qQ1/Xg9+YEBo="; + }) + (qubesPatch { + name = "1003-libxl-do-not-start-qemu-in-dom0-if-possible"; + hash = "sha256-HbYo4SIPK5fp/KeJW9y0etnXrktvYCTlMdMAticiGo0="; + }) + (qubesPatch { + name = "1004-systemd-enable-xenconsoled-logging-by-default"; + hash = "sha256-cH1FjAC561gyHkmi1x5Yh2x9gHikWIeFnWe9a6GMR18="; + }) + (qubesPatch { + name = "1005-hotplug-trigger-udev-event-on-block-attach-detach"; + hash = "sha256-j8DVPKHwju5gTxo2pt/nhyRK+uEWm90DAW+GYCJbIKg="; + }) + (qubesPatch { + name = "1006-libxl-use-EHCI-for-providing-tablet-USB-device"; + hash = "sha256-fECl6ZN0OZPyd+tmbAESks+WYytXQFPE8EWtg6oueGM="; + }) + (qubesPatch { + name = "1007-libxl-allow-kernel-cmdline-without-kernel-if-stubdom"; + hash = "sha256-jZpcicFPPhwQ5twHBOISwQGfDUi8gfqRylVU5ErJELk="; + }) + (qubesPatch { + name = "1008-libxl-Force-emulating-readonly-disks-as-SCSI"; + hash = "sha256-J1ikG0uS6tBEbM4XaQzE3NQuoSCMU0elOi76hiEnfUU="; + }) + (qubesPatch { + name = "1009-tools-xenconsole-replace-ESC-char-on-xenconsole-outp"; + hash = "sha256-NfYqkVX9JVSyivIti0cCJqNYEvVrFR6YeINzmELnjUM="; + }) + (qubesPatch { + name = "1010-libxl-disable-vkb-by-default"; + hash = "sha256-Rre4t5RN9/ArJTWvekus5AGHQZBAEvYIPQpL+K++H1o="; + }) + (qubesPatch { + name = "1011-Always-allocate-domid-sequentially-and-do-not-reuse-"; + hash = "sha256-qTW6KEXHpXgTQ940wr6lPXuK8rdnRLTb9PPzfctDOuA="; + }) + (qubesPatch { + name = "1012-libxl-add-qubes-gui-graphics"; + hash = "sha256-l9X41h1oXffflAkGDHSbqJPHMI9pZWCSoYQgMyoCXWI="; + }) + (qubesPatch { + name = "1013-Additional-support-in-ACPI-builder-to-support-SLIC-a"; + hash = "sha256-Dkk0JrWwTA8s6iN8YzSOgxY8D/jXVpmPb1rym/XtsRc="; + }) + (qubesPatch { + name = "1014-libxl-conditionally-allow-PCI-passthrough-on-PV-with"; + hash = "sha256-F+02vSeVvSYGOE+e5HmRxzdY/xJNh4AVseh2QV0cV7U="; + }) + (qubesPatch { + name = "1015-gnttab-disable-grant-tables-v2-by-default"; + hash = "sha256-jU1NGV8fdzIyDuDQkd7JxJrHds50jmcnRM7zOHL0CjM="; + }) + (qubesPatch { + name = "1016-cpufreq-enable-HWP-by-default"; + hash = "sha256-xJ7XKtJHW/hUqZ3WYcafiTK9+z4JWNadG1tmWCoMqnI="; + }) + (qubesPatch { + name = "1017-Fix-IGD-passthrough-with-linux-stubdomain"; + hash = "sha256-XWEgC7JQ0buCjaILLbiJjMqC76M4Kcuf9OHVlk4LuvU="; + }) + ]; + OTHERS = [ + (qubesPatch { + name = "1100-Define-build-dates-time-based-on-SOURCE_DATE_EPOCH"; + hash = "sha256-IrkLEu9sVX6vu9D3ixBz1M2todAm9+YKc54KvnOL8tI="; + }) + (qubesPatch { + name = "1101-docs-rename-DATE-to-PANDOC_REL_DATE-and-allow-to-spe"; + hash = "sha256-k3CflQthQWK3GPgsDPTFqRv9047J0grar16X1X/VIt8="; + }) + (qubesPatch { + name = "1102-docs-xen-headers-use-alphabetical-sorting-for-incont"; + hash = "sha256-mQUp2w9lUb7KDq5MuPQjs6y7iuMDeXoZjDjlXfa5z44="; + }) + (qubesPatch { + name = "1103-Strip-build-path-directories-in-tools-xen-and-xen-ar"; + hash = "sha256-DzEBjWqhew3u+8H8D8B8luwcr0B0L9enGmgrEm1Fzh4="; + }) + (qubesPatch { + name = "1200-hypercall-XENMEM_get_mfn_from_pfn"; + hash = "sha256-2tRs+RyvkkmJasyMgj4VIf19jtpEIpvtaEWpfDkYnhg="; + }) + (qubesPatch { + name = "1201-patch-gvt-hvmloader.patch"; + hash = "sha256-uE2YEv94h1/7uOyI43+aTEjeIBqTaRqfSQyuhzvhxP8="; + }) + (qubesPatch { + name = "1202-libxl-Add-partially-Intel-GVT-g-support-xengt-device"; + hash = "sha256-MipDZNzYE5YC4vOXbdd4ZKsU/oB/PDT7KFI0xZly40w="; + }) + ]; + UNUSED = [ + (qubesPatch { + name = "0317-xen-list-add-LIST_HEAD_RO_AFTER_INIT"; + hash = "sha256-q2lWcFTT7xq2lFjmBFq/5mYdvkKW81/3H2jEwRA/+aQ="; + }) + (qubesPatch { + name = "0318-x86-mm-add-API-for-marking-only-part-of-a-MMIO-page-"; + hash = "sha256-UbBgHADeeXXk0DzoITFhm8WqOh0Q9Ghbpaol3tBwKDw="; + }) + (qubesPatch { + name = "0319-drivers-char-Use-sub-page-ro-API-to-make-just-xhci-d"; + hash = "sha256-rzKXfmd587y9lTEYd7Gc/q2wmdTVeOLhthUBOGLtlZ0="; + }) + (qubesPatch { + name = "1020-xen-tools-qubes-vm"; + hash = "sha256-XgDGLgiloljHqUfHN8pdJIN+1pLFzwCYnOS+Nz0qjbA="; + }) + ]; +} diff --git a/pkgs/development/python-modules/qubes-app-linux-usb-proxy/default.nix b/pkgs/development/python-modules/qubes-app-linux-usb-proxy/default.nix new file mode 100644 index 0000000000000..1000c8f9a993b --- /dev/null +++ b/pkgs/development/python-modules/qubes-app-linux-usb-proxy/default.nix @@ -0,0 +1,94 @@ +{ + buildPythonPackage, + fetchFromGitHub, + setuptools, + distutils, + stdenv, + patsh, + pkgs, + usbguard, + systemd, + wrapPython, +}: +let + inherit (pkgs) qubes-core-qubesdb hwdata; + version = "1.3.1"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-app-linux-usb-proxy"; + rev = "refs/tags/v${version}"; + hash = "sha256-i06Q6AcSxDvyjE5zott/+p2fm0cminqeHx5f/Yx+tRU="; + }; + + sys-usb = stdenv.mkDerivation { + inherit version src; + pname = "qubes-app-linux-usb-proxy-sys-usb"; + format = "custom"; + + nativeBuildInputs = [ + patsh + wrapPython + ]; + + buildInputs = [ + qubes-core-qubesdb + usbguard + systemd # udevadm + ]; + + patchPhase = '' + substituteInPlace qubes-rpc/qubes.USB{,Attach} \ + --replace-fail "/usr/lib/qubes/" "$out/lib/qubes/" + substituteInPlace src/usb-export \ + --replace-fail "/usr/lib/qubes/" "$out/lib/qubes/" + ''; + + buildPhase = "true"; + + installTargets = ["install-vm"]; + postInstall = '' + mv $out/usr/* $out/ + rm -d $out/usr + + for script in usb-detach-all usb-export usb-import; do + patsh -f $out/lib/qubes/$script -s ${builtins.storeDir} + done + wrapPythonProgramsIn $out/lib/qubes + + rm $out/etc/qubes/suspend-pre.d/usb-detach-all.sh + ln -sf $out/lib/qubes/usb-detach-all $out/etc/qubes/suspend-pre.d/usb-detach-all.sh + ''; + + installFlags = [ "DESTDIR=$(out)" "PREFIX=" ]; + }; +in +buildPythonPackage { + inherit version src; + pname = "qubes-app-linux-usb-proxy"; + format = "custom"; + + patchPhase = '' + substituteInPlace Makefile \ + --replace-fail "python3 setup.py install" "python3 setup.py install --prefix=." + substituteInPlace qubesusbproxy/core3ext.py \ + --replace-fail "/usr/share/hwdata" "${hwdata}/share/hwdata" + ''; + + passthru = { + inherit sys-usb; + }; + + nativeBuildInputs = [ + setuptools + distutils + ]; + + buildPhase = "python3 setup.py build"; + + dontUsePypaInstall = true; + installTargets = ["install-dom0"]; + + makeFlags = [ "DESTDIR=$(out)" ]; + + pythonImportsCheck = [ "qubesusbproxy" ]; +} diff --git a/pkgs/development/python-modules/qubes-core-admin-client/0001-refactor-template-paths.patch b/pkgs/development/python-modules/qubes-core-admin-client/0001-refactor-template-paths.patch new file mode 100644 index 0000000000000..abcc8846ec184 --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-admin-client/0001-refactor-template-paths.patch @@ -0,0 +1,181 @@ +From 4a217a930d4481d5185ce37bcdf43bbcce7d97d8 Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Mon, 16 Sep 2024 19:13:12 +0200 +Subject: [PATCH 1/3] refactor: template paths + +--- + qubesadmin/app.py | 21 +++------------------ + qubesadmin/backup/dispvm.py | 5 ++++- + qubesadmin/backup/restore.py | 6 +++--- + qubesadmin/config.py | 4 ++-- + qubesadmin/device_protocol.py | 2 +- + qubesadmin/tools/qvm_start.py | 2 +- + qubesadmin/tools/qvm_start_daemon.py | 8 ++++---- + 7 files changed, 18 insertions(+), 30 deletions(-) + +diff --git a/qubesadmin/app.py b/qubesadmin/app.py +index a882eea..c4541e4 100644 +--- a/qubesadmin/app.py ++++ b/qubesadmin/app.py +@@ -40,13 +40,7 @@ import qubesadmin.utils + import qubesadmin.vm + import qubesadmin.config + import qubesadmin.device_protocol +- +-try: +- import qubesdb +- has_qubesdb = True +-except ImportError: +- has_qubesdb = False +- ++import qubesdb + + class VMCollection(object): + """Collection of VMs objects""" +@@ -263,17 +257,8 @@ class QubesBase(qubesadmin.base.PropertyHolder): + def local_name(self): + """ Get localhost name """ + if not self._local_name: +- local_name = None +- if has_qubesdb: +- try: +- local_qdb = qubesdb.QubesDB() +- local_name_b = local_qdb.read('/name') +- if local_name_b: +- local_name = local_name_b.decode() +- except qubesdb.Error: +- pass +- if local_name is None: +- local_name = os.uname()[1] ++ local_qdb = qubesdb.QubesDB() ++ local_name = local_qdb.read('/name').decode() + self._local_name = local_name + + return self._local_name +diff --git a/qubesadmin/backup/dispvm.py b/qubesadmin/backup/dispvm.py +index 47307dc..9c271d3 100644 +--- a/qubesadmin/backup/dispvm.py ++++ b/qubesadmin/backup/dispvm.py +@@ -32,6 +32,7 @@ import qubesadmin + import qubesadmin.exc + import qubesadmin.utils + import qubesadmin.vm ++import qubesdb + + LOCKFILE = '/var/run/qubes/backup-paranoid-restore.lock' + +@@ -173,9 +174,11 @@ class RestoreInDisposableVM: + ['qvm-copy-to-vm', self.dispvm_name, path], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) ++ local_qdb = qubesdb.QubesDB() ++ local_name = local_qdb.read('/name').decode() + return '/home/{}/QubesIncoming/{}/{}'.format( + self.dispvm.default_user, +- os.uname()[1], ++ local_name, + os.path.basename(path) + ) + +diff --git a/qubesadmin/backup/restore.py b/qubesadmin/backup/restore.py +index 6fb8a6e..e9ff515 100644 +--- a/qubesadmin/backup/restore.py ++++ b/qubesadmin/backup/restore.py +@@ -282,7 +282,7 @@ def launch_scrypt(action, input_name, output_name, passphrase): + :param passphrase: passphrase + :return: subprocess.Popen object + ''' +- command_line = ['scrypt', action, '-f', input_name, output_name] ++ command_line = ['@scrypt@/bin/scrypt', action, '-f', input_name, output_name] + (p, pty) = launch_proc_with_pty(command_line, + stdin=subprocess.PIPE if input_name == '-' else None, + stdout=subprocess.PIPE if output_name == '-' else None, +@@ -996,9 +996,9 @@ class BackupRestore(object): + + backup_stdin = vmproc.stdout + if isinstance(self.app, qubesadmin.app.QubesRemote): +- qfile_unpacker_path = '/usr/lib/qubes/qfile-unpacker' ++ qfile_unpacker_path = '@qfile_unpacker@/lib/qubes/qfile-unpacker' + else: +- qfile_unpacker_path = '/usr/libexec/qubes/qfile-dom0-unpacker' ++ qfile_unpacker_path = '@qfile_unpacker@/libexec/qubes/qfile-dom0-unpacker' + # keep at least 500M free for decryption of a previous chunk + tar1_command = [qfile_unpacker_path, + str(os.getuid()), self.tmpdir, '-v', +diff --git a/qubesadmin/config.py b/qubesadmin/config.py +index d348bf6..485f404 100644 +--- a/qubesadmin/config.py ++++ b/qubesadmin/config.py +@@ -22,8 +22,8 @@ + + #: path to qubesd socket + QUBESD_SOCKET = '/var/run/qubesd.sock' +-QREXEC_CLIENT = '/usr/lib/qubes/qrexec-client' +-QREXEC_CLIENT_VM = '/usr/bin/qrexec-client-vm' ++QREXEC_CLIENT = '@qrexec_dom0@/bin/qrexec-client' ++QREXEC_CLIENT_VM = '@qrexec_domU@/bin/qrexec-client-vm' + QUBESD_RECONNECT_DELAY = 1.0 + QREXEC_SERVICES_DIR = '/etc/qubes-rpc' + +diff --git a/qubesadmin/device_protocol.py b/qubesadmin/device_protocol.py +index c9c7506..e98b0db 100644 +--- a/qubesadmin/device_protocol.py ++++ b/qubesadmin/device_protocol.py +@@ -422,7 +422,7 @@ class DeviceInterface: + # subclass subclass_name <-- single tab + # prog-if prog-if_name <-- two tabs + result = {} +- with open(f'/usr/share/hwdata/{bus}.ids', ++ with open(f'@hwdata@/share/hwdata/{bus}.ids', + encoding='utf-8', errors='ignore') as pciids: + # for `class_name` and `subclass_name` + # pylint: disable=used-before-assignment +diff --git a/qubesadmin/tools/qvm_start.py b/qubesadmin/tools/qvm_start.py +index 39fca0c..6f25da9 100644 +--- a/qubesadmin/tools/qvm_start.py ++++ b/qubesadmin/tools/qvm_start.py +@@ -74,7 +74,7 @@ parser_drive.add_argument('--cdrom', metavar='IMAGE', + + parser_drive.add_argument('--install-windows-tools', + action='store_const', dest='drive', default=False, +- const='cdrom:dom0:/usr/lib/qubes/qubes-windows-tools.iso', ++ const='cdrom:dom0:@qubes_windows_tools@/lib/qubes/qubes-windows-tools.iso', + help='temporarily attach Windows tools CDROM to the domain') + + +diff --git a/qubesadmin/tools/qvm_start_daemon.py b/qubesadmin/tools/qvm_start_daemon.py +index 7982b1f..4bfa590 100644 +--- a/qubesadmin/tools/qvm_start_daemon.py ++++ b/qubesadmin/tools/qvm_start_daemon.py +@@ -39,8 +39,8 @@ import qubesadmin.tools + import qubesadmin.vm + from qubesadmin.tools import xcffibhelpers + +-GUI_DAEMON_PATH = '/usr/bin/qubes-guid' +-PACAT_DAEMON_PATH = '/usr/bin/pacat-simple-vchan' ++GUI_DAEMON_PATH = '@qubes_guid@/bin/qubes-guid' ++PACAT_DAEMON_PATH = '@qubes_guid@/bin/pacat-simple-vchan' + QUBES_ICON_DIR = '/usr/share/icons/hicolor/128x128/devices' + + GUI_DAEMON_OPTIONS = [ +@@ -319,7 +319,7 @@ def get_monitor_layout(): + """Get list of monitors and their size/position""" + outputs = [] + +- with subprocess.Popen(['xrandr', '-q'], stdout=subprocess.PIPE) as proc: ++ with subprocess.Popen(['@xrandr@/bin/xrandr', '-q'], stdout=subprocess.PIPE) as proc: + for line in proc.stdout: + line = line.decode() + if not line.startswith("Screen") and not line.startswith(" "): +@@ -452,7 +452,7 @@ class DAEMONLauncher: + guid_cmd += ['-T'] # prefix window titles with VM name + # get owner of X11 session + session_owner = None +- for line in subprocess.check_output(['xhost']).splitlines(): ++ for line in subprocess.check_output(['@xhost@/bin/xhost']).splitlines(): + if line == b'SI:localuser:root': + pass + elif line.startswith(b'SI:localuser:'): +-- +2.45.2 + diff --git a/pkgs/development/python-modules/qubes-core-admin-client/0002-refactor-fixup-paths.patch b/pkgs/development/python-modules/qubes-core-admin-client/0002-refactor-fixup-paths.patch new file mode 100644 index 0000000000000..dc956182c9f0b --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-admin-client/0002-refactor-fixup-paths.patch @@ -0,0 +1,43 @@ +From e12a3d6151bb61d746cedc1ff497fee1eebb5f0e Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Mon, 16 Sep 2024 19:20:55 +0200 +Subject: [PATCH 2/3] refactor: fixup paths + +--- + Makefile | 6 +++--- + setup.py | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/Makefile b/Makefile +index c34bc5c..537b8c4 100644 +--- a/Makefile ++++ b/Makefile +@@ -13,9 +13,9 @@ install: + install -d $(DESTDIR)/etc/xdg/autostart + install -m 0644 etc/qvm-start-daemon.desktop $(DESTDIR)/etc/xdg/autostart/ + install -m 0644 etc/qvm-start-daemon-kde.desktop $(DESTDIR)/etc/xdg/autostart/ +- install -d $(DESTDIR)/usr/bin +- ln -sf qvm-start-daemon $(DESTDIR)/usr/bin/qvm-start-gui +- install -m 0755 scripts/qubes-guivm-session $(DESTDIR)/usr/bin/ ++ install -d $(DESTDIR)/bin ++ ln -sf qvm-start-daemon $(DESTDIR)/bin/qvm-start-gui ++ install -m 0755 scripts/qubes-guivm-session $(DESTDIR)/bin/ + install -d $(DESTDIR)/etc/qubes/post-install.d + install -m 0755 scripts/30-keyboard-layout-service.sh \ + $(DESTDIR)/etc/qubes/post-install.d/30-keyboard-layout-service.sh +diff --git a/setup.py b/setup.py +index 5c70893..fb108c8 100644 +--- a/setup.py ++++ b/setup.py +@@ -26,7 +26,7 @@ def get_console_scripts(): + # create simple scripts that run much faster than "console entry points" + class CustomInstall(setuptools.command.install.install): + def run(self): +- bin = os.path.join(self.root, "usr/bin") ++ bin = os.path.join(self.root, "bin") + try: + os.makedirs(bin) + except: +-- +2.45.2 + diff --git a/pkgs/development/python-modules/qubes-core-admin-client/0003-fix-do-not-crash-on-pool-with-no-volumes.patch b/pkgs/development/python-modules/qubes-core-admin-client/0003-fix-do-not-crash-on-pool-with-no-volumes.patch new file mode 100644 index 0000000000000..cf2939e9596d5 --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-admin-client/0003-fix-do-not-crash-on-pool-with-no-volumes.patch @@ -0,0 +1,25 @@ +From 2448b386505af8540f21b0f81275f45776070f8c Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Sat, 14 Sep 2024 00:09:19 +0200 +Subject: [PATCH 3/3] fix: do not crash on pool with no volumes + +--- + qubesadmin/storage.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/qubesadmin/storage.py b/qubesadmin/storage.py +index 27f5696..99e8d81 100644 +--- a/qubesadmin/storage.py ++++ b/qubesadmin/storage.py +@@ -430,6 +430,8 @@ class Pool(object): + 'dom0', 'admin.pool.volume.List', self.name, None) + except qubesadmin.exc.QubesDaemonAccessError: + raise qubesadmin.exc.QubesPropertyAccessError('volumes') ++ if volumes_data == b'': ++ return + assert volumes_data.endswith(b'\n') + volumes_data = volumes_data[:-1].decode('ascii') + for vid in volumes_data.splitlines(): +-- +2.45.2 + diff --git a/pkgs/development/python-modules/qubes-core-admin-client/default.nix b/pkgs/development/python-modules/qubes-core-admin-client/default.nix new file mode 100644 index 0000000000000..819e1fb8c0e62 --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-admin-client/default.nix @@ -0,0 +1,93 @@ +{ + buildPythonPackage, + fetchFromGitHub, + qubes-core-qrexec, + qubes-core-qubesdb, + qubes-gui-daemon, + tqdm, + pyxdg, + pkgs, + lxml, + pyaml, + xcffib, + socat, + substituteAll, + bash, + distutils, + setuptools, + # Used by qvm-template required for proper initial setup, will not work on NixOS, however. + rpm, +}: + +let + inherit (pkgs) hwdata scrypt; + inherit (pkgs.xorg) xrandr xhost; + + version = "4.3.4"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-core-admin-client"; + rev = "refs/tags/v${version}"; + hash = "sha256-0K8eNzwoCpiq1FdFsJz7aIgqq3Zm4CbWHhZBmnFrWU8="; + }; +in +buildPythonPackage { + inherit version src; + pname = "qubes-core-admin-client"; + format = "other"; + + patches = [ + (substituteAll { + src = ./0001-refactor-template-paths.patch; + env = { + inherit scrypt hwdata xrandr xhost; + # TODO: Depends on agent-linux, meaning this path is located on remote machine. + # Lets assume paranoid backup/restore won't work for now. + qfile_unpacker = "/var/empty"; + qrexec_dom0 = qubes-core-qrexec.dom0; + qrexec_domU = qubes-core-qrexec.domU; + # TODO: package windows tools + qubes_windows_tools = "/var/empty"; + qubes_guid = qubes-gui-daemon; + }; + }) + ./0002-refactor-fixup-paths.patch + ./0003-fix-do-not-crash-on-pool-with-no-volumes.patch + ]; + + postPatch = '' + # It makes zero sense, but those symlinks are installed by other package in QubesOS! + # https://github.com/QubesOS/qubes-core-admin/blob/fca5ec7f3bf3c567676384b39c29b6163bef7531/Makefile#L182-L188 + # Can't just use ln in postInstall, because wrappers break everything. + pushd qubesadmin/tools + cp qvm_device.py qvm_usb.py + cp qvm_device.py qvm_pci.py + popd + ''; + + nativeBuildInputs = [ + distutils + setuptools + ]; + + propagatedBuildInputs = [ + tqdm + pyxdg + rpm + lxml + pyaml + xcffib + qubes-core-qubesdb + + # Script dependencies + bash + socat + ]; + + pythonImportsCheck = [ "qubesadmin" ]; + + makeFlags = [ + "DESTDIR=$(out)" + "PYTHON_PREFIX_ARG=--prefix=." + ]; +} diff --git a/pkgs/development/python-modules/qubes-core-admin/0001-refactor-use-mutable-systemd.patch b/pkgs/development/python-modules/qubes-core-admin/0001-refactor-use-mutable-systemd.patch new file mode 100644 index 0000000000000..fcd94f746a11c --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-admin/0001-refactor-use-mutable-systemd.patch @@ -0,0 +1,37 @@ +From f116903e1b0763f3f2a137642088e261ada8feee Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Mon, 16 Sep 2024 18:54:00 +0200 +Subject: [PATCH 1/6] refactor: use mutable systemd + +--- + qubes/vm/qubesvm.py | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py +index fa7fd3ec..49b2540d 100644 +--- a/qubes/vm/qubesvm.py ++++ b/qubes/vm/qubesvm.py +@@ -1066,14 +1066,15 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): + # workaround https://bugzilla.redhat.com/show_bug.cgi?id=1181922 + if newvalue: + retcode = subprocess.call( +- ["sudo", "ln", "-sf", +- "/usr/lib/systemd/system/qubes-vm@.service", +- "/etc/systemd/system/multi-user.target.wants/qubes-vm@" ++ ["ln", "-sf", ++ "/etc/systemd/system/qubes-vm@.service", ++ "/etc/systemd-mutable/system/multi-user.target.wants/qubes-vm@" + "{}.service".format(self.name)]) + else: + retcode = subprocess.call( +- ['sudo', 'systemctl', 'disable', +- 'qubes-vm@{}.service'.format(self.name)]) ++ ["rm", "-f", ++ "/etc/systemd-mutable/system/multi-user.target.wants/qubes-vm@" ++ "{}.service".format(self.name)]) + if retcode: + raise qubes.exc.QubesException( + 'Failed to set autostart for VM in systemd') +-- +2.45.2 + diff --git a/pkgs/development/python-modules/qubes-core-admin/0002-fix-broken-qvm-device-symlinks.patch b/pkgs/development/python-modules/qubes-core-admin/0002-fix-broken-qvm-device-symlinks.patch new file mode 100644 index 0000000000000..6e4a12d3bf0b5 --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-admin/0002-fix-broken-qvm-device-symlinks.patch @@ -0,0 +1,31 @@ +From dadc0d427eddaf49a6b213e7345c86e81a9c84e7 Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Mon, 16 Sep 2024 18:54:05 +0200 +Subject: [PATCH 2/6] fix: broken qvm-device symlinks + +--- + Makefile | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/Makefile b/Makefile +index 7a410ade..89cc36fc 100644 +--- a/Makefile ++++ b/Makefile +@@ -179,13 +179,7 @@ ifeq ($(OS),Linux) + $(MAKE) install -C linux/system-config + endif + $(PYTHON) setup.py install -O1 --skip-build --root $(DESTDIR) +- ln -sf qvm-device $(DESTDIR)/usr/bin/qvm-block +- ln -sf qvm-device $(DESTDIR)/usr/bin/qvm-pci +- ln -sf qvm-device $(DESTDIR)/usr/bin/qvm-usb +- install -d $(DESTDIR)/usr/share/man/man1 +- ln -sf qvm-device.1.gz $(DESTDIR)/usr/share/man/man1/qvm-block.1.gz +- ln -sf qvm-device.1.gz $(DESTDIR)/usr/share/man/man1/qvm-pci.1.gz +- ln -sf qvm-device.1.gz $(DESTDIR)/usr/share/man/man1/qvm-usb.1.gz ++ # skipping qvm-device symlink installation, qvm-device is a binary in qubes-core-admin-client, not in qubes-core-admin! + $(MAKE) install -C relaxng + mkdir -p $(DESTDIR)/etc/qubes + ifeq ($(BACKEND_VMM),xen) +-- +2.45.2 + diff --git a/pkgs/development/python-modules/qubes-core-admin/0003-refactor-template-paths.patch b/pkgs/development/python-modules/qubes-core-admin/0003-refactor-template-paths.patch new file mode 100644 index 0000000000000..f20b28cb6d995 --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-admin/0003-refactor-template-paths.patch @@ -0,0 +1,267 @@ +From 6dd10e7dcb2406958ec7407d4cd34aee9639e223 Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Mon, 16 Sep 2024 18:54:09 +0200 +Subject: [PATCH 3/6] refactor: template paths + +--- + linux/aux-tools/startup-misc.sh | 4 ++-- + linux/systemd/qubes-core.service | 6 +++--- + linux/systemd/qubes-qmemman.service | 2 +- + linux/systemd/qubes-reload-firewall@.service | 4 ++-- + linux/systemd/qubes-vm@.service | 2 +- + linux/systemd/qubesd.service | 2 +- + qubes-rpc/qubes.FeaturesRequest | 2 +- + qubes-rpc/qubes.GetDate | 2 +- + qubes-rpc/qubes.NotifyTools | 2 +- + qubes-rpc/qubes.NotifyUpdates | 2 +- + qubes/app.py | 2 +- + qubes/config.py | 8 ++++---- + qubes/device_protocol.py | 2 +- + qubes/ext/pci.py | 2 +- + qubes/storage/file.py | 4 ++-- + qubes/vm/qubesvm.py | 3 +++ + templates/libvirt/xen.xml | 4 ++-- + 17 files changed, 28 insertions(+), 25 deletions(-) + +diff --git a/linux/aux-tools/startup-misc.sh b/linux/aux-tools/startup-misc.sh +index 03822727..6a282fe5 100755 +--- a/linux/aux-tools/startup-misc.sh ++++ b/linux/aux-tools/startup-misc.sh +@@ -2,14 +2,14 @@ + + # Misc dom0 startup setup + +-/usr/lib/qubes/fix-dir-perms.sh ++%out%/lib/qubes/fix-dir-perms.sh + DOM0_MAXMEM=$(/usr/sbin/xl list 0 | tail -1 | awk '{ print $3 }') + xenstore-write /local/domain/0/memory/static-max $[ $DOM0_MAXMEM * 1024 ] + + xl sched-credit -d 0 -w 2000 + cp /var/lib/qubes/qubes.xml /var/lib/qubes/backup/qubes-$(date +%F-%T).xml + +-/usr/lib/qubes/cleanup-dispvms ++%out%/lib/qubes/cleanup-dispvms + + if [ -e /sys/module/grant_table/parameters/free_per_iteration ]; then + echo 1000 > /sys/module/grant_table/parameters/free_per_iteration +diff --git a/linux/systemd/qubes-core.service b/linux/systemd/qubes-core.service +index 34ce40fd..0239d420 100644 +--- a/linux/systemd/qubes-core.service ++++ b/linux/systemd/qubes-core.service +@@ -9,11 +9,11 @@ StandardOutput=syslog + RemainAfterExit=yes + # Needed to avoid rebooting before all VMs have shut down. + TimeoutStopSec=180 +-ExecStart=/usr/lib/qubes/startup-misc.sh +-ExecStop=/usr/bin/qvm-shutdown -q --all --wait ++ExecStart=%out%/lib/qubes/startup-misc.sh ++ExecStop=@qubes_client@/bin/qvm-shutdown -q --all --wait + # QubesDB daemons stop after 60s timeout in worst case; speed it up, since no + # VMs are running now +-ExecStop=-/usr/bin/killall qubesdb-daemon ++ExecStop=-@killall@/bin/killall qubesdb-daemon + + [Install] + WantedBy=multi-user.target +diff --git a/linux/systemd/qubes-qmemman.service b/linux/systemd/qubes-qmemman.service +index a2830ef0..48a1b39b 100644 +--- a/linux/systemd/qubes-qmemman.service ++++ b/linux/systemd/qubes-qmemman.service +@@ -3,7 +3,7 @@ Description=Qubes memory management daemon + + [Service] + Type=notify +-ExecStart=/usr/bin/qmemmand ++ExecStart=%out%/bin/qmemmand + StandardOutput=syslog + + [Install] +diff --git a/linux/systemd/qubes-reload-firewall@.service b/linux/systemd/qubes-reload-firewall@.service +index ac5cb5d8..61680c7f 100644 +--- a/linux/systemd/qubes-reload-firewall@.service ++++ b/linux/systemd/qubes-reload-firewall@.service +@@ -3,8 +3,8 @@ Description=Reload firewall for VM %i + + [Service] + Type=simple +-ExecStart=/usr/bin/qvm-firewall --force-root -r %i +-ExecStartPost=/bin/sh -c '/usr/bin/qvm-firewall --force-root %i | grep -q "expires at" || systemctl stop %p@%i.timer' ++ExecStart=@qubes_client@/bin/qvm-firewall --force-root -r %i ++ExecStartPost=/bin/sh -c '@qubes_client@/bin/qvm-firewall --force-root %i | grep -q "expires at" || systemctl stop %p@%i.timer' + Group=qubes + + [Install] +diff --git a/linux/systemd/qubes-vm@.service b/linux/systemd/qubes-vm@.service +index 7ccfb53b..f81175fe 100644 +--- a/linux/systemd/qubes-vm@.service ++++ b/linux/systemd/qubes-vm@.service +@@ -6,7 +6,7 @@ ConditionKernelCommandLine=!qubes.skip_autostart + [Service] + Type=oneshot + Environment=DISPLAY=:0 +-ExecStart=/usr/bin/qvm-start --skip-if-running %i ++ExecStart=@qubes_client@/bin/qvm-start --skip-if-running %i + Group=qubes + RemainAfterExit=yes + +diff --git a/linux/systemd/qubesd.service b/linux/systemd/qubesd.service +index 44711761..a44e1d49 100644 +--- a/linux/systemd/qubesd.service ++++ b/linux/systemd/qubesd.service +@@ -4,7 +4,7 @@ Before=systemd-user-sessions.service + + [Service] + Type=notify +-ExecStart=/usr/bin/qubesd ++ExecStart=%out%/bin/qubesd + StandardOutput=syslog + KillMode=process + Restart=on-failure +diff --git a/qubes-rpc/qubes.FeaturesRequest b/qubes-rpc/qubes.FeaturesRequest +index a3f561c5..22c441ca 100755 +--- a/qubes-rpc/qubes.FeaturesRequest ++++ b/qubes-rpc/qubes.FeaturesRequest +@@ -1,4 +1,4 @@ + #!/bin/sh + +-exec /usr/bin/qubesd-query -c /var/run/qubesd.misc.sock -e --fail \ ++exec @qubesdb_client@/bin/qubesd-query -c /var/run/qubesd.misc.sock -e --fail \ + "$QREXEC_REMOTE_DOMAIN" qubes.FeaturesRequest dom0 "" >/dev/null 2>&1 +diff --git a/qubes-rpc/qubes.GetDate b/qubes-rpc/qubes.GetDate +index 95d8f03f..94585df5 100755 +--- a/qubes-rpc/qubes.GetDate ++++ b/qubes-rpc/qubes.GetDate +@@ -43,7 +43,7 @@ def main(argv): + env = {**os.environ, "LC_ALL": "C"} + # print dom0 time if clockvm is dom0 or is not running + date_arg = "-Ins" if arg else "-Iseconds" +- os.execve("/usr/bin/date", ("date", "-u", date_arg), env) ++ os.execve("@coreutils@/bin/date", ("date", "-u", date_arg), env) + else: + # passthrough request to the clockvm + p = clockvm.run_service("qubes.GetDate" + arg, stdout=None, stdin=subprocess.DEVNULL) +diff --git a/qubes-rpc/qubes.NotifyTools b/qubes-rpc/qubes.NotifyTools +index 71bc422d..0c4a8ba1 100755 +--- a/qubes-rpc/qubes.NotifyTools ++++ b/qubes-rpc/qubes.NotifyTools +@@ -1,4 +1,4 @@ + #!/bin/sh + +-exec /usr/bin/qubesd-query -c /var/run/qubesd.misc.sock -e --fail \ ++exec @qubesdb_client@/bin/qubesd-query -c /var/run/qubesd.misc.sock -e --fail \ + "$QREXEC_REMOTE_DOMAIN" qubes.NotifyTools dom0 "" >/dev/null 2>&1 +diff --git a/qubes-rpc/qubes.NotifyUpdates b/qubes-rpc/qubes.NotifyUpdates +index f51e4fc2..3270821e 100755 +--- a/qubes-rpc/qubes.NotifyUpdates ++++ b/qubes-rpc/qubes.NotifyUpdates +@@ -1,4 +1,4 @@ + #!/bin/sh + +-exec /usr/bin/qubesd-query -c /var/run/qubesd.misc.sock --fail \ ++exec @qubesdb_client@/bin/qubesd-query -c /var/run/qubesd.misc.sock --fail \ + "$QREXEC_REMOTE_DOMAIN" qubes.NotifyUpdates dom0 "" >/dev/null 2>&1 +diff --git a/qubes/app.py b/qubes/app.py +index 2a00355b..5fd49bbe 100644 +--- a/qubes/app.py ++++ b/qubes/app.py +@@ -936,7 +936,7 @@ class Qubes(qubes.PropertyHolder): + self.env = jinja2.Environment( + loader=jinja2.FileSystemLoader([ + '/etc/qubes/templates', +- '/usr/share/qubes/templates', ++ '%out%/share/qubes/templates', + ]), + undefined=jinja2.StrictUndefined, + autoescape=True) +diff --git a/qubes/config.py b/qubes/config.py +index d44ff035..9556926a 100644 +--- a/qubes/config.py ++++ b/qubes/config.py +@@ -30,10 +30,10 @@ import os.path + + qubes_base_dir = "/var/lib/qubes" + system_path = { +- 'qrexec_daemon_path': '/usr/sbin/qrexec-daemon', +- 'qrexec_client_path': '/usr/bin/qrexec-client', +- 'qrexec_rpc_multiplexer': '/usr/lib/qubes/qubes-rpc-multiplexer', +- 'qubesdb_daemon_path': '/usr/sbin/qubesdb-daemon', ++ 'qrexec_daemon_path': '@qrexec_dom0@/libexec/qrexec-daemon', ++ 'qrexec_client_path': '@qrexec_dom0@/bin/qrexec-client', ++ 'qrexec_rpc_multiplexer': '@qrexec_util@/libexec/qubes-rpc-multiplexer', ++ 'qubesdb_daemon_path': '@qubesdb_daemon@/bin/qubesdb-daemon', + + # Relative to qubes_base_dir + 'qubes_appvms_dir': 'appvms', +diff --git a/qubes/device_protocol.py b/qubes/device_protocol.py +index 3d8b9aaa..c5e215c4 100644 +--- a/qubes/device_protocol.py ++++ b/qubes/device_protocol.py +@@ -400,7 +400,7 @@ class DeviceInterface: + # subclass subclass_name <-- single tab + # prog-if prog-if_name <-- two tabs + result = {} +- with open(f'/usr/share/hwdata/{bus}.ids', ++ with open(f'@hwdata@/share/hwdata/{bus}.ids', + encoding='utf-8', errors='ignore') as pciids: + # for `class_name` and `subclass_name` + # pylint: disable=used-before-assignment +diff --git a/qubes/ext/pci.py b/qubes/ext/pci.py +index 1535a7f9..5ac33fd9 100644 +--- a/qubes/ext/pci.py ++++ b/qubes/ext/pci.py +@@ -54,7 +54,7 @@ def load_pci_classes(): + # subclass subclass_name <-- single tab + # prog-if prog-if_name <-- two tabs + result = {} +- with open('/usr/share/hwdata/pci.ids', ++ with open('@hwdata@/share/hwdata/pci.ids', + encoding='utf-8', errors='ignore') as pciids: + class_id = None + subclass_id = None +diff --git a/qubes/storage/file.py b/qubes/storage/file.py +index 74161ac1..94ee2de4 100644 +--- a/qubes/storage/file.py ++++ b/qubes/storage/file.py +@@ -34,8 +34,8 @@ import qubes.storage + import qubes.utils + + BLKSIZE = 512 +-CREATE_SCRIPT = '/usr/lib/qubes/create-snapshot' +-DESTROY_SCRIPT = '/usr/lib/qubes/destroy-snapshot' ++CREATE_SCRIPT = '%out%/lib/qubes/create-snapshot' ++DESTROY_SCRIPT = '%out%/lib/qubes/destroy-snapshot' + + # 256 KiB chunk, same as in create-snapshot script. Header created by + # struct.pack('<4I', 0x70416e53, 1, 1, 256) mimicking write_header() +diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py +index 49b2540d..85cb4b08 100644 +--- a/qubes/vm/qubesvm.py ++++ b/qubes/vm/qubesvm.py +@@ -1815,6 +1815,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): + if not self.debug: + qrexec_args.insert(0, "-q") + ++ # Original qrexec daemon had this argument as optional, now it is mandatory ++ qrexec_args.insert(0, "--policy-program=@qrexec_client@/bin/qrexec-policy-exec") ++ + qrexec_env = os.environ.copy() + if not self.features.check_with_template('qrexec', False): + self.log.debug( +diff --git a/templates/libvirt/xen.xml b/templates/libvirt/xen.xml +index a9ce7c1d..43d64617 100644 +--- a/templates/libvirt/xen.xml ++++ b/templates/libvirt/xen.xml +@@ -204,8 +204,8 @@ + {% endif %} + {% if vm.features.check_with_template('audio-model', False) + or vm.features.check_with_template('stubdom-qrexec', False) %} +- kernel="/usr/libexec/xen/boot/qemu-stubdom-linux-full-kernel" +- ramdisk="/usr/libexec/xen/boot/qemu-stubdom-linux-full-rootfs" ++ kernel="@xen@/libexec/xen/boot/qemu-stubdom-linux-full-kernel" ++ ramdisk="@xen@/libexec/xen/boot/qemu-stubdom-linux-full-rootfs" + {% endif %} + /> + +-- +2.45.2 + diff --git a/pkgs/development/python-modules/qubes-core-admin/0004-fix-fixup-paths.patch b/pkgs/development/python-modules/qubes-core-admin/0004-fix-fixup-paths.patch new file mode 100644 index 0000000000000..ab5b1536185ff --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-admin/0004-fix-fixup-paths.patch @@ -0,0 +1,178 @@ +From 6a7a20222a5511748ff8fbe6cafc477299acb999 Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Mon, 16 Sep 2024 18:54:14 +0200 +Subject: [PATCH 4/6] fix: fixup paths + +--- + Makefile | 19 +++++-------------- + doc/Makefile | 4 ++-- + linux/aux-tools/Makefile | 8 ++++---- + linux/aux-tools/startup-misc.sh | 4 ++-- + linux/system-config/Makefile | 6 +++--- + qvm-tools/qubes-hcl-report | 2 +- + qvm-tools/qvm-console-dispvm | 2 +- + qvm-tools/qvm-sync-clock | 2 +- + relaxng/Makefile | 2 +- + setup.py | 2 +- + 10 files changed, 21 insertions(+), 30 deletions(-) + +diff --git a/Makefile b/Makefile +index 89cc36fc..05fe8910 100644 +--- a/Makefile ++++ b/Makefile +@@ -188,7 +188,6 @@ ifeq ($(BACKEND_VMM),xen) + endif + mkdir -p $(DESTDIR)/etc/qubes-rpc + mkdir -p $(DESTDIR)/etc/qubes/policy.d +- mkdir -p $(DESTDIR)/usr/libexec/qubes + install -m 0644 qubes-rpc-policy/90-default.policy \ + $(DESTDIR)/etc/qubes/policy.d/90-default.policy + install -m 0644 qubes-rpc-policy/85-admin-backup-restore.policy \ +@@ -199,12 +198,12 @@ endif + cp qubes-rpc/qubes.NotifyTools $(DESTDIR)/etc/qubes-rpc/ + cp qubes-rpc/qubes.NotifyUpdates $(DESTDIR)/etc/qubes-rpc/ + cp qubes-rpc/qubes.ConnectTCP $(DESTDIR)/etc/qubes-rpc/ +- install -m 0755 qvm-tools/qubes-bug-report $(DESTDIR)/usr/bin/qubes-bug-report +- install -m 0755 qvm-tools/qubes-hcl-report $(DESTDIR)/usr/bin/qubes-hcl-report +- install -m 0755 qvm-tools/qvm-sync-clock $(DESTDIR)/usr/bin/qvm-sync-clock +- install -m 0755 qvm-tools/qvm-console-dispvm $(DESTDIR)/usr/bin/qvm-console-dispvm ++ install -m 0755 qvm-tools/qubes-bug-report $(DESTDIR)/bin/qubes-bug-report ++ install -m 0755 qvm-tools/qubes-hcl-report $(DESTDIR)/bin/qubes-hcl-report ++ install -m 0755 qvm-tools/qvm-sync-clock $(DESTDIR)/bin/qvm-sync-clock ++ install -m 0755 qvm-tools/qvm-console-dispvm $(DESTDIR)/bin/qvm-console-dispvm + for method in $(ADMIN_API_METHODS_SIMPLE); do \ +- ln -sf ../../var/run/qubesd.sock \ ++ ln -sf /var/run/qubesd.sock \ + $(DESTDIR)/etc/qubes-rpc/$$method || exit 1; \ + done + install qubes-rpc/admin.vm.volume.Import $(DESTDIR)/etc/qubes-rpc/ +@@ -238,14 +237,6 @@ endif + mkdir -p "$(DESTDIR)$(DOCDIR)" + cp qubes/storage/callback.json.example "$(DESTDIR)$(DOCDIR)/qubes_callback.json.example" + +- mkdir -p $(DESTDIR)$(DATADIR) +- mkdir -p $(DESTDIR)$(DATADIR)/vm-templates +- mkdir -p $(DESTDIR)$(DATADIR)/appvms +- mkdir -p $(DESTDIR)$(DATADIR)/vm-kernels +- mkdir -p $(DESTDIR)$(DATADIR)/backup +- mkdir -p $(DESTDIR)$(STATEDIR) +- mkdir -p $(DESTDIR)$(LOGDIR) +- + msi: + rm -rf destinstdir + mkdir -p destinstdir +diff --git a/doc/Makefile b/doc/Makefile +index 2f3e8abe..302803d1 100644 +--- a/doc/Makefile ++++ b/doc/Makefile +@@ -165,6 +165,6 @@ autoxml.rst: ../relaxng/qubes.rng example.xml + + .PHONY: install + install: man +- mkdir -p $(DESTDIR)/usr/share/man/man1 ++ mkdir -p $(DESTDIR)/share/man/man1 + rm -rf $(BUILDDIR)/man/_static +- cp $(BUILDDIR)/man/* $(DESTDIR)/usr/share/man/man1/ ++ cp $(BUILDDIR)/man/* $(DESTDIR)/share/man/man1/ +diff --git a/linux/aux-tools/Makefile b/linux/aux-tools/Makefile +index d919c84f..6bfbe916 100644 +--- a/linux/aux-tools/Makefile ++++ b/linux/aux-tools/Makefile +@@ -2,7 +2,7 @@ all: + true + + install: +- mkdir -p $(DESTDIR)/usr/lib/qubes +- cp cleanup-dispvms $(DESTDIR)/usr/lib/qubes +- cp startup-misc.sh $(DESTDIR)/usr/lib/qubes +- cp fix-dir-perms.sh $(DESTDIR)/usr/lib/qubes/ ++ mkdir -p $(DESTDIR)/lib/qubes ++ cp cleanup-dispvms $(DESTDIR)/lib/qubes ++ cp startup-misc.sh $(DESTDIR)/lib/qubes ++ cp fix-dir-perms.sh $(DESTDIR)/lib/qubes/ +diff --git a/linux/aux-tools/startup-misc.sh b/linux/aux-tools/startup-misc.sh +index 6a282fe5..d66b609f 100755 +--- a/linux/aux-tools/startup-misc.sh ++++ b/linux/aux-tools/startup-misc.sh +@@ -1,9 +1,9 @@ +-#!/bin/sh ++#!/usr/bin/env bash + + # Misc dom0 startup setup + + %out%/lib/qubes/fix-dir-perms.sh +-DOM0_MAXMEM=$(/usr/sbin/xl list 0 | tail -1 | awk '{ print $3 }') ++DOM0_MAXMEM=$(xl list 0 | tail -1 | awk '{ print $3 }') + xenstore-write /local/domain/0/memory/static-max $[ $DOM0_MAXMEM * 1024 ] + + xl sched-credit -d 0 -w 2000 +diff --git a/linux/system-config/Makefile b/linux/system-config/Makefile +index 68ce7f50..74928d2f 100644 +--- a/linux/system-config/Makefile ++++ b/linux/system-config/Makefile +@@ -2,6 +2,6 @@ all: + true + + install: +- mkdir -p $(DESTDIR)/etc/xen/scripts $(DESTDIR)/usr/lib/qubes +- install -m 0755 create-snapshot destroy-snapshot $(DESTDIR)/usr/lib/qubes +- install -m 0644 -D tmpfiles-qubes.conf $(DESTDIR)/usr/lib/tmpfiles.d/qubes.conf ++ mkdir -p $(DESTDIR)/etc/xen/scripts $(DESTDIR)/lib/qubes ++ install -m 0755 create-snapshot destroy-snapshot $(DESTDIR)/lib/qubes ++ install -m 0644 -D tmpfiles-qubes.conf $(DESTDIR)/lib/tmpfiles.d/qubes.conf +diff --git a/qvm-tools/qubes-hcl-report b/qvm-tools/qubes-hcl-report +index 831b04d6..6e8ad6cc 100755 +--- a/qvm-tools/qubes-hcl-report ++++ b/qvm-tools/qubes-hcl-report +@@ -1,4 +1,4 @@ +-#!/bin/bash -- ++#!/usr/bin/env bash -- + + # The Qubes OS Project, https://www.qubes-os.org + # +diff --git a/qvm-tools/qvm-console-dispvm b/qvm-tools/qvm-console-dispvm +index 73a0f79d..5dc44267 100755 +--- a/qvm-tools/qvm-console-dispvm ++++ b/qvm-tools/qvm-console-dispvm +@@ -1,4 +1,4 @@ +-#!/bin/bash -- ++#!/usr/bin/env bash -- + set -eu + print_usage() { + cat >&2 << USAGE +diff --git a/qvm-tools/qvm-sync-clock b/qvm-tools/qvm-sync-clock +index 930cef85..0771eb1b 100755 +--- a/qvm-tools/qvm-sync-clock ++++ b/qvm-tools/qvm-sync-clock +@@ -1,4 +1,4 @@ +-#!/usr/bin/python3 ++#!/usr/bin/env python3 + # -*- encoding: utf8 -*- + # + # The Qubes OS Project, http://www.qubes-os.org +diff --git a/relaxng/Makefile b/relaxng/Makefile +index 922179a3..18308b71 100644 +--- a/relaxng/Makefile ++++ b/relaxng/Makefile +@@ -1,4 +1,4 @@ +-RELAXNGPATH = /usr/share/doc/qubes/relaxng ++RELAXNGPATH ?= /usr/share/doc/qubes/relaxng + install: + mkdir -p $(DESTDIR)$(RELAXNGPATH) + cp *.rng $(DESTDIR)$(RELAXNGPATH) +diff --git a/setup.py b/setup.py +index 69bace60..442706ef 100644 +--- a/setup.py ++++ b/setup.py +@@ -19,7 +19,7 @@ def get_console_scripts(): + # create simple scripts that run much faster than "console entry points" + class CustomInstall(setuptools.command.install.install): + def run(self): +- bin = os.path.join(self.root, "usr/bin") ++ bin = os.path.join(self.root, "bin") + try: + os.makedirs(bin) + except: +-- +2.45.2 + diff --git a/pkgs/development/python-modules/qubes-core-admin/0005-fix-python-prefix-arg.patch b/pkgs/development/python-modules/qubes-core-admin/0005-fix-python-prefix-arg.patch new file mode 100644 index 0000000000000..8b313e2c2c712 --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-admin/0005-fix-python-prefix-arg.patch @@ -0,0 +1,25 @@ +From 94e7c943206537658d7a16f4035d4557067fbf68 Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Mon, 16 Sep 2024 20:41:53 +0200 +Subject: [PATCH 6/6] fix: python prefix arg + +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 05fe8910..f2b65d20 100644 +--- a/Makefile ++++ b/Makefile +@@ -178,7 +178,7 @@ ifeq ($(OS),Linux) + $(MAKE) install -C linux/aux-tools + $(MAKE) install -C linux/system-config + endif +- $(PYTHON) setup.py install -O1 --skip-build --root $(DESTDIR) ++ $(PYTHON) setup.py install -O1 --skip-build $(PYTHON_PREFIX_ARG) --root $(DESTDIR) + # skipping qvm-device symlink installation, qvm-device is a binary in qubes-core-admin-client, not in qubes-core-admin! + $(MAKE) install -C relaxng + mkdir -p $(DESTDIR)/etc/qubes +-- +2.45.2 + diff --git a/pkgs/development/python-modules/qubes-core-admin/default.nix b/pkgs/development/python-modules/qubes-core-admin/default.nix new file mode 100644 index 0000000000000..bb105c415548f --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-admin/default.nix @@ -0,0 +1,179 @@ +{ + lib, + buildPythonPackage, + fetchFromGitHub, + lxml, + docutils, + jinja2, + pyaml, + qubes-core-qrexec, + qubes-core-qubesdb, + qubes-core-admin-client, + qubes-core-libvirt, + pyinotify, + killall, + coreutils, + pkgs, + patsh, + bash, + lvm2, + util-linux, + substituteAll, + writeShellScript, + distutils, + setuptools, + fetchpatch, + qubes-vmm-xen, + qubes-vmm-pyxen, + qubes-core-qubesdb-client ? pkgs.qubes-core-qubesdb, + qubes-core-qubesdb-daemon ? pkgs.qubes-core-qubesdb.daemon, + # Uses entrypoints to provide usb device type extension. + # It may make sense to pass it to systemd service PYTHONPATH? + qubes-app-linux-usb-proxy, +}: +let + inherit (pkgs) hwdata; + + # Original qubes.GetDate RPC uses qubes-core-admin-client package api, and + # we want to avoid circular dependency here. + # This script is short, and easily reproducible in just bash. + # The only bad thing here is that original supports ClockVM... But they are + # not used in dom0 anyway. + getDateRpc = writeShellScript "qubes.GetDate" '' + if test "$#" -lt 1 || test "$#" -gt 2; then + echo "wrong number of arguments, must have at most 1" >&2 + exit 1 + fi + + arg="-Iseconds" + if test "$#" -ge 2 && test "$1" -ne 0; then + arg="-Ins" + fi + + env -i date -u $arg + ''; + + version = "4.3.6"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-core-admin"; + rev = "refs/tags/v${version}"; + hash = "sha256-wOkY0qeUF1VezSGTMzYfoELyed058rmjIDEQonSqKeg="; + }; +in +buildPythonPackage { + inherit version src; + pname = "qubes-core-admin"; + format = "custom"; + + patches = [ + ./0001-refactor-use-mutable-systemd.patch + ./0002-fix-broken-qvm-device-symlinks.patch + (substituteAll { + # Note that out is substituted using %out%, and the actual + # substitution is done in postPatch + src = ./0003-refactor-template-paths.patch; + env = { + inherit killall hwdata coreutils; + qubes_client = qubes-core-admin-client; + qrexec_dom0 = qubes-core-qrexec.dom0; + qrexec_util = qubes-core-qrexec.util; + qrexec_client = qubes-core-qrexec; + qubesdb_daemon = qubes-core-qubesdb-daemon; + qubesdb_client = qubes-core-qubesdb-client; + qubes_vmm_xen = qubes-vmm-xen; + }; + }) + ./0004-fix-fixup-paths.patch + ./0005-fix-python-prefix-arg.patch + + # Accepted upstream, remove after package update + # https://github.com/QubesOS/qubes-core-admin/pull/619 + (fetchpatch { + name = "bad-field-name"; + url = "https://patch-diff.githubusercontent.com/raw/QubesOS/qubes-core-admin/pull/619.patch"; + hash = "sha256-CiDxk8CdDU6Kv6Wp5QTsgifWLeernvOg4bm6nJt/gjE="; + }) + ]; + + postPatch = '' + cat linux/aux-tools/startup-misc.sh + substituteInPlace \ + linux/{aux-tools/startup-misc.sh,systemd/qubes-{core,qmemman}.service,systemd/qubesd.service} \ + qubes/{app.py,storage/file.py} \ + --replace-fail "%out%" "$out" + + substituteInPlace qubes-rpc-policy/generate-admin-policy \ + --replace-fail "#!/usr/bin/python3" "#!/usr/bin/env python3" + # FIXME: Shouldn't it use build-system/nativeBuildInputs/idk? + wrapPythonProgramsIn qubes-rpc-policy "${lxml} ${docutils} ${jinja2} ${pyaml}" + ''; + + nativeBuildInputs = [ + patsh + setuptools + distutils + ]; + + propagatedBuildInputs = [ + lxml + docutils + jinja2 + pyaml + qubes-core-qrexec + qubes-core-qubesdb + qubes-core-admin-client + qubes-core-libvirt + qubes-app-linux-usb-proxy + pyinotify + qubes-vmm-pyxen + + # For scripts + bash + lvm2 + util-linux.bin + coreutils + ]; + + buildFlags = [ "all" ]; + + dontUsePypaInstall = true; + postInstall = '' + mkdir -p $man/share + + # TODO: Move to libexec? + patsh -f $out/lib/qubes/create-snapshot -s ${builtins.storeDir} + patsh -f $out/lib/qubes/destroy-snapshot -s ${builtins.storeDir} + wrapPythonProgramsIn $out/lib/qubes ${qubes-core-admin-client} + + cp ${getDateRpc} $out/etc/qubes-rpc/qubes.GetDate + ''; + + makeFlags = [ + "DESTDIR=$(out)" + "DOCDIR=/share/doc/qubes" + "RELAXNGPATH=/share/doc/qubes/relaxng" + "FILESDIR=/share/qubes" + "UNITDIR=/lib/systemd/system" + "BACKEND_VMM=xen" + "PYTHON_PREFIX_ARG=--prefix=." + ]; + + pythonImportsCheck = [ "qubes" ]; + + outputs = [ + "out" + "man" + ]; + + meta = { + description = "Qubes dom0 daemon & RPC"; + homepage = "https://qubes-os.org"; + license = lib.licenses.gpl2Plus; + maintainers = with lib.maintainers; [ + lach + sigmasquadron + ]; + platforms = lib.platforms.linux; + }; +} diff --git a/pkgs/development/python-modules/qubes-core-qrexec/0001-refactor-remove-dependency-of-util-on-daemon.patch b/pkgs/development/python-modules/qubes-core-qrexec/0001-refactor-remove-dependency-of-util-on-daemon.patch new file mode 100644 index 0000000000000..c719849dfe6b1 --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-qrexec/0001-refactor-remove-dependency-of-util-on-daemon.patch @@ -0,0 +1,24 @@ +From f74f3e966d6ca5d4d806714c83431717c6ce7ffb Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Sun, 14 Sep 2024 11:45:07 +0200 +Subject: refactor: remove dependency of util on daemon + +--- + qrexec.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/qrexec.h b/qrexec.h +index a8fc06b..a507825 100644 +--- a/qrexec.h ++++ b/qrexec.h +@@ -165,7 +165,6 @@ enum { + #define MEMINFO_WRITER_PIDFILE "/var/run/meminfo-writer.pid" + #define QUBES_RPC_MULTIPLEXER_PATH "/usr/lib/qubes/qubes-rpc-multiplexer" + #define QREXEC_DAEMON_SOCKET_DIR "/var/run/qubes" +-#define QREXEC_POLICY_PROGRAM "/usr/bin/qrexec-policy-exec" + #define QREXEC_SERVICE_PATH "/usr/local/etc/qubes-rpc:/etc/qubes-rpc" + + // directory for services configuration (for example 'wait-for-session' flag) +-- +2.45.2 + diff --git a/pkgs/development/python-modules/qubes-core-qrexec/0002-refactor-remove-default-policy-prgram.patch b/pkgs/development/python-modules/qubes-core-qrexec/0002-refactor-remove-default-policy-prgram.patch new file mode 100644 index 0000000000000..ccd7ef12c50f5 --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-qrexec/0002-refactor-remove-default-policy-prgram.patch @@ -0,0 +1,44 @@ +From 7cbd328359af3a79b799dc2f099183f29baa83f4 Mon Sep 17 00:00:00 2001 +From: Yaroslav Bolyukin +Date: Sun, 14 Sep 2024 11:45:07 +0200 +Subject: refactor: remove default policy prgram + +--- + daemon/qrexec-daemon.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/daemon/qrexec-daemon.c b/daemon/qrexec-daemon.c +index 61c1004..3da967b 100644 +--- a/daemon/qrexec-daemon.c ++++ b/daemon/qrexec-daemon.c +@@ -113,7 +113,7 @@ static const char default_user_keyword[] = "DEFAULT:"; + + static int opt_quiet = 0; + +-static const char *policy_program = QREXEC_POLICY_PROGRAM; ++static const char *policy_program = NULL; + + #ifdef __GNUC__ + # define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) +@@ -1535,8 +1535,7 @@ static _Noreturn void usage(const char *argv0) + fprintf(stderr, " -q, --quiet - quiet mode\n"); + fprintf(stderr, " --socket-dir=PATH - directory for qrexec socket, default: %s\n", + QREXEC_DAEMON_SOCKET_DIR); +- fprintf(stderr, " -p, --policy-program=PATH - program to execute to check policy, default: %s\n", +- QREXEC_POLICY_PROGRAM); ++ fprintf(stderr, " -p, --policy-program=PATH - program to execute to check policy\n"); + fprintf(stderr, " -D, --direct - run directly, don't daemonize, log to stderr\n"); + exit(1); + } +@@ -1580,7 +1579,7 @@ int main(int argc, char **argv) + usage(argv[0]); + } + } +- if (argc - optind < 2 || argc - optind > 3) { ++ if (argc - optind < 2 || argc - optind > 3 || policy_program == NULL) { + usage(argv[0]); + } + remote_domain_id = atoi(argv[optind]); +-- +2.45.2 + diff --git a/pkgs/development/python-modules/qubes-core-qrexec/default.nix b/pkgs/development/python-modules/qubes-core-qrexec/default.nix new file mode 100644 index 0000000000000..0544a6860ae34 --- /dev/null +++ b/pkgs/development/python-modules/qubes-core-qrexec/default.nix @@ -0,0 +1,276 @@ +{ + lib, + stdenv, + buildPythonPackage, + fetchFromGitHub, + qubes-core-vchan-xen, + pkg-config, + pandoc, + pyinotify, + python, + pygobject3, + wrapPython, + gtk3, + wrapGAppsHook3, + gobject-introspection, + gbulb, + patsh, + bash, + socat, + kmod, + setuptools, + distutils, +}: + +let + inherit (lib) optionalString; + + version = "4.2.22"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-core-qrexec"; + rev = "refs/tags/v${version}"; + hash = "sha256-GxT2KpxIOeRF9j9Lc9SRHqM2G58juFtTd/lXoEJzIyY="; + }; + makeFlags = [ "DESTDIR=$(out)" "LIBDIR=/lib" "INCLUDEDIR=/include" "PYTHON_PREFIX_ARG=--prefix=." ]; + + base = buildPythonPackage { + inherit version src; + pname = "qubes-core-qrexec-base"; + format = "custom"; + + postPatch = '' + substituteInPlace qrexec/client.py \ + --replace-fail "/usr/bin/qrexec-client-vm" "${domU}/bin/qrexec-client-vm" \ + --replace-fail "/usr/bin/qrexec-client" "${dom0-bootstrap}/lib/qubes/qrexec-client" \ + --replace-fail "/usr/lib/qubes/qubes-rpc-multiplexer" "${util}/libexec/qubes-rpc-multiplexer" + substituteInPlace policy-agent-extra/qrexec-policy-agent.desktop \ + --replace-fail "Exec=/usr/lib/qubes/qrexec-policy-agent-autostart" "Exec=$out/lib/qubes/qrexec-policy-agent-autostart" + ''; + + nativeBuildInputs = [ + pkg-config + setuptools + distutils + gobject-introspection + wrapGAppsHook3 + ]; + + buildInputs = [ + qubes-core-vchan-xen + util + gtk3 + ]; + + propagatedBuildInputs = [ + pyinotify + pygobject3 + gbulb + qubes-core-vchan-xen + ]; + + buildFlags = ["all-base"]; + + dontUsePypaInstall = true; + installTargets = ["install-base"]; + + postInstall = '' + mv $out/usr/bin $out/ + mv $out/usr/lib/* $out/lib/ + rm -d $out/usr/{lib,} + ''; + + pythonImportsCheck = [ "qrexec" ]; + + inherit makeFlags; + }; + + # qrexec-client-vm qrexec-fork-server + domU = stdenv.mkDerivation { + inherit version src; + pname = "qubes-core-qrexec-domU"; + + postPatch = '' + substituteInPlace systemd/qubes-qrexec-agent.service \ + --replace-fail "ExecStart=/usr/lib/" "ExecStart=$out/lib/" \ + --replace-fail "modprobe" "${kmod}/bin/modprobe" + ''; + + nativeBuildInputs = [ + pkg-config + pandoc + ]; + + buildInputs = [ + qubes-core-vchan-xen + util + ]; + + buildFlags = ["all-vm"]; + + installTargets = ["install-vm"]; + + postInstall = '' + mv $out/usr/{bin,share} $out/ + mv $out/usr/lib/* $out/lib/ + rm -d $out/usr/{lib,} + ''; + + inherit makeFlags; + }; + + dom0 = dom0-core false; + dom0-bootstrap = dom0-core true; + # base depends on boostrap, thus building core 2 times: + # one time it is just the binary usable by base, second time it depends + # on base and provides everything. + dom0-core = isBootstrap: stdenv.mkDerivation { + inherit version src; + pname = "qubes-core-qrexec-daemon${optionalString isBootstrap "-core"}"; + + patches = [ + ./0002-refactor-remove-default-policy-prgram.patch + ]; + + postPatch = optionalString (!isBootstrap) '' + substituteInPlace systemd/qubes-qrexec-policy-daemon.service \ + --replace-fail "ExecStart=/usr/bin/qrexec-policy-daemon" "ExecStart=${base}/bin/qrexec-policy-daemon" + ''; + + nativeBuildInputs = [ + pkg-config + patsh + wrapPython + ]; + + buildInputs = [ + qubes-core-vchan-xen + util + bash + socat + ]; + + buildFlags = ["all-dom0"]; + + installTargets = ["install-dom0"]; + + postInstall = '' + mkdir $out/libexec + mv $out/usr/sbin/* $out/libexec + mv $out/usr/bin $out/ + mv $out/usr/lib/qubes $out/lib/ + rm -d $out/usr/{lib,sbin,} + '' + optionalString isBootstrap '' + # This service is using binary from base package + rm $out/lib/systemd/system/qubes-qrexec-policy-daemon.service + # rpc services depend on base + rm -rf $out/etc/qubes/policy.d + rm -rf $out/etc/qubes-rpc + rm -d $out/{etc/{qubes,},lib/systemd/{system,}} + '' + optionalString (!isBootstrap) '' + for rpcname in policy.List policy.Get policy.Replace policy.Remove \ + policy.include.List policy.include.Get policy.include.Replace \ + policy.include.Remove policy.GetFiles; + do + ln -sf ${base}/bin/qubes-policy-admin $out/etc/qubes-rpc/$rpcname + done + patsh -f $out/etc/qubes-rpc/qubes.WaitForSession -s ${builtins.storeDir} + wrapPythonProgramsIn $out/etc/qubes-rpc ${base} + ''; + + inherit makeFlags; + }; + + # Util hardcodes agent paths, but it is used by agent. + # Building separate package for agent, which doesn't use those paths. + util = stdenv.mkDerivation { + inherit version src; + pname = "qubes-core-qrexec-util"; + sourceRoot = "${src.name}/libqrexec"; + + patches = [ + ./0001-refactor-remove-dependency-of-util-on-daemon.patch + ]; + + postPatch = '' + # rpc-multiplexer is included in both util and base packages to fix dependency cycle. + substituteInPlace qrexec.h \ + --replace-fail "/usr/lib/qubes/qubes-rpc-multiplexer" "$out/libexec/qubes-rpc-multiplexer" + ''; + + postInstall = '' + mkdir -p $out/libexec + cp ../lib/qubes-rpc-multiplexer $out/libexec/ + ''; + + nativeBuildInputs = [ + pkg-config + ]; + + buildInputs = [ + qubes-core-vchan-xen + ]; + + inherit makeFlags; + }; + + # Both python client library, and commands, needs to be split to module and application. + client = buildPythonPackage { + inherit version src; + pname = "qubes-core-qrexec"; + format = "custom"; + + patchPhase = '' + ''; + + nativeBuildInputs = [ + gobject-introspection + wrapGAppsHook3 + patsh + ]; + + buildInputs = [ + gtk3 + ]; + + propagatedBuildInputs = [ + pyinotify + pygobject3 + gbulb + qubes-core-vchan-xen + + # For scripts + bash + socat + ]; + + postInstall = '' + mv $out/${python.sitePackages}/usr/bin $out/bin + wrapGApp $out/bin/qrexec-policy-agent + + mkdir $out/lib/qubes + cp lib/qrexec-policy-agent-autostart $out/lib/qubes/ + + mkdir -p $out/etc/qubes/ + cp -r policy.d $out/etc/qubes/ + + mkdir -p $out/etc/qubes-rpc + ln -sf /var/run/qubes/policy-agent.sock $out/etc/qubes-rpc/policy.Ask + ln -sf /var/run/qubes/policy-agent.sock $out/etc/qubes-rpc/policy.Notify + # policy.RegisterArgument depends on qrexec client python api, and can't be moved to qrexec.dom0 package. + cp qubes-rpc-dom0/* $out/etc/qubes-rpc/ + + patsh -f $out/etc/qubes-rpc/qubes.WaitForSession -s ${builtins.storeDir} + wrapPythonProgramsIn $out/etc/qubes-rpc $out + + install -d $out/etc/xdg/autostart -m 755 + ''; + + pythonImportsCheck = [ "qrexec" ]; + }; +in +base.overrideAttrs (oldAttrs: { + passthru = oldAttrs.passthru // { + inherit domU dom0 dom0-bootstrap util; + }; +}) diff --git a/pkgs/development/python-modules/qubes-desktop-linux-commons/default.nix b/pkgs/development/python-modules/qubes-desktop-linux-commons/default.nix new file mode 100644 index 0000000000000..b8f9395bfa667 --- /dev/null +++ b/pkgs/development/python-modules/qubes-desktop-linux-commons/default.nix @@ -0,0 +1,43 @@ +{ + buildPythonPackage, + fetchFromGitHub, + setuptools, + distutils, + pyxdg, + qubes-core-admin-client, + qubes-imgconverter, + graphicsmagick, +}: +let + version = "4.2.12"; + src = fetchFromGitHub { + owner = "QubesOS"; + repo = "qubes-desktop-linux-common"; + rev = "refs/tags/v${version}"; + hash = "sha256-I/Kxn6nR+eqUU4bsyVPDeVHUQBS4kEsknllb3pdpdMc="; + }; +in +buildPythonPackage { + inherit version src; + pname = "qubes-desktop-linux-common"; + format = "setuptools"; + + nativeBuildInputs = [ + graphicsmagick + distutils + ]; + + propagatedBuildInputs = [ + pyxdg + qubes-core-admin-client + qubes-imgconverter + # Wanted at runtime + setuptools + ]; + + postInstall = '' + make install $makeFlags + ''; + + makeFlags = ["DESTDIR=$(out)"]; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index b79143c50a5fc..45f7f9530b6e0 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -26557,6 +26557,8 @@ with pkgs; qemu_xen_4_17 = lowPrio (qemu.override { hostCpuTargets = [ "i386-softmmu" ]; xenSupport = true; xen = xenPackages.xen_4_17-slim; }); qemu_xen = qemu_xen_4_19; + qemu_qubes = lowPrio (qemu.override { hostCpuTargets = [ "i386-softmmu" ]; xenSupport = true; xen = qubes-vmm-xen; }); + qemu_test = lowPrio (qemu.override { hostCpuOnly = true; nixosTestRunner = true; }); quick-lint-js = callPackage ../development/tools/quick-lint-js { }; diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index 5f4c18055d164..b9891b2768835 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -13278,6 +13278,36 @@ self: super: with self; { quaternion = callPackage ../development/python-modules/quaternion { }; + qubes-app-linux-usb-proxy = callPackage ../development/python-modules/qubes-app-linux-usb-proxy { }; + + qubes-core-admin = callPackage ../development/python-modules/qubes-core-admin { }; + + qubes-core-admin-client = callPackage ../development/python-modules/qubes-core-admin-client { }; + + qubes-core-libvirt = callPackage ../development/python-modules/libvirt { + libvirt = pkgs.qubes-core-libvirt; + # FIXME: Override maintainers + }; + + qubes-core-qrexec = callPackage ../development/python-modules/qubes-core-qrexec { }; + + qubes-core-qubesdb = toPythonModule (pkgs.qubes-core-qubesdb.override { + inherit python; + withPython = true; + }).pythonModule; + + qubes-desktop-linux-common = callPackage ../development/python-modules/qubes-desktop-linux-commons { }; + + qubes-imgconverter = (pkgs.qubes-linux-utils.override { + inherit python; + withPython = true; + }).imgconverter; + + # It would be nicer for closure size, if there was a separate output for python. + qubes-vmm-pyxen = toPythonModule (pkgs.qubes-vmm-xen.override { + inherit python; + }); + qudida = callPackage ../development/python-modules/qudida { }; querystring-parser = callPackage ../development/python-modules/querystring-parser { };