始めに - Linuxディストリビューションのインストールから


まずLinuxディストリビューションのインストールから始める. ところで, Linuxディストリビューションとは? Windowsとは何が違う? インストールする際に気をつけることとは? これらを今回は説明していく.

ミニコンピュータとUnix

Linuxの説明 (/README) には次のようにある.

Linuxとは

Linuxはネットに散らばっているハッカーが緩くつながったチームの助けを借りて, Linus Torvaldsが一から作ったUnixオペレーティングシステムのクローンです.

(略)

ではそのUnixとは何だろうか. ここではその簡単な歴史を説明する.

歴史の始まり

Unix はアメリカの携帯電話会社, AT&Tのベル研究所で, ミニコンピュータ, PDP-7で使用することを目的に開発された. 1970年代のことである (ソース). 「ミニ」といっても今のスマートフォンのようなものではなく, 随分大きいものだった. それでも当時広く使われていたメインフレームと呼ばれるコンピュータよりは小型だった.

オスロのPDP-7

(Tore Sinding Bekkedal氏により撮影. CC-BY-SA 1.0のもとでライセンス.)

Unixは オペレーティングシステム と呼ばれるソフトウェアである. オペレーティングシステム (特に カーネル と呼ばれる中核部分) は主にハードウェアを抽象化して扱いやすくする. またこれにより異なる構成でも利用しやすくなる (移植性). また, ストレージやメモリ, CPUを使用する時間など資源を管理する役割がある. Unixはオペレーティングシステムに有用な概念をいくつか発明し, その多くは今でも有効である.

また, Unixは ソースコード を添えて無料で公開されていた. ソースコードとは, 人間が書いたプログラムのそのままの状態である. 実行するにはコンピュータが読める機械語の形式 (オブジェクトコード) に変換する必要があり, この形で配布されることが多い. しかし, 同時に人間にとっては加筆, 修正, 引用が困難になる. このオブジェクトコードの性質は商業製品として販売する企業には都合の良いものであったが, 独占禁止法でコンピュータ業界に進出することが許されていなかった当時のAT&Tはソースコードを公開する必要があった (ソース).

かくしてUnixには誰もが使え, 学べ, 改良できるオペレーティングシステムとなった. そのコミュニティの中で人々は技術的な知見を得て, Unix哲学 と呼ばれて文書化されたりもした. 文化的には後の ハッカー文化 と呼ばれるものに繋がったりするとかなんとか.

戦争

1980年代になると, Unixのコミュニティは変化を迎えた.

AT&Tはコンピュータへの進出が許可され, Unixを商業製品として活用するために他者に制約を課した. また, AT&Tは企業にライセンスを行い, それらの企業は自社の機器にUnixを移植し, オブジェクトコードのみを配布した(ソース). これが商用Unixの系譜を作った.

一方で, カリフォルニア, バークレイ校では以前から開発していたUnixの派生である BSD (Berkley Software Distribution) を教育機関向けの安価なライセンスを受けて配布した. やがてBSDは少なくなったAT&T由来のコードが分離, 除去され, 無償で配布されるに至った. これにより, 再びオープンな開発が行えるようになったが, 同時にAT&Tは潜在的な商業的機会を失った. 1990年代初頭, AT&Tはソースコードの混入や特許問題を主張し訴訟を起こし, その間BSDの開発は停滞した (ソース).

この間, 自由に扱えるUnixは存在しなかった. その望みを叶えるために開発され始めたのが Linux である. Linux開発コミュニティは実用性を主眼におき, 当時普及し始めていたインターネット上で発展した.

それからもUnixの世界では競争が続いた.

その後

結果として, Linuxは自由に扱えるUnixとして開発者, 後にいくつかの企業の支持を得て, 最も普及したUnixとなった. 一方で, 商用UnixのSolarisや, BSDの後継なども現在も続いている.

それらのUnixの事実上の後継はかつてのUnixの地位を取って代わり, メインフレームやサーバーで用いられるようになった. このため, LinuxもWebにも欠かせない存在になった. 一方で, 個人でも使えることを目的に低性能なコンピュータでも動作するように作られたLinuxは, パソコンはもちろん, スマートフォンや他の小型の電子機器でも用いられるようになり, 様々なコンピュータで動作している.

IBM PCとBIOS/UEFIファームウェア, Windows

