2007年06月29日

Designing BSD Rootkits

Practical Common Lisp

表題の書籍を読んだ。

An Introduction to Kernel Hacking との副題の通り、悪いことをするための本というよりはそれをネタにしたFreeBSDカーネルへのいざないという感じの本。以下に紹介するようにカーネルコードに密着した話題だけが扱われている。

カーネルのソースコードに手を出してみたい気持ちはあるものの、難しそうだとか先に知らないといけない事が多そうで敷居が高そうだと感じて先へ進めない読者(筆者のことです)のハードルを下げるには丁度具合のいい本だと思う。130ページ程度と薄く、考え込むほど難しいところもなく(5章は例外)気軽に読めた。

内容は次のよう。トピック毎に内容に即した短いプログラムが提示されていて、自分で実際に試してみることができるのは非常に大きい。ただしどこか間違えると大体リブートする破目になるので、qemu上に環境を作って試す方がいい(特に5章以降)。 下心なくとも、ルートがあればこんなことも可能なのかというだけでも単純に面白い。

続きを読む

2005年05月25日

Code Reading 第9章: Architecture

ソフトウェアの設計の視点から、構成方法のタイプ、切り口について解説。 加えて、モジュールやクラスなどパッケージングの様々なレベルを説明。

9.1 System Structures

システムをどのようにサブシステムで構成するかという方法の紹介。

Centralized Repository and Distributed Approaches (9.1.1)
クライアント・サーバ。黒板システム(key/valueペアでレポジトリにアクセス。プログラムをデータの流れ通りに構成しなくても部分同士が通信できる。例: apache)。またそれを分散システムで実現するためのRPC、CORBA、RMIなども少し紹介。
Data-Flow Architectures (9.1.2)
データの変換の連続として処理をモデル化。要するにUNIXのパイプで流す処理。data-flow diagramを描いてみると役に立つ。例: makewhatis。
Object-Oriented Structures (9.1.3)
UMLによる図を描くのはシステムの構造を理解するのに有益。コードを読んで図を生成するツールもある(例: ArgoUML)。
Layered Architecture (9.1.4)
例: ファイルシステム(fwriteからデバイスの書き込みまで。Half-Sync/Half-Async)
Hierarchies (9.1.5)
同じ対象でも視点を変えて何通りもの階層構造がある
Slicing (9.1.6)
分析テクニック。コードから、ある点数の特定箇所での値への影響に着目して関係するコードを抜き出すこと。

9.2 Control models

Event-Driven Systems (9.1.1)
例: GUI。多数の発生源からのイベントを統合。
System Manager (9.2.2)
要素の一つがマネージャとして他の要素の実行を制御する。
State Transition (9.2.3)
有限状態機械。

9.3 Element Packaging

今度はコードを読む際に必要となるボトムアップな視点からの分析に役立つ視点。 コードを読む際には、大きなソフトウェアがどのような方法で各単位に分割されるかを知ることが重要。

Modules (9.3.1)
例: nvi(ファイルとモジュールが1:1), BSD window(複数ファイル/モジュール)、NetBSDカーネル(ディレクトリ/モジュール)
Namespaces (9.3.2)
C++のnamespaceやJavaのpackage。
Objects (9.3.3)
オブジェクト指向の説明。長いが省略できる。C++等の言語機能のみに頼らない(頼れない)実現方法の例も。
Generic Implementations (9.3.4)
任意の型の要素に使えるデータ構造やアルゴリズム。C/C++のマクロによる表現やC++のテンプレート。
Abstract Data Types (9.3.5)
要するに抽象データ型。
Libraries (9.3.6)
効用: Code Reuse, Encapsulation, Structure(モジュールごとにライブラリにする), Optimization of the Build Process, Reduction of Code Size, Dynamic Linking(Windowsではリソースの切り替えにも使われる)。
Processes and Filters (9.3.7)
UNIXのプロセス。例: apache、gccのコンパイラドライバ。UNIXのフィルタ。
Components (9.3.8)
ActiveX, JavaBeans, CORBA。
Data Repositories (9.3.9)

9.4 Architecture Reuse

多くのシステムは確立されたアーキテクチャを利用。基本的な事柄すぎてわざわざ文書化されていないことも多い。

