# 02. OS System ________________________________________ * この記事ではIA-32のことをx86と呼ぶ DLL地獄 https://ja.wikipedia.org/wiki/DLL%E5%9C%B0%E7%8D%84 インサイドWindows 第6版 上 https://bookplus.nikkei.com/atcl/catalog/12/P94700/ github windows-internals-guide/security https://github.com/windows-internals-guide/security [試して理解]Linuxのしくみ https://gihyo.jp/book/2018/978-4-7741-9607-7 Linuxとpthreadsによる マルチスレッドプログラミング入門 https://www.shuwasystem.co.jp/book/9784798053721.html ________________________________________ ## 1. 全体概要 ________________________________________ ### 1.1. Windows/Linux共通 基本編 1. フォルダとファイルによる階層構造がある 2. 実行ファイルは実行できる(絶対パスor相対パスor環境変数PATH) 3. 実行ファイルは、パラメータを読み込む - レジストリ(Windowsのみ) - 設定ファイル - 環境変数 - コマンドライン引数 4. 共有DLLの仕組みは、単に特定のフォルダに保存しているだけ - WinSxS(Winネイティブ系) - GAC(.NET系) 5. インストーラの行儀が悪い場合がある - 既存の共有DLLを勝手に上書き保存&アンインストール時削除 - レジストリ、環境変数が勝手に上書きや削除 - より新しい下位互換性のあるDLLが既にインストールされていて、インストーラが古いDLLを入れようとしてOSに突っぱねられた時に中止してしまう DLL地獄編 - 共有DLLとそれを使用する側の想定バージョンが違うのが根本原因 - 共有DLLを使用しなければ、WindowsXP以降であれば大半は回避できる - ODP.NETなど、DLLがさらに別のネイティブDLLを呼ぶなどの場合、現在でも問題が発生しうる プログラマー編 1. 実行プログラムの基本単位はプロセス - プロセスごとにメモリを確保する - プロセスを複製する例:apacheのprefork - プロセスの中で並列処理する仕組みはスレッドと呼ばれる 2. Windowsのタスクという用語は、バズワード - Windows OSカーネルから見れば、タスクなどという概念はない - タスクマネージャが表示しているのは、プロセスの一覧 - 列を右クリックすれば、プロセスID列を表示させることができる 3. Windowsのジョブという用語は、複数のプロセスをまとめるグループの単位 4. Windowsのレジストリの使われ方は、静的パラメータ以外にも多岐にわたる - 静的パラメータ - OS・カーネルレベルの設定 - 個々の一般アプリケーションレベルの設定 - キャッシュのように機能しているパターン - 別の実パラメータへのファサードとして機能しているパターン スレッド補足 1. 歴史的には、メモリがかつかつだった80年代末ごろのIntel486にて、プロセスフォークせずに疑似並列処理したい、という要件で生まれた - 当時補足:Windows3.xが疑似マルチタスクを実現したが、これはプロセスを高速に切り替えるという仕組みで、各プロセスはそれぞれメモリを確保が必要 2. シングルコアCPUの処理速度の限界とマルチコアCPUの登場により、マルチスレッドに「処理時間の改善」という2つ目の目的ができた - 実際のところ、シングルコアCPUでも多少の処理速度の改善は見込めた(システムの時間消費の大半はプロセスの切り替えと待ち時間であるため) 論理機能 - ユーザ認証(ログインユーザの識別。ADではKerberos(KRB5)) - コンピュータ認証(ADにおける、クライアントマシン自体の正当性検証) - ディレクトリサービス(共通規格はLDAP。ADもLDAPに沿っている) - ユーザDBのような用途がほとんど - SQL・トランザクション・WALをサポートしない代わりに高速 - ファイルシステム(共有ファイルサーバの共通規格はNFS。WindowsはNFSクライアントを内蔵してない) ________________________________________ ### 1.2. Windowsのローカル権限 上位権限について 1. Administratorアカウントが存在する 2. Administratorsグループが存在する 3. 管理者権限操作はUACダイアログ(管理者として実行)が表示される 4. UACダイアログは常に手動操作が必要になる 5. ただし、AdministratorはAdministrators所属ユーザーよりも根源的 - UACダイアログの操作が不要 - アカウントロックがない - Virtual Storeが機能しない 6. Administratorは有効化方法や初期設定は世代やEditionによって異なる ```text ※ 初期設定において、管理者権限操作とAdministratorsは等価と考えて良い 一部の権利はローカルセキュリティポリシーで変更可能 ``` 権限の割り当てについて 1. Windowsのファイル権限はグループかユーザーを割り当てる方式 2. 初期グループ:Administrators、Users、Guests など 3. 初期ユーザー:Administrator、初期作成ユーザ、Guest など 4. アカウントの種類の変更はAdministoratorsへの所属を切り替えている 5. ファイル共有時などには、Everyone(だれでも)を指定できる Windowsのフォルダ共有 1. Windowsのフォルダ共有の要素にはネットワークプロファイル、フォルダの共有状況の2つの軸がある - ネットワークプロファイル - フォルダ共有(= net share) 2. ネットワークプロファイルは、信頼済み(private)、信頼できない(public)の2つを用意してある - 他PCからのネットーワーク探索を許可するか - フォルダ共有を許可するか 3. ネットワークと共有センター > 共有の詳細設定について - 全てのネットワーク > パブリックフォルダーの共有を有効にする際、C:\Usersフォルダが丸ごと共有されてしまう - 無効にしても、共有されたままになる - 全てのネットワーク > パスワード保護共有はGuest有効/無効を切り替えている 4. リモートデスクトップやファイル共有は以下の順番で自動解決を試みる - 現在ログインしているユーザー - Guest(有効な場合) Windowsのフォルダ共有の罠 ```text 以下のいずれかを実行すると、C:\UsersがEveryoneで公開されてしまう 1. ネットワークと共有センター > 共有の詳細設定 > 全てのネットワーク > パブリックフォルダーの共有 有効化 2. Usersフォルダ以下のいずれのフォルダを「ネットワークのファイルとフォルダーの共有 > 共有(S)」によって共有する (共有ウィザード。(旧名:簡易ファイルの共有)) 共有ウィザードによる誤った共有をさせないようにするには、以下のチェックを外す コントロールパネル > エクスプローラーのオプション > 表示 > 共有ウィザードを使用する(推奨) ``` Windowsのオブジェクトモデル ```text オブジェクトマネージャ :ハンドル制御などの内部実装 主なAPIから参照可能なオブジェクト:Process、Thread、File、Token、Event、Timer、Directoryなど 主な制御内容等 :オブジェクトhandleのopen、close、deleteなど(ファイルやプロセス操作そのもの) SRM(Security Reference Monitor) :オブジェクトモデル水準のセキュリティを検証し結果を返すインターフェース ALPC(Advanced LPC) :プロセス間通信の仕組みの内部実装。APIとしては公開されていない ``` Windowsのセキュリティモデル ```text 要約 LSAポリシー、SAM、ADの3つに基づいて解決される 要素や用語(抜粋) LSASS :Local Security Authority Subsystem Service。セキュリティ検証を実際に行うexeおよびプロセス Msv1_0.dllやKerberos.dllもこのプロセスから利用される LSAポリシー :LSAポリシー SAM :Security Accounts Manager。ローカルユーザー名・ローカルグループ名に対する管理プロセス (DBに対するDBMS的な役割) SAMDB :SAMのデータ AD :Active Directory Winlogon.exe:ログオン画面やスクリーンセーバーなどを実現してるexe LogonUI.exe :ログオン画面やスクリーンセーバーなどを実現してるexe DAC :随意アクセス制御 (D)ACL :(随意)Access Control List フォルダ共有状況の確認 cmd > net share C$ C:¥ Default Share IPC$ Remote IPC ADMIN$ C:\WINDOWS Remote Admin ``` ________________________________________ ### 1.3. Linuxの権限 1. root権限と通常権限が存在する 2. Linuxのファイル権限はパーミッションで管理する方式 3. SELinuxを有効にしている場合はこれも影響する ________________________________________ ## 2. CPUとOS ________________________________________ ### 2.1. CPU命令、カーネル、システムコール CPU特権レベル、カーネル ```text 1. x86やx64では4段階の特権レベルを用意している(リングプロテクション) - なお、リアルモード/プロテクトモード/ロングモードとは全く別概念である - I/Oアドレス空間にアクセスできるのは、特権レベルが0か1の場合 2. OS側では、特権レベルをカーネルモード、ユーザモードとして対応させる - 例えばWinNT系は、レベル0と3だけ使用している 3. カーネルモードで行う処理は、具体的に以下の処理 - Windowsの場合、スケジューラ(*)、など - Linuxの場合、プロセス管理、プロセススケジューラ(*)、メモリ管理、デバイスドライバ、など * どちらも実際にはプロセスではなくスレッドをスケジュールしている (乱暴に言えば、プロセスはメモリの確保単位、スレッドは動作単位と言える) ``` カーネルモード、ユーザモード、システムコール ```text 1. OSから見た際、各プロセスの動作はカーネルモードかユーザモードかの2種類である 2. ユーザモードからカーネルモードの操作が必要な場合、必ずシステムコールを介する - この考え方は、Windows、Linuxなど共通 3. OSのrootユーザやAdministratorユーザは、あくまで何でもできるユーザである - カーネルモード/ユーザモードとは別次元の話である 4. 32bit Windowsでは、歴史的な理由からデバイスドライバはカーネルモードで実行される - その一方で、特に制限はないため、カーネルが確保したOS用のメモリに直接アクセスできてしまう - つまり、デバイスドライバがやらかすとシステムが止まったり、悪意あるアクセスがされる - デバイスドライバが署名制になったのは、上記の理由から ``` ________________________________________ ### 2.2. プロセス、スレッド、メモリ プロセスとスレッドの仕組み ```text プロセスの構成要素や仕組み - プロセスは動作の基本単位 - 仮想メモリ空間(*)経由の実メモリ確保や運用 - この仕組みの一部は、x86系のCPU自体でサポートされている - プログラムコード - ディスクリプタ(ハンドル) - アクセストークン(ユーザ情報等のコンテキスト) - プロセスID - スレッド * ここで言う仮想メモリ空間とは、典型的なページングファイル(仮想メモリ)の説明とは毛色が違い、以下のような意味である (実際には同じ概念を説明しているのだが、仮想メモリ=ストレージのメモリ転用という説明は乱暴すぎる) 各プロセスから見えるメモリ空間は、実メモリに関わらず、見た目はCPUやOSが定義する最大メモリを占有しているかのように見えている 実際にメモリを使用しようとするときに確保できるかは、CPUやカーネルがよしなにやる また、それが物理メモリなのかページングなのかはプロセスは知らない プログラムから見たプロセスのメモリの用途の内訳 - コード領域(プログラムコード) - 静的領域(グローバル変数) - ヒープ領域(malloc、new) - スタック領域(ローカル変数、引数) スレッド - スタック領域は個別だが、その他のメモリは共有する ``` ________________________________________ ## 3. CPU、BIOS、その他 ________________________________________ ### 3.1. CPU史要約 x86、x64系 ```text _4bit:i4004 _8bit:i8080、Z80 16bit:i8086、i80286 32bit:i80386(x86、IA-32) 64bit:IA-64は放棄され、x64が採用された https://www.intel.co.jp/content/dam/www/public/ijkk/jp/ja/documents/developer/IA32_Arh_Dev_Man_Vol1_Online_i.pdf x86のアーキテクチャ ・Architectualレジスタの構成 ・基本プログラム実行レジスタ ・汎用レジスタEAX(アキュムレータレジスタ) ・汎用レジスタEBX(ベースレジスタ) ・汎用レジスタECX(カウンタレジスタ) ・汎用レジスタEDX(データレジスタ) ・汎用レジスタESI(Srcレジスタ) ・汎用レジスタEDI(Destレジスタ) ・汎用レジスタEBP(スタックベースポインタレジスタ) ・汎用レジスタESP(スタックポインタレジスタ) ・セグメントレジスタCS(コードセグメントレジスタ。16bit) ・セグメントレジスタDS(データセグメントレジスタ。16bit) ・セグメントレジスタSS(スタックセグメントレジスタ。16bit) ・セグメントレジスタES(エクストラセグメントレジスタ。16bit) ・セグメントレジスタFS(エクストラ2。16bit) ・セグメントレジスタGS(エクストラ3。16bit) ・EFLAGS ・EIP ・リアルモード。レガシBIOSやそれに対する1次ブートローダの動作モード ・プロテクトモード。マルチタスクに対応し、アドレスバスに対応したモード ・仮想86モード。32bitOS環境から16bit環境を呼び出す際に使用されるモード ・ページング機構 ・どのプロセスでも、仮想的に4GiBのメモリを認識する機能 ・1Byte * 2^32 = 4294967296Byte = 4GiB x64のアーキテクチャ ・ロングモード - 64bitモード ・ロングモード - 互換モード ``` ARM系 ```text 1991 : ARM6 1994 : ARM7TDMI(2G携帯、ゲームボーイアドバンス、iPod) 2009 : Cortex-A v7 A8(Apple A4はこれを元に開発) 2012 : Cortex-A v8 A50系 ``` x86とWindows ```text ・i80386以降、CPU側がマルチタスクと仮想メモリ空間に対応した ・Windows3.xは、MS-DOS上のGUIアプリケーションランチャだった ・Windows9x系 ・各仮想デバイスをまとめた、WIN386.EXEVMM32.VXDを生成 ・MS-DOSはブートローダで、Windowsが直接カーネルとなった ・依然としてプロセスが別プロセスのメモリを書き換える可能性があった ・WinNT系 ・NTLDRがブートローダである ・プロセスが別プロセスのメモリを書き換える心配がなくなった ・MS-DOSの実体はNTVDM.EXEになった。仮想86モードである ``` ________________________________________ ### 3.2. OSが起動するまで(x86、x64) レガシBIOSの場合 1. CPUの初期化 2. 0xFFFF0を読む(BIOSへのジャンプがある) 3. 作業メモリの確保 3. 割り込みルーチンのセットアップ 4. Power On Self Test(POST) - CPU、RAM、割り込みコントローラ、DMAコントローラのテスト - チップセット(ノースブリッジ・サウスブリッジ)のテスト - その他PCパーツや基本的な入出力機器の検出、初期化、テスト 5. BIOS拡張ROMの対応 6. CPUバグパッチの適用(P6以降) 7. BIOSメニュー起動 or ブートローダのロード - ブートデバイスを検出 - ブートセクタを0x7C00に読みだし UEFIでの変更点 1. BIOSの1~7までと同手順 2. プロテクトモードの移行 3. UEFIメニュー起動 or ブートローダのロード - GPT(FAT形式のEFIシステムパーティション)の検出 - GPTのロード その他UEFIの特長 - ACPIの標準搭載化 - アセンブラではなくPEバイナリ(Windowsライクなバイナリ) - UEFI用ファームウェアデバイスドライバの拡充(USB、NIC等) - UEFI用CPU非依存デバイスドライバランタイムの提供(EBC) ________________________________________ ### 3.3. CPUのハイパースレッド ```text - CPUのコアは実際のところ、大半が転送待ちである - 転送待ちしてる間に別の処理をさせられるようCPUを構成してしまおうという発想 - 1つの物理コアに対して2つある様に見せかける - 物理的なレジスタは、実際に2倍用意する - CPUが良い感じに頑張って処理する ```