diff options
author | John Ericson <John.Ericson@Obsidian.Systems> | 2019-05-12 19:11:52 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-12 19:11:52 -0400 |
commit | 395bcc0b27ce0d3c8a9af09737ba076a089a8dd6 (patch) | |
tree | 96577d77b261a1f49c107600a6370f4dbd8f01c2 /nixos | |
parent | d8cac92f55a0f5328286006698bc0519b99ecb30 (diff) | |
parent | 93a522cf0c4ce02c01201c77f1f6ce9d19efd9f9 (diff) |
Merge pull request #61257 from matthewbauer/add-binfmt-emulated-systems
nixos/binfmt: handle emulatedSystems
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/modules/rename.nix | 3 | ||||
-rw-r--r-- | nixos/modules/system/boot/binfmt.nix | 314 |
2 files changed, 222 insertions, 95 deletions
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 70807ccf7cd8..aa3d120c97f1 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -234,6 +234,9 @@ with lib; (mkRenamedOptionModule [ "hardware" "ckb" "enable" ] [ "hardware" "ckb-next" "enable" ]) (mkRenamedOptionModule [ "hardware" "ckb" "package" ] [ "hardware" "ckb-next" "package" ]) + # binfmt + (mkRenamedOptionModule [ "boot" "binfmtMiscRegistrations" ] [ "boot" "binfmt" "registrations" ]) + ] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter" "jsonExporter" "minioExporter" "nginxExporter" "nodeExporter" "snmpExporter" "unifiExporter" "varnishExporter" ] diff --git a/nixos/modules/system/boot/binfmt.nix b/nixos/modules/system/boot/binfmt.nix index 15e84dc021e2..d6c0f0504868 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,249 @@ 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)} - ''; + + getEmulator = system: (lib.systems.elaborate { inherit system; }).emulator pkgs; + + # Mapping of systems to “magicOrExtension” and “mask”. Mostly taken from: + # - https://github.com/cleverca22/nixos-configs/blob/master/qemu.nix + # and + # - https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh + # TODO: maybe put these in a JSON file? + magics = { + armv6l-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''; + }; + 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''; + }; + aarch64_be-linux = { + magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff''; + }; + i386-linux = { + magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00''; + mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff''; + }; + i486-linux = { + magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00''; + mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff''; + }; + i586-linux = { + magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00''; + mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff''; + }; + i686-linux = { + magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00''; + mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff''; + }; + x86_64-linux = { + magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00''; + mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff''; + }; + alpha-linux = { + magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90''; + mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff''; + }; + sparc64-linux = { + magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff''; + }; + sparc-linux = { + magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff''; + }; + powerpc-linux = { + magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff''; + }; + powerpc64-linux = { + magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff''; + }; + powerpc64le-linux = { + magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00''; + }; + mips-linux = { + magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff''; + }; + mipsel-linux = { + magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff''; + }; + mips64-linux = { + magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff''; + }; + mips64el-linux = { + magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00''; + mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff''; + }; + riscv32-linux = { + magicOrExtension = ''\x7fELF\x01\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\xff\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\xff\xff\xfe\xff\xff\xff''; + }; + x86_64-windows = { + magicOrExtension = ".exe"; + recognitionType = "extension"; + }; + i686-windows = { + magicOrExtension = ".exe"; + recognitionType = "extension"; + }; + }; + 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" ]; - }; + boot.binfmt = { + registrations = mkOption { + default = {}; - offset = mkOption { - default = null; - description = "The byte offset of the magic number used for recognition."; - type = types.nullOr types.int; - }; + 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. + ''; - magicOrExtension = mkOption { - description = "The magic number or extension to match on."; - type = types.str; - }; + 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" ]; + }; - mask = mkOption { - default = null; - description = - "A mask to be ANDed with the byte sequence of the file before matching"; - type = types.nullOr types.str; - }; + offset = mkOption { + default = null; + description = "The byte offset of the magic number used for recognition."; + type = types.nullOr types.int; + }; - interpreter = mkOption { - description = '' - The interpreter to invoke to run the program. + magicOrExtension = mkOption { + description = "The magic number or extension to match on."; + type = types.str; + }; - Note that the actual registration will point to - /run/binfmt/''${name}, so the kernel interpreter length - limit doesn't apply. - ''; - type = types.path; - }; + mask = mkOption { + default = null; + description = + "A mask to be ANDed with the byte sequence of the file before matching"; + type = types.nullOr types.str; + }; - preserveArgvZero = mkOption { - default = false; - description = '' - Whether to pass the original argv[0] to the interpreter. + interpreter = mkOption { + description = '' + The interpreter to invoke to run the program. - See the description of the 'P' flag in the kernel docs - for more details; - ''; - type = types.bool; - }; + Note that the actual registration will point to + /run/binfmt/''${name}, so the kernel interpreter length + limit doesn't apply. + ''; + type = types.path; + }; - 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; - }; + preserveArgvZero = mkOption { + default = false; + description = '' + Whether to pass the original argv[0] to the interpreter. - 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 'P' flag in the kernel docs + for more details; + ''; + type = types.bool; + }; - See the description of the 'C' flag in the kernel docs - for more details. + 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; + }; - Implies/requires openBinary = true. - ''; - 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). - 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; + 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; + } // (magics.${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 (system: dirOf (dirOf (getEmulator system))) cfg.emulatedSystems)); + + environment.etc."binfmt.d/nixos.conf".source = builtins.toFile "binfmt_nixos.conf" + (lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine config.boot.binfmt.registrations)); + system.activationScripts.binfmt = '' + mkdir -p -m 0755 /run/binfmt + ${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet config.boot.binfmt.registrations)} + ''; + systemd.additionalUpstreamSystemUnits = lib.mkIf (config.boot.binfmt.registrations != {}) [ "proc-sys-fs-binfmt_misc.automount" "proc-sys-fs-binfmt_misc.mount" ]; |