「Unix v4 でバッファ・オーバーフローを修正:まるで 1973 年のことのように」

2026/01/09 3:29

「Unix v4 でバッファ・オーバーフローを修正:まるで 1973 年のことのように」

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

要約

この記事は、2025年に磁気テープから1枚のUNIX v4を回収し、PDP‑11シミュレータを使用して現代ハードウェア上で正常にコンパイルできた経緯を記述しています。ソースコードには、

/etc/passwd
を読み込み TTY エコーを無効化し、パスワードを入力させて
crypt()
でハッシュ化し
/bin/sh
を起動する全約50行の
su.c
ユーティリティが含まれています。ただし、プログラムはパスワードを100バイトバッファに読み込む際に境界チェックを行わないため、オーバーフローでクラッシュしたりサイレントに終了したりする可能性があります。攻撃者はまずリソースを枯渇させて
getpw()
が失敗するようにし、その後過剰に長いパスワードを供給してこの脆弱性を悪用できるでしょう。

著者は1973年の行編集ツール

ed
を使用してソースを修正し、インデックスカウンタ
i
とガード
if (++i >= sizeof(password)) goto error;
を入力ループ内に追加しました。編集後、
cc su.c
a.out
が生成され、これを
/bin/su
に移動しました。setuid ビットと適切な所有権を設定するために
chmod 4755 /bin/su
を実行し、パーミッションを復元しました。

この演習は、UNIX v4 が現代システム上で自己コンパイルできることを示す一方で、当時のセキュリティ重視度が現在の基準に比べて低いことを浮き彫りにしています。読者には、例えばオーバーフローが検出された際に TTY エコーを再有効化するなど、エラーハンドリング後も端末機能を保つようパッチをさらに洗練させることを提案しています。

本文

はじめに
2025 年、UNIX v4 の唯一既知のコピーが磁気テープ上で発見されました¹。
このバージョンはコンピュータ史上重要な転換点を示します――UNIX を C へ書き直した瞬間です。愛好家たちはすぐにデータを復元し、PDP‑11 シミュレータ² 上でシステムを実行することに成功しました。この貴重なアーティファクトに魅せられ、私はその調査のためにインスタンスを構築しました。

配布物にはソースコードが含まれているため、いくつかの主要ユーティリティの実装を精査しました。

su(1)
プログラムを監査している最中にバグを発見したので、これを修正しましょう。


UNIX v4 の
su(1)

50 年以上前の古いソフトウェアですが、su は現代版と同様に機能します。セット UID で root 実行ファイルとして設計されており、root パスワードを検証します。正しい認証情報が入力されると、root シェルが起動し、権限のないユーザーは特権から脱却できます。

su.c
は 50 行未満のコードです:

/* su -- become super-user */

char    password[100];
char    pwbuf[100];
int     ttybuf[3];

main()
{
        register char *p, *q;
        extern fin;

        if(getpw(0, pwbuf))
                goto badpw;
        (&fin)[1] = 0;
        p = pwbuf;
        while(*p != ':')
                if(*p++ == '\0')
                        goto badpw;
        if(*++p == ':')
                goto ok;
        gtty(0, ttybuf);
        ttybuf[2] =& ~010;
        stty(0, ttybuf);
        printf("password: ");
        q = password;
        while((*q = getchar()) != '\n')
                if(*q++ == '\0')
                        return;
        *q = '\0';
        ttybuf[2] =| 010;
        stty(0, ttybuf);
        printf("\n");
        q = crypt(password);
        while(*q++ == *p++);
        if(*--q == '\0' && *--p == ':')
                goto ok;
        goto error;

badpw:
        printf("bad password file\n");
ok:
        setuid(0);
        execl("/bin/sh", "-", 0);
        printf("cannot execute shell\n");
error:
        printf("sorry\n");
}

