トップ «前の日記(2011-02-24) 最新 次の日記(2011-02-26)» 編集



2011-02-25 :-(


0500 起床

0830 出勤

0900 実機

_ 午後

1300 コード読み書き

1700 退勤


1800 買い物

2200 飯。厚切り豚バラの照り焼き

_ 買い物

@有隣堂 川崎BE


_ [jail][chroot][NetBSD][翻訳]Securing Systems with chroot - O'Reilly Media

chroot でのセキュアシステム

by Emmanuel Dreyfus


Buffer Overflows (バッファーオーバーフロー)

One popular technique crackers use to compromise machines is exploiting buffer overflows. Buffer overflows are programming bugs which often plague software written with the C language, which makes such mistakes easy to make. Here is an example:

クラッカーたちがマシンを破るときに常用するのがバッファーオーバーフローを利用したものだ。バッファーオーバーフローは C で書かれたソフトウェアにときどき潜むバグで、簡単にミスる。たとえばこう。

int getfilename(void)
   * dos filenames are 8 chars + one dot + 3 chars + trailing nul char
   * => total 13 chars
   char tmp[13];

   (void)scanf("%s", tmp);
   /* more code, more bugs... */
   return 0;

So what happens? The programmer has expected the user to supply a DOS filename, which should fit in a 13 character buffer. Unfortunately, he has failed to validate user input. If the user types a filename which is 25 bytes long, scanf() will copy all the 25 bytes in the buffer, which is only 13 bytes long. The extraneous data will overwrite memory locations near the buffer.

これで何が起きるのか? プログラマは、ユーザーが DOS ファイル名( 13 文字だ )を与えることを期待している。しかしユーザーの入力を検証しようとすると失敗する。ユーザーが 25 バイト以上のファイル名を入力すると、scanf() は 13 バイトぶんしかないバッファーに 25 バイト全てをコピーしようとする。そしてバッファーの近くにあるメモリを上書きするのである。

Local variables such as the buffer used in this example are allocated on a memory area called the stack. The processor maintains the stack, using a register known as the stack pointer to keep track of the memory location of the top of the stack. The stack pointer moves with every function call, and some or all of the following data is pushed on the stack: the current contents of the CPU's registers, the arguments to the function, and a placeholder for the function's return value. Additionally, a placeholder for local variables is created.

この例のバッファーのように、ローカル変数にたいしてメモリを確保したものは、スタックと呼ばれる。プロセッサがスタックを管理しており、確保したメモリのスタックポインタを保持するためにレジスタが使われる。スタックポインタはあらゆる関数呼び出しで移動され、CPU レジスタの現在値、関数の引数、関数の戻り値の placeholder のうちいくつか、あるいは全てのデータがスタックに乗せられる。さらに、ローカル変数の placeholder が作成される。

On a function return, the stack pointer moves down, and the CPU registers are restored from the values stored on stack. Thus the calling function gets its context restored and is not disturbed by the actions of the called function did.

関数が戻るとスタックポインタは下り、CPU レジスタはスタック上に置かれた値を復帰させる。このように、関数呼び出しはコンテキストを復帰させ、関数呼び出しによる影響を受けないようになっている。

What is overwritten when our buffer overflows? First, other local variables, the return value of the function, the function's arguments...then, the saved CPU registers, including the address to which the CPU should return when it completes the called function. A buffer overflow corrupts this value, and the function will return somewhere else in memory. The odds are against finding valid code there. The program will terminate on an illegal instruction, an address error, or perhaps a segmentation fault.

バッファーオーバーフローで上書きされると何が起きるのか? 最初に、関数の戻り値や関数の引数のローカル変数があるとする。そして、関数呼び出しが完了したときに CPU が戻るアドレスも CPU レジスタに格納される。バッファーオーバーフローはこの値を破壊し、関数をメモリ内のどこか別のところに返す。そしてどこかのコードに辿りつく。プログラムは不正な命令により終了し、アドレスエラーやセグメンテーションフォルトを発生させる。

Exploiting Buffer Overflows (バッファーオーバーフロー攻撃)

If the user happens to be a clever cracker, he could enter data which is valid machine code, overwriting the return address with the address of his code. We end up with the situation where the user has successfully tricked our program into executing his code.


This is a real problem if the program is running under a privileged user ID, such as the system superuser (root). An attacker could execute his code with the privileges of a superuser. The next step for our cracker is to include an exec() system call and execute a command such as /bin/sh with superuser privileges to gain full control of the machine.

プログラムがシステムのスーパーユーザー ( root )などの特権ユーザーで実行されているとしよう。攻撃者は特権を持つスーパーユーザーとして彼のコードを実行できるのである。次にクラッカーは exec() システムコールを仕込み、/bin/sh のようなでコマンドを特権スーパーユーザーで実行し、マシンの全制御を得るのである。

There are various places in the system where such a situation can arise: setuid binaries (su, passwd, pppd), privileged programs which parse user files (sendmail, cron), and network daemons which answer user requests (sshd, named, ntpd, and so on). Problems in network daemons are critical since they mean that a remote user can compromise the system over the Internet.

これはシステム内の様々な箇所で発生しうる状況である。setuid バイナリ (su, passwd, pppd)、ユーザーファイルを解析する特権プログラム(sendmail, cron)、そしてユーザーリクエストに回答するネットワークデーモン(sshd, named, ntpd など)。ネットワークデーモンでの問題は、リモートユーザーがインターネットを超えてシステムをどうにでも出来るという致命的な問題である。

Enhancing security by using chroot jails (chroot jails によるセキュリティ強化)

Securing programs which take some user input is not easy. The errors are not always as obvious as a buffer overflow. Additionally, since the complexity of network services is always increasing, many programs use third party libraries which provide services such as compression or cryptography. Security problems in those libraries can compromise the security of any program that uses them, something that developers cannot necessarily anticipate.


One solution is to admit that network daemons are inherently insecure. Therefore, the best option is to reduce the consequences of a security exploitation.

1 つの解決策は、ネットワークデーモンは本質的にセキュアではないと認めることだ。ゆえに、最良の選択肢はセキュリティ攻撃を減らすことだ。

The first measure is to run the service as a non-privileged user. That way, an intruder who breaks into the machine will not have full control. Daemons such as innd (Internet Network News Daemon) and ircd (Internet Relay Chat Daemon) use this behavior by default.

最初にやることは、非特権ユーザーでサービスを走らせることだ。こうすることで、侵入者がマシンを破ったとしても全制御されることはない。innd (Internet Network News Daemon) と ircd (Internet Relay Chat Daemon) は既定でこの動作をする。

This is a good first measure to tighten system security, but it is not perfect. Once the intruder has a shell access with the privileges of the compromised daemon, even though it is unprivileged, he can still affect the compromised daemon and look for local security flaws, such as might exist in other setuid binaries.

システムのセキュリティを強固にするにはよいのだが、完璧ではない。非特権であっても{ it はどれを指している???? } 侵害されたデーモンの特権でシェルを使えるようになった場合、侵害されたデーモンに影響を及ぼし、setuid されたバイナリといったローカルセキュリティの穴を探すことを許してしまう。

An additional measure is to chroot the daemon. Chrooting is a verb named after the chroot(2) system call, which is used to change the root of the filesystem as seen by the calling process.

ほかに、デーモンを chroot する方法がある。Chrooting とは、chroot(2) システムコールを呼んだあとの状態のことである。プロセス呼び出しのときのファイルシステムの root を変更するときに使う。

When a process requests to chroot to a given directory, any future system calls issued by the process will see that directory as the filesystem root. It becomes impossible to access files and binaries outside the tree rooted on the new root directory. This environment is known as a chroot jail.

与えられたディレクトリに chroot する要求がプロセスからあると、今後のあらゆるシステムコールはそのディレクトリをファイルシステムの root とみなして動作するようになる。これで新しい root ディレクトリの外のディレクトリツリーのファイルやバイナリにアクセスすることが出来なくなる。この環境は chroot jail として知られている。

It is possible to experiment with chrooting easily. Just create a tree with a few binaries, including root's shell as listed in /etc/passwd:

簡単な chroot を試すことが出来る。/etc/passwd に書いてある root 用シェルを含めていくつかのバイナリのためにディレクトリを作るだけだ。


If these binaries are dynamically linked on your system (this is the case on most Linux distributions), make sure you include the dynamic linker and the required libraries (typically /lib/ld.so.1 and /lib/libc.so.1).

あんたのシステムでこれらのバイナリが動的リンクされている( Linux ディストリビューションンではよくあること )ならば、動的リンカと、必要なライブラリ ( /lib/ld.so.1 や /lib/libc.so.1 など )も含めること。

You can then try the chroot(1) command, which just performs the chroot(2) system call and runs a shell. Only root can use this command:

そうしたら chroot(1) コマンドを実行する。これはたんに chroot(2) を実行し、シェルを走らせるだけだ。root でやること。

# ls /
bin     etc     dev     home    sbin    tmp     usr     var
# chroot /tmp
# ls /
# ls /bin
sh      ls

Once you are in the chrooted shell, you only have access to the chrooted area. There is no way to escape it; you are in the jail. Other processes still see the normal filesystem root as the root of the filesystem.

chroot なシェルに入ったら、もはや chroot された領域にしかアクセスできない。jail に入ったら脱出する手段は無い。他のプロセスでは、ファイルシステムの root が普通のファイルシステムの root に見えるだろう。

However, there are some ways of getting out of a chroot jail if the process is still running with superuser privileges. It is possible to do a mount(2) system call in order to remount the real root filesystem and then to chroot in it. It would also be possible to create a /dev/kmem device using the mknod(2) system call, and then modify the filesystem root in kernel memory. If the chrooted process runs with superuser privileges, there are many ways of breaking out of the chroot jail. This is why, when chrooting a process, the user ID should always be changed to a non-privileged user.

しかし、プロセスがスーパーユーザー特権を持っていると、chroot から脱出できてしまう。mount(2) システムコールによって実際のファイルシステムの root をマウントし、そちらに chroot できてしまう。mknod(2) システムコールで /dev/kmem を作成し、ファイルシステムの root をカーネルメモリーに確保することでも可能である。プロセスがスーパーユーザー特権で動作していると、いくつもの方法で chroot jail を脱出できるのである。ということで、chroot させるプロセスは必ず非特権ユーザーのユーザー ID に変更すること。

The only way left for an unprivileged process to get out of a chroot jail would be to exploit a kernel security hole. If there is some buffer overflow on a system call argument, it could be possible to execute some code with kernel privileges and to set a new filesystem root for the process. Great care is taken when validating system call arguments, so this should not happen. This kind of security hole has been encountered in the past, but there has been much less problem with system call argument validation than with buffer overflows in network daemons and setuid binaries. For an example of a real system call buffer overflow, take a look at this sobering paper.

非特権プロセスが chroot jail を脱出する方法はただひとつ。カーネルのセキュリティホールを突くしかない。システムコールの引数でバッファーオーバーフローを起こせば、何らかのコードをカーネル特権で実行できるようになり、プロセスに新しいファイルシステム root を設定するのである。システムコールの引数を評価するように注意すればよい。そうすれば発生しない。この種のセキュリティホールは日常的によくあるのだが、ネットワークデーモンや、setuid されたバイナリはシステムコールの引数を評価することにより問題を最小限にしている。ここでは実際のシステムコールのバッファーオーバーフローの例をお見せした。

Summary (まとめ)

We have seen one common security flaw and have learned how it may be exploited. We have also discussed one approach to minimizing this damage. chroot is not perfect, but, with care, it can lead to more secure systems. Next time we will demonstrate how to run a daemon (ntpd) chrooted on NetBSD.

どこにでもあるような 1 つのセキュリティ欠陥と、それがどう悪用されるのかを見てきた。そのダメージを最小限にする方法についても議論した。chroot は完璧ではないが、システムをさらにセキュアにするためには使える。次回は、NetBSD の chroot でデーモン (ntpd) を走らせてみよう。 { その次回の記事が無いよ!!! }

Editor's Note: an earlier version of this article had reversed the arguments to scanf(). This has been corrected.

著者注: この文書の初期では scanf() の引数が逆だった。いまは正しい。

Emmanuel Dreyfus is a system and network administrator in Paris, France, and is currently a developer for NetBSD.