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 { in {
emulatorAvailable = pkgs: (selectEmulator pkgs) != null; emulatorAvailable = pkgs: (selectEmulator pkgs) != null;
# whether final.emulator pkgs.pkgsStatic works
staticEmulatorAvailable = pkgs: final.emulatorAvailable pkgs
&& (final.isLinux || final.isWasi || final.isMmix);
emulator = pkgs: emulator = pkgs:
if (final.emulatorAvailable pkgs) if (final.emulatorAvailable pkgs)
then selectEmulator pkgs then selectEmulator pkgs

View File

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

View File

@ -28,8 +28,6 @@ let
'' ''
else interpreter; 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: # Mapping of systems to “magicOrExtension” and “mask”. Mostly taken from:
# - https://github.com/cleverca22/nixos-configs/blob/master/qemu.nix # - https://github.com/cleverca22/nixos-configs/blob/master/qemu.nix
@ -280,28 +278,50 @@ in {
''; '';
type = types.listOf (types.enum (builtins.attrNames magics)); 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 = { 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; { boot.binfmt.registrations = builtins.listToAttrs (map (system: assert system != pkgs.stdenv.hostPlatform.system; {
name = system; name = system;
value = { config, ... }: let value = { config, ... }: let
interpreter = getEmulator system; elaborated = lib.systems.elaborate { inherit system; };
qemuArch = getQemuArch 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 interpreterReg = let
wrapperName = "qemu-${qemuArch}-binfmt-P"; wrapperName = "qemu-${qemuArch}-binfmt-P";
wrapper = pkgs.wrapQemuBinfmtP wrapperName interpreter; wrapper = pkgs.wrapQemuBinfmtP wrapperName interpreter;
in in
if preserveArgvZero then "${wrapper}/bin/${wrapperName}" if isQemu && !useStaticEmulator then "${wrapper}/bin/${wrapperName}"
else interpreter; else interpreter;
in ({ in ({
preserveArgvZero = mkDefault preserveArgvZero; preserveArgvZero = mkDefault isQemu;
interpreter = mkDefault interpreterReg; interpreter = mkDefault interpreterReg;
wrapInterpreterInShell = mkDefault (!config.preserveArgvZero); fixBinary = mkDefault useStaticEmulator;
wrapInterpreterInShell = mkDefault (!config.preserveArgvZero && !config.fixBinary);
interpreterSandboxPath = mkDefault (dirOf (dirOf config.interpreter)); interpreterSandboxPath = mkDefault (dirOf (dirOf config.interpreter));
} // (magics.${system} or (throw "Cannot create binfmt registration for system ${system}"))); } // (magics.${system} or (throw "Cannot create binfmt registration for system ${system}")));
}) cfg.emulatedSystems); }) cfg.emulatedSystems);