青木日記

<前の日 | この月 | 次の日>

2005-05-14

■ setup.rb config --siteruby (2)

考えてみると --libruby の一族も値は不変であるべきのような気がする。 ruby にパスが埋め込まれてるってのもあるけど、 こいつらはオプションとして指定するためにあるわけじゃなくて、 値として使うためにあるからだ。

※ こういうことね。

$ ruby setup.rb config --rbdir=\$librubyver --sodir=\$librubyverarch

だからやっぱり --libruby* の値も不変にすべきだろう。

あと、--installdirs=std/site というのがあると いいんじゃねーかと提案されたので、これも実装しておこう。 ついでに home ってのがあってよさそうだなあ。

……いや、甘かった。この仕様だと stow が使えない。 やっぱりパラメタライズしないとだめだ。

■ setup.rb config --siteruby (3)

目先を変えて典型的なパターンを考えてみる。

  • パターン 1: プラットフォームのポリシーに従い site_ruby にインストール

この場合、パラメタライズしてあろーがなかろーがどうでもいい。 現状の setup.rb で問題なし。

  • パターン 2: プラットフォームのポリシーに従い libruby にインストール

プログラムのインストーラをそのまま活用するシステムでありうる。 この場合も現状の setup.rb で問題なし。

  • パターン 3: ポリシは全部無視して $HOME 以下にインストール

ちょっと面倒。--prefix=$HOME --rbdir=$HOME/lib/ruby --sodir=$HOME/lib/ruby のように三つ指定する必要がある。--installdirs=home を用意すれば一つになるか。 しかし ~/lib/ruby を固定にしてしまってよいのか、少し疑問。

  • パターン 4: プラットフォームのポリシーに従いローカルインストール (ruby はベンダインストールなので別の場所にある)

これが一番の問題か。 例えば ruby が /usr にあるけど /usr/local に入れたいという場合。 /usr/local という値は rbconfig からは取れないので、 適切な値を自動設定するには全てのプラットフォーム向けの値を用意しておくしかない。 この場合は --prefix=/usr/local --rbdir=\$siterubyver --sodir=\$siterubyverarch かな? --installdirs が用意されれば --prefix=/usr/local --installdirs=site で、多少は簡潔になりそうだな。

また、今回の変更もこのパターンでの便を考えてのことだ。

うーん、usrlocal, usrlocalxxx, opt くらいの 代表的なモデルは用意してもいいかもしれないなあ。 なんか自分から棺桶に片足つっこんでる気がするけど。

  • パターン 5: stow

この場合はまた別の問題として、 prefix その他をインストール時だけすりかえる手段が必要になる。 --override=prefix,/usr/pkg/tmail みたいなオプションを用意するか。

Makefile の場合は環境変数で上書きできるんだよね。 環境変数も見ようかなあ。でもなあ。 make の場合は環境変数を見るのはわかりやすいけど (イメージ的に sh と近いからかな)、 /bin/sh 独立なイメージのある setup.rb で環境変数を見るのはあまり直感的でない。 やはり --override 形式にしよう。

(12:48)

■ ruby 1.8.3 preview 1 / Tru64UNIX 5.1B

tunami:~/src/ruby-1.8.3 % uname -srm
OSF1 V5.1 alpha
 
tunami:~/src/ruby-1.8.3 % /usr/local/pkg/ruby-1.8.3p1/bin/ruby --version
ruby 1.8.3 (2005-05-12) [alphaev6-osf5.1b]
 
tunami:~/src/ruby-1.8.3 % gcc --version
gcc (GCC) 3.4.3
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
tunami:~/src/ruby-1.8.3 % /usr/local/pkg/ruby-1.8.3p1/bin/ruby test/runner.rb
Loaded suite test
Started
................................. 略
Finished in 175.576072 seconds.
 
  1) Error:
