search
LoginSignup
0

More than 1 year has passed since last update.

posted at

NetBSD+qemuでPaXフラグまわりの設定を行う

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_READMAP_SHAREDPROT_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フラグの設定周りでハマってしまった話を紹介しました。発生するエラーと対応方法が分かってしまえば何ということはありませんが、同様の問題に遭遇してしまった人の参考になればと思います。

参考URL

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0