メインコンテンツまでスキップ

OS概要

所要時間: 20分


はじめに

「OS(オペレーティングシステム)」という言葉はよく聞きますが、実際に何をしているのでしょうか?

このドキュメントでは、OSの基本的な役割と構造を理解します。


1. OSの役割

OSがないとどうなるか

┌─────────────────────────────────────────────────────────────────────┐
│ OSがない世界 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ アプリケーションが直接ハードウェアを制御 │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ App A │ │ App B │ │ App C │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ ↓ ↓ ↓ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ハードウェア │ │
│ │ CPU メモリ ディスク ネットワーク │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 問題: │
│ ❌ 各アプリがハードウェアの詳細を知る必要がある │
│ ❌ アプリ同士がリソースを奪い合う │
│ ❌ あるアプリのバグが全体をクラッシュさせる │
│ ❌ セキュリティ境界がない │
│ │
└─────────────────────────────────────────────────────────────────────┘

OSがある世界

┌─────────────────────────────────────────────────────────────────────┐
│ OSがある世界 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ App A │ │ App B │ │ App C │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └────────────────┬┴─────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ オペレーティングシステム │ │
│ │ ・リソース管理(CPU、メモリ、ディスク) │ │
│ │ ・プロセス管理 │ │
│ │ ・ファイルシステム │ │
│ │ ・ネットワーク │ │
│ │ ・セキュリティ │ │
│ └──────────────────────────┬──────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ハードウェア │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 利点: │
│ ✅ アプリはハードウェアの詳細を知らなくてよい │
│ ✅ リソースを公平に分配 │
│ ✅ アプリ同士を隔離 │
│ ✅ セキュリティ境界を提供 │
│ │
└─────────────────────────────────────────────────────────────────────┘

OSの主要な役割

役割説明
抽象化ハードウェアの複雑さを隠すファイルとして扱う(実際はブロックデバイス)
リソース管理CPU、メモリ、I/Oを公平に分配スケジューリング
隔離プロセス間を分離メモリ保護
セキュリティ権限管理、アクセス制御ユーザー、パーミッション

2. カーネルとユーザー空間

二つの世界

┌─────────────────────────────────────────────────────────────────────┐
│ カーネル空間とユーザー空間 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ユーザー空間 │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ bash │ │ nginx │ │ java │ │ mysql │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ │ ・一般的なアプリケーションが動作 │ │
│ │ ・制限された権限 │ │
│ │ ・ハードウェアに直接アクセス不可 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ ↑↓ システムコール │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ カーネル空間 │ │
│ │ │ │
│ │ ・OSの中核部分 │ │
│ │ ・全ての権限を持つ │ │
│ │ ・ハードウェアに直接アクセス可能 │ │
│ │ ・プロセス管理、メモリ管理、ファイルシステム │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ハードウェア │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘

なぜ分離するのか

┌─────────────────────────────────────────────────────────────────────┐
│ 分離の理由 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 安全性 │
│ ───────── │
│ ユーザー空間のアプリがバグで暴走しても、 │
│ カーネルやハードウェアは保護される │
│ │
│ 例: アプリが無限ループしても、OSは kill できる │
│ │
│ 2. セキュリティ │
│ ──────────── │
│ 一般ユーザーのアプリが他のプロセスのメモリを │
│ 読み書きできない │
│ │
│ 例: 悪意あるアプリがパスワードを盗めない │
│ │
│ 3. 安定性 │
│ ───────── │
│ 1つのアプリがクラッシュしても、 │
│ 他のアプリやOSは動き続ける │
│ │
│ 例: ブラウザがクラッシュしても、他のアプリは動く │
│ │
└─────────────────────────────────────────────────────────────────────┘

CPUの特権レベル(x86の場合)

┌─────────────────────────────────────────────────────────────────────┐
│ CPUの特権レベル(Ring) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────┐ │
│ │ Ring 3(ユーザーモード) │ │
│ │ ┌───────────────────────────────┐ │ │
│ │ │ Ring 2(未使用) │ │ │
│ │ │ ┌───────────────────────┐ │ │ │
│ │ │ │ Ring 1(未使用) │ │ │ │
│ │ │ │ ┌───────────────┐ │ │ │ │
│ │ │ │ │ Ring 0 │ │ │ │ │
│ │ │ │ │ カーネル │ │ │ │ │
│ │ │ │ └───────────────┘ │ │ │ │
│ │ │ └───────────────────────┘ │ │ │
│ │ └───────────────────────────────┘ │ │
│ └───────────────────────────────────────┘ │
│ │
│ Ring 0: 最高特権(カーネルモード) │
│ - 全ての命令を実行可能 │
│ - ハードウェアに直接アクセス可能 │
│ │
│ Ring 3: 最低特権(ユーザーモード) │
│ - 制限された命令のみ │
│ - 特権操作はシステムコール経由 │
│ │
│ ※ Ring 1, 2 は通常使用されない(仮想化で使う場合あり) │
│ │
└─────────────────────────────────────────────────────────────────────┘

3. システムコール

システムコールとは

ユーザー空間のアプリがカーネルの機能を呼び出すためのインターフェースです。

