名前
unshare -
プロセス実行コンテキストの一部を分離する
書式
#define _GNU_SOURCE
#include <sched.h>
int unshare(int flags);
説明
unshare()
を使うと、プロセス
(やスレッド)
は他のプロセス
(やスレッド)
と現在共有している
実行コンテキストの一部を分離することができる。
実行コンテキストの一部、たとえばマウント名前空間
(mount namespace)
などは、新しいプロセスを
fork(2) または vfork(2)
を使って生成したときに、暗黙のうちに共有される。
一方、仮想メモリーなどは、
clone(2)
を使ってプロセスやスレッドを生成するときに、明示的に共有することを要求できる。
unshare()
の主な利用法は、プロセスが新しいプロセスを生成することなく、
共有実行コンテキストを制御することである。
flags
引数はビットマスクであり、
実行コンテキストのどの部分の共有を解除するかを表す。
この引数は、以下の定数の
0 個以上の OR
で指定する:
- CLONE_FILES
- clone(2) CLONE_FILES
フラグの効果を取り消す。
ファイルディスクリプターテーブルを共有させず、
呼び出し元プロセスは他のプロセスとファイルディスクリプターを共有しなくなる。
- CLONE_FS
- clone(2) CLONE_FS
フラグの効果を取り消す。ファイルシステム属性を共有させず、呼び出し元プロセスは、ルートディレクトリ
(chroot(2))、カレントディレクトリ
(chdir(2))、 umask (umask(2))
を他のプロセスと共有しなくなる。
- CLONE_NEWCGROUP
(Linux 4.6 以降)
- This flag has the same effect as the clone(2)
CLONE_NEWCGROUP flag. Unshare the cgroup namespace. Use of
CLONE_NEWCGROUP requires the CAP_SYS_ADMIN capability.
- CLONE_NEWIPC
(Linux 2.6.19 以降)
- このフラグは clone(2)
CLONE_NEWIPC
フラグと同じ効果を持つ。
IPC
名前空間を共有せず、呼び出し元プロセスは
他のプロセスとは共有しない固有の
IPC
名前空間のコピーを持つ。
このフラグを指定すると、
CLONE_SYSVSEM
も暗黙のうちに指定される。
CLONE_NEWIPC
を使用するには
CAP_SYS_ADMIN
ケーパビリティが必要である。
- CLONE_NEWNET
(Linux 2.6.24 以降)
- このフラグは clone(2)
CLONE_NEWNET
フラグと同じ効果を持つ。ネット
ワーク名前空間を共有せず、呼び出し元プロセスは他のプロセスとは共有しな
い固有のネットワーク名前空間のコピーを持つ。CLONE_NEWNET
を使用する には
CAP_SYS_ADMIN
ケーパビリティが必要である。
- CLONE_NEWNS
- このフラグは clone(2)
CLONE_NEWNS
フラグと同じ効果を持つ。
マウント名前空間を共有せず、呼び出し元プロセスは
他のプロセスとは共有しない固有の名前空間のコピーを持つ。
このフラグを指定すると、
CLONE_FS
も暗黙のうちに指定される。
CLONE_NEWNS
を使用するには
CAP_SYS_ADMIN
ケーパビリティが必要である。詳細は
mount_namespaces(7) を参照。
- CLONE_NEWPID
(Linux 3.8 以降)
- このフラグは clone(2)
CLONE_NEWPID
フラグと同じ効果を持つ。
PID
名前空間を共有しない。
呼び出し元プロセスは、
すでに存在するどのプロセスとも共有されない新しい
PID 名前空間を、
自身の子プロセス用に持つことになる。
このプロセスにより作成される最初の子プロセスはプロセス
ID 1 を持ち、
この新しい名前空間において
init(1)
の役割を持つとみなされる。
CLONE_NEWPID
を指定すると、自動的に
CLONE_THREAD
も指定されたものとみなされる。
CLONE_NEWPID
を使用するには
CAP_SYS_ADMIN
ケーパビリティが必要である。
詳細な情報は pid_namespaces(7)
を参照。
- CLONE_NEWTIME
(Linux 5.6 以降)
- Unshare the time namespace, so that the calling process has a new time
namespace for its children which is not shared with any previously
existing process. The calling process is not moved into the new
namespace. Use of CLONE_NEWTIME requires the CAP_SYS_ADMIN
capability. For further information, see time_namespaces(7).
- CLONE_NEWUSER
(Linux 3.8 以降)
- このフラグは clone(2)
CLONE_NEWUSER
フラグと同じ効果を持つ。
ユーザー名前空間を共有せず、
呼び出し元プロセスはすでに存在するどのプロセスとも共有されない新しいユーザー名前空間に移動される。
CLONE_NEWUSER
フラグを指定して
clone(2)
で作成された子プロセスと同様に、
呼び出し元は新しい名前空間ですべてのケーパビリティを獲得する。
- CLONE_NEWUSER
を使うには、呼び出し元プロセスがスレッド化されていないことが必要である。
CLONE_NEWUSER
を指定すると、自動的に
CLONE_THREAD
が指定されたものとみなされる。
Linux 3.9 以降では、 CLONE_NEWUSER
が指定された場合
CLONE_FS
も指定されたとみなされる。
CLONE_NEWUSER
を使うには、呼び出し元プロセスのユーザー
ID とグループ ID が、
呼び出した時点で、
呼び出し元プロセスのユーザー名前空間のユーザー
ID とグループ ID
にマッピングされている必要がある。
- ユーザー名前空間の詳細は
user_namespaces(7) を参照。
- CLONE_NEWUTS
(Linux 2.6.19 以降)
- このフラグは clone(2)
CLONE_NEWUTS
フラグと同じ効果を持つ。
UTS IPC
名前空間を共有せず、呼び出し元プロセスは他のプロセスとは共有しない
固有の UTS IPC
名前空間のコピーを持つ。
このフラグを指定すると、
CLONE_FS
も暗黙のうちに指定される。CLONE_NEWUTS
を使用するには
CAP_SYS_ADMIN
ケーパビリティが必要である。
- CLONE_SYSVSEM
(Linux 2.6.26 以降)
- このフラグは clone(2)
CLONE_SYSVSEM
フラグの効果を逆転させる。
System V
セマフォの調整値
(semadj) を共有せず、
呼び出し元プロセスは他のプロセスとは共有されない新しい空の
semadj リストを持つ。
そのプロセスが、自分の現在の
semadj
リストへの参照を持つ最後のプロセスであれば、
このリストの調整値は対応するセマフォに適用される
(semop(2)
に説明がある通り)。
上記に加えて、
呼び出し元がシングルスレッドの場合
(すなわち別のプロセスやスレッドとアドレス空間を共有していない場合)、
CLONE_THREAD, CLONE_SIGHAND, CLONE_VM
を指定することができる。
この場合、
これらのフラグは効果を持たない。
(CLONE_THREAD
を指定すると自動的に
CLONE_VM
が指定されたとみなされ、
CLONE_VM
を指定すると自動的に
CLONE_SIGHAND
が指定されたとみなされる点に注意してほしい。)
プロセスがマルチスレッドの場合、
これらのフラグを使用するとエラーとなる。
flags に 0
が指定された場合、
unshare()
は何も行わないので、
呼び出し元プロセスの実行コンテキストは、何も変更されない。
返り値
成功した場合は 0
が返される。
失敗した場合は -1
が返されて、 errno
にはエラーを示す値が設定される。
エラー
- EINVAL
- flags
に不正なビットが指定された。
- EINVAL
- CLONE_THREAD, CLONE_SIGHAND, CLONE_VM が
flags
に指定されたが、
呼び出したプロセスはマルチスレッドである。
- EINVAL
- flags に CLONE_NEWIPC
が指定されたが、カーネルでオプション
CONFIG_SYSVIPC と CONFIG_IPC_NS
が有効になっていなかった。
- EINVAL
- flags に CLONE_NEWNET
が指定されたが、カーネルでオプション
CONFIG_NET_NS
が有効になっていなかった。
- EINVAL
- flags に CLONE_NEWPID
が指定されたが、カーネルでオプション
CONFIG_PID_NS
が有効になっていなかった。
- EINVAL
- flags に CLONE_NEWUSER
が指定されたが、カーネルでオプション
CONFIG_USER_NS
が有効になっていなかった。
- EINVAL
- flags に CLONE_NEWUTS
が指定されたが、カーネルでオプション
CONFIG_UTS_NS
が有効になっていなかった。
- EINVAL
- CLONE_NEWPID was specified in flags, but the process has
previously called unshare() with the CLONE_NEWPID flag.
- ENOMEM
- 呼び出し元のコンテキストのうち共有を解除する必要がある部分をコピーするために、
十分なメモリーが確保できなかった。
- ENOSPC (Linux 3.7
以降)
- CLONE_NEWPID was specified in flags, but the limit on the nesting
depth of PID namespaces would have been exceeded; see
pid_namespaces(7).
- ENOSPC (Linux
4.9 以降; 以前は EUSERS)
- CLONE_NEWUSER が flags
に指定されており、
この呼び出しによりネストされたユーザー名前空間数の上限を超えてしまう。
user_namespaces(7) を参照。
- From Linux 3.11 to Linux 4.8, the error diagnosed in this case was
EUSERS.
- ENOSPC (Linux
4.9 以降)
- One of the values in flags specified the creation of a new user
namespace, but doing so would have caused the limit defined by the
corresponding file in /proc/sys/user to be exceeded. For further
details, see namespaces(7).
- EPERM
- 呼び出し元プロセスはこの操作を行うのに必要な特権を持っていなかった。
- EPERM
- CLONE_NEWUSER が flags
に指定されたが、
呼び出し元の実効ユーザー
ID
もしくは実効グループ
ID
が親名前空間にマッピングがない
(user_namespaces(7) 参照)。
- EPERM (Linux 3.9
以降)
- CLONE_NEWUSER が flags
に指定され、
呼び出し元が chroot
された環境にいる
(すなわち、呼び出し元の
root
ディレクトリが呼び出し元が属するマウント名前空間の
root
ディレクトリに一致しない)。
-
EUSERS (from Linux 3.11 to Linux 4.8)
- CLONE_NEWUSER was specified in flags, and the limit on the
number of nested user namespaces would be exceeded. See the discussion of
the ENOSPC error above.
バージョン
unshare()
システムコールは Linux
カーネル 2.6.16
で追加された。
準拠
unshare()
システムコールは Linux
固有である。
注意
clone(2)
で新しいプロセスを生成したときに共有される全てのプロセス属性を、
unshare()
によって共有の解除ができるわけではない。
特に、カーネル 3.8
時点では、 unshare() に
CLONE_SIGHAND, CLONE_THREAD, CLONE_VM
の効果を取り消すためのフラグが実装されていない。
これらの機能は、必要であれば将来追加されるかもしれない。
例
以下のプログラムは
unshare(1)
コマンドの簡単な実装である。
このコマンドは、1
つ以上の名前空間の
unshare を行ってから、
コマンドライン引数で指定されたコマンドを実行する。
以下はこのプログラムの使用例である。
新しいマウント名前空間でシェルを実行し、
元のシェルと新しいシェルが別のマウント名前空間にいることを確認している。
$ readlink /proc/$$/ns/mnt
mnt:[4026531840]
$ sudo ./unshare -m /bin/bash
# readlink /proc/$$/ns/mnt
mnt:[4026532325]
2 つの readlink(1)
コマンドの出力が違うことから、
2
つのシェルは異なるマウント名前空間にいることが分かる。
プログラムのソース
/* unshare.c
A simple implementation of the unshare(1) command: unshare
namespaces and execute a command.
*/
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
/* A simple error-handling function: print an error message based
on the value in 'errno' and terminate the calling process */
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
static void
usage(char *pname)
{
fprintf(stderr, "Usage: %s [options] program [arg...]\n", pname);
fprintf(stderr, "Options can be:\n");
fprintf(stderr, " -C unshare cgroup namespace\n");
fprintf(stderr, " -i unshare IPC namespace\n");
fprintf(stderr, " -m unshare mount namespace\n");
fprintf(stderr, " -n unshare network namespace\n");
fprintf(stderr, " -p unshare PID namespace\n");
fprintf(stderr, " -t unshare time namespace\n");
fprintf(stderr, " -u unshare UTS namespace\n");
fprintf(stderr, " -U unshare user namespace\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
int flags, opt;
flags = 0;
while ((opt = getopt(argc, argv, "CimnptuU")) != -1) {
switch (opt) {
case 'C': flags |= CLONE_NEWCGROUP; break;
case 'i': flags |= CLONE_NEWIPC; break;
case 'm': flags |= CLONE_NEWNS; break;
case 'n': flags |= CLONE_NEWNET; break;
case 'p': flags |= CLONE_NEWPID; break;
case 't': flags |= CLONE_NEWTIME; break;
case 'u': flags |= CLONE_NEWUTS; break;
case 'U': flags |= CLONE_NEWUSER; break;
default: usage(argv[0]);
}
}
if (optind >= argc)
usage(argv[0]);
if (unshare(flags) == -1)
errExit("unshare");
execvp(argv[optind], &argv[optind]);
errExit("execvp");
}
この文書について
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。