杂项二进制格式的内核支持 (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 的字符串(其中您可以根据需要选择 :),并将其 echo 到 /proc/sys/fs/binfmt_misc/register

以下是这些字段的含义

  • name

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

  • type

    是识别类型。魔数填 M,扩展名填 E

  • offset

    是魔数/掩码在文件中的偏移量,以字节为单位。如果省略它,则默认为 0(即写作 :name:type::magic...)。当使用文件名扩展名匹配时会被忽略。

  • magic

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

  • mask

    是一个(可选的,默认为全 0xff)掩码。您可以通过提供一个长度和形式类似于魔数的字符串来屏蔽掉某些位不参与匹配。掩码与文件的字节序列进行按位与操作。请注意,您必须转义任何 NUL 字节;解析会在遇到第一个 NUL 字节时停止。当使用文件名扩展名匹配时会被忽略。

  • interpreter

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

  • flags

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

    P - preserve-argv[0]

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

    O - open-binary

    binfmt_misc 的传统行为是将二进制文件的完整路径作为参数传递给解释器。包含此标志后,binfmt_misc 将打开文件进行读取,并将其描述符以键“AT_EXECFD”传递到辅助向量中,从而允许解释器执行不可读的二进制文件。应谨慎使用此功能——必须信任解释器不会泄露不可读二进制文件的内容。

    C - credentials

    目前,binfmt_misc 的行为是根据解释器来计算新进程的凭据和安全令牌。当包含此标志时,这些属性将根据二进制文件进行计算。它还隐式包含 O 标志。应谨慎使用此功能,因为当使用 binfmt_misc 运行归 root 所有且具有 setuid 的二进制文件时,解释器将以 root 权限运行。

    F - fix binary

    binfmt_misc 的通常行为是在调用 misc 格式文件时惰性地派生二进制文件。然而,在面对挂载命名空间和根目录更改时,这种方式效果不佳,因此 F 模式会在安装仿真时立即打开二进制文件,并使用打开的镜像来派生模拟器,这意味着一旦安装,它将始终可用,无论环境如何变化。

存在一些限制

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

  • 魔数必须驻留在文件的头 128 字节中,即 offset+size(magic) 必须小于 128

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

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

您可能希望在启动期间将二进制格式添加到您的某个 /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 hdimages)

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

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

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

您可以通过向 /proc/sys/fs/binfmt_misc/status/proc/.../the_name 写入 0(禁用)或 1(启用)来启用/禁用 binfmt_misc 或某个二进制类型。使用 cat 查看该文件可获知 binfmt_misc/the_entry 的当前状态。

您可以通过向 /proc/.../the_name/proc/sys/fs/binfmt_misc/status 写入 -1 来删除某个条目或所有条目。

提示

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

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

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