at 18.09-beta 4.7 kB view raw
1{ config, lib, ... }: 2let 3 inherit (lib) mkOption types optionalString; 4 5 cfg = config.boot.binfmtMiscRegistrations; 6 7 makeBinfmtLine = name: { recognitionType, offset, magicOrExtension 8 , mask, preserveArgvZero, openBinary 9 , matchCredentials, fixBinary, ... 10 }: let 11 type = if recognitionType == "magic" then "M" else "E"; 12 offset' = toString offset; 13 mask' = toString mask; 14 interpreter = "/run/binfmt/${name}"; 15 flags = if !(matchCredentials -> openBinary) 16 then throw "boot.binfmtMiscRegistrations.${name}: you can't specify openBinary = false when matchCredentials = true." 17 else optionalString preserveArgvZero "P" + 18 optionalString (openBinary && !matchCredentials) "O" + 19 optionalString matchCredentials "C" + 20 optionalString fixBinary "F"; 21 in ":${name}:${type}:${offset'}:${magicOrExtension}:${mask'}:${interpreter}:${flags}"; 22 23 binfmtFile = builtins.toFile "binfmt_nixos.conf" 24 (lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine cfg)); 25 26 activationSnippet = name: { interpreter, ... }: 27 "ln -sf ${interpreter} /run/binfmt/${name}"; 28 activationScript = '' 29 mkdir -p -m 0755 /run/binfmt 30 ${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet cfg)} 31 ''; 32in { 33 options = { 34 boot.binfmtMiscRegistrations = mkOption { 35 default = {}; 36 37 description = '' 38 Extra binary formats to register with the kernel. 39 See https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html for more details. 40 ''; 41 42 type = types.attrsOf (types.submodule ({ config, ... }: { 43 options = { 44 recognitionType = mkOption { 45 default = "magic"; 46 description = "Whether to recognize executables by magic number or extension."; 47 type = types.enum [ "magic" "extension" ]; 48 }; 49 50 offset = mkOption { 51 default = null; 52 description = "The byte offset of the magic number used for recognition."; 53 type = types.nullOr types.int; 54 }; 55 56 magicOrExtension = mkOption { 57 description = "The magic number or extension to match on."; 58 type = types.str; 59 }; 60 61 mask = mkOption { 62 default = null; 63 description = 64 "A mask to be ANDed with the byte sequence of the file before matching"; 65 type = types.nullOr types.str; 66 }; 67 68 interpreter = mkOption { 69 description = '' 70 The interpreter to invoke to run the program. 71 72 Note that the actual registration will point to 73 /run/binfmt/''${name}, so the kernel interpreter length 74 limit doesn't apply. 75 ''; 76 type = types.path; 77 }; 78 79 preserveArgvZero = mkOption { 80 default = false; 81 description = '' 82 Whether to pass the original argv[0] to the interpreter. 83 84 See the description of the 'P' flag in the kernel docs 85 for more details; 86 ''; 87 type = types.bool; 88 }; 89 90 openBinary = mkOption { 91 default = config.matchCredentials; 92 description = '' 93 Whether to pass the binary to the interpreter as an open 94 file descriptor, instead of a path. 95 ''; 96 type = types.bool; 97 }; 98 99 matchCredentials = mkOption { 100 default = false; 101 description = '' 102 Whether to launch with the credentials and security 103 token of the binary, not the interpreter (e.g. setuid 104 bit). 105 106 See the description of the 'C' flag in the kernel docs 107 for more details. 108 109 Implies/requires openBinary = true. 110 ''; 111 type = types.bool; 112 }; 113 114 fixBinary = mkOption { 115 default = false; 116 description = '' 117 Whether to open the interpreter file as soon as the 118 registration is loaded, rather than waiting for a 119 relevant file to be invoked. 120 121 See the description of the 'F' flag in the kernel docs 122 for more details. 123 ''; 124 type = types.bool; 125 }; 126 }; 127 })); 128 }; 129 }; 130 131 config = lib.mkIf (cfg != {}) { 132 environment.etc."binfmt.d/nixos.conf".source = binfmtFile; 133 system.activationScripts.binfmt = activationScript; 134 systemd.additionalUpstreamSystemUnits = 135 [ "proc-sys-fs-binfmt_misc.automount" 136 "proc-sys-fs-binfmt_misc.mount" 137 ]; 138 }; 139}