皆さん御久しぶりです。Vim 使いの「ブイ」(仮名)です。
最近、セキュリティについて興味が出てきました。 よく報道されるセキュリティ問題は CPU や OS に関するものばかりですが、我々の身近なソフトウェアにもセキュリティの問題は発見されたりします。 もちろん我々が毎日使っている Vim にもセキュリティ問題が発見されたことがあるのです。ソフトウェアのセキュリティ問題を分析するには、そのソフトウェアに対する深い知識が必要でなかなか難しいものです。 しかし、これがテキストエディタの話なら理解がし易いのではないでしょうか。
今回は Vim のセキュリティ問題にどのようなものがあったのか見ていくことにしましょう。Vim のセキュリティ問題とは、CVE 番号[1] が発行されているものと定義しました。
https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=vim
上記のページを見ると分かりますが、古いものを含めると Vim に関連する脆弱性報告は502 個にものぼるようです。あまりに古いものを調査していても検証が大変なので、今回は比較的最近報告されたものに絞ることにします。
1 CVE-2016-1248
https://jvndb.jvn.jp/ja/contents/2016/JVNDB-2016-005938.html https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-1248
CVE-2016-1248 とは、以下のように説明されています。
vim before patch 8.0.0056 does not properly validate values for the
'filetype', 'syntax' and 'keymap' options, which may result in the execution
of arbitrary code if a file with a specially crafted modeline is opened.
簡単に説明すると、Vim 8.0.0056 以前の Vim は modeline の値をちゃんとチェックしていないので、悪意のある modeline が含まれたファイルを開いたときに、modeline に記述された任意コードが実行される危険性があるということです。
modeline とは、ファイルを開いたときに任意のオプションをセットするための機能です。
もちろんこの問題は同じコードベースを使っている neovim にも存在し、そちらも既に修正が行われています。
この脆弱性を検証するには modeline を有効にする必要があります。デフォルトでオンになっていますが、modeline は一部のディストリビューションでは標準設定で無効化されていることに注意が必要です。
検証のため、手元で Vim 8.0.0055 をビルドしてみることにしました。 Vim 8.0.0055 は以下で手に入ります。
https://github.com/vim/vim/releases/tag/v8.0.0055
8.0.0055 をビルドしました。
$ ./src/vim -Nu NONE --version | head
VIM - Vi IMproved 8.0 (2016 Sep 12, compiled Apr 19 2018 15:09:13)
適用済パッチ: 1-55
次にモードラインを仕込んだ怪しいファイルを作成し、Vim で開いてみます。
$ echo -e '// vim: set ft=\x00!touch\ hoge\x00 : ' > hoge
$ ./src/vim -Nu NONE hoge
:set filetype?
filetype=^@!touch hoge^@
手元では任意コードの実行は確認できなかったものの、[2] ファイルを開くだけで怪しい値が filetype に入ってくることを確認しました。
それでは、問題が修正された Vim 8.0.0056 を試してみることにしましょう。
$ VIM - Vi IMproved 8.0 (2016 Sep 12, compiled Apr 19 2018 16:01:56)
適用済パッチ: 1-56
$ echo -e '// vim: set ft=\x00!touch\ hoge\x00 : ' > hoge
$ ./src/vim -Nu NONE hoge
modelines の処理中にエラーが検出されました:
行 1:
E474: 無効な引数です: ft=^@!touch\ hoge^@
:set filetype?
filetype=
filetype のセットが拒否されました。ちゃんと対応されているようです。 せっかく Vim の脆弱性の話をやっている以上これで終わってしまうのは勿体無いので、どのような変更が行われたのかチェックしてみることにしましょう。
Vim は github で管理されているので、github のページで変更点を見るのが簡単です。
https://github.com/vim/vim/commit/d0b5138ba4bccff8a744c99836041ef6322ed39a
テストが追加されたりいろいろ変更されていますが、今回の肝は以下の変更でしょう。
+/*
+ * Return TRUE if "val" is a valid 'filetype' name.
+ * Also used for 'syntax' and 'keymap'.
+ */
+ static int
+valid_filetype(char_u *val)
+{
+ char_u *s;
+
+ for (s = val; *s != NUL; ++s)
+ if (!ASCII_ISALNUM(*s) && vim_strchr((char_u *)".-_", *s) == NULL)
+ return FALSE;
+ return TRUE;
+}
valid_filetype() という関数が追加され、filetype の値を検査するようになったようです。これは filetype の値として正当なアルファベット、数値、 .-_
以外の値のセットを拒否するという処理になっています。これにより、不正な値をセットしようとすると実際に Vim 8.0.0056 で再現したようにエラーになります。
2 CVE-2017-1000382, CVE-2017-17087
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-1000382 https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-17087
この二つの CVE はどちらもスワップファイルに関する脆弱性です。
以下の文章を参照すると理解が早いと思われます。
http://openwall.com/lists/oss-security/2017/11/27/2 http://www.openwall.com/lists/oss-security/2017/10/31/1
二つの CVE に分かれてしまっているので話がややこしいことになっています。
CVE-2017-1000382
これは Vim が作成するスワップファイルがファイルと同じディレクトリにあるので公開ディレクトリにあるファイルを Vim で編集した場合、ファイルが公開されてしまう可能性があるという物です。これを回避するには、Vim がスワップファイルを作成しないようにする、スワップファイルの作成ディレクトリを 'directory'
オプションで変えるということが考えられます。
CVE-2017-17087
これは Vim が作成するスワップファイルが Vim の user と usergroup で作成されており、umask を無視しているので情報漏洩の危険があるというものです。 エディタのグループがファイルのグループと異なる場合に問題となります。
どのような危険性があるのか解説します。通常は編集しているファイルの読み取り権限がないとファイルが読めません。しかし、編集しているファイルのコピーがスワップファイルとして Vim によって作成されているというのがポイントです。編集しているファイルの読み取り権限がなくても、スワップファイルの読み取り権限があれば、スワップファイルを経由して対象のファイルが間接的に読めてしまうということです。
ちなみにこれも Vim がスワップファイルを作成しないように設定すれば回避できます。
CVE-2017-17087 の問題は Vim 8.0.1263 で修正されているようです。
https://github.com/vim/vim/commit/5a73e0ca54c77e067c3b12ea6f35e3e8681e8cf8
パッチを見てみたところ、「スワップファイルのグループ読み取りがセットされていて、グループ外からの読み込みが不可能になっている場合、スワップファイルと編集ファイルのグループが異なっているかチェックする。異なっていた場合には所有者以外からの読み込みビットを落とす」という処理になっているようです。
3 CVE-2017-6350
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-6350
この CVE はバッファオーバーフローに関するものです。Vim 8.0.0378 で修正されているため、次のパッチを確認したほうが理解が早いでしょう。
https://github.com/vim/vim/commit/0c8485f0e4931463c0f7986e1ea84a7d79f10c75
Vim 8.0.0378 の変更で見るべきなのは以下の変更です。
- array = (char_u **)U_ALLOC_LINE(sizeof(char_u *) * uep->ue_size);
+ if (uep->ue_size < LONG_MAX / (int)sizeof(char_u *))
+ array = (char_u **)U_ALLOC_LINE(sizeof(char_u *) * uep->ue_size);
従来のルーチンは sizeof(char_u *) * uep->ue_size
の部分で整数オーバーフローが発生する危険性がありました。整数オーバーフローが発生すると、極端に小さなメモリ領域が確保されることになりバッファオーバーフローへと繋がります。
修正後のルーチンではオーバーフローを事前にチェックしていることが分かります。
[1]: CVE 番号とは「共通脆弱性識別子」と呼ばれ、一つの脆弱性を表す一意な番号のことです。最近の重大な脆弱性には通称が付くことがよくあります。呼び名が違っていても CVE 番号が同じなら同じ脆弱性と区別することができます。
[2]: 以下に検証コードがあったので、今回はそれを参考に手元でも試しました。 https://github.com/vim/vim/commit/d0b5138ba4bccff8a744c99836041ef6322ed39a
しかし手元での任意コードの実行には失敗しました。他の情報がないか調査しましたが、残念ながら見つかりませんでした。そもそも、モードラインにより不正なオプションをセットされただけで単純に任意コードを実行できるようになるとは考えづらいため、本来はもう少し細かな条件があるのかもしれません。
This article is made by Vim.