[BitVisor-devel:31] BitVisor newprocess patch
Shougo Matsushita
shougo @ softlab.cs.tsukuba.ac.jp
2012年 2月 29日 (水) 15:50:55 JST
BitVisorメーリングリストの皆さん
筑波大学 ソフトウェア研究室の松下正吾です。
今回のパッチはBitVisorに動的プロセス生成機能を追加します。BitVisorはこれまでも
newprocess()を用いてプロセスを生成することはできました。BitVisorの組み込みプロ
セスはBitVisorのソースコードcore/builtin/bin_xxx.cにあります。しかし、この組み
込みプロセスはBitVisorに静的に組み込まなければならないという制限がありました。
プロセスを変更すると、BitVisorを再コンパイル・再起動が必要になります。今回のパ
ッチを用いると、プロセスのプログラムを変更した場合でもBitVisorの再ビルドや
BitVisorの再起動が必要なく、新しいプログラムをロードしてプロセスを生成できるよ
うになります。
本パッチで追加する機能は、プロセスのプログラムを開発する人とBitVisorの管理者は
別であるという考えに基いています。危険なプロセスをBitVisorで実行されると困るの
で、BitVisorに動的にロードできるプロセスはBitVisorの管理者に予め署名されたもの
に限定します。
本パッチでプロセスを動的ロードする場合、まず公開鍵・秘密鍵のペアを予め生成し、
公開鍵をBitVisorのソースコードに埋め込んでおきます。そして動的ロードしたいプロ
セスのバイナリを用意し、BitVisorの管理者がさきほどの秘密鍵によって署名を行いま
す。実際にゲストOSからプロセスのバイナリを動的ロードする時には、プロセスのバイ
ナリとその署名をBitVisorにvmmcallの引数として送信します。
(1) ハイパバイザコール vmmcall_newprocessのインタフェース
今回追加した、vmmcall_newprocessハイパバイザーコールのインタフェースを下に示し
ます。binary_addrはロードするELF形式のバイナリが格納されている変数のアドレス、
binary_sizeはロードするバイナリのサイズです。sign_addrはBitVisorの管理者による
署名が格納されている変数のアドレス、sign_sizeは署名のサイズです。sign_addrの署
名が合わない場合、このvmmcallはエラーを返します。
int vmmcall_newprocess(ulong binary_addr, ulong binary_size, ulong
sign_addr, ulong sign_size)
この機能を実装するため、core/process.cに次の関数を追加しました。
int
newprocess2(void *addr)
{
return process_new(0, addr);
}
この関数はBitVisorに元から実装されていたnewprocess()とは違い、BitVisor内のアド
レスからELFバイナリを読み込み、プロセスとして実行します。vmmcall_newprocess()は
最終的に、newprocess2()の呼び出しに変換されています。
実行できるプロセスの仕様はBitVisor組み込みのプロセスと同じで、32bitのELFファイ
ルとなっています。BitVisor組み込みのプロセスと同じビルド工程により生成すること
ができます。
(2) vmmcall_newprocessを利用するためのスタブ関数
ゲストOSで用いるスタブ関数を以下に示します。スタブ関数のインタフェースはvmmcall
の引数で示したものと同じです。
int vmmcall_newprocess(ulong binary_addr, ulong binary_size,
ulong sign_addr, ulong sign_size)
{
int r;
asm volatile ("vmcall" : "=a" (r) : "a" (vmmcall_newprocess_num),
"b" (binary_addr), "c" (binary_size),
"d" (sign_addr), "S" (sign_size));
return r;
}
この関数をゲストOSで呼び出すと、binary_addrに示されるアドレスからbinary_sizeを
読み込み、BitVisorのプロセスとして実行します。sign_addr, sign_sizeにはプロセス
として実行するELFバイナリの署名データとその長さを指定します。正常に終了すると、
戻り値は0以上になります。失敗すると0以下の値が返ります。
(3) 公開鍵・秘密鍵の組の生成と変換
プロセスの動的ロード機能を利用するためには、鍵の生成と署名の作成が必要となりま
す。BitVisorの管理者は、次のようなコマンドであらかじめ公開鍵と秘密鍵の組を生成
します。
$ openssl genrsa 1024 >test_private_key.pem
上記のコマンドを実行すると、公開鍵・秘密鍵のペアが生成されます。生成されたデー
タはテキストファイルです。
$ cat test_private_key.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCutrhDOf7YygrFWdcUGBRULAJQsldIXRMvqzUrF519Uzc5epv1
Cz+N3XOqucEjfuRxWUq7w78l3Txhubfi923ECJZbD7t2+7qjoNX2bzx6ZmQ1sAQX
kzodbRnqpBXuMI4YUJn61RRT5fvA7EINO1bSr4mV8+JiKhF4+n5wRF3nHwIDAQAB
AoGBAIxHUTNJAYH21ycVt0b+/nOG0mUQjFwhvyHrCUmMMHtLsW+JLmdVnLW/NPvD
IXvqimkoFIUl6ffw5mZgw3CM0afcuZu9lPpaRhcDS9tJtMjaB6sGkS+I5T+j9jTe
Mgzb7v9yYqBt5dR59VM8Nzmy7HXaf2TYvCBs1eXoDcymYj1BAkEA2F9ZmlKnh2d6
9vLjE5OMtNKZuUkfyEJgQB4PGTMB5RpbMVsN4HRPc6semMj5ALX+bVJFUrnGZ6di
F0HAWwNIaQJBAM62MiH6zT1T81D1guqObjwLra5lPDR/PQEhfV9M93mI5SUm0fEw
Zq7d2f6TQ2PpllxOZeYj/Z7ZY405WyREAkcCQQCMK3kImHMfLNJkGIUysWt92NDt
T4nfWeCwqMhvMrQPjzt0heA/gBnYfQqdP9TPuRbSC3INXXxCuhS5rEbIrx/BAkEA
pDtjZ1XhXLlnVspI4lyZPoG00xtBkyAIcu6NsnrvIBNgo3zNTkg7PPGscjPEVgxP
VzU+hnPP3DYxfxGz1QNnnwJAOlVtBNCf3hOSa/xQ0xzcZ5YSaoFGysx8DLXaKr39
txTjbXftY8m22JHB87BRSfU+07qKkgv4ql//d+yXEYxP6g==
-----END RSA PRIVATE KEY-----
$ openssl rsa -in test_private_key.pem -pubout -out test_public_key.pem
上記のコマンドより、公開鍵・秘密鍵のペアから公開鍵のみを取りだします。この公開
鍵データも次のようなテキストファイルとなっています。
$ cat test_public_key.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCutrhDOf7YygrFWdcUGBRULAJQ
sldIXRMvqzUrF519Uzc5epv1Cz+N3XOqucEjfuRxWUq7w78l3Txhubfi923ECJZb
D7t2+7qjoNX2bzx6ZmQ1sAQXkzodbRnqpBXuMI4YUJn61RRT5fvA7EINO1bSr4mV
8+JiKhF4+n5wRF3nHwIDAQAB
-----END PUBLIC KEY-----
(4) 公開鍵のBitVisorへの埋め込み
そしてcore/newprocess_pubkey.hに公開鍵のデータを埋め込み、
core/vmmcall_newprocess.cのソースコード内でこれを#includeするようにします。
#define EXEC_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\r\n" \
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCutrhDOf7YygrFWdcUGBRULAJQ\r\n" \
"sldIXRMvqzUrF519Uzc5epv1Cz+N3XOqucEjfuRxWUq7w78l3Txhubfi923ECJZb\r\n" \
"8+JiKhF4+n5wRF3nHwIDAQAB\r\n"
"-----END PUBLIC KEY-----\r\n"
このとき改行文字として、"\r\n"で区切ることに注意してください。
プロセスのプログラムの開発者は、開発したプロセスのプログラムをBitVisorの管理者
へ送ります。管理者はその内容を確認し、先ほど生成した秘密鍵で署名します。プロセ
スのプログラムの開発者は、ユーザにその署名されたプロセスのプログラムを送ります。
ユーザは、vmmcall_newprocessハイパバイザーコールでその署名されたプロセスのプ
ログラムをBitVisorにロードすることを要求します。BitVisorは、その署名されたプロ
セスのプログラムの署名を自身が持つ管理者の公開鍵で検証し、それが正しければプロ
グラムをロードします。
vmmcall_newprocessハイパバイザーコール戻り値により、ゲストOSはロードした
BitVisorプロセスのdescを得ることができます。
ちなみに、プロセスのプログラムを変更すると、これまでの署名が使えなくなるため、
もう一度署名を生成してもらう必要があります。
(5) プログラムの開発
プロセスのプログラムはcore/builtin/bin_xxx.cにあるBitVisorの組み込みコマンドと
同様に開発することができます。
今回のパッチでは、samples/loader/bin_hello.cに下のようなサンプルプログラムを用意しました。
プログラムの内容は、単純に標準出力にメッセージを表示するだけです。単にmakeを実
行するだけでビルドすることができるので参考にしてください。
--------------------------------------------------------------------------
#include <lib_lineinput.h>
#include <lib_printf.h>
#include <lib_syscalls.h>
int _start (int msgcode, int proc_number, struct msgbuf *buf, int bufcnt)
{
printf("Hello, World!\n");
return 0;
}
--------------------------------------------------------------------------
(6) 秘密鍵での署名
ELFバイナリの署名を簡単に生成するため、signという簡易的な署名ツールを作成しまし
た。Linux環境で動作を確認しています。ビルドにはOpenSSLの開発者用ライブラリが必
要です。ソースコードはguest/loader/sign.cにあります。
このプログラムの実行例は以下のようになります。
$ ./sign bin_hello test_private_key.pem test_sign
出力が何もなければ、署名ファイルtest_signが生成されています。
(7) ロードと実行
vmmcall_newprocess()を簡単に使用できるようにするため、loaderというプログラムを
作成しました。Linux環境での動作を確認しています。ソースコードは
guest/loader/loader.cにあります。
このプログラムの実行例は以下のようになります。
$ ./loader bin_hello test_sign
desc = 6
プログラムの第一引数はプロセスとして実行するELFバイナリのファイル名です。
BitVisor組み込みのプロセスと同様にして、あらかじめ作成しておきます。
test_signにはあらかじめ生成しておいた署名データを指定します。
-------------- next part --------------
テキスト形式以外の添付ファイルを保管しました...
ファイル名: bitvisor-newprocess.patch
型: text/x-patch
サイズ: 18073 バイト
説明: 無し
URL: <http://www.bitvisor.org/archives/bitvisor-devel/attachments/20120229/a5b6ac46/attachment.bin>
BitVisor-devel メーリングリストの案内