(toppers-users 2947) TINETデータグラム獲得・設定時のパディング書き込み位置異常

MOTEGI Fumiaki fumiaki.motegi @ towada-wd.co.jp
2009年 5月 18日 (月) 20:05:36 JST


初めて投稿させていただきます。
(株)トワダ・ウェルデザインの茂木と申します。

TINET 1.4のIPv4データグラム獲得・設定関数 in4_get_datagram に
パディングの書き込み位置を誤る不具合が有ります。
IPv6の関数 in6_get_datagram も同様の問題を抱えているようです。
以下に詳細を書きますので、不具合で間違いないかご確認のうえ、新しい
バージョンに反映していただければ幸いです。もし、すでに1.5で修正済
みでしたら、お騒がせしてすみません。

関数 in4_get_datagram には、4オクテット境界までパディングで埋める
処理が有ります。TINET 1.4ではin_subr.cの190行の処理です。以下に
引用します。
  memset((VP)(GET_IP4_SDU(*nbuf) + len), 0, (size_t)(align - len));
マクロを展開すると、次のようになります。
  memset((VP)(((UB*)((*nbuf)->buf) + ((sizeof(T_ETHER_HDR)) + (((UB)((UB)(((((T_IP4_HDR*)((*nbuf)->buf +
  (sizeof(T_ETHER_HDR)))))->vhl)&0x0f)) << 2)))) + len), 0, (size_t)(align - len));
この中の「〜 ->vhl」という箇所は、ネットワークバッファ内のIPv4ヘッ
ダからバージョンおよびヘッダ長を取得する処理です。ところが、この
時点ではネットワークバッファを獲得したばかりで、まだその中にIPv4
ヘッダを書き込んでいません。そのため、誤ったヘッダ長に基づいてパ
ディングの書き込み先を決定してしまいます。その結果、獲得したネット
ワークバッファの領域外へパディングを書き込む可能性があります。

実際に、TINET 1.32で領域外へ書き込むことを確認しました。確認した
現象では、1つ隣りのバッファの先頭から2バイト目以降を3バイトに渡っ
てゼロクリアしていました。そこには、固定長メモリプールのフリーリス
ト(※1)が書き込まれていたので、後ほどその破壊されたフリーリストの
値を先頭アドレスとしたネットワークバッファを使用することになり、
CPUが例外を発生してリセットするという現象を起こしました。
※1 …… 正確な表現ではないかもしれません。固定長メモリプールが返
         却されたメモリ領域を管理するために、そのメモリ領域の先頭
         の32bitを使用しています。2番目に返却されたメモリ領域の先
         頭には、1番目に返却されたメモリ領域へのポインタが記録さ
         れています。

IPv6では試していません。しかし、IPv6ヘッダを書き込む前にそのヘッ
ダにアクセスするソースコードになっているようですから、同様の問題
を抱えていると思います。
IPv4については、次のように修正できます。しかし、IPv6の修正も考え
ると、IPヘッダを書き込んでからパディングで埋めるように修正した方
が一貫性があって良いのかもしれません。
  memset((VP)((*nbuf)->buf + IF_IP4_HDR_SIZE + len), 0, (size_t)(align - len));

試験環境:
  JSPカーネル 1.42
  TINET 1.32 (該当箇所のソースコードは1.4と同じです。)
  CPU SH7616

以上、よろしくお願いいたします。