目次: Linux
前回はbinfmt_miscの使い方や動作を調べました。今回はDebian特有の挙動を見ていきたいと思います。細かいことを言えばQEMUの実装の話でありbinfmt_miscの実装ではありません。しかし二者は密接に関わっているので関連項目として取り上げます。
Debianのbinfmt_miscの設定では、インタープリターに/usr/libexec/qemu-binfmt/以下のファイルを指定します。このディレクトリには独特なファイル名(例: (arch名)-binfmt-P)のシンボリックリンクが置かれています。一例を紹介します。
$ ls -la /usr/libexec/qemu-binfmt/riscv64-binfmt-P lrwxrwxrwx 1 root root 29 May 20 22:14 /usr/libexec/qemu-binfmt/riscv64-binfmt-P -> ../../bin/qemu-riscv64-static
この/usr/libexec/qemu-binfmt/riscv64-binfmt-Pはシンボリックリンクで、実体はQEMU(/usr/bin/qemu-riscv64-static)であることが解ると思います。引数を何も指定せずに実行すると普通のQEMUとは異なるメッセージを出力します。
$ /usr/libexec/qemu-binfmt/riscv64-binfmt-P qemu: /usr/libexec/qemu-binfmt/riscv64-binfmt-P has to be run using kernel binfmt-misc subsystem
メッセージを出力しているのは見た通りQEMUです、が、オリジナルのQEMUにこのメッセージを出すコードはありません。
Debianのqemu-user-staticパッケージソースコードを見るとこのエラーメッセージを表示するためのパッチがありました。
// qemu/debian/patches/linux-user-binfmt-P.diff
diff --git a/linux-user/main.c b/linux-user/main.c
index e44bdb17b8..587bd02db2 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -562,7 +562,7 @@ static void usage(int exitcode)
exit(exitcode);
}
-static int parse_args(int argc, char **argv)
+static int parse_args(int argc, char **argv, bool *preserve_argv0)
{
const char *r;
int optind;
@@ -579,6 +579,28 @@ static int parse_args(int argc, char **argv)
}
}
+ /* HACK alert.
+ * when run as an interpreter using kernel's binfmt-misc mechanism,
+ * we have to know where are we (our own binary), where's the binary being run,
+ * and what it's argv[0] element.
+ * Only with the P interpreter flag kernel passes all 3 elements as first 3 argv[],
+ * but we can't distinguish if we were run with or without this P flag.
+ * So we register a special name with binfmt-misc system, a name which ends up
+ * in "-binfmt-P", and if our argv[0] ends up with that, we assume we were run
+ * from kernel's binfmt with P flag and our first 3 args are from kernel.
+ */
+ if (strlen(argv[0]) > sizeof("binfmt-P") &&
+ strcmp(argv[0] + strlen(argv[0]) - sizeof("binfmt-P"), "-binfmt-P") == 0) {
+ if (argc < 3) {
+ (void) fprintf(stderr, "qemu: %s has to be run using kernel binfmt-misc subsystem\n", argv[0]); //★★エラーメッセージ★★
+ exit(EXIT_FAILURE);
+ }
+ exec_path = argv[1];
+ handle_arg_argv0(argv[2]);
+ *preserve_argv0 = true;
+ return 2;
+ }
+
optind = 1;
for (;;) {
if (optind >= argc) {
コマンド名の末尾が-binfmt-Pであり、引数が3つより少ない場合にエラーを出す実装です。引数を渡すか、シンボリックリンクをリネームして実行するとエラーメッセージは出現しなくなります。
# ls -la riscv64-binfmt-P_ lrwxrwxrwx 1 root root 29 May 20 22:14 riscv64-binfmt-P_ -> ../../bin/qemu-riscv64-static # ./riscv64-binfmt-P_ qemu: no user program specified # ../../bin/qemu-riscv64-static qemu: no user program specified
QEMUで実行するbinfmt_miscのバイナリタイプ設定はこんな感じで、
# less /usr/lib/binfmt.d/qemu-riscv64.conf :qemu-riscv64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/libexec/qemu-binfmt/riscv64-binfmt-P:OCPF # ★FlagsはO, C, P, Fの4つ★
実装のコメントを見る限り、下記の条件を満たすことを期待しています。
この条件から外れる場合はエラーにしたいようです。riscv64-binfmt-Pのリンク先の実体はQEMUですが、間違ってQEMUとして起動することを防いでいる……?そこまでする理由があまり思いつかないですけど、昔に何かあったのかな?
< | 2024 | > | ||||
<< | < | 08 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
合計:
本日: