glibcで見つかった致命的な脆弱性「GHOST」は具体的になにが問題なのか
2015年1月27日、glibcに致命的なネットワーク脆弱性が発見されたと報じられました。glibcはlinuxのデストリビューションのほとんどで使用されている重要なライブラリで、そのライブラリの問題は直接リンクしているソフトウェアはおろか、間接的に使っているインタープリタを経由して動くスクリプトなど多岐に渡ります。
ここではリリースされているパッチから具体的にどういった場合に問題が出るのかを見てみます。
問題の箇所(digits_dot.c)
size_needed = (sizeof (*host_addr)
- + sizeof (*h_addr_ptrs) + strlen (name) + 1);
+ + sizeof (*h_addr_ptrs)
+ + sizeof (*h_alias_ptr) + strlen (name) + 1);
このコードは __nss_hostname_digits_dotsという関数の中で呼ばれます。この関数はよく使われるDNSのルックアップAPIであるgethostname_rから1.1.1.1などIPをホスト名として指定された時の処理の為に呼ばれます。
__nss_hostname_digits_dotsのシグネチャは以下の通り
int __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
char **buffer, size_t *buffer_size,
size_t buflen, struct hostent **result,
enum nss_status *status, int af, int *h_errnop)
bufferはワーキング用のバッファで、gethostname_r系の呼び出し側が提供します。このバッファの必要サイズはホスト名nameのサイズに比例して大きくなります。その為__nss_hostname_digits_dotsでは十分なサイズがあるか比較を行います。その計算に問題があり、必要サイズを少なく見積もっていた(上記size_neededの変更)のが問題の原因です。
ホスト名を操作できる外部からの攻撃者は、nameのサイズをぎりぎりまでふやす事で溢れさせます。そしてワーキングバッファの後方にはnameがコピーされます。つまり、攻撃者の任意のデータを溢れた領域に書く事が出来ると言うわけです。
おわりに
実はこの問題、2013年にすでにフランスのメーリングリストで発覚してパッチが作成されており、glibcの2.18以降であれば修正されています。どちらかというとディストリビューション側の重要性の認識が遅れて古いバージョンが使われていたままであったのことが問題の様です。
多岐に及ぶ依存ライブラリの問題報告を全部チェックするのは現実的に不可能ですし、デグレードの危険があるので機械的にモジュールをアップデートするのもリスクが伴います。この様なケースを未然に防ぐのは難しい問題だと思います。今回の一件ではデストリビューション管理側の問題管理の限界について考えさせられました。
おまけで現在のシステムでglibcを使っているプロセスを一覧するコマンドを掲載します(参考リンクより)。glibcをアップデートしたあとにはこれらのプロセスを再起動させる必要があります。
> lsof | grep libc | awk '{print $1}' | sort | uniq
参考リンク
- glibc に脆弱性 CVE-2015-0235 通称 「GHOST」 が発見される | WWW WATCH
- Critical glibc update (CVE-2015-0235) in gethostbyname() calls