要点は次の通りです:

  1. getpw()
    を呼び出し、
    /etc/passwd
    から UID 0(root)のエントリを取得します。読み取りに失敗したりフォーマットが不正な場合でも su は続行します。この挙動は部分的に破損したシステムでの可用性を保つための安全策ですが、同時にセキュリティ上の問題(無権限ユーザーが
    getpw()
    を失敗させることで資源を消費できる)も孕んでいます。
  2. TTY のエコーをオフにし、パスワード入力を促します。
  3. 文字単位で読み込み、改行または NUL が来るまで続けます。NUL が出た場合は即座に終了します(バッファサイズのチェックが無いため)。
  4. 読み込み完了後、エコーを再度有効化し、
    crypt()
    でハッシュ化して保存済みハッシュと比較します。一致すればシェルを起動、そうでなければ終了します。

問題点:パスワードバッファは固定長(100 バイト)ですが、入力ループに境界チェックがありません。ユーザーが 100 文字以上入力するとバッファオーバーフローが発生し、プログラムがクラッシュします。実際に長い文字列を試すと、次のような挙動になります。

# su
password:<long input>
Memory fault -- Core dumped

TTY エコーを無効化しているため、クラッシュ後はターミナルが入力を表示しなくなります。可視性を回復するには

stty echo
を打ち込み Enter を押してください。


su(1)
の修正

UNIX では自己再コンパイルに必要なソースコードが付属しているため、v4 でも同様です。これを利用すればシステム上で直接 su をパッチし、再コンパイルできます。

1973 年はエディタ機能が限定されており、

vi
emacs
はまだ存在していませんでした。代わりに
ed
という行指向テキストエディタを使用します。
ed
はリスト・削除・追加といった基本操作が可能で、今回の修正には十分です。

バッファオーバーフロー防止

入力ループ中にカウンタ

i
を導入し、読み込むたびにバッファサイズをチェックします。以下は差分です:

--- a/s2/su.c
+++ b/s2/su.c
@@
        register char *p, *q;
        extern fin;
+       register int i;

@@
-       while((*q = getchar()) != '\n')
+       i = 0;
+       while((*q = getchar()) != '\n') {
+               if (++i >= sizeof(password))
+                       goto error;
                if(*q++ == '\0')
                        return;
+       }

ed
での編集手順

# chdir /usr/source/s2
# ed su.c

起動するとファイルサイズが表示され、入力待ち状態になります。

  • i
    は挿入モードに入り、現在行の前にテキストを追加します。
  • d
    は行削除、
    p
    は内容出力です。
  • 行番号を入力するとその行へ移動し、Enter を押すと行内容が表示されます。

以下は実際の編集セッション(画面録画)です:

741
8
        register char *p, *q;

        extern fin;
i
        register int i;
.
24
        printf("password: ");

        q = password;
i
        i = 0;
.
p
        i = 0;

        while((*q = getchar()) != '\n')
d
i
        while((*q = getchar()) != '\n') {
.

                if(*q++ == '\0')
i
                if (++i >= sizeof(password))
                        goto error;
.

                if(*q++ == '\0')

                        return;

        *q = '\0';
i
        }
.
w
811
q
  • まず行 8 に移動し、
    Return
    を数回押して挿入位置を決めます。
  • i
    で変数宣言を追加し、
    .
    で挿入モードを終了します。
  • while ループに入り、カウンタ初期化と境界チェックを追加しました。
  • w
    で変更を書き込み、ファイルサイズが増えたことを確認後、
    q
    で終了します。

ビルドとデプロイ

修正済みソースは単一ファイルなのでコンパイルは簡単です:

# cc su.c

出力される実行ファイル

a.out
/bin/su
に置き換えます:

# mv a.out /bin/su

しかし、セット UID ビットが設定されていないため権限を付与する必要があります:

# ls -l /bin/su
-rwxrwxrwx 1 root     2740 Jun 12 19:58 /bin/su

# chmod 4755 /bin/su

# ls -l /bin/su
-rwsr-xr-x 1 root     2740 Jun 12 19:58 /bin/su

結論

