🦀

Homebrew経由で入れたbinutilsを使ってビルドスクリプトを使うようなcargo build --releaseをするとSIGKILLが出て死ぬ

#tech

2024-06-29

タイトルの通り.Homebrew経由で入れたbinutilsを使ってcargo build --releaseするとbuild-script-buildSIGKILLが出る.cargo buildすると正常に通る.

M1 MAXが載ったmacでやっていたのでチップの問題を疑ったが,原因はbinutilsをどう入れているかに起因したという話.

そもそもの経緯

セキュリティ・キャンプ2024 全国大会 OS自作ゼミで,ひとまず以前作成したRISC-V 32bit向けRust製カーネルを64bitにしていくことになった.それ自体は割とすぐできたが,その後のユーザーランドを追加する部分でこの問題が発生した.まずは当時の状態を貼る:

https://github.com/lapla-cogito/amia/tree/972369554093b1591276bc793f7122587cf4354a

この後の説明に必要な部分だけ説明すると,ディレクトリ構造が次のようになっていて,

$ tree -L 2 -d
.
├── kernel
│   ├── src
│   └── target
└── user
    ├── src
    └── target

6 directories

kernelにはカーネルのソースコード,userにはユーザーランドのソースコードを入れている.ビルド手順はMakefile.tomlに定義されているrunというジョブにあるが,大雑把に言うとuserをビルドしてそのバイナリをkernelにリンクさせる形式でkernelをビルドする.この際にkernelに入ってcargo build --releaseするとSIGKILLが起こって死ぬ問題が発生した.

SIGKILLが起こる様子
様子

ここでbuild-script-build内でSIGKILLが起こっていることは分かるのでとりあえず雑にこのバイナリに対してfileとかotoolとかを刺してみるが有用っぽい情報は得られなかった.

「きびし~」と思って試しにcargo buildすると,これは通る.あと普段のこのOSの開発はWSL2上でやっているのだが,こちらだとどちらのビルドも通る.少し調べたがエスカレしておいて良さそうと思ったので,セキュキャンのDiscordサーバーで講師にエスカレした(見ていただいてありがとうございます...).

調査

一緒に調査したところ,まずlldbを刺してみると良いのではという話になり,lldbrunしてみた.その様子がこちら:

lldb上でMalformed Mach-Oと言われる様子
lldbを刺した様子

"Malformed Mach-O file"と宣っている.普通にビルドしただけなのにMalformedとか言われるの大分心外だが!?みたいな気持ちになり,なる.皆さんも同じ状況ならなると思います.

ここから調査すると,次のようなIssueが見つかった:

https://github.com/rust-lang/rust/issues/122902

https://github.com/rust-lang/cargo/issues/13683

どうやらbinutilsをHomebrew経由で入れると,中に入っているstripが壊れていてMalformedなMach-Oになるらしい.確かにそれならreleaseビルドでだけ死ぬのも納得だが,だが...

で,更に調査するとHomebrew経由のbinutilsと使ってビルドしたものとMacにデフォルトで入っているbinutils系のコマンドを使ってビルドしたものではMach-Oのバージョンが異なるので,binutils側が追従できていないんだろうなあの気持ちになる(前者が2,後者が1).

ということでbrew uninstall binutilsをしてビルドして難を逃れている.上で挙げたIssueはどれも"Homebrew経由で入れるの止めようね!笑"でcloseされているのできびしい気持ちにはなる.