2009年07月23日

fno-delete-null-pointer-checks

CNET Japan : Linuxの脆弱性を突くゼロデイエクスプロイトが公開に

Linux Kernel の脆弱性により、見慣れない GCC のコンパイルオプションが話題になっています。恥かしながら、私は今回の一件で始めて知りました。GCC の online manual を見る限り、少なくとも GCC 3.0.4 からは存在するオプションのようです。

GCC Manual 3.10 Options That Control Optimization -fdelete-null-pointer-checks

マニュアルの説明を読むと、既に一回ポインタを間接参照した後の NULL チェックは無意味だから削除するという、何の問題も無い最適化に見えます。

GCC 4.4.1 までは -O2,-O3,-Os で有効になっていたようですが、最新のマニュアルでは(一部のターゲットを除き)全ての最適化レベル(-O0 含む)で有効になると書いてあります。

このリンク元のブログ記事のコード
struct sock *sk = tun->sk;  // initialize sk with tun->sk

if (!tun)
return POLLERR; // if tun is NULL return error
を一見した時、何が問題なのかよくわからなかった (NULL チェックがあろうがなかろうが、NULL ポインタを参照した瞬間に SEGV が発生して kernel panic になるはず、と思った) のですが、kosaki さんの記事を読んで納得。

革命の日々 : 「Linux カーネルの zero-day exploit コード、リリースされる」への余談

Linux Kernel では、ユーザプロセスが 0 番地に mmap を実行することが可能なので、

(1) 0 番地を間接参照しても SEGV が発生しないようにできる。
(2) NULL チェックが GCC の最適化によって削除されてしまっている。
(3) Kernel が 0 番地にアクセスしてしまう。(任意のコードを実行させることができる。)

というメカニズムのようです。なるほど。

私は、これは GCC の問題というよりは、ポインタを NULL チェック無しでいきなり参照している Linux Kernel のコードの問題だと思います。しかし、Kernel などのセキュリティが重要なソフトウェアをビルドする際には、fno-delete-null-pointer-checks を付けておいた方が良さそうです。

# あるいは、NULL チェックが行われていないポインタ参照全てにデフォルトのチェックコードを挿入するようなオプションがあれば良いのかもしれません。

トラックバックURL

トラックバック一覧

1. [linux]Linuxでの0番地のmmapについて  [ 組み込みの人。 ]   2009年07月24日 00:36
Linux Kernel では、ユーザプロセスが 0 番地に mmap を実行することが可能なので、 KMC Staff Blog:fno-delete-null-pointer-checks http://trackback.blogsys.jp/livedoor/kmckk/1202810 直接リンク先の本題とは関連しないけれど、Linuxでの0番地のmmapについて思い出した

コメント一覧

1. Posted by kosaki   2009年07月23日 21:22
それ、誤読アルヨ。
kernelの問題はカーネルのコード直して解決できる。tunデバイスの問題も一瞬で修正された。
でも、ユーザ空間のif文も同じように消えてしまうので、知らないうちに大きなセキュリティーホール空いてるね。ありとあらゆるユーザ空間を調査できないよね。現実的には。
という応用問題を取り扱ったエントリなんです。元々のexploitはご指摘のとおりカーネル直せばすむのですが、それで終わらないよね。と
2. Posted by 若槻   2009年07月24日 09:23
> kosaki さん

C の規格では、NULL ポインタはその型の全ての正しい値と異なり、かつ偽の論理値を持つ値と定められているそうなので (S&G しか当たってませんが… 5.3.2)、GCC が最適化のために使用する仮定は全くもって正当なものであり、正しく動作しなかったりセキュリティに不備があるのはコードの書き方の問題だと私は思うのですが。

もちろん、現実的には、なるべく安全側に振っておくにこしたことはないということは理解できますし、そのために本エントリで取り上げたオプションは有用だと思います。

また、現状 GCC と Linux Kernel は非常に密接な関係があるわけですから、よりセキュアなコードを出す方向に GCC を開発していく努力も、さらに一歩応用問題の解決を進めるためには必要だとも思います。
3. Posted by kosaki   2009年07月25日 15:14
Linuxは実利優先の文化なので

・0番地へのmmapを完全拒否するとWINEが作れないらしい。Windowsはクソだな。
→ じゃあ、0番地へのmmapを許すオプション作ろうぜー
・0番地へのmmapを悪用すると、exploit出来るらしい。でも、それってデーモンがバカなコード書いた時だけだからカーネルの問題じゃないよね。ユーザ空間書き直せばいいんだよ
→ うだうだ言わずに対策汁!

というように、べき論とは違う方向に話しが進むことは、ママあります。
実のところ、中の人はあんまり悪いと思っていなかったり。
4. Posted by 若槻   2009年07月27日 10:08
> kosaki さん

なるほど、Wine の影響でそのような仕様になっているのですか。Linux Kernel が特別実利優先というよりも、セキュリティと利便性のトレードオフという、よくある話だと思いました。

Linux Kernel は、基本的にカーネルコードは信頼する方針ですよね。カーネルコード (ドライバ含む)をちゃんと書けば対策不要という主張ならば、過激ですが、わからなくもないです。

しかし、ユーザ空間のプログラムはちゃんと対策して欲しいところです… とりあえず Wine が欲しい人なんて非常に限られていると思うので、デフォルトは禁止しておくべきですよね。

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード