KDOC 293: 『超例解Linuxカーネルプログラミング』

この文書のステータス

  • 作成
    • <署名>
  • レビュー
    • <署名>

概要

『超例解Linuxカーネルプログラミング』は、カーネル開発を解説する本。

メモ

  • 1章: Linuxカーネルの開発フロー
  • LWN.netは、Linux開発のニュースサイト(p29)
  • Linuxカーネルは現場のプロによる修正が多く入っている。プロの修正が無償で見られることは、じつはすごいこと(p29)
  • 2章: ソフトウェアの品質とライセンス
  • stableブランチに入れるソースコードに関して、ルールが定められている(p45)
    • ただしくテストされていなければならない
    • 1つのコンテキストにおいて、修正量が100行を超えてはならない
    • たったひとつのバグが修正されなければならない
    • ユーザを悩ましている本当のバグを修正しなければならない。憶測でバグ修正をしてはいけない
    • クリティカルな問題が修正されなければならない。、つまりビルドエラー、カーネルパニック、ハングアップ、データ破損、セキュリティ問題など
    • つまらない修正は含めてはならない。スペルミスの修正や空白の調整など
  • Linuxのデバイスドライバは静的型と動的型に分類できる。静的型は直接カーネルにリンクされており、起動時にデバイスドライバも起動するもの。動的型はカーネルの動作中にデバイスドライバのモジュールを組み込んだり取り外せる(p56)
  • rodataセクションは、const宣言された定数や文字列定数が配置される領域。rodataセクションに配置されたデータは静的なデータであり、動的に確保されたカーネルメモリではないので、メモリを確保する操作も不要である(p60)
  • 実際の修正例をもとに、起こしがちなバグを解説している
  • ワークキューというカーネルの仕組みを利用すると、指定した関数を遅延実行させられる(p62)
  • 割り込みハンドラは登録したあとはいつ呼び出されるかわからない。登録する前に必要な初期設定をしておかないといけない(p80)
  • ネットワークインターフェースが有効かどうかは、ipコマンドで見たときに「stateがUP」であるという意味。以前はifconfigが使われていたが、現在では非推奨となっている、という(p85)
  • ネットワークカードから発生する割り込みを禁止する処理は、ネットワークカードのレジスタにゼロを書き込んでいる(p86)
  • ポーリングモードの欠点はパケットの受信処理が遅くなること。割り込みモードとポーリングモードのどちらを選択するかは、カーネルへの負荷とネットワーク性能のトレードオフとなる
  • SystemTapという仕組みを利用するのが手軽。SystemTap専用のスクリプト言語を使って簡単なコードを書くことで、自動的にカーネルコードが生成され、動作中のカーネルに組み込める(p89)
    • apt install systemtap
    • 手順: p90
  • ネットワークインターフェイスをUPからダウンに変更中にネットワークから割り込みがきた場合が問題であるコード例(p95)
  • ネットワークのパケットはいつ外部から入ってくるかわからないので、完全にネットワークドライバが停止していない限り、割り込みハンドラが呼び出されてしまう。割り込みはネットワークカードというハードウェアから上がってくるものなので、ソフトウェアで割り込み禁止にしない限り、延々と割り込みがくる。ハードウェアから見るといつまでも割り込みが処理されていないように見える。そして割り込みが無限に上がってくるとCPU1つを使い続けることになり、負荷が上がる(p95)
  • ポインタはメモリ空間を指し示すアドレスなので、メモリ空間が4GBなのであれば、0から(4G-1)の数値を表現できる必要がある。32bitだとポインタのサイズが4バイト
# 32bitに格納できる整数の数をGBに直す
2**32 / 1000 / 1000 / 1000.0
4.294
  • 5章: 32bit/64bitに関する落とし穴
  • カーネル関数の printk() は、C言語の printf() に似せて作られているという。従来、 printk() の「%p」はポインタのアドレスを表示していたが、セキュリュティ上があるということで、でたらめな値が表示されるように実装が変更された。ポインタのアドレスをハッシュ化して、元の値がいくつかをわからなくする。「%px」では本当のポインタアドレスを表示する(p101)
  • Kprobesは、Linuxカーネルの動作中に任意の箇所にブレークポイントを仕掛けられ、そのブレークポイントにデバッグ用コードを設定できる仕組みのこと。SystemTapはKprovesの仕組みを利用したツールである(p103)
  • Kprovesではデバッグしたい関数にブレークを設定するには関数のアドレス、つまり関数ポインタのアドレスが必要である(p104)
  • ドライバをビルドして、 insmod でドライブを組み込む。不要になったドライバは rmmod で取り外せる(p106)
    • ドライバをロードしたことが /var/log/syslog にログ保存される
  • 6章: 処理終了の待ち合わせ
  • I2Cとはシリアルバスのこと。組み込み分野ではよく用いられる
  • DNA(Direct Memory Access)。I/OデバイスがCPUを介さずに直接メモリにアクセスできる(p116)
  • Linuxカーネルのコンプリージョン機能。コンプリージョンを使うと処理完了まで待ち合わせできる。具体的にはユーザープロセスの状態を「割り込み不可なスリープ状態」にして通知を受けたら起動する。待ち合わせ中はユーザープロセスにSIGKILLを送ってもプロセスを強制終了できない(p118)
  • ハードウェア割り込みは割り込みハンドラの登録解除しない限りいつ発生するかわからない。割り込みハンドラを登録解除してからメモリ解放しなければならない(p127)
  • 7章: シンプルなミス
  • マイクロコード: CPUの命令コードの塊のようなもので、CPUのバグ修正をソフトウェアレベルで行える仕組み。CPUのメーカーからベンダーに提供され、BIOSやOSに組み込まれる(p146)
  • 8章: セキュリティ
  • CPUの投機的実行を悪用した脆弱性。投機的実行はプログラムを先読みして実行していく仕組み。同時に実行することで範囲外アクセスが可能になったりする。1つのプロセスで読み込まれたデータはCPUのキャッシュに載るが、そのキャッシュデータを別のプロセスから読み出すことで本来読まれてはならないデータを読み出せるというもの(p153)
  • CPU脆弱性問題
    • スペクターv1
    • スペクターv2
    • メルトダウン
  • Linuxの端末実装は3つのレイヤーで構成される。最上位はキャラクタデバイスのインターフェースを提供し、中間層がldisc、最下位層はハードウェアおよび疑似端末と通信するドライバになる(p155)
  • kfreeなどでメモリが解放されてもメモリの内容はそのままになっている。なので、情報漏えいしたらまずい内容をメモリに乗せる場合はメモリを解放する前にメモリをゼロクリアするのが定石である(p156)

感想

  • 今のメジャーな文字列形式はなんだろうか。ヌル終端で合っているか
  • Linux開発文脈でifconfigは非推奨となっている、ということか、ユーザ全体で非推奨となっているのか
  • 32bit CPUって、一度に処理できるデータサイズ…つまりポインタサイズが32bit(4バイト)ということなのか。命令の長さなどは関係ない
  • 汎整数拡張
    • intが元の型のすべての値を表現できる場合はintに変換され、そうでない場合はunsigned intに変換される
signed char result1, c1, c2, c3;
signed int result2;
c1 = 100;
c2 = 3;
result1 = c1 * c2;
result2 = c1 * c2;
printf("char: %d\n", result1);
printf("int: %d\n", result2);
char: 44
int: 300
  • 階層で関数呼び出しを示す書き方、良い
i2c_transfer
  __i2c_transfer
    adap->algo->master_xfer
      i2c_imx_xfer

関連

なし。