┌─────────────────────────────────────────────────────────────────────┐
│ システムコールの流れ │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ユーザー空間 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ アプリケーション │ │
│ │ │ │
│ │ fd = open("/etc/passwd", O_RDONLY); ← ファイルを開きたい │ │
│ │ │ │ │
│ │ ↓ │ │
│ │ ┌─────────────────┐ │ │
│ │ │ Cライブラリ │ ← glibc の open() 関数 │ │
│ │ │ (glibc) │ │ │
│ │ └────────┬────────┘ │ │
│ └───────────┼─────────────────────────────────────────────────┘ │
│ │ システムコール(ソフトウェア割り込み) │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ カーネル空間 │ │
│ │ │ │
│ │ ┌─────────────────┐ │ │
│ │ │ システムコール │ ← sys_open() カーネル関数 │ │
│ │ │ ハンドラ │ │ │
│ │ └────────┬────────┘ │ │
│ │ ↓ │ │
│ │ ┌─────────────────┐ │ │
│ │ │ ファイルシステム │ ← ext4, xfs など │ │
│ │ └────────┬────────┘ │ │
│ │ ↓ │ │
│ │ ┌─────────────────┐ │ │
│ │ │ デバイス │ ← ディスクドライバ │ │
│ │ │ ドライバ │ │ │
│ │ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘

主要なシステムコール

カテゴリシステムコール説明
プロセスfork, exec, exit, waitプロセス生成・終了
ファイルopen, read, write, closeファイル操作
メモリmmap, brk, munmapメモリ管理
ネットワークsocket, bind, listen, acceptソケット操作
その他ioctl, fcntlデバイス制御など

strace で確認

# hello world プログラムのシステムコールを追跡
$ strace echo "hello"
execve("/usr/bin/echo", ["echo", "hello"], ...) = 0
brk(NULL) = 0x55a8b8c4c000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
...
write(1, "hello\n", 6) = 6 ← 出力
close(1) = 0
exit_group(0) = ?
# ファイル関連のシステムコールのみ追跡
$ strace -e openat,read,write,close cat /etc/hostname
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
read(3, "myhost\n", 131072) = 7
write(1, "myhost\n", 7) = 7
close(3) = 0

4. なぜ sudo が必要なのか

特権操作の例

┌─────────────────────────────────────────────────────────────────────┐
│ sudo が必要な理由 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 特権操作(カーネルが制限): │
│ │
│ ❌ 一般ユーザーはできない │
│ ・1024以下のポートでlisten(例: 80, 443) │
│ ・他ユーザーのファイルを読み書き │
│ ・システム設定の変更 │
│ ・カーネルモジュールのロード │
│ ・raw ソケットの作成(ping) │
│ │
│ sudo の役割: │
│ ・一時的に root 権限を取得 │
│ ・特権操作を許可 │
│ ・監査ログに記録 │
│ │
│ 例: │
│ $ python -m http.server 80 │
│ PermissionError: [Errno 13] Permission denied │
│ │
│ $ sudo python -m http.server 80 │
│ Serving HTTP on 0.0.0.0 port 80 ... ← 成功 │
│ │
└─────────────────────────────────────────────────────────────────────┘

権限の仕組み

┌─────────────────────────────────────────────────────────────────────┐
│ Linux の権限モデル │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ユーザー │
│ ├── root (UID 0) ─── 全ての権限 │
│ └── 一般ユーザー ─── 制限された権限 │
│ │
│ プロセス │
│ ├── 実行ユーザーのUID/GIDを継承 │
│ └── 実効UID(EUID)で権限チェック │
│ │
│ ファイル │
│ ├── 所有者(user) │
│ ├── グループ(group) │
│ └── その他(other) │
│ └── パーミッション(rwx) │
│ │
│ 特殊ビット │
│ ├── setuid: 実行時に所有者の権限で動作 │
│ ├── setgid: 実行時にグループの権限で動作 │
│ └── sticky: 削除を所有者のみに制限 │
│ │
└─────────────────────────────────────────────────────────────────────┘

5. Linux カーネルの構成

モノリシックカーネル

┌─────────────────────────────────────────────────────────────────────┐
│ Linux カーネルの構造 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Linux はモノリシックカーネル(一枚岩) │
│ ※ ただしモジュールで拡張可能 │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ カーネル │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ プロセス │ │ メモリ │ │ ファイル │ │ │
│ │ │ スケジューラ│ │ マネージャ │ │ システム │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ ネットワーク│ │ デバイス │ │ セキュリティ│ │ │
│ │ │ スタック │ │ ドライバ │ │ (SELinux等) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 利点: 高速(コンポーネント間の通信が速い) │
│ 欠点: カーネルのバグが全体に影響 │
│ │
│ 比較: │
│ ・マイクロカーネル(Minix, QNX): 最小限、安全だが遅い │
│ ・ハイブリッド(Windows NT, macOS): 中間的なアプローチ │
│ │
└─────────────────────────────────────────────────────────────────────┘

カーネルモジュール

# ロード済みモジュールの確認
$ lsmod
Module Size Used by
ext4 761856 1
mbcache 16384 1 ext4
jbd2 122880 1 ext4
...

# モジュールの情報
$ modinfo ext4
filename: /lib/modules/.../ext4.ko
description: Fourth Extended Filesystem
author: Remy Card, Stephen Tweedie, ...
license: GPL

# モジュールのロード/アンロード(要root)
$ sudo modprobe <module_name>
$ sudo rmmod <module_name>

まとめ

┌─────────────────────────────────────────────────────────────────────┐
│ 覚えておくべきポイント │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. OSの役割 │
│ → 抽象化、リソース管理、隔離、セキュリティ │
│ │
│ 2. カーネル空間とユーザー空間 │
│ → 特権レベルの分離、安全性の確保 │
│ │
│ 3. システムコール │
│ → ユーザー空間からカーネルへの唯一の窓口 │
│ │
│ 4. 特権操作 │
│ → sudo が必要な理由、UID/GID の仕組み │
│ │
└─────────────────────────────────────────────────────────────────────┘

次のステップ