オペレーティングシステム 其の五 20170517
システムコールについて少し
プロセス切り替え:タイマー割り込みで切り替えを行う.
この時の割り込みハンドラの役割は
- 退避
- 実行プロセスの決定
- 復帰
スケジューリングのイメージ
これについては図で説明したほうがわかりやすい.下の図の説明としては、基本的に実行可能スタックに入っているプロセスを選出して実行しているが、I/Oデバイスの入力がいる場合はブロックスタックに貯められ、入力が入るまで待機させている.これによってI/O入力待ちのプロセスに余分な仮想CPUを割り当てないようにしている.
PCで起こるフリーズ現象はプロセスがずっとブロック状態になっているために起きてしまう.
この一般的な例としてはC言語ではgetchar()関数がわかりやすい
⇒キーボードから文字が入力されるまで処理がストップしている(ブロック状態にある)
システムコールでもスケジューリングのブロック機能が役立っている
⇒int 0x80;でシステムコールした時にカーネルではブロック状態と同じことになっている.入力がなければずっと待たされるが、ブロックされたことには気づいていない.プロセスの生成・終了の欄を見た後だとわかりやすいかもしれない.
プロセス間通信
プロセスごとに処理が独立しているとは言ったものの、プロセス同士が相互的に動きたいときもある.
⇒それぞれの特別なインターフェースが必要.
この特別なインターフェースを実現するための方法として3つほど挙げることができる.
①共有メモリ:複数プロセスがメモリを共有.通信というより、掲示板的な用法といえる.
②共有ファイル:二つのプロセスで一つのファイルを開く.同時に開くことは難しいので、どちらかが書く、もう一方が読むとしておけば、相互通信は実現することができる.
③ソケット:インターネット通信にも使われている.メリットはマシン内、ネットワーク内どちらでも動かすことができること.デメリットは別マシンと通信するように手順を踏む必要があること.
プロセスについての話はここまで.
システムコールについてさらに
(復習)システムコールとはring3がring0に命令を依頼するときに用いられるもの
しかし、いちいちシステムコールするのは面倒くさい.
⇒ライブラリにこのシステムコールの機能を備えた関数が存在すればラク.例えばunistd.hの中にあるwrite関数.
ファイルディスクリプタ
ファイルを開く⇒プロセス構造体に情報が入る
⇒情報が入ったところのインデックスがファイルディスクリプタとして記憶される.
これによってファイルの入出力はファイルディスクリプタ経由で行うことができる.
つまり、ファイルディスクリプタとはファイル情報が入っているインデックス(番地)のことである.
プロセスの生成・消滅
これもシステムコールで制御する.
重要なのはforkとexec
fork():0かほかの値を返り値として返してくれる.これによって一つのプロセスから二つに分岐することが可能になるので、親プロセスと子プロセスに分けることが可能になる.基本的に0が帰ると子プロセス、その他が帰ると親プロセスの処理に分岐する.
exec():実行可能ファイルを実行する.親プロセスと同じプログラムではつまらないので、別のプログラムを実行してやる.
つまり、fork()でプロセスを生成してやり、生成したプロセスの中身をexec()で実行し、最終的にexit()で親プロセスに帰ってくることでプロセスを終了する.子プロセスの実行が終わり、exit()で帰ってくるまで、親プロセスはブロック状態になっている.
シェルについて
システムコール的に考えると、コマンドに対応したプロセスをfork()で分岐させてexec()で実行.それが終わったら、fork()の上とつなぎループを作る.図で説明したほうがわかりやすい.
とりあえずシステムコールの話もこれでひと段落.
OS知識とセキュリティ
ここまでの知識でセキュリティ攻撃側についてちょっとだけ理解できる.
攻撃方法
①コード実行:攻撃者が指定した命令を被害者が実行する
②制御奪取
の2step
ここではスタックオーバーフローという手法について説明する.
被害者側のメモリに、データが格納されているスタック以上のデータをコピーさせることによってreturn処理時にシェルコードを実行してもらうという乗っ取り方.シェルコードとは、シェルを乗っ取るためのコード.もっと詳しく説明すると、「シェルをexecveシステムコールで起動させるプログラム」.
被害者メモリ側のreturnの位置などは事前に探りを入れておき、めぼしをつける必要がある.