nixos/binfmt: Add option to use static emulators when available

The fixBinary flag will be enabled if a static emulator is in use.
This commit is contained in:
Zhaofeng Li 2023-05-27 11:11:49 -06:00 committed by Julius Michaelis
parent 4658a06076
commit b8c1ef98e4
3 changed files with 33 additions and 8 deletions

View File

@ -296,6 +296,10 @@ let
in {
emulatorAvailable = pkgs: (selectEmulator pkgs) != null;
# whether final.emulator pkgs.pkgsStatic works
staticEmulatorAvailable = pkgs: final.emulatorAvailable pkgs
&& (final.isLinux || final.isWasi || final.isMmix);
emulator = pkgs:
if (final.emulatorAvailable pkgs)
then selectEmulator pkgs

View File

@ -96,6 +96,7 @@ lib.runTests (
canExecute = null;
emulator = null;
emulatorAvailable = null;
staticEmulatorAvailable = null;
isCompatible = null;
}?${platformAttrName};
};

View File

@ -28,8 +28,6 @@ let
''
else interpreter;
getEmulator = system: (lib.systems.elaborate { inherit system; }).emulator pkgs;
getQemuArch = system: (lib.systems.elaborate { inherit system; }).qemuArch;
# Mapping of systems to “magicOrExtension” and “mask”. Mostly taken from:
# - https://github.com/cleverca22/nixos-configs/blob/master/qemu.nix
@ -280,28 +278,50 @@ in {
'';
type = types.listOf (types.enum (builtins.attrNames magics));
};
preferStaticEmulators = mkOption {
default = false;
description = ''
Whether to use static emulators when available.
This enables the kernel to preload the emulator binaries when
the binfmt registrations are added, obviating the need to make
the emulator binaries available inside chroots and chroot-like
sandboxes.
'';
type = types.bool;
};
};
};
config = {
assertions = lib.mapAttrsToList (name: reg: {
assertion = reg.fixBinary -> !reg.wrapInterpreterInShell;
message = "boot.binfmt.registrations.\"${name}\" cannot have fixBinary when the interpreter is invoked through a shell.";
}) cfg.registrations;
boot.binfmt.registrations = builtins.listToAttrs (map (system: assert system != pkgs.stdenv.hostPlatform.system; {
name = system;
value = { config, ... }: let
interpreter = getEmulator system;
qemuArch = getQemuArch system;
elaborated = lib.systems.elaborate { inherit system; };
useStaticEmulator = cfg.preferStaticEmulators && elaborated.staticEmulatorAvailable pkgs;
interpreter = elaborated.emulator (if useStaticEmulator then pkgs.pkgsStatic else pkgs);
inherit (elaborated) qemuArch;
isQemu = "qemu-${qemuArch}" == baseNameOf interpreter;
preserveArgvZero = "qemu-${qemuArch}" == baseNameOf interpreter;
interpreterReg = let
wrapperName = "qemu-${qemuArch}-binfmt-P";
wrapper = pkgs.wrapQemuBinfmtP wrapperName interpreter;
in
if preserveArgvZero then "${wrapper}/bin/${wrapperName}"
if isQemu && !useStaticEmulator then "${wrapper}/bin/${wrapperName}"
else interpreter;
in ({
preserveArgvZero = mkDefault preserveArgvZero;
preserveArgvZero = mkDefault isQemu;
interpreter = mkDefault interpreterReg;
wrapInterpreterInShell = mkDefault (!config.preserveArgvZero);
fixBinary = mkDefault useStaticEmulator;
wrapInterpreterInShell = mkDefault (!config.preserveArgvZero && !config.fixBinary);
interpreterSandboxPath = mkDefault (dirOf (dirOf config.interpreter));
} // (magics.${system} or (throw "Cannot create binfmt registration for system ${system}")));
}) cfg.emulatedSystems);