Linux Namespace

50
Linux Namespace @masami256

description

Namespace feature

Transcript of Linux Namespace

Page 1: Linux Namespace

Linux Namespace@masami256

Page 2: Linux Namespace

Table of Contents

• Namespace overview

• System calls

• kernel implementation

• Namespace Example

Page 3: Linux Namespace

namespace overview

Page 4: Linux Namespace

Namespace?

• リソース

• 所謂コンテナ型仮想化を実現する上で重要な機能の一つ

Page 5: Linux Namespace

Resource

• Namespaceにおけるリソース

• cpuやmemoryと言った物理的な計算資源ではない

• ホスト名、ネットワーク設定、pidなどのカーネルが扱うデータ

Page 6: Linux Namespace

Feature• プロセス間でカーネルのリソースを共有

• fork(2)の実行時は親プロセスとリソースを共有

• namespace毎に独立したリソース

• 名前空間の状態を変えるような処理を行っても別の名前空間に属するプロセスには影響は及ばない

Page 7: Linux Namespace

Namespace representation• 名前空間はファイルとしてユーザー空間から見える

• setns(2)で利用 masami@miko:~$ ls -l /proc/self/nstotal 0dr-x--x--x 2 masami masami 0 Aug 31 00:15 .dr-xr-xr-x 8 masami masami 0 Aug 31 00:15 ..lrwxrwxrwx 1 masami masami 0 Aug 31 00:15 ipc -> ipc:[4026531839]lrwxrwxrwx 1 masami masami 0 Aug 31 00:15 mnt -> mnt:[4026531840]lrwxrwxrwx 1 masami masami 0 Aug 31 00:15 net -> net:[4026531957]lrwxrwxrwx 1 masami masami 0 Aug 31 00:15 pid -> pid:[4026531836]lrwxrwxrwx 1 masami masami 0 Aug 31 00:15 user -> user:[4026531837]lrwxrwxrwx 1 masami masami 0 Aug 31 00:15 uts -> uts:[4026531838]

Page 8: Linux Namespace

Namespaces• uts

• net

• pid

• mnt

• ipc

• user

Page 9: Linux Namespace

uts namespace

• ホスト名、ドメイン名などのデータ

• カーネルバージョン等もあるが変更不可

• ゲストが自ホスト名を変えてもホストOS側には影響はでない

Page 10: Linux Namespace

net namespace• ネットワーク関連のリソース

• Network device

• IP address

• Routing table

• Filtering table

• Port number

• /proc/net

• etc…

Page 11: Linux Namespace

pid namespace

• 親プロセスとは別のpidを利用可能に

• namespace Aのpid:1000とnamespace Bのpid:1000は別の存在

• procfsを適切に分ければ他のnamespceのプロセスを参照できなくなる

Page 12: Linux Namespace

mnt namespace

• マウントしているファイルシステムを表す

• 名前空間分離時は親プロセスのmnt namespaceをコピー

• 分離後に親プロセスがusb stickなどをマウントしてもゲスト側からは見えない

Page 13: Linux Namespace

ipc namespace

• System V IPCで使用するリソースを分離

• 共有メモリ、セマフォ、メッセージキュー

Page 14: Linux Namespace

user namespace• ホストとは別のuid/gid体系を持てる

• ホストのuid/gidとゲストのuid/gidマッピングが必要

• 設定しないと65534が設定される

• groupsは65534番のgroup入りする

• 他のnamespaceと違い、独立していない

• 他のnamespace空間は個々にuser namespaceを持っている

• 各namespaceのコピー処理関数はuser nsを受け取るのでget_user_ns()で参照カウントを増やしている

Page 15: Linux Namespace

uid/gid mapping

• マッピングを行うシステムコールは無い

• 以下のファイルを用いてマッピングを実施

• /proc/<pid>/uid_map

• /proc/<pid>/gid_map

Page 16: Linux Namespace

