NetBSD Advent Calendar 2020 7日目の記事です。
今日はNetBSD上でqemuを動かす際にハマった個所があったので、メモも兼ねて記事にしておこうと思います。
背景
ソースコードからビルドしたqemuをNetBSDで動かそうとした際、以下のようなエラーに引っかかってしまいました。ググってみたところ、どうやらPaXまわりの設定により、エラーとなっているようです。
$ /opt/qemu-5.0.1/bin/qemu-system-x86_64
Could not allocate dynamic translator buffer
PaX
NetBSDにおけるPaXはメモリに関する脆弱性緩和(exploit mitigation)機能であり、security(7)によると以下の3つが利用可能となっています。
- PaX ASLR (Address Space Layout Randomization).
- PaX MPROTECT (mprotect(2) restrictions)
- PaX SegvGuard
ktrussでエラーが発生するまでをトレースする
ktruss(1)でqemuを起動してからエラーになるまでの流れをトレースしてみます。
どうやらエラーはmmap(2)を呼び出した際に発生しており、 EACCESS
が返されているようです。
$ ktruss /opt/qemu-5.0.1/bin/x86_64-softmmu/qemu-system-x86_64
...中略...
738 1 qemu-system-x86_ mmap(0, 0x40000000, 0x7, 0x1002, 0xffffffff, 0, 0) Err#13 EACCES
738 1 qemu-system-x86_ write(0x2, 0x747369b7da00, 0x2d) = 45
"Could not allocate dynamic translator buffer\n"
mmap(2)のマニュアルの"ERRORS"の節には以下の説明があり、どうやらメモリの読み書きや属性に関する要因により発生するエラーのようです。
$ man 2 mmap
...中略...
ERRORS
mmap() will fail if:
[EACCES] The flag PROT_READ was specified as part of the prot
parameter and fd was not open for reading.
The flags MAP_SHARED and PROT_WRITE were specified as
part of the flags and prot parameters and fd was not
open for writing.
PaX mprotect restrictions prohibit the requested pro-
tection.
PROT_READ
や MAP_SHARED
、 PROT_WRITE
のフラグの扱いが原因という可能性もありますが、qemuの処理的にメモリの読み書きをしないというのは考えにくいため、残りの "PaX mprotect restrictions" の可能性から調べてみます。
paxctl
PaXまわりの属性を操作するためのコマンドとして、paxctl(8)が提供されています。マニュアルを見ると、mprotect(2)まわりで付与されている制限は m
オプションで無効化できるようです。
$ man 8 paxctl
NAME
paxctl -- list and modify PaX flags associated with an ELF program
SYNOPSIS
paxctl flags program ...
...中略...
m Explicitly disable PaX MPROTECT (mprotect(2) restrictions) for
program.
さっそく試してみます。 sudo paxctl +m <実行バイナリ>
でmprotect(2)まわりの制限(というかPaXフラグ)を落とします。
$ sudo paxctl /opt/qemu-5.0.1/bin/x86_64-softmmu/qemu-system-x86_64
No PaX flags.
$
$ # PaX MPROTECTフラグを落とす(無効化する)。
$ # (メッセージなどは出力されず、そのままコマンドが終了してプロンプトが返される)
$ sudo paxctl +m /opt/qemu-5.0.1/bin/x86_64-softmmu/qemu-system-x86_64
$
$ sudo paxctl /opt/qemu-5.0.1/bin/x86_64-softmmu/qemu-system-x86_64
PaX flags:
m: mprotect(2) restrictions, explicit disabl
この設定により、qemuが起動するようになりました。ひとまずこれで問題解決です。
$ # qemuが起動するようになった!(^_^)
$ /opt/qemu-5.0.1/bin/x86_64-softmmu/qemu-system-x86_64
VNC server running on ::1:5900
その他:パッケージのqemuではダメなの?
じつはこの問題を調査する前に、パッケージでインストールしたqemuを利用しようとしていました。ところが私の環境ではなぜかSEGVでqemuが落ちてしまうという状態になっており、ソースからビルドしたものを利用していました。
パッケージ版のqemuは上記の設定でもSEGVになってしまうため、こちらはもう少し調査が必要そうです。
$ # 設定可能なPaXフラグ全てを落としてもSEGVになってしまう...。
$ sudo paxctl +a /usr/pkg/bin/qemu-system-x86_64
$ sudo paxctl +g /usr/pkg/bin/qemu-system-x86_64
$ sudo paxctl +m /usr/pkg/bin/qemu-system-x86_64
$
$ sudo paxctl /usr/pkg/bin/qemu-system-x86_64
PaX flags:
a: ASLR, explicit disable
g: Segvguard, explicit disable
m: mprotect(2) restrictions, explicit disabl
$
$ /usr/pkg/bin/qemu-system-x86_64
Segmentation fault (コアダンプ)
$
$ ktruss /usr/pkg/bin/qemu-system-x86_64
...中略...
1284 1 qemu-system-x86_ mmap(0, 0x9000, 0x3, 0x1002, 0xffffffff, 0, 0) = 0x7f7ff7edc000
1284 1 qemu-system-x86_ SIGSEGV SIG_DFL
まとめ
NetBSDでqemuを動かす際にPaXフラグの設定周りでハマってしまった話を紹介しました。発生するエラーと対応方法が分かってしまえば何ということはありませんが、同様の問題に遭遇してしまった人の参考になればと思います。