もう一つの歴史

もう一つの歴史はパソコンの歴史である. パソコンは「パーソナルコンピュータ」, 個人用コンピュータでありUnixが動作していたミニコンなどとは性質が異なる. 現在のパソコンはAppleとMachintoshやGoogleのChromeBookを除いて殆どがIBM PCを先祖とする.

1980年代当時, パソコンの規格は統一されておらず, 他のメーカーのパソコンのソフトウェアが動作しないのが当たり前だった. IBM PCはそのようなパソコンの1つだった. IBM PCは非常に人気になった.

他社はIBM PC用のソフトウェアとの互換性とその市場を獲得するためIBM PCの互換機の開発を始めた. IBMは他社の周辺機器開発のため オープンアーキテクチャ としてその情報を広く公開していたため, 互換機の開発は容易であったが, 1つ罠が仕掛けられていた. それが BIOS である. BIOSはコンピュータの起動などに用いられるソフトウェアで, IBMはこれのソースコードも公開していたが, これを互換機の開発に用いることは禁止されていた. 多くの技術者はそれを知る前に読んでしまい, 結果として互換機開発ができなくなってしまったという.

しかし, それでも諦めずにいくつかの会社はBIOSの独自実装に成功した. IBMのコードを解析し, 仕様書を作る (リバースエンジニアリング) する人と実際のコードを書く人を完全に隔離し, IBMの権利を侵害せずに独自実装 (クリーンルーム設計) できたのだ. これについては「何も知らない学生を口説いてコンピュータ技術を叩き込み, コードの実装をさせた」とか「独自実装されたBIOSもほぼ完全な互換性を保っていた」とかいう伝説がある.

かくしてIBM PCの互換機は市場に溢れ, ついには標準たる存在になった.

一方で, IBM PC用のOSである MS-DOS (IBMはIBM-DOSとしてOEM販売していた) を開発していた MicrosoftWindows を開発し, これもデファクトスタンダードとなった.

その後

技術が進化するにつれ, IBM PCの互換機は進化し, もはや互換機とは呼べない存在になった.

MicrosoftはMS-DOSベースであったWindowsの後継として Windows NT を開発し, 現在はこれの後継OSが用いられている.

ハードウェアやOSが変化する中, 最後まで残ったBIOSも UEFI (Unified Extensible Firmware Interface) を実装したファームウェアに取って代わられた. (それでも未だに1980年台のコードが内部にあるとかないとか. 実態は不明である.)

パソコンにLinuxをインストールする

今回はVAIO VJP132C11NにUbuntuをインストールする. 内蔵ストレージはSSDで, Windowsが導入されている. また中々イイ感じのUEFIファームウェアが搭載されている.

Ubuntu GNOMEのインストールCDをダウンロードする

Linuxはあくまでもカーネルであり, それ単体でOSとしては機能しない. そこで, アプリケーションなどを合わせて提供する Linuxディストリビューション という存在がある. 今回はディストリビューションの中でも特にパソコン (デスクトップと呼ばれる) で人気のUbuntuを用いる. 今回はグラフィカルなユーザーインターフェイス (GUI) を提供するデスクトップ環境に GNOME を用いたUbuntu GNOMEというフレーバーを用いた.

GNOMEの画像

(イイ感じな画像. GNOMEはGPL-2.0などでライセンスされている.)

Ubuntu GNOMEは次のページから入手できる. 理科大の無線はカスであり, また, BitTorrentを使えないので自宅でダウンロードすることをおすすめする.

UbuntuGNOME/GetUbuntuGNOME - Ubuntu Wiki

Ubuntu GNOMEを起動する

まず最初に, ストレージにUbuntu GNOMEを書き込む. ISO形式なのでディスクに書き込んでも良いが, 実はこれはUSBメモリにも書き込める. Windowsなら Win32 Disk Imager が使える.

Win32 Disk Imagerの画像

書き込んだら, 再起動する. テキトーなキーを押してブートメニューやファームウェア設定に入れないか探る. 今回の場合よくわからなかったので, Windows 10からShiftを押しながら再起動を行い, ファームウェア設定に入った. ファームウェア設定に「USBから起動」というズバリといった感じのボタンがあったのでこれを選択した. あとは勝手にUbuntu GNOMEが起動する.

ストレージを構成する