uid/gid mapping• ゲストのuid0をホストのuid1000にマッピング

• gidも同様に masami@miko:~$ ./a.out -U -M '0 1000 1' -G '0 1000 1' bash root@miko:~# iduid=0(root) gid=0(root) groups=0(root),65534root@miko:~# cat /proc/self/uid_map /proc/self/gid_map 0 1000 1 0 1000 1root@miko:~# touch test.txtroot@miko:~# ls -la test.txt -rw-r--r-- 1 root root 0 Aug 31 12:00 test.txtroot@miko:~# """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""masami@miko:~$ ls -la test.txt-rw-r--r-- 1 masami masami 0 Aug 31 12:00 test.txtmasami@miko:~$

Page 17: Linux Namespace

In an user namespace

•マッピングなしでuser namespaceをunshare I have no name!@miko:/proc/640$ ls -la /usr/bin/sudo-rwsr-xr-x 1 65534 65534 142792 May 9 15:58 /usr/bin/sudo!

•通常の状態 I have no name!@miko:/proc/640$ exitlogoutmasami@miko:~$ ls -la /usr/bin/sudo-rwsr-xr-x 1 root root 142792 May 9 15:58 /usr/bin/sudo

Page 18: Linux Namespace

how to uid/gid mapping1. clone(2)を呼ぶ

1. CLONE_NEWUSERをflagsにセット

2. exec()系のシステムコールを呼ぶ前にマッピングを行う

1. /proc/<child process pid>/uid_map

2. /proc/<child process pid>/gid_map

3. exec()系の関数を呼んで新たなプログラムを実行

Page 19: Linux Namespace

system calls

Page 20: Linux Namespace

system calls

• clone(2)

• unshare(2)

• setns(2)

Page 21: Linux Namespace

clone(2) • clone(2)でpid namespaceを分離した場

• 子プロセスから見ると自分のpidは1として見える

• 親プロセスからは親プロセスのpid namespaceでのpidが振られたように見える

• clone(2)の戻り値を使ってwaitpid(2)で待つことができる

Page 22: Linux Namespace

clone(2)

CLONE_NEWUTS uts namespace

CLONE_NEWPID pid namecpace

CLONE_NEWNS mnt namespace

CLONE_NEWNET net namespace

CLONE_NEWIPC ipc namespace

CLONE_NEWUSER user namespace

clone(2)で使用するフラグはsched.hをincludeして使用できるが、 CLONE_NEWUSERは_GNU_SOURCEをdefineする必要あり

Page 23: Linux Namespace

unshare(2)• 自分を親プロセスの名前空間から分離させる

• pid namespaceは分離できない

• 一時期サポートされていたが2013/03/06から対象外になった

• pidns: Don't have unshare(CLONE_NEWPID) imply CLONE_THREAD

• https://github.com/torvalds/linux/commit/6e556ce209b09528dbf1931cbfd5d323e1345926

• unshare(1)の場合エラーにならないが何もおきない

Page 24: Linux Namespace

setns(2)• 既存の名前空間に自身を参加させる

• clone(2)、unshare(2)は親の名前空間から分離して新規の名前空間を持つようになる

• 名前空間への参加には対象の名前空間のファイルディスクリプタを使用する

• 別のpid namespaceに参加する場合、プロセス自身のpidは変わらない

• 子プロセスからpidが変わる

Page 25: Linux Namespace

kernel implementation

Page 26: Linux Namespace

kernel/nsproxy.c

• namespace共通の処理を行う

• namespaceの作成、コピーなど

• 個々のnamespaceについてはそれぞれが実施

Page 27: Linux Namespace

kernel/nsproxy.c

• 前スライドでnamespace共通と説明したけど

• user namespaceは扱っていない

• user namespaceはcred.cや個々のnamespaceが管理

Page 28: Linux Namespace

