diff options
author | Matthew Bauer <mjbauer95@gmail.com> | 2019-05-10 18:03:24 -0400 |
---|---|---|
committer | Matthew Bauer <mjbauer95@gmail.com> | 2019-05-10 18:05:59 -0400 |
commit | 153598ebb02adaa690cb7ee67475ce07b0edd138 (patch) | |
tree | 4a0e017af2e9ca3e730c3c454a198f5bfea8abf3 /nixos/modules/system | |
parent | 366f70e3455297ea4f0c9eafea08b8df4bd4bed6 (diff) |
nixos/binfmt: handle emulatedSystems
Fixes #61248
Diffstat (limited to 'nixos/modules/system')
-rw-r--r-- | nixos/modules/system/boot/binfmt.nix | 258 |
1 files changed, 151 insertions, 107 deletions
diff --git a/nixos/modules/system/boot/binfmt.nix b/nixos/modules/system/boot/binfmt.nix index 15e84dc021e2..1efe397c011d 100644 --- a/nixos/modules/system/boot/binfmt.nix +++ b/nixos/modules/system/boot/binfmt.nix @@ -1,8 +1,8 @@ -{ config, lib, ... }: +{ config, lib, pkgs, ... }: let inherit (lib) mkOption types optionalString; - cfg = config.boot.binfmtMiscRegistrations; + cfg = config.boot.binfmt; makeBinfmtLine = name: { recognitionType, offset, magicOrExtension , mask, preserveArgvZero, openBinary @@ -13,125 +13,169 @@ let mask' = toString mask; interpreter = "/run/binfmt/${name}"; flags = if !(matchCredentials -> openBinary) - then throw "boot.binfmtMiscRegistrations.${name}: you can't specify openBinary = false when matchCredentials = true." + then throw "boot.binfmt.registrations.${name}: you can't specify openBinary = false when matchCredentials = true." else optionalString preserveArgvZero "P" + optionalString (openBinary && !matchCredentials) "O" + optionalString matchCredentials "C" + optionalString fixBinary "F"; in ":${name}:${type}:${offset'}:${magicOrExtension}:${mask'}:${interpreter}:${flags}"; - binfmtFile = builtins.toFile "binfmt_nixos.conf" - (lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine cfg)); - activationSnippet = name: { interpreter, ... }: "ln -sf ${interpreter} /run/binfmt/${name}"; - activationScript = '' - mkdir -p -m 0755 /run/binfmt - ${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet cfg)} - ''; -in { - options = { - boot.binfmtMiscRegistrations = mkOption { - default = {}; - - description = '' - Extra binary formats to register with the kernel. - See https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html for more details. - ''; - - type = types.attrsOf (types.submodule ({ config, ... }: { - options = { - recognitionType = mkOption { - default = "magic"; - description = "Whether to recognize executables by magic number or extension."; - type = types.enum [ "magic" "extension" ]; - }; - - offset = mkOption { - default = null; - description = "The byte offset of the magic number used for recognition."; - type = types.nullOr types.int; - }; - - magicOrExtension = mkOption { - description = "The magic number or extension to match on."; - type = types.str; - }; - mask = mkOption { - default = null; - description = - "A mask to be ANDed with the byte sequence of the file before matching"; - type = types.nullOr types.str; - }; - - interpreter = mkOption { - description = '' - The interpreter to invoke to run the program. - - Note that the actual registration will point to - /run/binfmt/''${name}, so the kernel interpreter length - limit doesn't apply. - ''; - type = types.path; - }; - - preserveArgvZero = mkOption { - default = false; - description = '' - Whether to pass the original argv[0] to the interpreter. - - See the description of the 'P' flag in the kernel docs - for more details; - ''; - type = types.bool; - }; + getEmulator = system: (lib.systems.elaborate { inherit system; }).emulator pkgs; - openBinary = mkOption { - default = config.matchCredentials; - description = '' - Whether to pass the binary to the interpreter as an open - file descriptor, instead of a path. - ''; - type = types.bool; - }; - - matchCredentials = mkOption { - default = false; - description = '' - Whether to launch with the credentials and security - token of the binary, not the interpreter (e.g. setuid - bit). - - See the description of the 'C' flag in the kernel docs - for more details. - - Implies/requires openBinary = true. - ''; - type = types.bool; - }; - - fixBinary = mkOption { - default = false; - description = '' - Whether to open the interpreter file as soon as the - registration is loaded, rather than waiting for a - relevant file to be invoked. - - See the description of the 'F' flag in the kernel docs - for more details. - ''; - type = types.bool; +in { + options = { + boot.binfmt = { + registrations = mkOption { + default = {}; + + description = '' + Extra binary formats to register with the kernel. + See https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html for more details. + ''; + + type = types.attrsOf (types.submodule ({ config, ... }: { + options = { + recognitionType = mkOption { + default = "magic"; + description = "Whether to recognize executables by magic number or extension."; + type = types.enum [ "magic" "extension" ]; + }; + + offset = mkOption { + default = null; + description = "The byte offset of the magic number used for recognition."; + type = types.nullOr types.int; + }; + + magicOrExtension = mkOption { + description = "The magic number or extension to match on."; + type = types.str; + }; + + mask = mkOption { + default = null; + description = + "A mask to be ANDed with the byte sequence of the file before matching"; + type = types.nullOr types.str; + }; + + interpreter = mkOption { + description = '' + The interpreter to invoke to run the program. + + Note that the actual registration will point to + /run/binfmt/''${name}, so the kernel interpreter length + limit doesn't apply. + ''; + type = types.path; + }; + + preserveArgvZero = mkOption { + default = false; + description = '' + Whether to pass the original argv[0] to the interpreter. + + See the description of the 'P' flag in the kernel docs + for more details; + ''; + type = types.bool; + }; + + openBinary = mkOption { + default = config.matchCredentials; + description = '' + Whether to pass the binary to the interpreter as an open + file descriptor, instead of a path. + ''; + type = types.bool; + }; + + matchCredentials = mkOption { + default = false; + description = '' + Whether to launch with the credentials and security + token of the binary, not the interpreter (e.g. setuid + bit). + + See the description of the 'C' flag in the kernel docs + for more details. + + Implies/requires openBinary = true. + ''; + type = types.bool; + }; + + fixBinary = mkOption { + default = false; + description = '' + Whether to open the interpreter file as soon as the + registration is loaded, rather than waiting for a + relevant file to be invoked. + + See the description of the 'F' flag in the kernel docs + for more details. + ''; + type = types.bool; + }; }; - }; - })); + })); + }; + + emulatedSystems = mkOption { + default = []; + description = '' + List of systems to emulate. Will also configure Nix to + support your new systems. + ''; + type = types.listOf types.string; + }; }; }; - config = lib.mkIf (cfg != {}) { - environment.etc."binfmt.d/nixos.conf".source = binfmtFile; - system.activationScripts.binfmt = activationScript; - systemd.additionalUpstreamSystemUnits = + config = { + boot.binfmt.registrations = builtins.listToAttrs (map (system: { + name = system; + value = { + interpreter = getEmulator system; + } // ({ + armv7l-linux = { + magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff''; + }; + aarch64-linux = { + magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff''; + }; + riscv64-linux = { + magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff''; + }; + x86_64-windows = { + magicOrExtension = ".exe"; + recognitionType = "extension"; + }; + i686-windows = { + magicOrExtension = ".exe"; + recognitionType = "extension"; + }; + }.${system} or (throw "Cannot create binfmt registration for system ${system}")); + }) cfg.emulatedSystems); + # TODO: add a nix.extraPlatforms option to NixOS! + nix.extraOptions = lib.mkIf (cfg.emulatedSystems != []) '' + extra-platforms = ${toString (cfg.emulatedSystems ++ lib.optional pkgs.stdenv.hostPlatform.isx86_64 "i686-linux")} + ''; + # nix.sandboxPaths = lib.mkIf (cfg.emulatedSystems != []) ([ "/run/binfmt" ] ++ (map getEmulator cfg.emulatedSystems)); + + environment.etc."binfmt.d/nixos.conf".source = builtins.toFile "binfmt_nixos.conf" + (lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine cfg.registrations)); + system.activationScripts.binfmt = lib.mkIf (cfg.registrations != {}) '' + mkdir -p -m 0755 /run/binfmt + ${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet cfg.registrations)} + ''; + systemd.additionalUpstreamSystemUnits = lib.mkIf (cfg.registrations != {}) [ "proc-sys-fs-binfmt_misc.automount" "proc-sys-fs-binfmt_misc.mount" ]; |