ストレージ構成は手動でやる.

ストレージは2段階で抽象化されている. 第一に パーティションテーブル, 次に ファイルシステム である.

パーティションテーブル はディスクを パーティション という 固定幅 の領域に分割する. パーティションテーブルにはBIOSでは MBR, UEFIでは GPT が用いられる.

私のPCでの場合の画像

(GNOME Disk Utilityで見た様子)

ファイルシステム はパーティション内に存在し, より高度な抽象化を可能にする. 例えば, ディレクトリ (GUIでは「フォルダ」と呼ばれる) による階層構造や, 可変長のファイル, 権限管理などである. これらの機能はOSと深く結びついており, 結果としてOSによって異なるファイルシステムを運用することとなり, そのためにパーティションを分ける必要がある.

まずはパーティションに含まれるファイルシステムを先に縮小する. まずは「アクティビティ」から terminalで検索する. すると 端末 が開かれる.

端末でntfsresizeコマンドを実行した様子

ここに コマンド を入力するとプログラムが実行される. これにはntfsresizeというコマンドを実行した画面である.

まずはディスクの状態を確認する. partedコマンドを用いる.

$ parted
警告: 管理者権限がありません。パーミッションに注意してください。
/dev/mapper/control: open failed: 許可がありません
エラー: デバイスがみつかりません。
やりなおし(R)/Retry/取消(C)/Cancel? c

partedには管理者権限が要る. 許可されたユーザーはsudoコマンドで特権を得られる.

$ sudo parted
GNU Parted 3.2
GNU Parted へようこそ! コマンド一覧を見るには 'help' と入力してください。
(parted)

まずストレージデバイスを表示しよう.

(parted) print devices
/dev/sda (128GB)
/dev/sdb (4GB)

/dev/sda/dev/sdbデバイスファイル である. Unixの場合デバイスはデバイスファイルとして抽象化され, ファイルの読み書きなどの動作がデバイスの操作に用いられる. 特に, ストレージ (ブロックデバイス) のデバイスファイルを読み書きすると, ファイルシステムなどを無視してデータを直接読み書きできる. パスはすべて/ (ルート) で始まり, デバイスファイルは/devというディレクトリに生成される. 容量からして, インストール先は/dev/sdaのようだ. /dev/sdaを選択する.

(parted) select /dev/sda
/dev/sda を使用

それでは, ディスクの構成を表示しよう.

(parted) print
モデル: ATA TOSHIBA THNSNC12 (scsi)
ディスク /dev/sda: 128GB
セクタサイズ (論理/物理): 512B/4096B
パーティションテーブル: gpt
ディスクフラグ: 

番号  開始    終了   サイズ  ファイルシステム  名前  フラグ
 1    1049kB  134MB  133MB   fat32                   boot, esp
 2    134MB   127GB  127GB   ntfs                    msftdata
 3    127GB   127GB  531MB   ntfs                    hidden, diag
 4    127GB   128GB  847MB   ntfs                    hidden, diag

明らかに容量が大きいのが2番のパーティションだ. こいつを縮めてUbuntu用の起動パーティションとシステムパーティションを作る領域を空ける. 起動パーティションは80GBからにしよう.

ディスクは セクタ と呼ばれる単位で区切られている. 他の単位だと変更する時にはややこしいので, 単位をセクタに変更し, もう一度表示する.

(parted) unit s
(parted) print
モデル: ATA TOSHIBA THNSNC12 (scsi)
ディスク /dev/sda: 250069680s
セクタサイズ (論理/物理): 512B/4096B
パーティションテーブル: gpt
ディスクフラグ: 

番号  開始        終了        サイズ      ファイルシステム  名前  フラグ
 1    2048s       262143s     260096s     fat32                   boot, esp
 2    262144s     247374922s  247112779s  ntfs                    msftdata
 3    247375872s  248412159s  1036288s    ntfs                    hidden, diag
 4    248414208s  250068991s  1654784s    ntfs                    hidden, diag

partedでパーティションサイズを変更できるのだが, その前にファイルシステムのサイズも同様に変更する必要がある. partedは一旦終了しよう.CtrlDを同時押しすると入力が終わったこと (EOF) が伝えられpartedが終了する.

NTFSファイルシステムのリサイズにはntfsresizeコマンドを用いる.