struct nsproxy• 各namespaceのデータを保持する構造体 !struct nsproxy { atomic_t count; struct uts_namespace *uts_ns; struct ipc_namespace *ipc_ns; struct mnt_namespace *mnt_ns; struct pid_namespace *pid_ns_for_children; struct net *net_ns;};

•user namespaceはstruct credにて管理

•struct task_structのreal_creadからuser namespaceを参照

Page 29: Linux Namespace

common namespace structure

• 各namespaceは以下の変数を必ず持つ

• 参照カウンタ

• procfsのinode番号

• user namespace

• user namespaceの場合は親プロセスへのポインタ

Page 30: Linux Namespace

init_nsproxy

• 最初のプロセスに設定されるnsproxy構造体

• これ以降はfork系関数の呼び出し時にこの構造体の参照カウンタをインクリメント

• namespaceを分けない場合:)

Page 31: Linux Namespace

struct nsproxy• mount namespace以外はビルド時に設定 struct nsproxy init_nsproxy = { .count = ATOMIC_INIT(1), .uts_ns = &init_uts_ns,#if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC) .ipc_ns = &init_ipc_ns,#endif .mnt_ns = NULL, .pid_ns_for_children = &init_pid_ns,#ifdef CONFIG_NET .net_ns = &init_net,#endif};

Page 32: Linux Namespace

Initialize mnt_ns

•init_mount_tree()からが実際の処理 start_kernel() @init/main.c --> vfs_caches_init() @fs/dcache.c --> mnt_init() @fs/namespace.c --> init_mount_tree() @fs/namespace.c --> create_mnt_ns() @fs/namespace.c

Page 33: Linux Namespace

Initialize user_ns

• user_nsはstruct credのデータ初期化時に設定 struct cred init_cred = { .usage = ATOMIC_INIT(4),~略~ .cap_bset = CAP_FULL_SET, .user = INIT_USER, .user_ns = &init_user_ns,

Page 34: Linux Namespace

copy_namespace()• int copy_namespaces(unsigned long flags, struct task_struct *tsk)

• copy_process()より呼ばれる

• flagにCLONE_NEWXXXがセットされていなければカレントプロセスのnsproxy構造体の参照カウンタを+1

• そうでなければcreate_new_namespace()で該当するnamespaceを作成する

Page 35: Linux Namespace

switch_task_namespace()• void switch_task_namespaces(struct task_struct *tsk, struct nsproxy *new)

• カレントプロセスの名前空間切り替えを行う

• unshare(2)で使用

• プロセスのexit()時にも使用

• 切り替え先のnamespaceにNULLを設定

Page 36: Linux Namespace

switch_task_namespace

• namespaceを切り替えた結果、切り替え前のnamespaceを参照するプロセスがいなくなった場合

• free_nsproxy()を呼んでnamespaceを解放

Page 37: Linux Namespace

free_nsproxy()• void free_nsproxy(struct nsproxy *ns)

• namespaceの解放

• 各namespaceの参照カウンタをデクリメント

• nsproxy構造体のインスタンス解放

• 通常はプロセスのexit時に実行される

Page 38: Linux Namespace

unshare_nsproxy_namespace()

• int unshare_nsproxy_namespaces(unsigned long unshare_flags, struct nsproxy **new_nsp, struct cred *new_cred, struct fs_struct *new_fs)

• unshare(2)の実行時に呼ばれる

• create_new_namespace()で名前空間を新規に作成

Page 39: Linux Namespace

procfs operations• namaspaceはprocfsで表現されるのでこれらを操作する関数を登録

• setns(2)が使うのがこれら

• 各namespace毎に登録 struct proc_ns_operations { const char *name; int type; void *(*get)(struct task_struct *task); void (*put)(void *ns); int (*install)(struct nsproxy *nsproxy, void *ns); unsigned int (*inum)(void *ns);};

Page 40: Linux Namespace

procfs operations• get()

• 対象namespaceの参照カウンタを+1

• put()

• 対象namespaceの参照カウンタを-1

• install()

• 現在のnamespaceの参照カウンタを-1し、新しいnamespaceをnsproxy構造体にセット

• inum()

• namespaceのinode番号を返す

Page 41: Linux Namespace

clone()• namespaceの操作と言ってもclone()固有で何かがあるわけでは無い

• copy_process()から以下の関数を呼ぶ

• copy_creds()

• user_nsのコピー/新規作成

• copy_namespace()

• 既存の各namespaceのコピー/新規作成

Page 42: Linux Namespace

setns()1.入りたいnamespaceのfile構造体からinodeを取得し、該当namespaceのproc_ns_operations構造体取得

2.create_new_namespace()でnsproxyの作成

•  flagsには0を渡すので既存のnamespaceの参照カウンタが増えるだけ

3.proc_ns_operations構造体のinstall()を呼んでnsproxyに対象のnamespaceを設定

4.switch_task_namespaces()でnamespaceの切り替えを実施

Page 43: Linux Namespace

unshare()1.unshareするnamespaceの取得

2.ファイルシステムのunshare

3. currentタスクのfs_struct構造体がコピーされる

4.ファイルディスクリプタのコピー

• 開いているファイルディスクリプタをdup_fd()でコピー

5.user namespaceの分離

• CLONE_NEWUSERがセットされていなければ何もしない

Page 44: Linux Namespace

unshare()!

6.unshare_nsproxy_namespaces()でその他namespaceの分離

• 実際の処理はcreate_new_namespaces()で実施

7.上記までの操作で何かしら実行が行われた場合は以下の処理を実施

• namepace(nsproxy)の変更があった場合はswitch_task_namespaces()で切り替え

• fs_structをコピーした場合はcurrentタスクのfs_struct構造体切り替え

8. ファイルディスクリプタをコピーした場合はcurrentタスクのファイルディスクリプタ切り替え

9. user_nsのunshareをした場合はstruct credの切り替え

Page 45: Linux Namespace

Namespace Example

• Namespace機能でどのように変わったか

Page 46: Linux Namespace

getpid() - 2.4.37

• task_struct構造体のメンバ変数(pid)をそのまま返却可能

#define getpid() (current->pid)

Page 47: Linux Namespace

getpid() - 3.16•プロセスが所属しているpid namespaceのpidを返す必要がある

getpid() -> task_tgid_vnr() -> task_tgid() -> pid_vnr() -> task_active_pid_ns() -> task_pid() -> ns_of_pid() -> pid_nr_ns()

Page 48: Linux Namespace

chown() - 2.4.37static int chown_common(struct dentry * dentry, uid_t user, gid_t group){~中略~ if (user == (uid_t) -1) user = inode->i_uid; if (group == (gid_t) -1) group = inode->i_gid; newattrs.ia_mode = inode->i_mode; newattrs.ia_uid = user; newattrs.ia_gid = group;

Page 49: Linux Namespace

chown() - 3.16static int chown_common(struct path *path, uid_t user, gid_t group){~中略~ uid = make_kuid(current_user_ns(), user); gid = make_kgid(current_user_ns(), group);! newattrs.ia_valid = ATTR_CTIME; if (user != (uid_t) -1) { if (!uid_valid(uid)) return -EINVAL; newattrs.ia_valid |= ATTR_UID; newattrs.ia_uid = uid; } if (group != (gid_t) -1) { if (!gid_valid(gid)) return -EINVAL; newattrs.ia_valid |= ATTR_GID; newattrs.ia_gid = gid; }

Page 50: Linux Namespace

Reference• LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術

• http://gihyo.jp/admin/serial/01/linux_containers

• Namespaces in Operation series

• http://lwn.net/Articles/531114/#series_index

• Professional Linux Kernel Architecture

• http://www.amazon.co.jp/dp/B004T6ICZ6