test_wsdl(XSD::TestEmptyCharset):
Iconv::InvalidEncoding: invalid encoding ("euc-jp", "utf-8")
(eval):6:in `iconv'
(eval):6:in `encode'
/usr/local/pkg/ruby-1.8.3p1/lib/ruby/1.8/rexml/source.rb:41:in `encoding='
/usr/local/pkg/ruby-1.8.3p1/lib/ruby/1.8/rexml/parsers/baseparser.rb:202:in `pull'
/usr/local/pkg/ruby-1.8.3p1/lib/ruby/1.8/rexml/parsers/streamparser.rb:16:in `parse'
/usr/local/pkg/ruby-1.8.3p1/lib/ruby/1.8/rexml/document.rb:171:in `parse_stream'
/usr/local/pkg/ruby-1.8.3p1/lib/ruby/1.8/xsd/xmlparser/rexmlparser.rb:27:in `do_parse'
/usr/local/pkg/ruby-1.8.3p1/lib/ruby/1.8/wsdl/xmlSchema/parser.rb:60:in `parse'
./test/xsd/test_noencoding.rb:15:in `test_wsdl'
 
1102 tests, 11438 assertions, 0 failures, 1 errors

(17:48)

■ Hyper Threading considered harmful

http://www.daemonology.net/hyperthreading-considered-harmful/

なんか詳細が気になってしまったので、 このページにあった論文 Colin Percival "Cache Missing For Fun And Profit", 2005 を簡単にまとめてみた。

■ Abstract

複数スレッドがキャッシュを共有しているために、 悪意のあるスレッドが同一プロセッサ上におけるスレッドの活動を監視できる。

■ 1. Introduction

HT ができた背景とか書いてるだけなので略

■ 2. Covert Communication via Paging

ページングを利用した covert channel の構築について。 covert channel とは、通常は通信に使うとは考えられないものを使った通信経路のこと。 ちょっと前に話題になった IP over DNS みたいなやつのことだな。 この節ではページアクセスにかかる時間の差を使った covert channel の構築方法が説明されている。 例えば、特定のページがページアウトされているかいないかで 1 ビットが伝達可能になる。

■ 3. L1 Cache Missing

HT Pentium 4 の L1 キャッシュを使った covert channel の構築方法。

  1. スパイプロセスがキャッシュを埋めておく。
  2. 特権プロセスが規則的にメモリにアクセスする。 アクセスしたところだけがキャッシュされる。
  3. スパイプロセスも規則的にメモリにアクセスし、 アクセスにかかる時間を計測して L1 キャッシュにヒットしたかどうか判定する。 遅くなったところで特権プロセスがメモリアクセスしているはず。 (このへんの関係がよくわからないな。キャッシュの埋まりかたに規則性がある?)

この方法と適切なエラー訂正機能を組み合わせた場合の 通信速度はおよそ 400KB/秒 である。

■ 4. L2 Cache Missing

HT Pentium 4 の L2 キャッシュを使った covert channel の構築方法。 基本的には L1 キャッシュの場合と同じ。 アドレス変換キャッシュがからんでくるので、 適当にレイテンシを追加する必要があるらしい。

■ 5. OpenSSL Key Theft

L1 cache covert channel を使って OpenSSL から秘密鍵を奪取する方法。 openssl rsautl -inkey priv.key -sign を動かしておき、 これに L1 cache spy をしかける (両方が同じ CPU で走るように工夫する)。

OpenSSL は Chinese Remainder Theorem と sliding window を使っているので かなり規則的にメモリにアクセスする。 スパイプロセスは L1 cache を監視することでこれを検出できる (具体的には 512 ビットの指数のうち 200 ビット程度を奪取できる)。

が、これ単独では RSA 鍵は再現できない。 最低でも指数の下位 256 ビットが必要である。 しかしこの不足分は計算開始時に決定されるテーブルの "footprint" を解析すれば補うことができる (このあたりの仕組みはさっぱりわからず)。 これは簡単ではないが、 OpenSSL の特定バージョンであることがわかっていれば 50% の確率で判明する。 結果として 110 ビットの指数が追加でき、 最終的には指数 512 ビットのうち 310 ビットが奪取できる。 これは RSA 鍵を解くには十分な値である。

■ 6. Solutions and Workarounds

CPU で取れる対策

  • HT をオフにする。嬉しくないが簡単。
  • スレッドごとにキャッシュを分ける。めんどい。
  • キャッシュの追い出しアルゴリズムでスレッドのパラメータに配慮する。 パフォーマンスに悪影響するかも?

OS で取れる対策

  • HT をオフにする。嬉しくないが簡単。
  • クレデンシャルの違うスレッドは同時には動かさない。 setuid(2) みたいなシステムコールがからむと難しい?

アプリケーションで取れる対策

  • 重要なデータには規則的にアクセスしないようにする。 コードがすごく変わるので難しそう。

その他

  • アプリケーションからクロックカウンタへのアクセスを禁止する。 例えば Pentium なら RDTSC を発行禁止にする。
  • それはあんまりだってことなら、せめて発行頻度を制限する。

■ 7. Recommendations

CPU

  • SMT ではキャッシュ追い出しアルゴリズムでスレッドを意識すべき。
  • マルチコアの場合、コア間でキャッシュを共有すべきではない。
  • x86 については、covert channel がふさがっているかどうか 判定する feature flag を用意すべき。

OS

  • 本稿で述べた covert channel が確認されるシステム上では、 違う権限のスレッドを一つの CPU で動かさないようにする。
  • めんどうなら、スレッドを一つしか動かさない (事実上の HT オフ)。

暗号ライブラリ

  • データや鍵に依存するメモリアクセスを行わないようにする。

■ 感想

セキュリティってめんどくせー。

「キャッシュを共有してるから」云々てのを聞いて 最初はもろにキャッシュの中身が見えるのかと思ったけど、 さすがにそこまでアホな実装をするはずがなかった。 コードの傾向もわかってないといけないみたいなので、 コード一発で任意のプロセスを覗けるってわけじゃないんだね。 思っていたよりはずっと限定的な穴だった。

なんにしても local exploit だし、 信用できないユーザのいないマシンでは関係ないと。

細かいところはこんど笹田さんに聞こう。

(20:57)

本日のツッコミ(全4件)
■ なかだ (2005-05-14 15:15)

--rb-dir=\$site-ruby-common も簡単にできるとちょっと嬉しいんですが。

■ Oni (2005-05-17 08:01)

ほんと、「めんどくせーーー!」って感じですね。「そりゃあ、そうやれば可能なんだろうけど・・・」うーむ。

■ kjana (2005-05-18 22:07)

local exploit に別の remote exploit での一般ユーザ奪取を組み合わされて、どこかが陥落してたのはいつのことだったか、っていう話があったり無かったり。

■ 青木 (2005-05-20 13:41)

> --rb-dir
そこまではちょっと……。
ちなみに最近はハイフンを取るようにしてるので
--rbdir=\$siteruby までは短縮できますが、
それはちょっと話が違いすぎる予感。


<前の日 | この月 | 次の日>
2002|04|05|06|07|08|09|10|11|12|
2003|01|02|03|04|05|06|07|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|04|05|06|09|10|
2009|07|
2010|09|