Ubuntuの起動パーティションの開始位置となる80GBはバイトだと85899345920バイトである. 論理セクタサイズは512バイトとpartedが言っているので, セクタに直すと 85899345920 / 512 = 167772160 セクタとなる. よって2番の終了位置は1つ手前の167772159セクタになる.

開始が262144セクタなので, サイズは85899345920 - 262144 = 167510016セクタになる. ntfsresizeはサイズをバイトで指定するので, これをバイトに直し167510016 * 512 = 85765128192バイトとなる.

計算した値をもとにntfsresizeでサイズを変更する.

$ sudo ntfsresize -s 85765128192 /dev/sda2

/dev/sda2は2番めのパーティションのデバイスファイルである.

済んだらpartedを開き, パーティションをリサイズする.

$ sudo parted /dev/sda
GNU Parted 3.2
/dev/sda2 を使用
GNU Parted へようこそ! コマンド一覧を見るには 'help' と入力してください。
(parted) resizepart 2 167772159

次に起動パーティションを作成する. 256MB = 524288セクタもあれば足りるだろう. 開始セクタが167772160だから, 終端は 167772160 + 524288 - 1 = 168296447セクタだ.

(parted) mkpart primary 167772160 168296447

同様に, Ubuntuのシステムパーティションを作る.

(parted) mkpart primary 168296447 247375871

パーティションを作成したらpartedを終了する.

起動パーティションはBtrfsというファイルシステムでフォーマットする.

$ mkfs.btrfs /dev/sda5

システムパーティションはcryptsetupコマンドで LUKS 暗号領域にする.

$ cryptsetup luksFormat /dev/sda6

暗号領域を開く. $ cryptsetup luksOpen /dev/sda6 root

/dev/mapper/rootというデバイスファイルができる. これが復号化された暗号領域である. 同様にBtrfsでフォーマットする.

$ mkfs.btrfs /dev/mapper/root

終わったら暗号領域を閉じる.

$ cryptsetup luksClose root

Ubuntu GNOMEをインストールする

「アクティビティ」を開くと左にアイコンが出ている (クイックアクセス). この1番上にUbuntuのインストーラがあるので, これを開始する. あとはウィザード形式なので簡単に進められる. ディスク設定のところでは「それ以外」を選択する. すると手動での設定画面になるので, 起動パーティションを/bootに, システムパーティションのロックを解除してできたデバイスファイルを/にそれぞれ割り当てる. 設定が済んだら続行する. 「swapはいらないか?」と聞かれるが, 今回は無視する.

インストールが終わったら再起動し, 無事にUbuntu GNOMEが起動するはずだ.

セキュアブート

UEFIの重要な機能が セキュアブート である.

旧来のBIOSでは, 起動過程が保護されておらず, ウイルスに感染するなどすると乗っ取られてしまった.

例えば, 正常にWindowsが起動する際の過程は次のようになる

BIOS -> Windows (起動成功)

しかし, これにウイルスが割り込めるのだ.

BIOS -> ウイルス (起動成功) -> Windows (感染)

このような事態を防止するのがセキュアブートである. セキュアブートで起動する際には, 起動ファイルに 電子署名 を施す. これが信頼できる存在によるものだった場合のみ起動を許可する.

UEFI -> Microsoftの電子署名付きのWindows (起動成功)
UEFI -> Microsoftの電子署名がないウイルス (起動失敗) -> Windows (起動失敗)

電子署名と公開鍵暗号

電子署名は 公開鍵暗号 を用いている. 通常の暗号 (共有鍵暗号) の場合, 暗号化する鍵と復号する鍵が一致する. 公開鍵暗号では, これに別のものを用いる. 暗号鍵と復号鍵は, 片方からもう片方を推測できないようになっている.

例えば, Microsoftが暗号鍵と復号鍵のペアを作り, 復号鍵のみをパソコンに組み込んで配布する (公開鍵). 暗号鍵はMicrosoft社内で厳重に管理する (秘密鍵). 電子署名をする際には, Microsoftは暗号鍵を使ってWindowsの起動プログラム (メッセージ) を暗号化し, 暗号化されたそれを利用者に配布する. パソコンは組み込まれた復号鍵を用いて復号し, 正常に復号できればそれを実行する. 公開鍵暗号は遅いため, 実際にはメッセージから生成される十分にユニークな短い値 (ハッシュ値) に署名をつけることが多い. ハッシュ値は特定のアルゴリズムによってメッセージから容易に算出できるが, 逆にハッシュ値からそれに合うメッセージを見つけるのは困難である. そのため, ハッシュ値に署名するのと直接署名するのは本質的に等価である.

