monomeg Lab. 第2開発室

プログラミングで学んだことの覚書やら、考察ネタやら、なんでもあり

「絶対特権主張しますっ!」で学ぶメモリ保護

正確には「IA-32(x86) プロテクトモードにおけるメモリ保護」ですかね…

経緯

数あるデレマス曲の中でも「絶対特権主張しますっ!」という曲は、そのキャッチーなメロディとは対照的に、「『あの女、あの人に優しくされて調子に乗っているけど本命は私なんだからあんまり馴れ馴れしくするな。あの人に近づいて良いのは自分だけ』というようなある種のヤンデレっぽさが垣間見える」曲で知られています。

その歌詞の持つ意味自体は、おおよそ他の2次元アイドルソングでもありそうな内容ではあるのですが、「特権」や「越権」というあまり日常生活では使われない単語がとにかく連発されるため、かなり頭の中に残ります…

そんな感じに頭の中に残った状態で、コンピュータアーキテクチャについて調べていたら「もしかしたら『絶対特権主張しますっ!』でメモリ保護を説明できるんじゃね?」という発想が浮かび、その勢いで家にあった「Linuxのブートプロセスをみる」(KADOKAWA/アスキー・メディアワークス)を読んで、無理やりエントリに落とし込んでみました。

それでは、本題に入ってみます。なお、特に明記しない限り、IA-32 CPU上のLinuxについて説明します。


わたしだけの 特権!特権!特権!特権!特権!です!

楽しそうに話したり 腕組んだりその類い

絶対!絶対!絶対!絶対!

絶対特権主張しますっ!(ますっ!)

おそらく、「特権レベル」のことですね。「CPUモード」とも呼ばれます。

プログラムが実行できるCPU命令の種類やアクセス可能なメモリの範囲、I/Oポートへのアクセスの可否を制御します。

複数の特権レベルの階層構造を概念的に表したものを「リングプロテクション」といいます。 特権レベルはRing 0〜3までありますが、Ring 0が一番権限が強く、Ring 3が一番権限が制限されます。

一例として、Ring 0ではカーネルが動作し、Ring 3ではユーザーが起動するプログラムのプロセスが動作します。root権限で実行されるプロセスもRing 3で動作します。Ring 1〜2は、仮想マシンを実現するために利用されますが、最近はRing 0より強い特権を持つIntel VTという技術が利用されています。

(ぜっ!ぜっ!ぜっ!ぜっ!ぜっ!ぜっ!絶対に!

ぜっ!ぜっ!ぜっ!ぜっ!ぜっ!ぜっ!う~ぜっ!)

Ring 3のプログラムがRing 0の特権レベルを要求する状況でしょうか?

その気 無いくせにあの人 優しい言葉をかけてくるから あなた達も 嬉しくなって 勘違いをしただけなの バ・カ・ねッ!

CPUが現在実行しているプログラムの特権レベルを、「CPL(Current Privilege Level:現行特権レベル)」といいます。CPLがRing 1~3のプログラムが「特権命令(プロセッサのステータスを変更するような命令や入出力命令)」の実行を試みると、CPUは「一般保護例外(Global Protection Fault)」を発生してOSに通知します。

おそらくRing 3のプログラムが特権命令を実行しようとしてCPUに怒られたのをからかっているんでしょう(こじつけ)

わたしだけの 特権!特権!特権!特権!特権!です!

CPUのCPLがRing 0~2のいずれかの特権レベルで動作しているとき、この状態を「スーパーバイザー・モード」といいます。一方、CPLがRing 3の状態を「ユーザーモード」といいます。

越えたらダメ! 一線!一線!一線!一線!境界線

わたしだけの 独占!独占!独占!独占!独占!です!

個人的感情で 近づくの禁じます

越権!越権!越権!越権! 越権行為許しません!(せん!)

(No! No! No! No! No! No! 越権です!

No! No! No! No! No! No! Oh No!)

メモリ保護の主な実現方法として、「セグメント方式」と「ページング方式」があります。

Linuxではメモリ保護を実現するためにセグメント方式は利用していません。しかしながら、CPUをプロテクトモードに移行させる目的として、セグメントディスクリプタ(Segment Descriptor)を作成しています。 セグメントの機能をメモリ保護には利用していないため、論理アドレスのオフセットとリニアアドレス(仮想アドレス)は等価となります。

メモリ保護の方法として採用しているページング方式とは、ページと呼ばれる小さな単位に仮想記憶を分割して割り当てる方式のことです。 ページングを行うページング回路は、(物理)アドレス空間を4KBまたは4MBの固定長のブロックに分割し、ブロック単位でアドレスの変換を行います。 この固定長のブロックのことをページフレーム(Page Frame)と呼びます。

論理アドレス物理アドレスに変換する際、CPUは論理アドレス物理アドレスとが対応付けられたテーブル(表)を参照します。 このテーブルは、2段階で構成されていて、1段階目のテーブルを「ページディレクトリ(Page Directory)」、2段階目のテーブルを「ページテーブル(Page Table)」と呼びます。

ページディレクトリの大きさは4KBで、ひとつ4バイトの大きさのPDE(ページディレクトリ・エントリ)が1024入っています。

ページテーブルの大きさも4KBで、ひとつ4バイトの大きさのPTE(ページテーブル・エントリ)が1024入っています。

PDEの2ビット目には「U/Sフラグ(ユーザー/スーパーバイザー・フラグ)」というフラグが設定されています。 U/Sフラグを0にセット(リセット)すると、ページフレームにアクセス可能な特権レベルはスーパーバイザー・モードのみとなり、ユーザーモードではアクセスが拒否されます。

32bit版Linuxカーネルはリニアアドレスの0xC0100000に配置されます(64bit版は0xffffffff80000000)。 0xC0000000以降1GBの、「システム領域を指すPDE」のすべてのU/Sフラグをリセットし、ユーザーモードでのアクセスを拒否します。

つまり、歌詞の「境界線」とはリニアアドレスの0xC0000000を意味し、「越権行為」とは特権レベルがユーザーモードの状態でのシステム領域へのアクセスを試みた行為を意味していたのです!! U/Sフラグが0だったので、CPUが「許しません」と怒ったわけですね。


ここから先も歌詞があるのですが、主に僕が力尽きたのという理由と、歌詞全文を載せると某団体から使用料を請求されそうという理由から、引用に留まる範囲で締めたいと思います。

思いのほか、割と歌詞とメモリ保護の仕組みがリンクしてたので発想が勝利した感じはあります…