実装について 前田俊行
実装の特徴 最小限の労力で実装した 既存のLinuxカーネルの機能をフル活用する Linuxカーネル本体を改造せずにすんだ
実装した2つの仕組み カーネル内でプログラムを実行する仕組み カーネル内からシステムコールを実行する仕組み
カーネル内でプログラムを実行する仕組み Linuxのカーネルモジュールの機構を利用 安全性はTALの型チェックにより保証される メモリ安全性と制御フロー安全性を保証
Linuxカーネルモジュール機構の仕組み 任意のプログラムをカーネル空間にロードする機能 シンボル管理機能
任意のプログラムをカーネル空間にロードする機能 Linuxでは任意のメモリイメージを カーネル空間にロードすることができる 参考 : create_module(2) init_module(2)
シンボル管理機能 カーネル空間 プログラム プログラム 参考 : procfs(5) load load jmp jmp tableA 0xe000 jmp jmp routineB 0xc000 1 :プログラム中のメモリアドレスを 「穴」としておき さらに名前をつけておく 3 : プログラムのロード時に 「穴」が埋められる tableA 0xe000 routineB 0xc000 2 : カーネルは 名前とアドレスの対応表 を用意しておく 参考 : procfs(5)
カーネル内でプログラムを実行する仕組みの全体像 3 : 安全ならばLinuxの カーネルモジュール機能を 用いてロード 1 : TALでプログラムを作成 型チェッカ 2 : TALの型チェッカで安全性チェック
カーネル内からシステムコールを実行する仕組み Linuxシステムコールのシステム関数を直接呼び出すことで実現
Linuxシステムコールの仕組み その1 : 割り込み発生 ユーザプログラムはシステムコールを実行するために割り込みを発生させる … // 引数の準備 … // システムコール番号の … // 指定など int 0x80 プログラム ユーザモード 割り込み発生! カーネルモード システムコール実行のために 特権モードへ遷移
Linuxシステムコールの仕組み その2 : システム関数の実行 カーネルはユーザプログラムから指定された番号をもとにシステム関数をシステム関数表から探し出し、実行する システム関数 sys_read システム関数表 システム関数 sys_write 1 2 システム関数 sys_open システムコール番号 3 4 システム関数 sys_execve 5 6
Linuxシステムコールの仕組み その3 : 割り込み終了 システム関数の実行が終了したら割り込み処理を終了し、ユーザプログラムへ帰る … // 返り値やエラー値の … // 指定 iret カーネル カーネルモード 割り込み処理終了 ユーザモード 一般モードへ遷移
カーネル内からシステムコールを呼び出す仕組みの全体像 直接システム関数を呼び出す カーネル空間 プログラム システム関数 sys_open … // 引数の準備 … jmp sys_open 直接呼び出し 安全性はTALの型チェックで保証
細かい話 :システム関数の 直接呼出について 現在の実装では、Linuxのそのままのシステム関数を利用しているので、直接呼び出す前(後)に前(後)処理を行っている 引数のマーシャリング、アンマーシャリング CとTALの配列のデータ表現間の相互変換 PopcornとCの呼び出し規約の違いの吸収 ただし、これは最新のPopcornでは解決されている
現在の実装の問題 実行できるユーザプログラムのサイズ、数に制限がある スタックオーバーフローを考慮していない ユーザプログラムがカーネルに常駐するため スタックオーバーフローを考慮していない スタックがオーバーフローしたら、さようなら
新しい実装方式の模索 プログラムを通常のユーザプロセスで実行する ただし、プロセスの特権レベルをカーネルと同じレベルにする Linuxなどではカーネル空間がユーザ空間の一部としてマップされていることを利用
新しい実装方式の問題 スタックの扱いが複雑 細かい話は長くなるので省略 特に割り込みスタック IA32の仕様がまずい
まとめ 既存のLinuxの機能を利用してカーネルを改造することなく実装した カーネルモジュールのロード機能を利用 システムコール関数を利用