ここで誰かがWindowsを書き換えてウイルスをつけようと考えたとする. 復号は公開鍵を用いて容易にできる. 一方で, 暗号化に必要な秘密鍵がないので, 暗号化してWindowsと差し替えることはできない. 暗号化できるのは秘密鍵を持ったMicrosoftだけなのだ. これが電子署名の仕組みである.

電子署名の話からは逸れるが, 電子署名とは反対に暗号鍵を公開鍵として復号鍵を秘密鍵とするものがある. Diffie-Hellman 鍵交換 である. これは例えば, TLS (Transport Layer Security) で用いられている. TLSはWebの通信を暗号化する方法 (プロトコル) である. URIがhttpではなくhttpsで始まるときにそれが用いられているものだ.

TLSでは, Webサーバーは 認証局 によって電子署名された公開鍵をクライアントに向けて送信する. クライアントは信用できる認証局によるものであること確認する. そのため, 間に信頼できない存在が入って公開鍵を差し替える (中間者攻撃 (MITM attack, Man In The Middle attack)) 危険はない. この公開鍵を用いて, クライアントは独自に生成した共有鍵を暗号化し, サーバーに送信する. 中間者は公開鍵と暗号化された共有鍵を盗めるが, 盗んでも公開鍵では復号できないので共有鍵は取り出せない. 一方で, サーバーは秘密鍵を用いて暗号化された共有鍵を復号する. これにより, 安全にサーバーとクライアントで共有鍵を交換することに成功した. 共有鍵は, 共有鍵暗号を用いた安全な接続に利用される.

セキュアブートの詳細な仕組み

セキュアブートはファームウェアによって実装されており, ファームウェアの簡単には置き換えられないという性質のため, セキュアブートの仕組み自体に柔軟性を持たせている. これによって, ユーザーが自身の要求にあった形にセットアップするすることが可能になっている. 一方で, それ故にやや複雑になってしまっている面がある.

UEFIのセキュアブートに関する変数

db (署名データベース) はUEFIアプリケーションの署名確認に用いられる公開鍵を含む. UEFIアプリケーションは対応する秘密鍵で署名されている必要がある. 複数登録できるので, 異なるベンダから提供されたアプリケーション (例えばCanonicalから提供されたUbuntuとMicrosoftから提供されたWindows) を共存させることが可能になる.

dbx (禁止署名データベース) は明示的に禁止された鍵やUEFIアプリケーションのハッシュ値を含む. これはdbより優先され, たとえ有効な署名が施されていてもdbxに含まれる公開鍵に対応する署名が施されていたり, UEFIアプリケーションから算出したハッシュ値がdbxに含まれていると実行が失敗する. 以前署名したアプリケーションに他のアプリケーションを実行できてしまう脆弱性があった場合などに, そのハッシュ値を登録すればその特定のアプリケーションのみを無効にできる.

KEK (鍵交換鍵) はdbdbxの更新情報の電子署名を確認する公開鍵のデータベースである. 新たな鍵が必要, あるいは既存の鍵が信用できなくなった場合などに更新情報に対応する電子署名を施してユーザーに配布する. 更新情報に適用にユーザーの明示的な操作は不要であり, 例えば Windows Update などで行える.

PK (プラットフォームキー) はKEKを更新できる唯一かつ単数の (データベースではない) 鍵であり, 最上位の鍵である.

2つのモード

1つは セットアップモード, もう1つは ユーザーモード である.

セットアップモードは, PKが登録されていないときの状態であり, このときすべての鍵を更新できる. この状態に移行するには, KEKで署名された更新情報を用いて鍵を更新するときとは異なり, ユーザーの明示的な操作が必要である.

ユーザーモードは, PKが登録されている状態であり, このときセキュアブートを有効にできる.

セットアップする

Ubuntuをインストールすると, Secure Bootは次の通りに動作するようにセットアップされる.

UEFI -> shim -> GRUB -> Linuxカーネル

