mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-05-08 20:27:03 +00:00
Merge pull request #61257 from matthewbauer/add-binfmt-emulated-systems
nixos/binfmt: handle emulatedSystems
This commit is contained in:
commit
395bcc0b27
2 changed files with 235 additions and 108 deletions
|
@ -234,6 +234,9 @@ with lib;
|
||||||
(mkRenamedOptionModule [ "hardware" "ckb" "enable" ] [ "hardware" "ckb-next" "enable" ])
|
(mkRenamedOptionModule [ "hardware" "ckb" "enable" ] [ "hardware" "ckb-next" "enable" ])
|
||||||
(mkRenamedOptionModule [ "hardware" "ckb" "package" ] [ "hardware" "ckb-next" "package" ])
|
(mkRenamedOptionModule [ "hardware" "ckb" "package" ] [ "hardware" "ckb-next" "package" ])
|
||||||
|
|
||||||
|
# binfmt
|
||||||
|
(mkRenamedOptionModule [ "boot" "binfmtMiscRegistrations" ] [ "boot" "binfmt" "registrations" ])
|
||||||
|
|
||||||
] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter"
|
] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter"
|
||||||
"jsonExporter" "minioExporter" "nginxExporter" "nodeExporter"
|
"jsonExporter" "minioExporter" "nginxExporter" "nodeExporter"
|
||||||
"snmpExporter" "unifiExporter" "varnishExporter" ]
|
"snmpExporter" "unifiExporter" "varnishExporter" ]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{ config, lib, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
inherit (lib) mkOption types optionalString;
|
inherit (lib) mkOption types optionalString;
|
||||||
|
|
||||||
cfg = config.boot.binfmtMiscRegistrations;
|
cfg = config.boot.binfmt;
|
||||||
|
|
||||||
makeBinfmtLine = name: { recognitionType, offset, magicOrExtension
|
makeBinfmtLine = name: { recognitionType, offset, magicOrExtension
|
||||||
, mask, preserveArgvZero, openBinary
|
, mask, preserveArgvZero, openBinary
|
||||||
|
@ -13,125 +13,249 @@ let
|
||||||
mask' = toString mask;
|
mask' = toString mask;
|
||||||
interpreter = "/run/binfmt/${name}";
|
interpreter = "/run/binfmt/${name}";
|
||||||
flags = if !(matchCredentials -> openBinary)
|
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" +
|
else optionalString preserveArgvZero "P" +
|
||||||
optionalString (openBinary && !matchCredentials) "O" +
|
optionalString (openBinary && !matchCredentials) "O" +
|
||||||
optionalString matchCredentials "C" +
|
optionalString matchCredentials "C" +
|
||||||
optionalString fixBinary "F";
|
optionalString fixBinary "F";
|
||||||
in ":${name}:${type}:${offset'}:${magicOrExtension}:${mask'}:${interpreter}:${flags}";
|
in ":${name}:${type}:${offset'}:${magicOrExtension}:${mask'}:${interpreter}:${flags}";
|
||||||
|
|
||||||
binfmtFile = builtins.toFile "binfmt_nixos.conf"
|
|
||||||
(lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine cfg));
|
|
||||||
|
|
||||||
activationSnippet = name: { interpreter, ... }:
|
activationSnippet = name: { interpreter, ... }:
|
||||||
"ln -sf ${interpreter} /run/binfmt/${name}";
|
"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 = ''
|
getEmulator = system: (lib.systems.elaborate { inherit system; }).emulator pkgs;
|
||||||
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, ... }: {
|
# Mapping of systems to “magicOrExtension” and “mask”. Mostly taken from:
|
||||||
options = {
|
# - https://github.com/cleverca22/nixos-configs/blob/master/qemu.nix
|
||||||
recognitionType = mkOption {
|
# and
|
||||||
default = "magic";
|
# - https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh
|
||||||
description = "Whether to recognize executables by magic number or extension.";
|
# TODO: maybe put these in a JSON file?
|
||||||
type = types.enum [ "magic" "extension" ];
|
magics = {
|
||||||
};
|
armv6l-linux = {
|
||||||
|
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'';
|
||||||
offset = mkOption {
|
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
|
||||||
default = null;
|
};
|
||||||
description = "The byte offset of the magic number used for recognition.";
|
armv7l-linux = {
|
||||||
type = types.nullOr types.int;
|
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'';
|
||||||
|
};
|
||||||
magicOrExtension = mkOption {
|
aarch64-linux = {
|
||||||
description = "The magic number or extension to match on.";
|
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00'';
|
||||||
type = types.str;
|
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
|
||||||
};
|
};
|
||||||
|
aarch64_be-linux = {
|
||||||
mask = mkOption {
|
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7'';
|
||||||
default = null;
|
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
|
||||||
description =
|
};
|
||||||
"A mask to be ANDed with the byte sequence of the file before matching";
|
i386-linux = {
|
||||||
type = types.nullOr types.str;
|
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'';
|
||||||
|
};
|
||||||
interpreter = mkOption {
|
i486-linux = {
|
||||||
description = ''
|
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
|
||||||
The interpreter to invoke to run the program.
|
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
|
||||||
|
};
|
||||||
Note that the actual registration will point to
|
i586-linux = {
|
||||||
/run/binfmt/''${name}, so the kernel interpreter length
|
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
|
||||||
limit doesn't apply.
|
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
|
||||||
'';
|
};
|
||||||
type = types.path;
|
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'';
|
||||||
preserveArgvZero = mkOption {
|
};
|
||||||
default = false;
|
x86_64-linux = {
|
||||||
description = ''
|
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00'';
|
||||||
Whether to pass the original argv[0] to the interpreter.
|
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
|
||||||
|
};
|
||||||
See the description of the 'P' flag in the kernel docs
|
alpha-linux = {
|
||||||
for more details;
|
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'';
|
||||||
type = types.bool;
|
};
|
||||||
};
|
sparc64-linux = {
|
||||||
|
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02'';
|
||||||
openBinary = mkOption {
|
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
|
||||||
default = config.matchCredentials;
|
};
|
||||||
description = ''
|
sparc-linux = {
|
||||||
Whether to pass the binary to the interpreter as an open
|
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12'';
|
||||||
file descriptor, instead of a path.
|
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
|
||||||
'';
|
};
|
||||||
type = types.bool;
|
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'';
|
||||||
matchCredentials = mkOption {
|
};
|
||||||
default = false;
|
powerpc64-linux = {
|
||||||
description = ''
|
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15'';
|
||||||
Whether to launch with the credentials and security
|
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
|
||||||
token of the binary, not the interpreter (e.g. setuid
|
};
|
||||||
bit).
|
powerpc64le-linux = {
|
||||||
|
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00'';
|
||||||
See the description of the 'C' flag in the kernel docs
|
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00'';
|
||||||
for more details.
|
};
|
||||||
|
mips-linux = {
|
||||||
Implies/requires openBinary = true.
|
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'';
|
||||||
type = types.bool;
|
};
|
||||||
};
|
mipsel-linux = {
|
||||||
|
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'';
|
||||||
fixBinary = mkOption {
|
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
|
||||||
default = false;
|
};
|
||||||
description = ''
|
mips64-linux = {
|
||||||
Whether to open the interpreter file as soon as the
|
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08'';
|
||||||
registration is loaded, rather than waiting for a
|
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
|
||||||
relevant file to be invoked.
|
};
|
||||||
|
mips64el-linux = {
|
||||||
See the description of the 'F' flag in the kernel docs
|
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'';
|
||||||
for more details.
|
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
|
||||||
'';
|
};
|
||||||
type = types.bool;
|
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";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf (cfg != {}) {
|
in {
|
||||||
environment.etc."binfmt.d/nixos.conf".source = binfmtFile;
|
options = {
|
||||||
system.activationScripts.binfmt = activationScript;
|
boot.binfmt = {
|
||||||
systemd.additionalUpstreamSystemUnits =
|
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 = {
|
||||||
|
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.automount"
|
||||||
"proc-sys-fs-binfmt_misc.mount"
|
"proc-sys-fs-binfmt_misc.mount"
|
||||||
];
|
];
|
||||||
|
|
Loading…
Add table
Reference in a new issue