UNIX v4 は歴史的な貴重品であり、現代のシステムと驚くほど似た構造を持っています。機能は古典的ですが、ロジックは今も通用します。ソースコードがそのまま付属し、C コンパイラが利用可能という当時の哲学のおかげで、バグ修正からビルド・デプロイまでをすべてシステム上で完結できました。

今回のバッファオーバーフローは 1973 年代では「セキュリティ」の主要課題とは見なされていませんでした。実際、任意コード実行への知識も十分に発展していない時期です。このエクササイズを通じて、

ed
のスキル向上とともに、古典的 UNIX の設計思想を体感してください。

最後の挑戦として、オーバーフロー検出ロジックに TTY エコー復元コード(

stty echo
)を追加し、エラー発生時でもターミナルが正しく動作するようにしてみてください。

同じ日のほかのニュース

一覧に戻る →

2026/01/09 4:54

**200 行以内で書く Claude スタイルプログラムの作り方** 1. **目標を定義する** * プログラムが解決すべき問題(例:テキスト生成、データ分析など)を決める。 * 必要な入力・出力、および制約事項を概略化する。 2. **適切な言語とライブラリを選ぶ** * 迅速なプロトタイピングには Python を推奨。 * `openai` や `anthropic` SDK を使用し、必要最低限のモジュール(例:`json`、`time`)のみインポートする。 3. **コード構成** ```python # 1️⃣ インポート import os, json, time from anthropic import Anthropic # 2️⃣ 設定 api_key = os.getenv("ANTHROPIC_API_KEY") client = Anthropic(api_key=api_key) # 3️⃣ コア関数 def generate_text(prompt: str, max_tokens: int = 200) -> str: response = client.completions.create( model="claude-2.1", prompt=prompt, max_tokens_to_sample=max_tokens, temperature=0.7, ) return response.completion # 4️⃣ ユーティリティ関数 def save_output(text: str, path: str) -> None: with open(path, "w", encoding="utf-8") as f: f.write(text) # 5️⃣ メインフロー if __name__ == "__main__": prompt = input("Enter your prompt: ") result = generate_text(prompt) print("\nGenerated Text:\n", result) save_output(result, "output.txt") ``` 4. **200 行以内に収める** * 不要なコメントや冗長なログを避ける。 * 繰り返しコードの代わりに簡潔なヘルパー関数を使う。 5. **テストと検証** * `generate_text` と `save_output` 用に単純なユニットテストを書く。 * 複数サンプルプロンプトでスクリプトが安定して動作するか確認する。 6. **パッケージング(任意)** * `requirements.txt` を追加: ``` anthropic==0.3.2 python-dotenv==1.0.0 ``` * セットアップと使い方を簡潔に説明した README を用意する。 7. **最終チェックリスト** * 未使用のインポートや変数がないこと。 * 文字列はすべて `utf-8` でエンコードされていること。 * 新しい環境でもエラーなく実行できること。 このテンプレートに沿えば、200 行以内でクリーンかつ機能的な Claude スタイルプログラムが完成します。実験・拡張・デプロイの準備は万端です。

## Japanese Translation: (to address missing elements while keeping clarity):** > 本記事では、JSON形式のツール呼び出し(`read_file`、`list_files`、`edit_file`)を介してLLMと対話し、ディスク上のファイルを操作する軽量なコーディングエージェントの構築方法を示します。 > エージェントのコアループは、ユーザーからの自然言語リクエストをLLMに送信し、そのJSONレスポンスからツール呼び出しを解析して対応するローカル関数を実行し、結果を会話へフィードバックします。ツールが要求されなくなるまでこのプロセスを繰り返します。各ツールは構造化された辞書を返します(`read_file` → `{file_path, content}`、`list_files` → `{path, entries}`、`edit_file` → テキストの作成または置換)。 > システムプロンプトは自動的に生成され、各ツールの名前・説明(docstringから取得)とシグネチャを列挙することでLLMが正しく呼び出せるようにします。例ではAnthropic API経由でClaude Sonnet 4を使用していますが、クライアント初期化部分を書き換えるだけで任意のLLMプロバイダーへ切り替え可能です。 > 実装はインポート、環境変数読み込み(`dotenv`)、ターミナルカラー補助関数、および`resolve_abs_path`ヘルパーを含めて約200行のPythonコードです。プロダクション向けエージェント(例:Claude Code)は、このパターンにgrep、bash、websearchなど追加ツールや高度なエラーハンドリング、ストリーミングレスポンス、要約機能、および破壊的操作の承認ワークフローを組み込んでいます。 > 読者は新しいツールを追加したりLLMプロバイダーを切替えたりして、最小限のボイラープレートで高度なコーディング支援が実現できることを体験できます。 この改訂された概要は主要なポイントをすべて網羅し、未支持の推測を避けつつメインメッセージを明確に保ち、あいまい表現を削除しています。