Frameworks (9.4.1)
例: MFC、Java AWT、ACE。
フレームワーク自体を学習することが理解の近道。それにはほとんど何もしない一番簡単なサンプルを調べたり変更したりするのがよい。
Code Wizards (9.4.2)
ウィザードを使って作られたものは作り手が基礎となるフレームワークについて部分的な理解しかしてない場合が往々にしてある。
Design Patterns (9.4.3)
例: Singleton パターン。
Domain-specific architecture (9.4.4)
分野によっては構成法が確立されている。例: ファイルの字句解析・構文解析。

練習問題ピックアップ

exercise 9.5: GNU tarのデータフローダイアグラムを描け。(着目点: リモートバックアップ、圧縮、固定長ブロックI/O)

exercise 9.6: UMLのモデリングツールを使ってオブジェクト指向アプリを解析せよ。

exercise 9.24: 各種デザインパターンのACEフレームワークで使われているコードを特定しコードに即してパターンの特長を説明せよ。

exercise 9.25: gccのソースコードの各部を典型的なコンパイラアーキテクチャに対応させよ。

2005年05月17日

Code Reading 第8章: Documentation

この章は8.2以外は短い。

8.1 Documentation Types

プロジェクトに関する文書をおおまかに5種類に分類。

the system specification document
システムの目的、機能要求、管理・技術的制約など。
→コードの動作する環境についての知識が得られる
the software requirements specification:
ユーザ要求の高レベルな記述、システム全体のアーキテクチャ、処理や外部インタフェース等の要求の詳細。
→コードを読んだり評価するベンチマークとなる
the design specification
システムのアーキテクチャ、モジュール間のインタフェースやデータやコードの構造など。
→コードの構造のロードマップ、特定のコードを読むときのガイドに。
system's test specification
テスト計画、テスト手続き、テスト結果等。
→コードのdry-run(机上での検討)をデータつきで提供してくれる
user documentation
機能の説明、インストール手順、その他もろもろ
→対象がどういうシステムなのか知らねば始まらない。

8.2 Reading Documentation

ソースコードを読む参考情報を文書から読み取る様々な例。

  • コードから動作を読み取るよりも文書から情報を得た方が理解が早い例: catの改行コードの処理のループ(manの-sオプションの説明を読む方が早い)。
  • 文書のセクションとソースファイルとがかなり対応(例: sendmail)。
  • 複雑なアルゴリズムは難解なコードよりも文章による説明の方がわかりやすいことも。 文書の情報により、識別子の名前からそれが意味するものを把握しやすくなる。l
  • デザイナーの思考や検討された対案などを読めることもある(例: Plan 9)。
  • システムの内部APIの説明文書(hsqldb/dev-docs/hsqldb/index.html, perl/perlguts.pod, FreeBSDやNetBSDのmbuf(9)をはじめとするmanのセクション9)。
  • テストケースや利用例(tcpdump(8))。
  • 実装上の問題、caveats(機能が働かない可能性の警告)、バグ。
  • OSやコンパイラのバグなど環境上の理由による問題とその対処→ソース上のコメントがほとんど。

8.3 Documentation Problem

文書は常に正しい情報を与えてくれるとは限らない。

  • 様々な理由により、実装された機能が文書化を避けられることもある
  • 文書が、システムは「どのように実装されているか」でなく「どのように実装されるべきか」を述べている可能性
  • コードの進化にドキュメントが追随しなかった場合

8.4 Additional Documentation Sources

ほかにもnon-traditionalな幅広い情報が得られる。comments, standards, publications, test cases, mailing lists, newsgroups, revesion logs, issue-tracking databases, marketing material, and the source code itself.

コメントは実行されるわけじゃないので正しいとは限らない。 標準を実装しているならその標準の文書。FAQなど。

オープンソースならでは: 読んでいるコードに特徴的な識別子をいくつか選んでメーリングリストなどのアーカイブを検索してみる。作者に直接問い合わせてみる(濫用禁止、対価をコミュニティへ還元せよ、作者はボランティアであることを忘れるな)

8.5 Common Open-Source Documentation Formats

オープンソースで用いられる文書形式の紹介: man (mdoc), Texinfo, DocBook, javadoc, Doxygen。

2005年05月14日

Code Reading 第7章

この章は非常に短い。coding standardの採用の必要性と、主なcoding standardsはどのような点について推奨基準を定めているかの説明。