UEFIはdbMicrosoft Corporation UEFI CA の公開鍵を持っており, shimがこれによって署名されていることを確認する. Microsoft Corporation UEFI CA は他者のUEFIバイナリを有償で署名するMicrosoftの証明局であり, その公開鍵はほとんどのUEFI実装に予め登録されている.

shimは Microsoft Corporation UEFI CA により署名されており, GRUBが Canonical Ltd. Secure Boot Signing の公開鍵で署名されていることを確認する.

Linuxカーネルは Canonical Ltd. Secure Boot Signing の公開鍵で署名されている.

ところで, shimは本質的に不要である. セットアップモードでdbCanonical Ltd. Secure Boot Signing の公開鍵を登録すれば, shimを除外できる. 以下にその手順を述べる.

ツールとして efitools を用いる. LinuxアプリケーションとUEFIアプリケーションの2つを選べるが, 当該機種ではefi-updatevarが正常にキーを書き込めなかったので, UEFIアプリケーションを用いることにした.

まずは efitools をインストールする.

sudo apt install efitools

aptパッケージマネージャ である. システムのコンポーネントを パッケージ として管理する.

次に, PKを生成する. キーのバックアップには署名が含まれておらず, PKはセットアップモードでも自身に署名を施す必要があるからである. 一時ディレクトリの/tmpに移動して作業を行う.

openssl req -new -x509 -newkey rsa:2048 -subj "/CN=173210's platform key/" -keyout PK.key -out PK.crt -days 16384 -nodes -sha256
cert-to-efi-sig-list -g `uuidgen` PK.crt PK.esl
sign-efi-sig-list -k PK.key -c PK.crt PK PK.esl /path/to/boot/media/KeyTool.efi/is/PK.auth
shred -u PK.key

OpenSSLはTLSの実装である. 証明書を発行する機能があるのでこれを使った. shredは安全に削除するコマンドである. 今回の場合, PKの秘密鍵は不要である (KEKを交換する時には明示的にセットアップモードにすればよい).

/path/to/boot/mediaは起動メディアへのパスと置き換えよ. FAT32でフォーマットされたUSBメモリなどが適当だ.

次に, Canonical Ltd. Secure Boot Signing の公開鍵を以下からダウンロードして同様に起動メディアにコピーする.

~ubuntu-bugcontrol/qa-regression-testing/master : contents of notes_testing/secure-boot/keys/canonical-signing-public.der

それから, /usr/share/efitools/efi/KeyTool.efiを適当な起動メディアにコピーし, EFI/boot/bootx64.efiに配置する. 以上で準備は整った.

WindowsでShiftを押しながら再起動したり, 起動時に特定のキーを押したりしてファームウェアの設定画面に入り, Secure Bootを一時的に無効にする. それからそのメディアから起動すると, KeyTool が開始されるはずである.

まずは, 鍵をバックアップする. Save Keysを選んで鍵を保存する.

次に, セットアップモードに移行する. ファームウェアの設定画面にセキュアブートの設定を削除 (復元 ではない) するとかセットアップモードに入るとかいう選択肢があるはずなので, それを選ぶ. そしてもう一度 KeyTool を起動する.

Edit Keysを選び, バックアップしたdb, dbx, KEKを追加する (PKはまだ追加 しない). それから, Canonical Ltd. Secure Boot SigningdbKEKに追加する. 最後に 自分で作成したPKを追加する.

以上でキーの更新は完了した. ファームウェア設定でセキュアブートを有効にして, UbuntuとWindowsの両方が起動することを確認しよう.

起動したら, Ubuntuでshimのブートエントリを削除し, GRUBのブートエントリを追加する.

まず, efibootmgrでshimのブートエントリを確認する.

$ efibootmgr
BootCurrent: 0001
Timeout: 0 seconds
BootOrder: 0001,0019
Boot0001  ubuntu

これを削除.

efibootmgr -b 0001 -B

そしてGRUBのブートエントリを追加だ.

efibootmgr -c -l '\EFI\ubuntu\grubx64.efi -L ubuntu

再度, Ubuntuを起動して動作を確認する.

長かった…

大丈夫だ. Ubuntuの場合カスタマイズすると言ったってこれくらいのことしかできない. 何もかもカスタマイズできるGentooなどを使うともっといろいろできてしまうので身を滅ぼすことになろう.

[top]