トップ «前の日記(2011-03-07) 最新 次の日記(2011-03-09)» 編集

ヨタの日々

2001|08|09|10|11|12|
2002|01|02|03|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|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|12|
2024|01|02|03|

2011-03-08 :-(

_

0500 起床

0830 出勤

0900 空腹による吐き気

_ 午後

1330 レーザー教育

_

1700 残業アワー

1930 退勤

2200 飯。チンジャオロース

_ [NetBSD][chroot][翻訳][ntp]chrooted ntpd in NetBSD - O'Reilly Media

NetBSD で chroot な ntpd (1)

by Emmanuel Dreyfus

02/13/2003

chrooting ntpd ( ntpd を chroot する )

As we explained in Securing Systems with chroot, Part One, a daemon must run with an unprivileged user ID (UID) in order to be safely chrooted. This is a problem, since many daemons need some superuser privileges in order to operate. In some situations, superuser privileges are only necessary during initialization, and it is possible to switch to an unprivileged UID later. This is the case for named, the Domain Name System (DNS) server from the Internet Software Consortium (ISC). named needs superuser privileges in order to bind to UDP port 53 (superuser privileges are needed on almost all Unix systems to bind to ports lower than 1024). Once this is done, named is able to chroot to a directory where the zone files are stored, and it can operate under an unprivileged UID, typically the user named.

第一部では、chroot でのセキュアシステムについて説明しよう。安全に chroot するためにデーモンは非特権ユーザー ID で動作させなくてはならない。ここで問題がある。多くのデーモンは、動作するためにスーパーユーザー特権が必要なのである。いくつかのデーモンは、スーパーユーザー特権が必要なのは初期化時だけであり、以降は非特権ユーザーIDに切り替えて動作させることができる。ここでは named( the Internet Software Consortium (ISC) によるドメインネームシステム(DNS)サーバー )を扱う。named は UDP ポート 53 に bind するときにスーパーユーザー特権が必要になる( ほとんどすべての Unix では 1024 以下のポート番号に bind するためにはスーパーユーザー特権が必要になる )。これにより、named はゾーンファイルの設置ディレクトリに chroot 出来るようになり、非特権ユーザーID ( named ユーザーが一般的 )で操作できるようになる。

ntpd needs superuser privileges for two operations: binding to UDP port 123 (at initialization time) and using time control system calls such as adjtime(2) and ntp_adjtime(2), which are restricted to the superuser.

ntpd は、スーパーユーザー特権が必要な操作が 2 つある。初期化時に UDP ポート 123 に bind することと、時刻制御のために adjtime(2) と ntp_adjtime(2) システムコールを呼ぶことだ。これらはスーパーユーザーでなければならない。

For the first operation, we could proceed as named does, first binding to UDP port 123, then calling chroot(2) and setuid(2). The problem is the second operation. To be able to chroot ntpd after initialization, we need a way to enable an unprivileged user to control the system clock. Such a feature was introduced in NetBSD 1.6, with the clockctl device.

第一の操作としては、named を UDP ポート 123 に bind させ、そして chroot(2) と setuid(2) する。問題は、第二の操作だ。ntpd の初期化後に chroot させ、非特権ユーザーでシステムクロックを制御させるようにせねばならない。これには NetBSD 1.6 では clockctl デバイスを使える。

The clockctl device ( clockctl デバイス )

On NetBSD, the system clock can be affected through four different system calls: adjtime(2), settimeofday(2), clock_settime(2), and ntp_adjtime(2), the last available only if the kernel was compiled with the NTP option.

NetBSD にはシステムクロックに影響するシステムコールが 4 つある。adjtime(2)、settimeofday(2)、clock_settime(2)、そして ntp_adjtime(2) だ。ntp_adjtime(2) はカーネルを NTP オプション付きでコンパイルしておく必要がある。

The clockctl device introduces alternative entry points to these system calls, through a special device file typically named /dev/clockctl. The alternative entry points are done through ioctl(2) system calls on the device file. ioctl(2) is a general purpose system call that enables the user to perform a custom action on a file object. We will see this in more depth in the next part of this article.

clockctl デバイスは、これらのシステムコールを使うための別のエントリーポイントを提供する。スペシャルデバイスファイルは、たいてい /dev/clockctl という名前である。このエントリーポイントによって、ioctl(2) システムコールでデバイスファイルを操作するのと同じことができる。ioctl(2) は、一般的には、ユーザーがファイルオブジェクトへの独自操作を有効にするためのシステムコールである。次の章でさらに詳しく見ていく。

If a user has write access to /dev/clockctl, then he can use the alternative entry points and can control the system clock. In order to chroot ntpd, we therefore just need to build a kernel with the clockctl device driver and ensure that the unprivileged user under which ntpd is running in the chroot jail has write access to /dev/clockctl.

ユーザーが /dev/clockctl に書き込むと、エントリーポイントを使えるようになり、 システムクロックを制御できるようになる。ntpd を chroot するために、clockctl デバイスを有効にしてカーネルをビルドし、chroot jail で非特権ユーザーで ntpd を走らせ、 /dev/clockctl に書き込ませるようにする。

In order to be administrator-friendly, NetBSD 1.6 comes with clockctl enabled in GENERIC kernels--the /dev/clockctl file is installed by default, and the startup scripts already know about clockctl. Therefore, the system administrator just has to add one line to /etc/rc.conf. Here are the relevant lines from /etc/defaults/rc.conf:

システム管理者に朗報。NetBSD 1.6 では GENERIC カーネルで clockctl が有効になっており、デフォルトで /dev/clockctl ファイルが作られ、clockctl のスタートアップスクリプトも入る。システム管理者は /etc/rc.conf に 1 行追加するだけだ。/etc/defaults/rc.conf には以下のように書いてある。

# To run the ntpd(8) NTP server as an unprivileged user under a
# chroot(2) cage, uncomment the following, after ensuring that:
#       - The kernel has "pseudo-device clockctl" compiled in
#       - /dev/clockctl is present
#
#ntpd_chrootdir="/var/chroot/ntpd"

The next part of this article is more developer-oriented. It deals with the implementation details of the chrooted ntpd. In the next two sections, we will focus on the userland modifications that were required in order to provide a chrootable ntpd, and we will discuss the implementation details of the clockctl device driver.

次の文書では開発者向けの説明をする。chroot された ntpd の実装の詳細について議論する。次の 2 つの章で ntpd を chroot するためにユーザーランドで必要な変更について具体的に見ていき、clockctl デバイスドライバを実装するための詳細を議論する。

Userland Modifications: libc (ユーザーランドの変更: libc)

Our goal was to make modifications as minor as possible in the NTP daemon. We especially did not want to introduce a new Application Programming Interface (API). This goal was achieved at the expense of introducing some magic into NetBSD's libc.

ここでは、NTP デーモンを変更することをゴールとする。新しいアプリケーションプログラミングインターフェース (API) を知る必要はない。NetBSD の libc の黒魔術に集約されている。

When a user program is built, each system call is turned into a library call to a function in the libc known as the system call stub. The function does the actual system call, and may do some additional handling for backward compatibility. The stubs that do more than just the system call have a C source file associated with them. They are listed in the SRC variable in src/lib/libc/sys/Makefile.inc. For an example of a system call stub that does additional handling, see src/lib/libc/sys/lseek.c.

ユーザープログラムをビルドするとき、各システムコールは、システムコールをスタブした libc 内の関数を呼ぶ形になる。関数は実際のシステムコールを呼び、上位互換性のためにいくつかハンドルを追加する。スタブは、C ソースファイルからたんにシステムコールを呼ぶだけよりも多くのことをおこなう。これらは src/lib/libc/sys/Makefile.inc の SRC 変数に列挙されている。src/lib/libc/sys/lseek.c にシステムコールスタブにハンドルを追加する例がある

On the other side, some system call stubs are utterly void; they only do the system call. In this case, the source file for the system call stub is automatically generated. These are listed in the ASM variable in src/lib/libc/sys/Makefile.inc. An autogenerated stub looks like this:

一方、いくつかのシステムコールスタブには、たんにシステムコールを呼ぶだけで何もしないものがある。この場合、システムコールスタブのソースファイルは自動的に生成される。これらは src/lib/libc/sys/Makefile.inc に ASM 変数に列挙されている。たとえばこう。

#include "SYS.h"
RSYSCALL(chdir)

Once generated, this file is src/lib/libc/chdir.S. The curious reader will look for the definition of the RSYSCALL macro, which is contained in src/lib/libc/arch/powerpc/SYS.h for PowerPC ports, for instance. The macro provides the few assembly lanugage instructions needed for the system call to set errno on error.

すると、src/lib/libc/chdir.S が生成される。好奇心旺盛なひとは、PowerPC ポートの src/lib/libc/arch/powerpc/SYS.h に RSYSCALL マクロが定義されていることに気付くだろう。このマクロは、システムコールがエラーになったときに errno を設定するための命令を提供する。

Before the clockctl implementation, adjtime(2), clock_settime(2), settimeofday(2), and ntp_adjtime(2) were implemented as the simple system call stubs. This has been changed in order to check for the existence and accessibility of /dev/clockctl.

先ほどの clockctl 実装 adjtime(2)、clock_settime(2)、settimeofday(2)、そして ntp_adjtime(2) は、簡単なシステムコールスタブとして実装されている。変更されたかどうか確認するには /dev/clockctl にアクセス出来るか確認すればよい{ ???????? }。

The code is nearly identical for the four system calls. It can be found for settimeofday(2) in src/lib/libc/sys/settimeofday.c. It performs roughly the following checks:

コードは 4 つのシステムコールとだいたい同じである。src/lib/libc/sys/settimeofday.c にある settimeofday(2) を見つけることができる。おおざっぱに以下のことをチェックする。

  • Are we running with root UID? If we are, use the system call. Root has no reason to use clockctl.
  • If we are not running with root UID, try to open /dev/clockctl and use the ioctl(2) to perform the settimeofday operation.
  • 我々が root の UID でならばシステムコールを使う。root ならば clockctl を使う必要がない
  • 我々が root の UID でなければ /dev/clockctl のオープンを試し、settimeofday の操作をするために ioctl(2) を使う

This turns each call to settimeofday(2) into several system calls: getuid(2), open(2), and ioctl(2). For the sake of performance, we have a keep-state feature, so that libc can remember if a process has already used clockctl. This is done using the __clockctl_fd variable. This variable is carried by libc but it behaves exaclty like a global variable for the process. Of course, each process has its own __clockctl_fd.

これは、getuid(2)、open(2)、そして ioctl(2) のいくつかのシステムコールで settimeofday(2) を呼ぶために返す。{???????????} パフォーマンス的な意味で keep-state の機能があるのだが、これにより、libc は clockctl がすでにプロセスから利用されているかを思い出すことができる{ ?????????? }。この処理は __clockctl_fd 変数を使えば完了する。__clockctl_fd 変数は、libc によって、プロセスのためのグローバル変数のように扱われる。もちろん、プロセスは独自の __clockctl_fd を持っている。

__clockctl_fd describes the state of the process regarding clockctl:

__clockctl_fd は clockctl に関するプロセスの状態として定義される:

  • -2 means that the process never called settimeofday(2), adjtime(2), clock_settime(2), or ntp_adjtime(2). This is the value at initialization time.
  • -1 means that the process should not use clockctl.
  • Any other value is the file descriptor we got when opening /dev/clockctl.
  • -2 はプロセスが settimeofday(2)、adjtime(2)、clock_settime(2)、ntp_adjtime(2) のいずれも呼ばなかったことを意味する。これは初期化時の値である
  • -1 はプロセスが clockctl を使わなかったことを意味する
  • それ以外の値は /dev/clockctl をオープンしたときのファイルディスクリプタである

On the first call to one of our four system call stubs, if UID is root, __clockctl_fd is immediatly set to -1. Otherwise, we attempt to open and use /dev/clockctl. Should this attempt fail, __clockctl_fd is set to -1. If it succeeds, then __clockctl_fd keeps the file descriptor returned by open(2). Future calls to the stub will use clockctl.

4 つのシステムコールスタブのうちの 1 つを初めて呼び出したとき、UID が root ならば __clockctl_fd は即座に -1 に設定される。/dev/clockctl をオープンしたり、利用するときも同様である。失敗したときも __clockctl_fd は -1 に設定される。成功したときは、open(2) の戻り値と同様にファイルディスクリプタとなる。将来的にはスタブは clockctl を使うようになるだろう。

When __clockctl_fd is -1, the real system call is always used.

__clockctl_fd が -1 だった場合、本当のシステムコールはすでに利用されている。

We end up with an implementation where the API for ntpd and other processes did not change. When the user process attempts to do a system call, we intercept it at the libc level and use either clockctl or the actual system call. This is nice, but the drawback is that we introduce some black magic in libc, which is not a nice solution. The good point is that since we did not change anything in the API, we can replace this black magic with anything else without disturbing user processes. For instance, if we ever introduce capabilities in NetBSD, we can revert to a void system call stub without ntpd being affected.

これで ntpd の API の実装は完了した。他のプロセスについては変更していない。ユーザープロセスがシステムコールを呼び出したとき、libc をぶんどり、clockctl か、またはシステムコールを利用させる。これはこれで良いのだが、libc の黒魔術でもあるのであまり良いともいえない。良い点は、我々は API をどれも変更していないことだ。ユーザープロセスに触れずに、libc の黒魔術だけで API を置き換えた。NetBSD だからこそ、ntpd を変更することなく、システムコールスタブを無効にできたのである。

_ [chroot][ntp][NetBSD][翻訳]chrooted ntpd in NetBSD - O'Reilly Media (2)

NetBSD で chroot な ntpd (2)

A word on the ioctl(2) system call and its use in clockctl: before talking about the changes to ntpd, it is worth explaining what the ioctl(2) system call does. On Unix systems, all objects are seen as files. This includes device files, terminals, and so on. Of course there are some object-specific operations that cannot be done through a file interface (read, write, lseek, etc.). These operations include, for instance, getting terminal characteristics when the file is the standard output, or ejecting the disk when the file is a a removable disk's device. Nearly everything that cannot be done through the standard file-related system calls is done using ioctl(2) calls.

clockctl 内で使用される ioctl(2) というシステムコールがある。ioctl(2) について知っておくとよいので、ntpd を変更する前に説明しておこう。Unix システムにおいて、すべてのオブジェクトはファイルである。それにはデバイスファイル、端末が含まれる。もちろんオブジェクトを扱う操作は、ファイルインターフェース無くしては出来ない( read、write、lseek など )。これらの操作には、ファイルが標準出力だったり、リムーバブルディスクを排出するときは、その端末から文字を取得することも含まれる。ファイルに関連する標準のシステムコールが無くてはほとんどのことは出来ないのだが、ioctl(2) を使えば出来る。

Here is ioctl(2)'s prototype:

ioctl(2) のプロトタイプはこう。

int ioctl(int d, unsigned long request, void *argp);

d is the file descriptor on which we operate, request is a value indicating which command we want to perform, and argp is an optional argument pointer. The structure of the argument itself depends on the request. Here is an example of ioctl use in a userland program, for getting the terminal width in columns:

d は操作するときに使用するファイルディスクリプタである。request はおこないたい処理で使う値である。argp はオプション引数のポインターである。引数の構造は request に依存する。以下にユーザーランドプログラムでの ioctl の例を示す。これは端末のカラム数を取得する。

/* col.c -- print the terminal width (端末の幅を印字する) */
#include <stdio.h>
#include <err.h>
#include <sys/ioctl.h>

int
main(void) {
  struct winsize ws;

  if (ioctl(1, TIOCGWINSZ, (void *)&ws) == 0)
    printf("terminal width = %d\n", ws.ws_col);
  else
    err(1, "ioctl failed");
  return 0;
}

In ioctl() first's argument, we have 1, standard output, which is attached to the controlling terminal. TIOCGWINSZ is a macro defined in <sys/ttycom.h> for getting window information on terminals. The third argument here is a pointer to a struct winsize where ioctl(TIOCGWINSZ) will write its data.

ioctl() の最初の引数は 1 である。これは制御する端末の標準出力を意味する。TIOCGWINSZ は <sys/ttycom.h> で定義されたマクロであり、端末のウィンドウについての情報を取得する。3 番目の引数は ioctl(TIOCGWINSZ) を実行して書き込まれる winsize 構造体へのポインターである。

Of course, TIOCGWINSZ will only work if the standard output is attached to a terminal. It's possible to check this:

もちろん TIOCGWINSZ は標準出力が端末になっているときにのみ動作する。以下のようにしてチェックする。

$ cc -o col col.c
$ ./col
terminal width = 80
$ ./col > toto
col: ioctl failed: Inappropriate ioctl for device

For the clockctl device, we use four ioctl commands, one for each of our system calls. All are defined in <sys/clockctl.h>: CLOCKCTL_SETTIMEOFDAY, CLOCKCTL_ADJTIME, CLOCKCTL_CLOCK_SETTIME, and CLOCKCTL_NTP_ADJTIME. Each command uses a pointer to a structure holding the system call arguments for its arguments.

clockctl デバイスを使うためにシステムコールから成る 4 つの ioctl コマンドを使う。全て <sys/clockctl.h> で定義されていて、CLOCKCTL_SETTIMEOFDAY、CLOCKCTL_ADJTIME、CLOCKCTL_CLOCK_SETTIME、そして CLOCKCTL_NTP_ADJTIME がある。各コマンドは、該当するシステムコールの引数で使う構造体へのポインターを使う。

To keep things simple, we use exactly the same structures as kernel when passing arguments to system calls. They are defined in <sys/syscallargs.h>:

単純に保つために、カーネルがシステムコールの引数を扱うのと同じような構造体を使う。それらは <sys/syscallargs.h> で定義されている。

struct sys_settimeofday_args {
  syscallarg(const struct timeval *) tv;
  syscallarg(const struct timezone *) tzp;
};

struct sys_adjtime_args {
  syscallarg(const struct timeval *) delta;
  syscallarg(struct timeval *) olddelta;
};

struct sys_clock_settime_args {
  syscallarg(clockid_t) clock_id;
  syscallarg(const struct timespec *) tp;
};

syscallarg() is a macro that deals with machine-dependent alignment and endianness issues. It enables us to deal with machine-independent, system call argument structure declarations, whereas in fact these are really machine-dependent.

syscallarg() はマシン依存のアライメントを扱い、エンディアンを気にしないようにしている。マシン独立にすることによって、マシン依存の部分を気にせずシステムコールの引数として構造体を定義できるようになる。

There is a special case for ntp_adjtime, which needs to set the value returned to userland. Since ioctl(2) already uses it to indicate error conditions, it is not possible for an ioctl command to set ioctl's return value. We work around this by including the return value in the ioctl argument (this is from <sys/clockctl.h>:

ntp_adjtime はユーザーランドへ値を返すという特殊なものである。エラー状態を扱うために ioctl(2) が使われる{ あれ??? }のだが、ioctl コマンドは ioctl の戻り値を設定することは出来ない。これを回避するために ioctl 引数に戻り値を含めるようにした。<sys/clockctl.h> より:

struct clockctl_ntp_adjtime_args {
  struct sys_ntp_adjtime_args uas;
  register_t retval;
};

The sys_ntp_adjtime_args struct is defined in <sys/syscallargs.h>. The kernel uses it to store ntp_adjtime(2) arguments:

sys_ntp_adjtime_args 構造体は <sys/syscallargs.h> で定義されている。カーネルは store ntp_adjtime(2) 引数を格納するために使う。

struct sys_ntp_gettime_args {
  syscallarg(struct ntptimeval *) ntvp;
};

Now that we have a precise idea of how the alternate entry points to the time-related kernel functions are made, let us move to kernel changes.

time-related kernel functions { ????????? } についてのエントリーポイントについて把握できたので、カーネルを変更しよう。

Kernel Changes: clockctl Device Driver Implementation ( カーネルの変更: clockctl デバイスドライバー実装 )

The clockctl device driver is a plain pseudodevice driver. There is some psuedodevice documentation explaining how to introduce such a driver into the NetBSD kernel. Since the kernel registration process is well described in the document, I will not cover it here. Let us focus on the driver structure itself. It can be found within the NetBSD sources in src/sys/dev/clockctl.c.

clockctl デバイスドライバーは疑似デバイスのドライバーである。疑似デバイスの文書には、NetBSD カーネルのデバイスドライバーの導入を説明したものがいくつかある。カーネルに慣れるにはこの文書はよいものなのだが、ここでは扱わない。clockctl ドライバーの構造体について注目しよう。NetBSD ソースの src/sys/dev/clockctl.c にある。

Each driver provides a set of functions, known as methods. The kernel calls the driver methods to execute operations such as open, read, write, ioctl, and so on. In NetBSD, the method names must be the name of actual operation prefixed with the driver name. For clockctl, we have clockctlopen(), clockctlread(), and so on.

各ドライバーは見慣れた関数群を提供する。カーネルは open、read、write、ioctl といったドライバー関数を呼び出す。NetBSD では、これらの関数はドライバーの接頭字がついた名前になる。clockctl では clockctlopen()、clockctlread() といったものだ。

When the user does an open(2) system call on the clockctl device file, the kernel will use the device major number to identify that the operation must be serviced by the clockctl driver. For character devices such as clockctl, this is done by reading the cdevsw array, which is defined in a machine-dependent file. (Unfortunately, driver major numbers are not unified on different NetBSD ports.) For the i386 port, the array is defined in src/sys/arch/i386/conf/majors.i386.

ユーザーが clockctl デバイスファイルにたいして open(2) システムコールを実行すると、clockctl ドライバーが操作するための識別子としてデバイスメジャー番号が使われる。clockctl のようなキャラクターデバイスは、cdevsw 配列(マシン依存のファイルで定義されている)の読み込みで完了する ( 残念ながらドライバーメジャー番号は NetBSD ポートで統一されていない )。i386 ポートでは、この配列は src/sys/arch/i386/conf/majors.i386 で定義されている。

Once the kernel knows which driver is to service the open request, it just calls the driver's open method. For read, write, ioctl, poll, and other operations, the process is the same. The actual code path is a bit complicated, because there are two abstraction layers before reaching the driver methods: the first makes any object appear to be a file to userland (this is done with struct file, defined in <sys/file.h>), and the second, known as the Virtual File System or VFS, enables the transparent use of different filesystem types (this is done using struct vnode, as defined in <sys/vnode.h>). An in-depth explanation of what happens exactly is out of the scope of this article, but it might pop up in an upcoming part of my series on IRIX binary compatibility on NetBSD.

カーネルは、ドライバーから open リクエストが来ると、ドライバーの open 関数を呼び出すだけである。read、write、ioctl、poll や他の操作についても同様である。ドライバーの関数へ辿りつくまでに 2 つの抽象化された階層があるので、コードの経路は割りと複雑である。最初の階層は、ユーザーランドにオブジェクトをファイルとして見せるためのものである( これには <sys/file.h> で定義された構造体を使う )。次の階層は、the Virtual File System や VFS として呼ばれ、異なるファイルシステム間を行き来できるようにする( これには <sys/vnode.h> で定義された vnode 構造体を使う )。これ以上深追いするのはこの文書の範囲を超えるのだが、NetBSD での IRIX バイナリ互換についての連載で取り扱うとする。

For clockctl, most methods are meaningless; only ioctl actually contains more than just return 0;. The ioctl method understands four commands, which we described in the section about libc.

clockctl のほとんどの関数は意味がない。ioctl だけがたんに 0 を返すだけではない処理をおこなう。ioctl 関数は先の章の libc で定義した 4 つの関数について知らない。この章では libc について説明する。

The job of the driver is really simple. A code snippet might say more than an explanation:

ドライバーの仕事はじつに簡単だ。以下のコード断片を見ていこう。

case CLOCKCTL_SETTIMEOFDAY: {
  struct sys_settimeofday_args *args = (struct sys_settimeofday_args *)data;

  error = settimeofday1(SCARG(args, tv), SCARG(args, tzp), p);
  if (error)
    return (error);
  break;
}

SCARG() is another macro which deals with machine-dependent differences in the way system call arguments are structured. The clockctl driver just calls the function the settimeofday(2) system call normally would have called. The only difference is that clockctl does not check if the user is root, since the permissions are enforced at the filesystem level. To request this ioctl(2) command, you must have opened /dev/clockctl for writing.

SCARG() はシステムコールの引数の構造体について、マシン依存の差異を吸収するマクロである。clockctl ドライバーはただ settimeofday(2) システムコールを呼んでいるだけである。唯一の差異は{ なにとの差異だって???? }、clockctl はユーザーが root かどうかチェックしていないことだ。root パーミッションンはファイルシステムレベルで強制される。ioctl(2) コマンドの request は、オープン済みの /dev/clockctl に書き込めなくてはならない。

Userland Modification: ntpd (ユーザーランドの変更: ntpd)

As we said, we wanted to make as few modifications to ntpd as possible. This goal was achieved, since we only added command-line options to specify the UID/GID to run the process as, and the directory to chroot to after initialization, using the following two new flags: ntpd [-u user[:group]] [-i /path/to/jail].

前述したように、ntpd を少々変更しておきたい。最終的にはコマンドラインにオプションンを追加して、UID/GiD を指定してプロセスを実行できるようにし、初期化後に chroot するディレクトリを変更できるようにする。そのために 2 つのフラグを追加する: ntpd [-u user[:group]] [-i /path/to/jail]

There is very little to tell about these changes. There are probably some OSes with ACLified system calls where it was already possible for a non-root user to set the time. Therefore the changes are not really NetBSD-specific. This is why they have been sent to the NTP team in order to be included in the next NTP release. Propagating this change to the NTP team also ensures that the -i and -u flags will not be used for something else in the future. Having to face a conflict between new ntpd flags from the NTP distribution and the NetBSD locally-patched ntpd would be quite uncomfortable.

これらの変更についてはあまり語ることはない。おそらくいくつかの OS では ACLified な{ ACL された、ということ???? }システムコールで非 root ユーザーが時刻を設定できるようになっている。よって、この変更は本当は NetBSD には合わない。次の NTP のリリースに含めてくれるように NTP チームには投げておいた。NTP チームが -i と -u フラグを実装してくれるまでは当面フラグを使用できない。NTP 配布物との間に競合が発生してしまうし、NetBSD 用 ntpd パッチはじつに気持ち悪い。

Conclusions (最後に)

This work enables ntpd to be chrooted. The method we chose to do this is not perfect. One could argue (and in fact some have) that it is bad to introduce magic into libc. The best solution to chroot ntpd would indeed be to introduce capabilities, which are kind of ACLified system calls. Some Linux distributions now ship a ntpd daemon running under a non-root UID, and they do this using capabilities. This is a much better approach.

ここでは ntpd を chroot させてみた。この手段は完璧とはいえない。検討事項が 1 つある( 本当はもう少しあるけど )。それは ilbc の魔術に頼っていることだ。ntpd を chroot させる最良の手段は、ACL されたシステムコールを使用することだ。いくつかの Linux ディストリビューションでは ACL なシステムコールによって非 root UID のもとで ntpd デーモンを走らせている。これがもっとも最良なのだ。

However, capabilities alone are a huge project. TrustedBSD is a subproject of FreeBSD that is aimed toward the implementation of filesystem access lists, capabilities, and other security features. The project was started years ago and is not finished yet. On NetBSD, nobody is working on capabilities, and in fact, people are waiting for TrustedBSD to settle before importing some code. It could be a very long time before NetBSD would have capabilities available. In the meantime, clockctl appears to be a good solution for chrooting any time-related daemon.

しかし、これをやるには大規模なプロジェクトになる。TrustedBSD という FreeBSD のサブプロジェクトは、ファイルシステムアクセスリストと、いくつかのセキュリティ機能に狙いを絞ったものである。プロジェクトは数年前に開始されたが、まだ完了していない。NetBSD ではこれについて誰も作業していない。というか TrustedBSD の実装を盛り込むことを考えている。NetBSD でこの機能が使えるようになるのはだいぶ先になるだろう。それまでの間は時刻関連のデーモンを chroot させるのは clockctl でおこなうのが妥当である。

The advantages of clockctl are simplicity and the fact that we do not modify any existing APIs. The ntpd modifications are only about chrooting, not about the way time is controlled. The day we want to replace clockctl by capabilities, there is nothing to change in ntpd; it will work immediately.

clockctl のよいところは、簡単で、既存の API を変更しなくて済むというところだ。ntpd への変更は、chroot に限ったものだけだし、時刻制御の部分については手をつけていない。clockctl を置き換えたことにより ntpd を変更せずに済んだ。これはすぐに動作するはずだ。

Finally, it is worth mentioning orthogonal efforts to improve general daemon security. systrace was introduced by Matthieu Herrb and Niels Provos from the OpenBSD project, and was integrated into NetBSD by Christos Zoulas. It is now maintained by Niels Provos, who joined the NetBSD team in the meantime. systrace enables the system administrator to write a list of allowed system calls for a given daemon. The kernel will ensure the daemon does not do any other operations. That way, if the daemon gets compromised, it will not be able to execute things like system("/bin/sh"), even if it runs as root.

最後に、一般的にデーモンのセキュリティを向上させるために真面目に取り組むことは有意義である{ ???????????? }。systrace は OpenBSD プロジェクトの Matthieu Herrb と Niels Provos によって提供され、NetBSD には Christos Zoulas が取り込んだ。現在は Niels Provos がメンテナンスしており、その間は彼は NetBSD チームに所属している。systrace は、システム管理者がシステムコールを許可するデーモンのリストを作成するときに使うツールである。カーネルはデーモンに他の操作を許可しない。デーモンに不具合があったとしても、root で起動されたデーモンが system("/bin/sh") のような処理を実行させないようにできる。

On another orthogonal direction, Jason Thorpe has made changes to NetBSD-current in order to remove the need for an executable stack. On processors that support it (which is not the case for the old 80x86), the stack can therefore be set non-executable, thus making impossible the whole class of exploits that use stack buffer overflows. The non-executable stack is not a new idea; it can be found in various OSes, but it is extermely effective at reducing security holes, at least on machines with a processor modern enough to be able to set memory as non-executable.

他の取り組みとしては、Jason Thorpe が executable stack に必要なものを NetBSD-current から削除した。executable stack に対応したプロセッサでは( 古い 80x86 以外 )、スタックを non-executable に設定することができる。これはスタックバッファオーバーフローへの攻撃を可能にしてしまう。non-executable stack は新しいアイデアではない。様々な OS で実装されており、モダンなプロセッサを使っているマシンならばメモリを non-executable に設定することは、セキュリティホールを削減するのに極めて有効である。

Acknowledgements (謝辞)

Thanks to John Klos, Simon Burge, and Christos Zoulas for reviewing this article.

この文書をレビューしてくれた John Klos、Simon Burge、そして Christos Zoulas に感謝。

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

Emmanuel Dreyfus はフランスのパリでシステム管理とネットワーク管理をしている。現在は NetBSD 開発者である。

_ chrooted ntpd in NetBSD (訳注)

ところで ntpd -i じゃイカンのかしら( ntpd - NetBSD Manual Pages )。いつ入ったオプションか分からないけど( release note 嫁 )