15 cfg = config.boot.binfmt;
31 type = if recognitionType == "magic" then "M" else "E";
32 offset' = toString offset;
33 mask' = toString mask;
34 interpreter = "/run/binfmt/${name}";
36 if !(matchCredentials -> openBinary) then
37 throw "boot.binfmt.registrations.${name}: you can't specify openBinary = false when matchCredentials = true."
39 optionalString preserveArgvZero "P"
40 + optionalString (openBinary && !matchCredentials) "O"
41 + optionalString matchCredentials "C"
42 + optionalString fixBinary "F";
44 ":${name}:${type}:${offset'}:${magicOrExtension}:${mask'}:${interpreter}:${flags}";
48 { interpreter, wrapInterpreterInShell, ... }:
49 if wrapInterpreterInShell then
50 pkgs.writeShellScript "${name}-interpreter" ''
52 exec -- ${interpreter} "$@"
57 # Mapping of systems to “magicOrExtension” and “mask”. Mostly taken from:
58 # - https://github.com/cleverca22/nixos-configs/blob/master/qemu.nix
60 # - https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh
61 # TODO: maybe put these in a JSON file?
64 magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'';
65 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
68 magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'';
69 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
72 magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00'';
73 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
76 magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7'';
77 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
80 magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'';
81 mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
84 magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
85 mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
88 magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
89 mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
92 magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
93 mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
96 magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00'';
97 mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
100 magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90'';
101 mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
104 magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02'';
105 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
108 magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12'';
109 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
112 magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14'';
113 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
116 magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15'';
117 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
119 powerpc64le-linux = {
120 magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00'';
121 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00'';
124 magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'';
125 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20'';
128 magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'';
129 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00'';
132 magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08'';
133 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
136 magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'';
137 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
139 mips64-linuxabin32 = {
140 magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20'';
141 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20'';
143 mips64el-linuxabin32 = {
144 magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00'';
145 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00'';
148 magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'';
149 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
152 magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'';
153 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
155 loongarch64-linux = {
156 magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02\x01'';
157 mask = ''\xff\xff\xff\xff\xff\xff\xff\xfc\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
160 magicOrExtension = ''\x00asm'';
161 mask = ''\xff\xff\xff\xff'';
164 magicOrExtension = ''\x00asm'';
165 mask = ''\xff\xff\xff\xff'';
168 magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16'';
169 mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
171 x86_64-windows.magicOrExtension = "MZ";
172 i686-windows.magicOrExtension = "MZ";
178 (lib.mkRenamedOptionModule [ "boot" "binfmtMiscRegistrations" ] [ "boot" "binfmt" "registrations" ])
183 registrations = mkOption {
187 Extra binary formats to register with the kernel.
188 See https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html for more details.
191 type = types.attrsOf (
196 recognitionType = mkOption {
198 description = "Whether to recognize executables by magic number or extension.";
207 description = "The byte offset of the magic number used for recognition.";
208 type = types.nullOr types.int;
211 magicOrExtension = mkOption {
212 description = "The magic number or extension to match on.";
218 description = "A mask to be ANDed with the byte sequence of the file before matching";
219 type = types.nullOr types.str;
222 interpreter = mkOption {
224 The interpreter to invoke to run the program.
226 Note that the actual registration will point to
227 /run/binfmt/''${name}, so the kernel interpreter length
233 preserveArgvZero = mkOption {
236 Whether to pass the original argv[0] to the interpreter.
238 See the description of the 'P' flag in the kernel docs
244 openBinary = mkOption {
245 default = config.matchCredentials;
247 Whether to pass the binary to the interpreter as an open
248 file descriptor, instead of a path.
253 matchCredentials = mkOption {
256 Whether to launch with the credentials and security
257 token of the binary, not the interpreter (e.g. setuid
260 See the description of the 'C' flag in the kernel docs
263 Implies/requires openBinary = true.
268 fixBinary = mkOption {
271 Whether to open the interpreter file as soon as the
272 registration is loaded, rather than waiting for a
273 relevant file to be invoked.
275 See the description of the 'F' flag in the kernel docs
281 wrapInterpreterInShell = mkOption {
284 Whether to wrap the interpreter in a shell script.
286 This allows a shell command to be set as the interpreter.
291 interpreterSandboxPath = mkOption {
295 Path of the interpreter to expose in the build sandbox.
297 type = types.nullOr types.path;
305 emulatedSystems = mkOption {
313 List of systems to emulate. Will also configure Nix to
314 support your new systems.
315 Warning: the builder can execute all emulated systems within the same build, which introduces impurities in the case of cross compilation.
317 type = types.listOf (types.enum (builtins.attrNames magics));
320 addEmulatedSystemsToNixSandbox = mkOption {
325 Whether to add the {option}`boot.binfmt.emulatedSystems` to {option}`nix.settings.extra-platforms`.
326 Disable this to use remote builders for those platforms, while allowing testing binaries locally.
330 preferStaticEmulators = mkOption {
333 Whether to use static emulators when available.
335 This enables the kernel to preload the emulator binaries when
336 the binfmt registrations are added, obviating the need to make
337 the emulator binaries available inside chroots and chroot-like
346 assertions = lib.mapAttrsToList (name: reg: {
347 assertion = reg.fixBinary -> !reg.wrapInterpreterInShell;
348 message = "boot.binfmt.registrations.\"${name}\" cannot have fixBinary when the interpreter is invoked through a shell.";
349 }) cfg.registrations;
351 boot.binfmt.registrations = builtins.listToAttrs (
354 assert system != pkgs.stdenv.hostPlatform.system;
360 elaborated = lib.systems.elaborate { inherit system; };
361 useStaticEmulator = cfg.preferStaticEmulators && elaborated.staticEmulatorAvailable pkgs;
362 interpreter = elaborated.emulator (if useStaticEmulator then pkgs.pkgsStatic else pkgs);
364 inherit (elaborated) qemuArch;
365 isQemu = "qemu-${qemuArch}" == baseNameOf interpreter;
369 wrapperName = "qemu-${qemuArch}-binfmt-P";
370 wrapper = pkgs.wrapQemuBinfmtP wrapperName interpreter;
372 if isQemu && !useStaticEmulator then "${wrapper}/bin/${wrapperName}" else interpreter;
376 preserveArgvZero = mkDefault isQemu;
378 interpreter = mkDefault interpreterReg;
379 fixBinary = mkDefault useStaticEmulator;
380 wrapInterpreterInShell = mkDefault (!config.preserveArgvZero && !config.fixBinary);
381 interpreterSandboxPath = mkDefault (dirOf (dirOf config.interpreter));
383 // (magics.${system} or (throw "Cannot create binfmt registration for system ${system}"))
386 ) cfg.emulatedSystems
388 nix.settings = lib.mkIf (cfg.addEmulatedSystemsToNixSandbox && cfg.emulatedSystems != [ ]) {
391 ++ lib.optional pkgs.stdenv.hostPlatform.isx86_64 "i686-linux";
392 extra-sandbox-paths =
394 ruleFor = system: cfg.registrations.${system};
395 hasWrappedRule = lib.any (system: (ruleFor system).wrapInterpreterInShell) cfg.emulatedSystems;
398 ++ lib.optional hasWrappedRule "${pkgs.bash}"
399 ++ (map (system: (ruleFor system).interpreterSandboxPath) cfg.emulatedSystems);
402 environment.etc."binfmt.d/nixos.conf".source = builtins.toFile "binfmt_nixos.conf" (
403 lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine config.boot.binfmt.registrations)
406 systemd = lib.mkMerge [
410 "d /run/binfmt 0755 -"
412 ++ lib.mapAttrsToList (name: interpreter: "L+ /run/binfmt/${name} - - - - ${interpreter}") (
413 lib.mapAttrs mkInterpreter config.boot.binfmt.registrations
417 (lib.mkIf (config.boot.binfmt.registrations != { }) {
418 additionalUpstreamSystemUnits = [
419 "proc-sys-fs-binfmt_misc.automount"
420 "proc-sys-fs-binfmt_misc.mount"
421 "systemd-binfmt.service"
423 services.systemd-binfmt.after = [ "systemd-tmpfiles-setup.service" ];
424 services.systemd-binfmt.restartTriggers = [ (builtins.toJSON config.boot.binfmt.registrations) ];