对各种二进制格式的内核支持 (binfmt_misc)

此内核功能允许您通过在 shell 中简单地键入其名称来调用几乎所有程序(有关限制,请参见下文)。 这包括例如已编译的 Java(TM)、Python 或 Emacs 程序。

要实现这一点,您必须告诉 binfmt_misc 哪个解释器必须用哪个二进制文件调用。 Binfmt_misc 通过将文件开头的某些字节与您提供的魔术字节序列(屏蔽掉指定的位)进行匹配来识别二进制文件类型。 Binfmt_misc 还可以识别文件名扩展名,例如 .com.exe

首先,您必须挂载 binfmt_misc

mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

要实际注册新的二进制类型,您必须设置一个类似于 :name:type:offset:magic:mask:interpreter:flags 的字符串(您可以根据需要选择 :),并将其回显到 /proc/sys/fs/binfmt_misc/register

以下是字段的含义

  • name

    是一个标识符字符串。 将在此名称下创建新的 /proc 文件,位于 /proc/sys/fs/binfmt_misc 下; 由于显而易见的原因,不能包含斜杠 /

  • type

    是识别的类型。 对于魔术,给出 M,对于扩展名,给出 E

  • offset

    是以字节为单位的文件中 magic/mask 的偏移量。 如果您省略它,则默认为 0(即,您编写 :name:type::magic...)。 使用文件名扩展名匹配时将被忽略。

  • magic

    是 binfmt_misc 正在匹配的字节序列。 魔术字符串可能包含十六进制编码的字符,如 \x0a\xA4。 请注意,您必须转义任何 NUL 字节; 解析会在第一个 NUL 字节处停止。 在 shell 环境中,您可能需要编写 \\x0a 以防止 shell 吞噬您的 \。 如果您选择了文件名扩展名匹配,则这是要识别的扩展名(不带 .,不允许使用 \x0a 特殊字符)。 扩展名匹配区分大小写,并且不允许使用斜杠 /

  • mask

    是一个(可选,默认为 all 0xff)掩码。 您可以通过提供像魔术字符串一样长并且与魔术字符串类似的字符串来屏蔽掉一些匹配位。 掩码与文件的字节序列进行与运算。 请注意,您必须转义任何 NUL 字节; 解析会在第一个 NUL 字节处停止。 使用文件名扩展名匹配时将被忽略。

  • interpreter

    是应该以二进制文件作为第一个参数调用的程序(指定完整路径)

  • flags

    是一个可选字段,用于控制解释器调用的多个方面。 它是大写字母的字符串,每个字母控制着某个方面。 支持以下标志

    P - preserve-argv[0]

    binfmt_misc 的旧行为是使用二进制文件的完整路径覆盖原始的 argv[0]。 当包含此标志时,binfmt_misc 将为此目的向参数向量添加一个参数,从而保留原始的 argv[0]。 例如,如果您的 interp 设置为 /bin/foo,并且您运行 blah(位于 /usr/local/bin 中),则内核将执行 /bin/foo,并将 argv[] 设置为 ["/bin/foo", "/usr/local/bin/blah", "blah"]。 interp 必须知道这一点,以便它可以执行 /usr/local/bin/blah,并将 argv[] 设置为 ["blah"]

    O - open-binary

    binfmt_misc 的旧行为是将二进制文件的完整路径作为参数传递给解释器。 当包含此标志时,binfmt_misc 将打开文件以进行读取,并将其描述符作为参数传递,而不是传递完整路径,从而允许解释器执行不可读的二进制文件。 应该谨慎使用此功能 - 必须信任解释器不会发出不可读二进制文件的内容。

    C - credentials

    当前,binfmt_misc 的行为是根据解释器计算新进程的凭据和安全令牌。 当包含此标志时,这些属性将根据二进制文件计算。 它也暗示了 O 标志。 应该谨慎使用此功能,因为当运行由 root 拥有的 setuid 二进制文件时,解释器将以 root 权限运行。

    F - fix binary

    binfmt_misc 的通常行为是在调用 misc 格式文件时延迟生成二进制文件。 然而,这在面对挂载命名空间和 changeroot 时效果不佳,因此 F 模式会在安装模拟后立即打开二进制文件,并使用打开的图像来生成模拟器,这意味着一旦安装,无论环境如何变化,它始终可用。

有一些限制

  • 整个注册字符串不得超过 1920 个字符

  • magic 必须位于文件的前 128 个字节中,即 offset+size(magic) 必须小于 128

  • 解释器字符串不得超过 127 个字符

要使用 binfmt_misc,您必须首先挂载它。 您可以使用 mount -t binfmt_misc none /proc/sys/fs/binfmt_misc 命令挂载它,或者您可以将一行 none  /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0 添加到您的 /etc/fstab,以便它在启动时自动挂载。

您可能需要在启动期间的某个 /etc/rc 脚本中添加二进制格式。 阅读您的 init 程序的手册,以了解如何正确执行此操作。

考虑添加条目的顺序! 稍后添加的条目将首先匹配!

一些示例(假设您位于 /proc/sys/fs/binfmt_misc 中)

  • 启用对 em86 的支持(类似于 binfmt_em86,仅适用于 Alpha AXP)

    echo ':i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:' > register
    echo ':i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:' > register
    
  • 启用对打包的 DOS 应用程序的支持(预配置的 dosemu hdimage)

    echo ':DEXE:M::\x0eDEX::/usr/bin/dosexec:' > register
    
  • 启用对使用 wine 的 Windows 可执行文件的支持

    echo ':DOSWin:M::MZ::/usr/local/bin/wine:' > register
    

有关 java 支持,请参见 Java(tm) 二进制内核 Linux 支持 v1.03

您可以通过将 0(禁用)或 1(启用)回显到 /proc/sys/fs/binfmt_misc/status/proc/.../the_name 来启用/禁用 binfmt_misc 或一个二进制类型。 Catting 文件会告诉您 binfmt_misc/the_entry 的当前状态。

您可以通过将 -1 回显到 /proc/.../the_name/proc/sys/fs/binfmt_misc/status 来删除一个条目或所有条目。

提示

如果您想将特殊参数传递给您的解释器,您可以为其编写一个包装脚本。 有关示例,请参见 Documentation/admin-guide/java.rst

您的解释器不应在 PATH 中查找文件名; 内核将传递给它要使用的完整文件名(或文件描述符)。 使用 $PATH 可能会导致意外的行为,并且可能存在安全隐患。

Richard Günther <rguenth@tat.physik.uni-tuebingen.de>