しらいです。

In article <YAS.04Mar8164712@kirk.is.tsukuba.ac.jp>,
Yasushi Shinjo <yas@is.tsukuba.ac.jp> wrote:
>新城@筑波大学情報です。こんにちは。

>>  この「最初からバグがない」という点が過信に繋がり兼ねないと
>> 思うので、私はこの考えには危険が伴うと思います。
>
>strcpy() と strlcpy() の話と「最初からバグを入れない」という
>話は別の話です。strcpy() を単純に strlcpy() 変えてもバグは残
>ります。つまり、分類(A)(B)両方の話です。

 なら構いませんが、<YAS.04Feb25010034@kirk.is.tsukuba.ac.jp>
で新城さんご自身が「strlcpy() を使うと、(A)は出てきません」
と書かれているので、この論法は一繋がりになっているのだと思っ
ていました。
 では、「最初からバグを入れない」という話も「(A) と (B) を
分類する」という話もこの際置いておきますが、この「strlcpy()
を使うと云々」という発言自体に過信はありませんか?

 この辺りは言葉の綾もあるかも知れませんので、本人が自覚さえ
していれば構わないのですが、言葉だけが一人歩きしてしまうと、
「strlcpy() を使うと security 上の弱点に繋がる bug は起きな
い」という思い込みが蔓延してしまい兼ねません。
 strlcpy() に限りませんが、programming 上の万全の策なんても
のはそう簡単には手に入りませんから、より安全な関数を用いると
いった工夫以上に、問題意識を常に持ち続けるという心掛けを大切
にして欲しいと思います。


>>  この過ちを侵している代表例が Samba ですね。こいつは一つも
>> strcpy() を使わないように工夫していますが、長さ指定ミスによ
>> る buffer overflow は過去幾つも発見されています。
>
>具体的にどんなバグだったのでしょうか。これを検証すると面白い
>データが得られると思います。

 Samba では文字列 (正確には char 型配列) は二種類のサイズに
大別されていまして、pathname を表す pstring 型 (実体は 1,024
文字分の char 型配列) と filename を表す fstring 型 (同様に
256 文字分) が用意されています。
 strcpy() を使おうとすると compile 時に error を吐くように
指定されていますので、文字列 copy は pstrcpy() か fstrcpy()
しか使えません。
 ところが、内部実装を追っていくと pstring 型を fstring 型で
受けたりその逆をしたりという実装が非常に多くて、結局この枠組
は全くと言っていい程役に立っていません。

 文字列 copy の際には、strncpy() でも構わないから常に size
を指定するように心がけておけば、このような size の違いは見落
とす可能性が減ると思うのですが、「文字列 copy 対策は既に万全
なのでチェックしなくてよい」という思い込みが幾つも security
hole を生んでしまうのです。
 どういう実装で bug を回避しようとも構わないのですが、問題
意識を低下させてしまう結果を生むような実装だけはやめておいた
方がいいというのが私の持論です。


>asprintf() って何ですか?

 こんなの(↓)です。
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/asprintf.3.html

 内部で malloc() を呼ぶことで、format 文字列を展開した後に
必要となる buffer を動的に確保してくれる形式の printf() 関数
です。
 snprintf() と違って、buffer size を指定する必要すらないた
め、library bug さえ無ければこの関数内で buffer overflow は
起こり得ません。

 GNU libc が発祥だそうですが、Linux 以外に *BSD にも移植さ
れていますね。


>> # 私は library bug に何度も悩まされた挙げ句、library 関数
>> #の互換品を自作する癖がついちゃいましたが :-)
>
>具体的に何というライブラリでしょうか。さしつかえなければ教え
>て下さい。

 色々ありますよ。Y2K の時には library 関数に見つかった bug
も多かったですし、buffer overflow のように security hole に
繋がるものも皆無ではありません。
 security hole ではないですけど、指定文字数ぎりぎりに \n が
存在すると無かったことにしてしまう fgets() なんてありました
っけ。今のところ他には適当なものを思い出せません。

 あと、OS による仕様の相違なんてのもありますね。「UNIX」を
名乗っている癖に POSIX 仕様に準拠していない OS なんてざらで
すよ。
 咄嗟に思いつくところでは、putenv() が引数自身を使うかその
複製を使うかなんていう相違があります。POSIX では前者なんです
が、割と多くの実装で後者ですね。間違えると当然 memory leak。

# library じゃないけど、HP-UX の make(1) は同一 timestamp
#を「古い」と見なすので POSIX 非準拠。最近の CPU だと make
#を何度も実行しないと timestamp の整合性が保てない :-<

-- 
                                               しらい たかし