パスワードを忘れた? アカウント作成
10720 story

OpenBSD、malloc(3) を改良。多数パッケージに影響か 32

ストーリー by Acanthopanax
セキュア養成 部門より

tamo 曰く、 "Undeadly.org の記事によると、3.8 リリースの近付く OpenBSD で malloc(3) に大きな変更が加えられたため、より多くのユーザによるテストが求められている。
変更点は、まず malloc(3) が brk(2) ではなく mmap(2) を使うようにしたこと。そして mmap(2) がランダムな領域を取るようにし、かつ、割り当てられた複数の領域が隣接することのないようにしたこと。これらにより、ソフトウェアにバグがあってオーバーフローしても、既存領域を上書きすることなく SIGSEGV で死ぬようになる。
また、free(3) は領域を実際にカーネルへ返してしまうようになった。そのため、free(3) したあとに読み書きしようとすると SIGSEGV することになる。
これらはどちらも legal ではあるが、プログラマに厳しい制約を課すことになる。言い換えれば、自然にセキュアなコードを書かせるものである。たとえば、この変更のおかげで X サーバのコードにバグを見付けることができた。free(3) 後のアクセスと、バッファを越えた読み出しである。
自分の使っているパッケージにこうしたバグがないかどうか、OpenBSD 3.8-beta で調べてみるようお奨めする。"

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • by mkosaki (13560) on 2005年08月25日 21時35分 (#787696) ホームページ 日記
    Linuxでもbrkを使わない(こともある)実装になっているんだけど、Linuxはそれによってsetrlimit(2)がうまく効かねーという業病をかかえてしまった。
    OpenBSDではどう回避するのかな?互換性問題でると思うんだけど。
  • by seoth (17664) on 2005年08月25日 18時55分 (#787601)
    Linux等でも同じようにmallocを修正すれば、バグの叩き出しができるんでしょうか?
    • Re:これはつまり (スコア:2, 参考になる)

      by Anonymous Coward on 2005年08月26日 12時52分 (#788069)
      Linuxではむかしからmallocはmmapを使っています。というかbrkはPOSIX.1ではないので意図的に使っていません。それからシステムコールになんかしたらパフォーマンスがあがらないので、そんな馬鹿なことを平気でする感覚がわからないです。mallocのバグ出しにはPurify [ibm.com] のような タイプの方法論を使うべきで、それをシステムコール云々での解決は問題解決のアプローチを間違えています。
      親コメント
      • by Anonymous Coward on 2005年08月26日 17時59分 (#788275)
        > mallocのバグ出しにはPurify [ibm.com] のようなタイプの方法論を使うべき

        理屈は分かるが...
        これは、BSD Purify を作って OpenBSD と一緒に配布した方が、よりセキュアだと言ってるの?
        それとも Pufity みたいなメモリチェッカーを使わないフリーソフト作者はこの世から排除すべきだと言っている?

        なんというか、ぼくは OpenBSD らしい方法だと思う。とにかくセキュアにしたい、でも怪しいフリーソフトも使ってみたい、という場合もまああるにはあると思うので、こういうのがあってもいいと思う。このぐらいやらないと、OpenBSD の存在意義が無いというかなんというか。
        親コメント
      • Re:これはつまり (スコア:2, すばらしい洞察)

        by tt_net (17623) on 2005年08月26日 19時53分 (#788340)
        > それからシステムコールになんかしたらパフォーマンスがあがらないので、

        ええと、malloc(3)はシステム「ライブラリ」のtypoですよね?

        たしか、OpenBSDは安全性をウリにしているOSだと思うので、パフォーマンスを犠牲にして安全性を保障するというのは一つの戦略として僕はわからんでもないです。システムライブラリのmallocを置き換えてしまえば、mallocを使用している多くのプログラムの安全性を一挙に高めることが出来ますからね。

        Purifyなどのツールはあくまで個々のプログラムを検査・分析する為のツールのように思います。一方で今回のOpenBSDの方法はOS上で走っているプログラムを含めたシステムトータルの安全性を高める戦略で、目的が異なります。

        そして、そのOpenBSDが検査にも使えるってのはあくまで2次的な用途です。こういうのをアレゲっていうんでしょ?(笑) ちがうかな。
        親コメント
        • by Anonymous Coward
          たぶんあなたはmallocの中身が理解できていないので、まず、そこから始めます。mallocはまずシステムコールmmapあるいはbrkを呼びある程度のメモリ空間をプールしておきます。次に、mallocが呼ばれたときに、その中を必要に応じて刻んで渡します。freeをされると、リサイクル用リストに入ります。次にmallocが呼ばれたらfreeされているリサイクル用リストに適切なものがあれば、そちらから引渡し、なければプールされている領域から取ります。これがユーザ空間で行われるため、単純なポインタの付け替えだけで処理できます。ですから非常に高速です。
          • Re:これはつまり (スコア:2, 参考になる)

            by zenkakueisuuji (20374) on 2005年08月29日 10時29分 (#789452) 日記
            OpenBSDは、この「システムコールで一度にある程度のサイズを取る」ということをせずに、mallocが呼ばれれば内部でシステムコールであるmmapを毎回呼びます。

            はずれ。
            元記事のリンク先に

            - As before, objects smaller than a page are allocated within shared pages that malloc(3) maintains. But their allocation is now somewhat randomized as well.
            と書いてある。malloc(3) が毎回 mmap(2) を呼ぶのではなく、今まで brk(2) を読んでいた箇所で mmap(2) を使うようにしただけ。free(3) がカーネルにメモリを返すのも当然毎回ではなくそのページ中に割り当てられたチャンクがすべて free(3) された時。
            毎回 mmap(3) を呼んで新たにページを割り当ててたら、システムコールのオーバーヘッド云々以前に、数バイト、数十バイト単位のチャンクを大量に malloc(3) するプログラムがメモリを食い尽くしてしまう。テストどころの騒ぎではない。火を見るより明らか。そんなことはしないでしょ。
            となると、この変更の効果は実用環境でのオーバーラン等の被害を減らし、またバグを検出しやすくすることではあるけど、徹底的にバグをたたき出すものではない。Purify のようなものとは用途がずれている。

            親コメント
          • by Anonymous Coward on 2005年08月27日 16時36分 (#788725)

            mmap や brk で大きめの領域を確保しおいて malloc がその領域から割り当てを行うことも、free した領域に関する扱いも処理系依存で実装により違うのでは?


            というのは置いておいて、OpenBSD 3.4 Release [openbsd.org] で、

            カーネルおよびユーザランドのユーティリティから、多数の安全ではない文字列関数が除去されました。 これは、OpenBSD でほとんど総合的に実施されてきた監査の一環であり、何千個もの strcpy(3)、 strcat(3)、 sprintf(3) や vsprintf(3) が、より安全で制限のある strlcpy(3)、 strlcat(3)、 snprintf(3)、 vsnprintf(3)、 や asprintf(3) で代替されました。

            と明らかに高速性よりも積極的なセキュリティを重視する戦略を取っているので、パフォーマンスは無視してでも潜在的に問題がありそうなところは徹底して潰すほうが OpenBSD らしいよ。

            親コメント
          • by tt_net (17623) on 2005年08月29日 4時31分 (#789379)
            大変有用な解説をありがとうございます。でも、ごめんなさい、それは踏まえてこの話はしているつもりでした(ところで、#788069のACさんですよね?) 。そもそも、それが分かってないと、このトピックの面白みがわかりませんし;)。

            つまり、#788069では、ユーザランドのライブラリ じゃなくてシステムコールで解決しようとしているのが馬鹿なこととおっしゃってたのですね。システムライブラリに組み込むのが馬鹿なことなのではなく、そのアルゴリズムに関する異議なのですよね?それなら合点です。すいません。

            ところで、ユーザランドでのmalloc置き換えの実装と言うと、例えば以下のものもそうなのではないかと想像しますが、これらと比べても今回のOpenBSDのアプローチはhigh costですかね? 昔、これらに類するツールをいくつかちょこっと試してみた感想なのですが、それらも通常のmallocを使った場合と比べて大分パフォーマンスが悪かった記憶がありますので、それ以上遅いと実用には向かない気がいたします。その時、私の使ったツールのアルゴリズムがたまたま悪かったのでしょうか? この種のツールのみなさんの比較経験を教えて頂けるとありがたいです。

            • ccmalloc http://www.inf.ethz.ch/personal/biere/projects/ccmalloc/
            • Electric Fence http://perens.com/FreeSoftware/


            # って、もうこの記事にはコメントつかなそうですが...
            親コメント
      • Re:これはつまり (スコア:1, すばらしい洞察)

        by Anonymous Coward on 2005年08月26日 13時17分 (#788101)
        わかってないなぁ。
        これはOpenBSD だぜ。
        いいじゃねぇか、実用OS を使った壮大な実験なんだよ、これは。
        親コメント
      • by urandom (26447) on 2005年08月26日 15時26分 (#788187)
        > Linuxではむかしからmallocはmmapを使っています。
        ふむ。

        > というかbrkはPOSIX.1ではないので意図的に使っていません。
        standard至上主義はよしとして、

        > それからシステムコールになんかしたらパフォーマンスがあがらないので、
        何をシステムコールにしたら性能が上がらないのでしょうか?
        malloc(3)をmmap(2)だろうがsbrk(2)だろうが、どっちにしろシステムコールを呼ぶ場合がある
        という状況に変わりはないと思うのですが。
        親コメント
    • Re:これはつまり (スコア:1, 参考になる)

      by Anonymous Coward on 2005年08月25日 19時04分 (#787610)
      valgrind [valgrind.org]とかで良くね?
      親コメント
    • by Anonymous Coward on 2005年08月26日 0時17分 (#787762)
      バグの叩き出しができるかどうかは運次第かもしれませんが、
      fj.comp.lang.cの定番だったmalloc/free論争には決着が
      付けられるかもしれません :-)
      親コメント
  • 2^(32-12-1) 回、つまり malloc(1) を51万回位呼び出すとアドレス使い果たして malloc() に失敗しちゃうのかな?
    (-1 は隣接ページを空けておく分)
  • by Anonymous Coward on 2005年08月25日 18時59分 (#787604)
    これ、実行性能は悪くなる変更ですけど、実際のパフォーマンスへの悪影響はどんなものでしょう。初期のバージョンだと 50% も遅くなったそうですが、現在のバージョンだと、どれくらい?
    • Re:性能は? (スコア:3, 興味深い)

      by SteppingWind (2654) on 2005年08月25日 21時48分 (#787702)

      やっぱり問題になりそうなのは愚直にmalloc-freeを繰り返すタイプのプログラムでしょうね. 今まではfreeした領域をプロセス内で保持して次のmallocで再利用していたので, うまくいくと(しかもうまくいく確率が高い)システムコールを呼び出す必要が無いので大幅に性能に効いてきますね.

      典型的にはリスト処理とかオブジェクトのインスタンス生成なんですけど, やっぱり自前でガーベージコレクションなどの処理を行う必要を覚悟しておけってこてなんでしょうかね.

      親コメント
    • by Anonymous Coward
      malloc/freeの使用頻度に依存するので、一概にどれくらいとは言えないでしょう。
      普通に使っていれば気になるほど遅くならないと思いますが。

      あまりに遅くなるようなら、自前のサブアロケータ用意するという逃げ道もありますが、
      それはそれで本末転倒ですな。
typodupeerror

物事のやり方は一つではない -- Perlな人

読み込み中...