qmailにバッファオーバーフローの脆弱性 109
ストーリー by wakatono
作者以外からの初めての脆弱性申告 部門より
作者以外からの初めての脆弱性申告 部門より
Anonymous Coward曰く、"1997年2月の公開以来6年11ヶ月の間にたった1度だけ(しかも発見者は作者自身)しかセキュリティホールの発見されなかったqmailにこの度新たなセキュリティホールが発見されてしまいました。
問題はqmailを構成するプログラムの一つであるqmail-smtpdにあり、2GB以上のSMTPセッションを受けるとバッファオーバーフローを引き起こす可能性があるとのこと。ただし対策はさほど難しくなく、/var/qmail/control/databytesに2G以下の数値を設定してこのプロセスを再起動すればよいそうです。
私も、自分が管理するメールサーバーでは漏れなくqmailを使っています。理由はなんと言っても構築後、ほとんどメンテナンスせずにいられるからです。さすがに最新バージョンのリリースから6年近くもたっており、十分枯れているだろうと思っていたんですが、ソフトウェアというものもなかなか枯れきらないものなのですね。"
とはいえ、作成された当時のことを考えると、2GB以上のSMTPセッションなんて想像もしなかっただろうなぁ…
再起動? (スコア:3, 参考になる)
qmail-smtpdってSMTPセッションごとにtcpserverなりinetd(げげ)から起動されるから、明示的な再起動はいらないんじゃないかと思うんですが。今生きているSMTPセッションをすぐに落として、という意味なのかしら。
# いずれにせよ、databytesを設定しないでqmailを運用するなんて俺自身は考えられないけど。
Re:再起動? (スコア:4, 参考になる)
Re:再起動? (スコア:2, 参考になる)
本当だ。オリジナルのアドバイザリ [guninski.com]もdatabytesの記述が消えて、
となっています。
Re:再起動? (スコア:2, 参考になる)
どのユーザにつけるのかわからないけど。
qmail-smtpd は受け取るだけで、ローカルユーザの権限のファイルになるのは、qmail-local が Maildir なり Mailbox に書き込む時だから。
Re:再起動? (スコア:2, 参考になる)
ちょっとqmail-smtpd.cを眺めてみました。
databytesが設定されていない状況であれば、qmailqにそれなりのquotaをかけてあれば、qmail-smtpdがSIGSEGVを食らう前に(qmail-queueがキューに書き出せなくなって落ちるため)SIGPIPEを食らって落ちてくれると思いますが、databytesを設定してあると無駄ということになりそうです。ちなみに、softlimitをかけてもこの件の解決にはなりません。件のコードはポインタをインクリメントしてるだけで、アロケートはしていませんので。
結局、blast()内でposがオーバーフローしないようにチェックしてやる以外に方法はないと思いました。
# そもそも、ヘッダフィールド長の上限(CRLF込みで1000bytes)をチェックしなくていいのかよとも思いますし。
Re:再起動? (スコア:1)
ヘッダに限らないや。RFC2822での1行の長さの制限でした。改めて読んでみると、受け入れちゃいけないわけじゃないみたいですね。
Re:再起動? (スコア:1, 参考になる)
データの量がdatabytesを超えた場合、エラーフラグを設定して
読み込みの作業を続ける。そしてデータを全て読み込み終わった
後でdatabytesを超えた旨のフラグが立っていたらクライアントに
エラーを通知するようになっている。だからdatabytesを設定しても
読み込み処理のバグは回避できない。
その他有用そうなもの:
qmail bug patch [securepoint.com]
未テストのパッチ(人柱の人は試して結果を報告だ)
Guninski may have been misled by gdb [securepoint.com]
バッファーオーバーフローが発生した様に見えるのはgdbの
問題であって今回の穴はただのSEGVかもしれないという説。
qmailのソースが (スコア:3, おもしろおかしい)
ちらっと見てみたら確かにすごい!!
適当に開いてみたtcpto.cの96行目当たりから
lastwhen = (unsigned long) (unsigned char) record[11];
lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[10];
lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[9];
lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[8];
when = now();
プログラミング初心者の私がいうのも何なんですが
よくこんな書き方で穴がないもんだ…。
マジックナンバーのオンパレードだし、コメントはさっぱりないし。
作者は天才なんだろうなぁ。
その他の例 (スコア:3, 参考になる)
例えば、qsmhook.cの
とか。なんでこんなにしてまで1行にしなきゃいけないんだろう。
難読プログラムコンテストにでも出す気なのか?
これ(qmail-smtpd.c)なんて
読みにくいのもそうだけどサイトのURLが変わったらどうすんのよ。
それだけでバージョンアップ?
他に気になる点は
databytes関連で、こんな個所もありました。
複数のif文まで1行ですか。はあ。
--------------------
/* SHADOWFIRE */
英語が母国語の人は (スコア:2, 参考になる)
日本人から見ると、構造化もへったくれもないただの汚いコードにしか見えない、ということなんだよ。
だから、このコードを英語があまりうまくない日本人が書いたとしたら、批判は当たりと思うよ。
Re:その他の例 (スコア:2, 興味深い)
if( x ) if ( y ) { ... }
って if( x && y ) { ... }
と同じじゃないんでしょうか(マクロで書くなら気をつけなきゃいけませんが)。
スタンダードではないですがある意味深いカッコがへっていいような気もするので、少なくとも「スタンダードでないからダメ」以外の理由でそんなに理に叶っていないとか特別に読みにくいコードには見えないです。
# でも僕は決してif( x ) if( y ) なんて書きませんよ
脆弱性発見とかいうトピックで、こんなにソースを見ている人がいるのかと思ってびっくりです。
---
飲酒済みにつき乱筆御容赦。
Cは文学だねぇ (スコア:2, フレームのもと)
で、「ここではこんなことを大切にして書く」というところが重要で、その「大切にしてるもの」が、そのコードでなぜ大切なのか?ということにちゃんと理由があるわけ。自分の書いたコードや自分が大切と思っていることしか強調できない「コドモ」は、所詮その程度のプログラミングの能力しかないんだよね。経験上、だけど。
ハードウエアの動きも頭の中でちゃんとできていて、それを考慮に入れたこの人のコードは、出来の良い文学の1つを読むみたいですよ。その文学が気に入るかどうか、ということとは別にね。
だから、今でもなかなか穴がみつからない完成度の高さを持っているわけで。
物事を自分がいま見える方向からだけ見て評価して、それを絶対と思っちゃだめよ。コードを通してその人の考えていることや人柄やコードを書いたときの体調まで見通せるくらいにならないと。
精進してくらはいね。
Re:Cは文学だねぇ (スコア:2, おもしろおかしい)
なるほど。俺がなぜいつまでたってもダメプログラマなのか
やっと分かりました。
プログラミングの勉強する前に、プロファイリングを
修めてきますよ。
良いプログラムに見えます (スコア:1)
ほとんどのCPUアーキテクチャで正しく動作する
良いプログラムに見えます。
エンディアンの問題とかメモリーのアクセス制限に引っかかることも
なさそうで、良く考えて作ってるなと思いますよ。
Re:良いプログラムに見えます (スコア:2, 参考になる)
うーん、そうですかねえ。プログラミング/アルゴリズムのお勉強の初歩の初歩、総和の計算を思い出してしまいました。sum=5+4+3+2+1というの。
DJBはライブラリ関数を信じないそうで、qmailにはその代替のサブルーチンを大量に含んでいます。だけど、微妙にライブラリ関数と引数並びが異なったり、中で初心者がやりそうなコードがあったりと、あまり人様に見せて誇れるコードでは無い様な。#476402のAC氏も述べているコンパイル時に警告が多発するのも、オーソドックスなコード書きからは外れてますし。
Re:良いプログラムに見えます (スコア:2, すばらしい洞察)
> くさい不思議なソースで脆弱性がないものどっちがいいの?
それは、尾籠な話ながら、固形の排泄物味のカレーとカレー味の固形の排泄物のどちらが食べたい?な質問ですね。
そのどちらもヤ!がボクの答、カレー味のカレーが良いですし、綺麗で脆弱性が無いのが良いでしょう。綺麗である事(論理構造がはっきりしていて読み易い、実行速度とオブジェクト量のバランスが取れている)事と脆弱性が無い事とは、相反する概念ではありませんよ。
# 綺麗だと検証が楽ですしね。(笑)
Re:良いプログラムに見えます (スコア:1)
qmailも…うーん。ソースをいじったことはあるんですが、書き方よりも独自Cライブラリのなれの問題かもしれません。
ライブラリを自分で追ったことがあるんですが、あれは割と苦行でした。
# 関数の実体を作るマクロ、こまごました(古い)最適化、ループの展開etc…
よくこれでバグなく動くなぁというのと作者が天才なんだろうなぁというのは僕も同感だったりします。
Re:qmailのソースが (スコア:1, すばらしい洞察)
フリーソフトって素人臭いコーディングが非常に多いんだけど、qmailって群を抜いてへんてこなコーディングなんだよねえ。悪いコード例、「絶対にこんな書き方をしてはいけない」の強力な実例として引き合いに出される場合もけっこうあったりして。
# まあ、うごきゃ良いってのはそうなんだが、
# このD. J. Bernsteinって人は、教育者だった事 [cr.yp.to]も
# あったりするんだよね。
Re:qmailのソースが (スコア:2, 興味深い)
いるのに、djbはまったく対応しようともしないので、結果パッチが乱立。
というわけで、djbにオーソライズされていないコードを利用せざるを
得ないのでは、セキュリティの確保とは正反対の方向に行っています。
また、各パッチを矛盾なくうまく当てようとするにはコードを読む必要が
あるのにもかかわらず、あのコードは…。
Re:qmailのソースが (スコア:1, 参考になる)
エンディアンに左右されずに4bytesな整数を扱いたいだけですよね。
Cで書けばこんな表現日常茶飯事のような。
# 関数使え or マクロ定義しろ って話?
最近はJavaしか知らない方が増えているらしいですけど、
そんな方から見ると、確かに異様なのかもしれませんが……
Re:qmailのソースが (スコア:2, すばらしい洞察)
素人が職人技を見てもそれがすごいことだとは必ずしも解らない、というのはプログラミングに限った話ではないとは思いますが、自分が使えればいいだけの職人技は後継者がいなければ廃れていきます。
それの何がすごいのか、他の方法の何がいけないのか、それを習得するための方法などがわかりやすく整理されていないことが、良いものではなく普及したものが残っていくということに拍車をかけているのだと思います。
Re:qmailのソースが (スコア:1, 参考になる)
コンパイルすると警告でまくるしね。
Re:qmailのソースが (スコア:1, おもしろおかしい)
Re:qmailのソースが (スコア:1, おもしろおかしい)
Re:qmailのソースが (スコア:1, 興味深い)
なpatch当てが必須なのにも関わらずこういうコード。なのでdjbなコード
を見てなんじゃこりゃ~と嘆く人が増えるんだろうなぁ。ライバル(というと
なんだけど)のWietse Zweitze Venema氏のコードと比較しちゃうとなおさら…。
Re:qmailのソースが (スコア:1, 興味深い)
美しかったり面白かったりするソフトウェアを思いつく人は教えてほしいなー。
難解Cプログラムコンテストは面白い。けど、逆方向で。
Re:qmailのソースが (スコア:1, 興味深い)
qmailのソースの各ファイルは小さいから簡単に修正すべき
場所を見つけられていいぜ。
メンテが面倒ってのはわからんなあ。MTAって一度設定したら
メンテ必要なのか?そんなにメール環境がよく変わるのか?
DJBツールの設定は確かに独特だけどね。おまけにmanが
わかりにくいからね。けど、一つの設定ファイルに色々な
設定項目をだらだら書くよりも良い方法だと思う。
賞金を (スコア:2, 興味深い)
Re:賞金を (スコア:1, 参考になる)
ううぅ (スコア:2, おもしろおかしい)
# 貧弱な鯖なので、ほんとにもたなそう…。
パッチ (スコア:2, 参考になる)
James Craig Burleyさん [ornl.gov] が パッチ [jcb-sc.com] を作ったそうです。
#まだ試してない
2GBのセッション (スコア:1)
100BASEの環境で一回の攻撃当たり何分かかるんだろう。
スループットで80Mでたとして...4分弱か
今どきまったりした攻撃だな。
今までのってバッファオーバーフローって
パケット数個で溢れてたような気がするし
やなぎ
字面じゃなく論旨を読もう。モデレートはそれからだ
Re:2GBのセッション (スコア:2, 参考になる)
「攻撃が出来てしまう」と言う事実が大事なわけで。
#時間の多寡なんて、
#攻撃されてることを検知してなければ無意味だし。
セキュリティホールというより・・・ (スコア:1)
いや、穴は穴なのですが。
Re:セキュリティホールというより・・・ (スコア:1)
2GB以上のSMTPセッションなんて有り得ないですよ
エ○ゲでもメールで送信しない限りは…(ぉ
ちなみに、僕が実際見た最大SMTPセッションは100MBだったそうな
まぁ、実際対策する必要のあるサーバーは少ないと思います。
//明日は明日の風が吹く
Re:セキュリティホールというより・・・ (スコア:1, 興味深い)
他のMTAはどうなんだろう・・
Re:セキュリティホールというより・・・ (スコア:1)
6年前っていうと、2GB超のファイルひとつ用意するのにも苦労した時代だったと思うんですけど…
2GB超 (スコア:1)
ってやって誰かさん [srad.jp]に怒られましたが OTL
#いまやなつかしい思いで(汗
枯れきらない? (スコア:1)
「枯れきった」とはどのような状態なのでしょうか?
Re:枯れきらない? (スコア:1)
もはや存在していない?
#つまり最も安全であると。
簡単に言えば (スコア:1)
そんな古いの、いまどき使ってるやつがいたのか!
という驚きの目で見られるようになれば「十分に枯れた」と言えるでしょう。MSな世界で言えば、いまどきのWindwos3.1みたいなものか。
うけとったメールの最大 (スコア:1, 参考になる)
1通の最大と、To,cc,bcc等×サイズで。
私は1通100Mか、120×2Mぐらいです。
QMTP同盟 (スコア:1, おもしろおかしい)
QMTPてのはDJB提唱のSMTPより効率の良いプロトコルだ。世にqmailを使っているサイトは多いけれど、QMTPを使っているサイトはほとんどないんじゃないかな。
QMTPでやりとりするメリットは?なんつっても効率がよい。
そして何よりも、ヘッダのReceived:にwith QMTPとなってかっこいい!
デフォルトでQMTPを使う方法は以下の通り。
1. QMTPパッチを当てる(http://www.qmail.org/qmail-1.03-qmtpc.patch)
2. QMTPでメールを受けるサーバはDNSのMXの優先順位を12801以降にする
3. inetdにqmail-qmtpdを設定する(ポート209)
これだけさ。さあ、君も今日からQMTPの仲間だ!
Re:QMTP同盟 (スコア:1)
QMTP 使うのに何で inetd …?
# daemontools でしょ,djb だったら.
Re:QMTP同盟 (スコア:1)
MXの優先順位の値は、絶対値に意味はありません。
12801というのはqmailの側の何かのmagic numberなのでしょうか?
databytesはディスクに保存されるバイト数!? (スコア:1)
databytes [qmail.jp]をみると「databytesはディスクに保存されるバイト数であって、ネットワークを通過するバイト数ではない。qmail-smtpdやqmail-queueのReceived行やenvelopeは含まない。」とあります。
qmail-smptd [qmail.jp]はメールの受信をSMTP通信で行う最前線のプロセス
どういう内部処理で問題が発生しているのかC言語を読めない^^;;ので分からないのですが、databytesを使う場合、実際は
databytes=2GB-(Received行やenvelopeの容量)
なのでしょうか?
2GBなんてメールを送受信する事は無いので実際は問題にならないと思うけど気になって^^;;
やはりココは、tcpserverで対策 [atmarkit.co.jp]がスマートの対策なのかな。
Re:databytesはディスクに保存されるバイト数!? (スコア:2)
これはqmail-smtpdに環境変数を渡すだけだから、 っていうか
Re:再起動? [srad.jp] を誰かをモデレートしてください。
ACでの書き込みだから気づいてない人が多いのでは?Re:databytesはディスクに保存されるバイト数!? (スコア:2, 参考になる)
以前の作者報告 [securityfocus.com]での対策(ulimitでの使用リソース制限) [securityfocus.com]では、対策出来ないのかなぁ?
この穴(B) [srad.jp]がこれで塞ぐことができないのであれば駄目っぽいですね。
Re:この話は (スコア:3, 参考になる)
2点に分けて発表しています。
そのうちのa)は、以前に発表されたものと同じではないかという
見解も出ていて、元ACはそのことを言いたいんだと思います。
ただ、同じくb)の
は、既知のものとは違うバッファオーバーフロー穴ですね。
こちらがどの程度問題になるかによると思うのですが。
# と偉そうに解説してますが、
# 他の人に説明してもらって気付いたんです…
-- garmy
Re:Date: Thu, 15 Jan 2004 17:52:58 +0200 (スコア:1)
見つけた人のようです。
このサイトによると、signed な整数をどんどんインクリメントすると、負になってしまうのが原因のようで、
1<<(sizeof(int)*8) byte の所で現れるバグですね。
#左シフトの不等号が出なかったので...