about summary refs log tree commit diff
path: root/nixos/modules/system
diff options
context:
space:
mode:
authorMatthew Bauer <mjbauer95@gmail.com>2019-05-10 18:03:24 -0400
committerMatthew Bauer <mjbauer95@gmail.com>2019-05-10 18:05:59 -0400
commit153598ebb02adaa690cb7ee67475ce07b0edd138 (patch)
tree4a0e017af2e9ca3e730c3c454a198f5bfea8abf3 /nixos/modules/system
parent366f70e3455297ea4f0c9eafea08b8df4bd4bed6 (diff)
downloadnixlib-153598ebb02adaa690cb7ee67475ce07b0edd138.tar
nixlib-153598ebb02adaa690cb7ee67475ce07b0edd138.tar.gz
nixlib-153598ebb02adaa690cb7ee67475ce07b0edd138.tar.bz2
nixlib-153598ebb02adaa690cb7ee67475ce07b0edd138.tar.lz
nixlib-153598ebb02adaa690cb7ee67475ce07b0edd138.tar.xz
nixlib-153598ebb02adaa690cb7ee67475ce07b0edd138.tar.zst
nixlib-153598ebb02adaa690cb7ee67475ce07b0edd138.zip
nixos/binfmt: handle emulatedSystems
Fixes #61248
Diffstat (limited to 'nixos/modules/system')
-rw-r--r--nixos/modules/system/boot/binfmt.nix258
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"
       ];