7.1 ソースコードに含まれる一般的な文書ファイルのファイル名とその説明

README, INSTALL, TODOなど。

7.2 Indentation

特になし。

7.3 Formatting

不揃いなフォーマッティングはバグの元。
コメントのフォーマットでは、/*- で始まる場合はアスキーアートによる図解など再整形されたくない内容を示す。Javalでは、/**で始まるものはjavadocにより処理される。
switch文でコードを書いた意図を表明する/* FALL THROUGH */と/* NOTREACHED */。

コメント中のXXX, FIXME, TODOの用法:

  • XXX: その部分のコードが正しくないが多くの場合動いてしまう
  • FIXME: コードが間違っていて修正を要する
  • TODO: 将来強化すべき箇所の表示

7.4 Naming Conventions

英文字の大小やアンダースコアによるBSD, Java, Windowsの命名規則を紹介。 名前を構成する規則や語彙などについての話はなかった。

7.5 Programming Practices

portabilityのためにコードの書き方をルール化。GNUは16bit環境を考えていないなど暗黙的な仮定があることに注意。
ユーザインタフェースやその処理方法も標準化。(コマンドライン引数の処理や、GUIアプリケーションのUIガイドライン)

7.6 Process Standards

多くのcoding guidelineはコードだけでなく文書やビルドプロセスにも標準化の範囲を広げている。(例: UNIXのman、GNUのtexinfo、BSDのソースツリーのMakefile)

主なcoding standards:

Code Reading 第6章

この章では、大規模なソフトウェアの構成やテクニックを、作る側の視点から解説している。

6.1 大規模プロジェクトで使われそうな設計や実装のテクニックのあらまし

「オプジェクト指向の利用」のようなコードレベルのことも挙げられているが、特に次の点が目を引いた。

  • nontrivial architecture
  • libraries, components, and processes
  • domain-specific and custom languages and tools
  • aggressive use of preprocessing

6.2 ソースコードのディレクトリ構造を見てプロジェクトの構成を把握する

構成方針を把握すれば、目的のソースコードを探し当てることは易しい。(例: FreeBSDのユーザランドを含む全ソースコード)
大規模プロジェクトでは、ソースコードには単に実行ファイルを構成することになる命令だけでなくずっと多くの情報が含まれている。

6.3 ビルドプロセスの概略

オブジェクトファイル(*.o)→ライブラリ・コンポーネント→実行ファイル、というファイルが構成される関係の説明。
ビルドプロセスで使われるツールとして、makeの解説、antとjamの紹介。

6.4 configuration (ビルドの条件の変更や、ソースコードの修正など)

ビルド時: makefileの変数、antのbuild.propertiesファイルによる設定。GNU configureの紹介。
実行時: 設定ファイル、環境変数、Javaのプロパティ、Windowsのレジストリから情報を読み込んで動作に反映。

6.5 Revision control

RCSやCVSの使い方。cvs logの例とその見方。

6.6 Project-Specific tools

例としてUNIXのconfig(8)を挙げている。プロジェクト固有のツールは回帰テストの処理にも使われる(例: perl/t/TEST)。また、javadocやperlのpodのような言語固有のドキュメント生成ツールもこの類として紹介。

6.7 Testing

ソースコードを読むときには、作業の一部としてまずテストコードやテストケースを調査して、それらを残りのコードを理解する役に立てるべき、との由。
ソースコードを読む際にはテストケースは機能仕様を部分的に代替したものといえる。

またデバッグのために使われるコーディングについても解説。

  • #ifdef DEBUG 〜 #endif
  • ロギング機能 (syslog, ReportEvent)、ロギングのデバッグレベル
  • assert (3通りの用法: コードの理解が正しいことのチェック、引数のチェック、戻り値の検証)

テストとして、JavaではJUnitによるユニットテスト、Cでは#ifdef DEBUG 〜 #endifで囲まれた簡単なmain()関数によるテストプログラムを紹介。

面白そうな練習問題

exercise 6.19: カーネルのconfigプログラムを読んでシステムのそれが設定できる側面を文書化せよ。

exercise 6.22: Perlの自動テストプロセッサTESTとテストケースを調査せよ。テストケースはどのように書き、回帰テスト中にどのように処理されるか説明せよ。