2026/01/09 5:37

**Sopro TTS:** CPU 上で動作し、ゼロショット音声クローン機能を備えた 1,690 万パラメータのモデル。

## Japanese Translation: ``` ## Summary Soproは、1億6900万パラメータで構築された軽量な英語テキスト・トゥー・スピーチシステムです。リアルタイムのストリーミング合成と、わずか数秒の参照音声からのゼロショットボイスクラーニングを提供します。そのアーキテクチャは重いTransformerをドリーテッドWaveNetスタイルの畳み込みと軽量なクロスアテンション層に置き換え、M3コアマシンでCPUリアルタイム係数0.25(約7.5秒で30秒分の音声生成)を達成します。モデルは依存関係が最小限で、PyTorch 2.6.0のみを必要とし、低スペックハードウェアでも効率的に動作します。 Soproは単純なPython API(`SoproTTS.synthesize`)、コマンドラインインターフェイス(`soprotts …`)、およびUvicornまたはDockerで起動できる対話型Webデモを通じて、非ストリーミング(`SoproTTS.synthesize`)とストリーミング(`SoproTTS.stream`)の両方のモードをサポートします。ストリーミング出力は非ストリーミングモードとビットレベルで完全に一致しないため、最高品質を求めるユーザーは非ストリーミング合成を使用することが推奨されます。 トレーニングにはEmilia YODAS、LibriTTS‑R、Mozilla Common Voice 22、およびMLSなどの公開コーパスからデータが採用され、WaveNet、Attentive Stats Pooling、AudioLM、CSMといった確立された手法を組み込んでいます。ボイスクラーニングの品質はマイクロフォンの品質に依存し、システムは略語よりも音素レベルの参照音声を好みます。 Soproは低リソースフットプリント、CPUフレンドリー、そして簡単な統合性を備えているため、チャットボット、アクセシビリティツール、組み込みデバイス、および軽量TTSと高品質ボイスクラーニングが必要なリアルタイムアプリケーションに最適です。 ```

2026/01/09 0:07

ボーズは古いスマートスピーカーをブリック化せず、オープンソースとして公開しています。

## Japanese Translation: **修正版要約** ボーズは、サウンドタッチスマートスピーカーのAPIドキュメントをオープンソース化することを発表し、公式クラウドサポートを2026年5月6日まで延長しました。これは元々計画されていた期間より約6か月長いものです。また、新しいサウンドタッチアプリの更新ではローカル制御が追加されるため、ユーザーはクラウドサービス終了後も機能を維持できます。Bluetooth、AirPlay、Spotify Connect、および物理的なAUX接続を通じて音楽ストリーミングを継続でき、グループ化、初期設定、構成などのリモートコントロール機能も動作します。APIをオープンソースにすることで、ボーズはクラウドサービス停止によって残されたギャップを埋めるカスタムツールを開発者が構築できるようにしています。この動きは、公式シャットダウン後にデバイス機能を維持したPebbleのRebble Allianceなど、コミュニティ主導の取り組みと共鳴します。

「Unix v4 でバッファ・オーバーフローを修正:まるで 1973 年のことのように」 | そっか~ニュース