追記

野良犬日記 2.1

RDF/RSS
この日記の検索

最近のツッコミ:


2016-04-04 (Mon) [mutt]Mutt-1.6.0出た [長年日記]

_ Mutt は、奇数と偶数の法則はもうやめるみたい

もう 1.4 が安定版と信じて使ってる人なんて殆どいなかったからユーザ的には意味ないけど、開発者が以前のコードを無視できるという意味では大きい。

Rocco の遺産であるテスト追加とか、やるのかな。


2016-01-17 (Sun) [長年日記]

_ [obsd][sec]tedu の outrageous roaming fees の適当訳

翻訳は適当なので、ちゃんと原文を見てください。

海外で予想外の電話料金になってしまうのって最低ですよね。のんびり快適な旅行のつもりが、ガーン! 1メガバイト 20 ドル!? ちゃんと契約書を読んでおけばよかったですね。もちろん、契約書を読む程度の情報強者なら、海外ローミング料金のことも知っていて、契約書を読む必要もなかったでしょうけど。まあそんなもんですよ人生も ssh も。

えっ、ssh にローミングが関係あるのかって? ちゃんと書面を読んでおくべきでしたね。Qualys のセキュリティアドバイザリ (https://www.qualys.com/2016/01/14/cve-2016-0777-cve-2016-0778/openssh-cve-2016-0777-cve-2016-0778.txt ) は、完壁どころじゃない最高の出来栄えです。さて、アドバイザリを読んだ我々 (訳注: OpenBSD 開発者たち) は、どうすればいいのでしょうか。

最大のバグは (とりあえず二番目のオーバーフローのやつは無視して)、秘密データのメモリが再利用されて漏れたことです。これが起こる可能性は前から知られていますし、対策も用意されていますが、頭を使わずに対策されるようにはなっていません。

まず、stdio はバッファを free しても中身をクリアしません。その選択は理解できます。stdio は秘密じゃないデータにもたくさん使われますから、パフォーマンスが重要なのですよね。あれ? そうかな。ファイルを閉じたりバッファを解放するのって、おそらく速度を稼ぐ必要のある場所ではありません。じゃあ、もうちょっときれいに掃除してもいいかもしれませんね。あるいは glibc のように mmap/munmap を使うか。やる価値はあるかもしれませんが、私は libc のサブシステムがそれぞれ独自のミニ malloc を開発するのを見たいとは思いません。今でも結構な数があって、それぞれにクセやバグがあるんです。

一段低レベルの話。free 自体はもう既定で (5.6 から) 冒頭 2k をクリアしています。これは別種の use-after-free バグに対する緩和策として設計されましたので、私としては、大きなバッファを毎回クリアするのはパフォーマンス低下に見合うほどの価値がないと見なしました。この検討過程で、バッファ内のデータとしても、ほとんどの鍵は 2048 バイトより小さいことを確認しました。

私の実験では、既定の動作で十分に鍵の暴露を防げるはずでした。どうやって Qualys が 5.8 で鍵をリークさせたのか、私はよくわかっていません。stdio バッファの中身を fclose の前と後で出力させるよう ssh にセットして中に鍵データがないことを確認したのですが、あまり時間がなかったので、今度は exploit を使ってもっと時間をかける必要がありますね。

OpenBSD の free には、攻撃者がデータの「お手入れ」をしにくくするよう邪魔するランダム化機能もいくつかありますが、その多くは小さめのチャンクのほうが効果を発揮するものです。free ページリストの挙動は今でもほぼ予測可能です。それでももちろん、攻撃者に一撃のチャンスしかないのか無限に試行できるのかによって事情は異なります。roaming バグの悪用は (訳注: 「connection suspended, press return to resume」と表示されるので) ごちゃごちゃ表示されますが、おそらく気付かれずに消えますよね? (訳注: ssh に ls をパイプしたりする例が Qualys の Mitigating Factors のところにある)

一段レベルを上げます。ssh は鍵の読み取りに stdio を使わないようにすべきか? 独自にメモリを mmap してそこに読み出すか? という問題、それをやれば分離はできますが、ちょっと私にはわかりません。Heartbleed の後に Akamai が同じようなことを提案していましたが、ちゃんとしたものになるまで何度か試行錯誤が必要でしたし、stdio の再発明は新しいバグを招き入れる良い方法でもありますから。使っている道具が信頼できないなら、もっと良い道具か何かを入手しましょう。余談ですが signify は stdio を使っていません。それが先見の明によるものだとは言えませんけどね。

ssh のあちらこちらに explicit_bzero を振りかけてまわった苦労が実際に功を奏して、潜在的な exploit vector をひとつつぶしていたのは嬉しいことです。それで、いつまでたってもどこか (stdio) にリークがあるように思える一方で、ふさぎ続けていれば全部ふさげるかもしれない、とも思えます。

メモリ統合の緩和策に関して (訳注: 断片化したリーク情報から鍵を再構成しにくくすることか?) は、よくやっていると考えています。バグをその正体がわからないうちに防ぐのは大変なことですし、チップが思ったとおりにランドしないことだってありますから (訳注: IC を乗せる余地がないという意味??)。確かに、stdio の中で何が起こっているかを非常に注意深く検討する必要はあるでしょう。何か変更を加える前にまず exploit を再現させる必要がありますけれども。

今回のリークは ssh-agent を使っていれば緩和できるものでした。その場合には暗号化された鍵しか漏れないからです。ひとつ思いついたのは、ssh が常に小さな agent を起動して暗号化された鍵を処理させ、メインプロセスでリークがあっても何も外に出ないようにできるのでは、というアイディアです。権限分離は残念ながらリモートからのコード実行による影響の軽減に重きを置いており、他の種類のバグを見過ごしてきました。

どちらかを選ばなければいけないとしたら、自分の実験的機能で情報漏れが起こるなら認証前のサーバサイドよりも認証後のクライアントサイドにあってほしいと言うしかありませんが、頭の悪い実験を減らすという選択肢があれば大喜びでそちらにします (訳注: 利用者の少ない機能やプログラムを削除することを「tedu する」と呼ぶほど、筆者は OpenBSD 開発者たちにコード断捨離の人として知られている)。とは言うものの、ローミングは、完成していれば皆に便利がられる機能だったでしょうね。mosh ユーザも何人か改宗させることができたでしょうに。

あと気に入ったのは、ssh が git で開発されればバグがなくなるだろうという提案です。

ところで、念のために鍵を更新しておこうという方もそうでない方も、そろそろ暗号化された鍵のパスワードクラックに対して大幅に改善された防御を提供する新しい秘密鍵フォーマット (http://www.tedunangst.com/flak/post/new-openssh-key-format-and-bcrypt-pbkdf ) の利用を今一度考慮してみてはいかがでしょうか。


2015-11-22 (Sun) [長年日記]

_ [obsd][sec]tedu の going full pledge

適当和訳

Theo の pledge 更新状況にはプログラムがたくさん載っているが、その中には pledge するのが少しアホくさく思えるものもあるかもしれない。でも、その一見アホくさい努力のおかげで見つかったバグや設計ミスもあるのだ。

おそらく、いくつかのプログラムに pledge は必要ない。「もし id に exploitable なバグがあれば、それどころじゃないだろう」という議論も、さもありなん。しかし、何にでも pledge させるという作業は、pledge というコンセプトが実効性を持つことの証明になっている。テストした最初の 5 つのプログラムが一発で動かなければ、あと 5 つ直そうとする人はいないだろう。それに比べて、100 個までいけたなら、あと 100 個も大したことはないだろうと自信を持って言える。まあ最低でも、「あいつよりデカいぜ」と自慢できる、気分の良い数字にはなる。

その他の場合に pledge は無駄に思えるかもしれないが、ひょっとすると無駄ではない。ksh を使って簡単な cgi スクリプトを書くことを想像してほしい。ksh に何らかのオーバーフロー(shellshock?)が潜んでいるところまで想像しよう。シェルはあまりきつく縛ることができない。当然のことながら、fork して他のプログラムを exec したり、ファイルを作成・変更したりする必要がある。 しかし、最低でもネットワーク関連のシステムコールを無効にすることができる。cgi が小規模な chroot の場合、攻略された ksh は、少数のプログラムを実行することはできるものの、ソケットを開いて内側からネットワークを割り当てることはできない。

他には、設計ミスと言ったほうが良さそうな、ある条件下で fork / exec しようとするプログラムもある。patched 形式の diff を受け取ると、実際に ed を実行する。もちろん ed は「!」コマンドによるシェルエスケープをサポートしているから、diff が任意のプログラムを実行する危険が潜んでいるのだ。patch はそうしたシーケンスを探して未然に防ごうとするが、もし騙されたら……、5.7 の errata 13 になる。pledge を patch に入れることがきっかけで、必要な ed コマンドをエミュレートして一切 exec しないよう設計し直すことになった。もし pledge が 1 年早く来ていたなら、このバグが exploitable になるのを防ぐのみならず、そもそも存在しないようにしてくれただろうに。

iked に pledge を入れたときには、小さなバグが見つかって修正された。chroot 内の子プロセスが、自分の設定を出力しようとして /etc/protocols にアクセスを試みていた。それが失敗して、fatal ではないので、プロトコル名のかわりに数値のまま出力していただけだ。しかしながら、pledge がファイルの open 許可を与えないため子プロセスをクラッシュさせるようになって、そのバグが表面化した。出力コードは別プロセスに移り、今では本来の望みどおりプロトコル名を表示するようになっている。

revoke をコールしたがるプログラムがある。この関数は close の重量級といったところで、あらゆるプロセスのあらゆるファイルインスタンスを閉じることができる。もともとのユースケースは init が端末を安全に再利用できるよう、次のユーザに渡す前に端末を強制的に閉じることだったが、いつしか TTY だけでなく、あらゆる種類のファイルを受け付けるように拡張されたのだ。その revoke に関してカーネルポリシーをどうするか決定する際、この拡張が再検討された。「もしかして、任意のファイルタイプは必要なくない?」そのとおり

こうした状況がどれも他のセキュリティポリシー機構で検出できなかったなどと言うつもりはない。だが systrace ポリシーが patch にあったとしても、当時の主流な考え方として「通常の動作 (ed の実行) は許可」だったから、おそらく助けにならなかっただろう。patch に対する AppArmor ポリシーは見つからない。他のシステムについてはよくわからない。まあ優先順位の高い標的ではなさそうだけど、内部設計を見直せただけだとしても、セキュリティ改善という成果があるわけで。

Posted 2015-11-20 18:33:58 by tedu Updated: 2015-11-20 18:33:58

2014-09-02 (Tue) [長年日記]

_ Windows 7 で chkdsk が "Disk check has been cancelled" になる場合

A disk check has been scheduled が表示されてカウントダウンになるけど、 10、9 となって 8 が表示される前に

   Disk check has been cancelled

と無慈悲に拒否されてしまう場合 (ぐぐったらこれでかなり悩んでる人がいるみたい) には

   chkntfs /t:0

と打っておくと、10 の時点で開始してくれるので大丈夫。

でも一体どうしてキーが押されたと思ってしまうのか。それは不明なまま……


2014-06-17 (Tue) [長年日記]

_ [obsd][sec]コーディングスタイルについてtedu が変数名に一言

http://www.tedunangst.com/flak/post/different-fixes-for-same-bug で変数の扱いについて書いている。

-	int ret;
-	ret = ssl3_handshake_mac(s, NID_md5, sender, len, p);
-	p += ret;
-	ret += ssl3_handshake_mac(s, NID_sha1, sender, len, p);
-	return (ret);

これがバグなのは返り値を確認していないからなのだけれども、 LibreSSL では修正ついでに変数名も変えて、

+	int ret_md5, ret_sha1;
+
+	ret_md5 = ssl3_handshake_mac(s, NID_md5, sender, len, p);
+	if (ret_md5 == 0)
+		return 0;
+	p += ret_md5;
+	ret_sha1 = ssl3_handshake_mac(s, NID_sha1, sender, len, p);
+	if (ret_sha1 == 0)
+		return 0;
+	return (ret_md5 + ret_sha1);

こうしたという話。

OpenSSL では元の ret を残して、

	int ret, sha1len;
 	ret=ssl3_handshake_mac(s,NID_md5,sender,len,p);
	if(ret == 0)
		return 0;

 	p+=ret;

	sha1len=ssl3_handshake_mac(s,NID_sha1,sender,len,p);
	if(sha1len == 0)
		return 0;

	ret+=sha1len;
 	return(ret);

というコードに修正している。

最初は「どっちも同じじゃん」と思ったのだけど、tedu によれば、この違いは大きいらしい。

たしかによく見ると、LibreSSL では ret_* が「関数からの返り値であり、チェックすべきもの」という意味で命名されているのに対し、OpenSSL では「return するためのもの」という意味に見える。

こうした違いが潜在的に goto fail などのバグの原因になるのだとか。


2002|06|07|08|09|10|11|12|
2003|01|02|03|04|05|06|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|10|11|12|
2011|02|04|05|06|07|08|09|10|11|12|
2012|01|03|04|05|06|09|11|12|
2013|02|03|09|10|11|
2014|02|03|04|06|09|
2015|11|
2016|01|04|