前回で 3.9 kernel での準備が出来たので,今回は少しだけユーザ名前空間を体験してみました.
なお,今回の評価はもうすぐ新しいバージョン 5.1 がリリース予定の Plamo Linux 5.1beta1 相当の環境上で行っています(宣伝).ここに自前でビルドした 3.9 カーネルと,util-linux の現時点の最新版である 2.23 をインストールしています.
ユーザ名前空間の体験は
が参考になります.というか今回のエントリはここに書いてある事を実行しているだけです.(^_^;) 最初の方に書いてある Ubuntu を使っての ppa からの色々なインストールはうまく行かないものがありました
まずはここにある nsexec というツール群を取得します.これは make を実行すればコンパイルは完了です.
usernsselfmap コマンドの処理
コンパイルが完了したところでまずは上記ページにあるように "usernsselfmap" コマンドを実行します.
- このコマンドは実行すると新しいユーザ名前空間を作成し,名前空間内で uid と gid を 0 にします.
- この uid/gid は,元の名前空間では実行したユーザの uid/gid にマッピングされています (マッピングについては第1回を参照してください).
このプログラムは非常に単純なものです.
int main(int argc, char *argv[]) { char *args[] = { "/bin/bash", NULL }; int ret; int origuid = getuid(); int origgid = getgid(); ret = unshare(CLONE_NEWUSER); ret = writemaps(getpid(), origuid, origgid); if (ret < 0) { printf("Error writing maps\n"); exit(1); } if (ret < 0) { perror("unshare"); exit(1); } ret = setgid(0); if (ret < 0) perror("setgid"); ret = setuid(0); if (ret < 0) perror("setuid"); ret = setgroups(0, NULL); if (ret < 0) perror("setgroups"); printf("execing bash (I am now %d %d)\n", getuid(), getgid()); execv(args[0], args); exit(1); }
この手のプログラミング知識のない私でも一瞬で分かる程度に簡単なコードです.(ソースのインデントがぐちゃぐちゃで見にくい...)
ユーザ名前空間の作成
さて,何をやるコマンドか把握できたところで実行してみます.
- まずは現在の id を確認します.uid/gid = 1000/100 のユーザです.
karma@plamo50:~/src/nsexec/nsexec$ id
uid=1000(karma) gid=100(users) groups=100(users),26(audio),28(dialout),29(video),32(cdrom),38(pulse),39(pulse-access),44(mlocate),1000(sudo) - usernsselfmap 実行
karma@plamo50:~/src/nsexec/nsexec$ ./usernsselfmap
starting from uid 1000 gid 100
setuid: Success
execing bash (I am now 0 0) - 新しいユーザ名前空間で bash が実行されていますので,現在の uid/gid を確認しておきます.root ユーザになっています.
root@plamo50:~/src/nsexec/nsexec# id
uid=0(root) gid=0(root) groups=0(root),65534(nogroup) - uid_map, gid_map を確認してみます.uid/gid=1000/100 を 0/0 へマッピングしています
root@plamo50:~/src/nsexec/nsexec# echo $$
7771
root@plamo50:~/src/nsexec/nsexec# cat /proc/7771/uid_map
0 1000 1
root@plamo50:~/src/nsexec/nsexec# cat /proc/7771/gid_map
0 100 1 - ファイルを作成してみます.当たり前ですが,所有者が root のファイルが出来上がります
root@plamo50:~/src/nsexec/nsexec# touch test
root@plamo50:~/src/nsexec/nsexec# ls -l test
-rw-r--r-- 1 root root 0 5月 8日 19:10 test
さて,上記で作ったファイルを元の名前空間で見てみるとどうなっているでしょうか.皆さんの予想通り
karma@plamo50:~/src/nsexec/nsexec$ ls -l test -rw-r--r-- 1 karma users 0 5月 8日 19:10 test
元の uid/gid の所有になっています.
ユーザ名前空間の確認
上記でファイルの作成を試しましたが,ここではユーザ名前空間の効果がはっきり分かる実験をしてみます.これも先に紹介したブログにありますけど...
- 作成したユーザ名前空間内でネットワークインターフェースを確認します.ネットワーク名前空間の作成は行っていないので,ここでは元のコンテキストと同じなので,usernsselfmap 実行前と同じインターフェースが見えます.
root@plamo50:~/src/nsexec/nsexec# /sbin/ifconfig
eth0 Link encap:Ethernet HWaddr 52:54:00:59:7f:7e
inet addr:192.168.122.149 Bcast:192.168.122.255 Mask:255.255.255.0
inet6 addr: fe80::5054:ff:fe59:7f7e/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:7631 errors:0 dropped:19 overruns:0 frame:0
TX packets:2947 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3682267 (3.5 MiB) TX bytes:367002 (358.4 KiB)
: (snip) - root であることを確認した後に ifconfig down を実行してみます.
root@plamo50:~/src/nsexec/nsexec# id
root なのに許可されていない操作でエラーになっています :-)
uid=0(root) gid=0(root) groups=0(root),65534(nogroup)
root@plamo50:~/src/nsexec/nsexec# /sbin/ifconfig eth0 down
SIOCSIFFLAGS: 許可されていない操作です
以上でユーザ名前空間の実験は終わりですが,先のブログエントリの実行例にあったように作成したユーザ名前空間で更にネットワーク名前空間とマウント名前空間を作成してみました.
ネットワーク名前空間の作成
この作成には util-linux に含まれている unshare コマンドを使ってみました (使い方は man 1 unshare 参照).元のブログにあるように実験用に取得した nsexec でも同じような事ができるので OK です (nsexec -h で使い方でます).
作成したユーザ名前空間内で新しくネットワーク名前空間を作成して bash を実行しています.
karma@plamo50:~/src/nsexec/nsexec$ ./usernsselfmap starting from uid 1000 gid 100 setuid: Success execing bash (I am now 0 0) root@plamo50:~/src/nsexec/nsexec# echo $$ 7803 root@plamo50:~/src/nsexec/nsexec# unshare -n /bin/bash root@plamo50:~/src/nsexec/nsexec# echo $$ 7907 root@plamo50:~/src/nsexec/nsexec# ls -l /proc/7803/ns 合計 0 lrwxrwxrwx 1 root root 0 5月 8日 19:27 ipc -> ipc:[4026531839] lrwxrwxrwx 1 root root 0 5月 8日 19:27 mnt -> mnt:[4026531840] lrwxrwxrwx 1 root root 0 5月 8日 19:27 net -> net:[4026531955] lrwxrwxrwx 1 root root 0 5月 8日 19:27 pid -> pid:[4026531836] lrwxrwxrwx 1 root root 0 5月 8日 19:27 user -> user:[4026532162] lrwxrwxrwx 1 root root 0 5月 8日 19:27 uts -> uts:[4026531838] root@plamo50:~/src/nsexec/nsexec# ls -l /proc/7907/ns 合計 0 lrwxrwxrwx 1 root root 0 5月 8日 19:32 ipc -> ipc:[4026531839] lrwxrwxrwx 1 root root 0 5月 8日 19:32 mnt -> mnt:[4026531840] lrwxrwxrwx 1 root root 0 5月 8日 19:32 net -> net:[4026532164] lrwxrwxrwx 1 root root 0 5月 8日 19:32 pid -> pid:[4026531836] lrwxrwxrwx 1 root root 0 5月 8日 19:32 user -> user:[4026532162] lrwxrwxrwx 1 root root 0 5月 8日 19:32 uts -> uts:[4026531838]
名前空間ファイルを見てみると net だけ別の名前空間にいることがわかります.ここで ifconfig を実行するとインターフェースは存在しません.新しいネットワーク名前空間なので当然です.
root@plamo50:~/src/nsexec/nsexec# /sbin/ifconfig
このユーザ名前空間内では root 権限ですから,新しく作ったネットワーク名前空間でインターフェースの操作は可能なはずです.ここで veth を作ってアドレスを割り当ててみます.
root@plamo50:~/src/nsexec/nsexec# /sbin/ip link add type veth root@plamo50:~/src/nsexec/nsexec# /sbin/ip link show 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000 link/ether 2e:af:82:91:91:e6 brd ff:ff:ff:ff:ff:ff 3: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000 link/ether be:a9:a9:2d:1e:19 brd ff:ff:ff:ff:ff:ff root@plamo50:~/src/nsexec/nsexec# /sbin/ifconfig veth0 10.10.10.10 up root@plamo50:~/src/nsexec/nsexec# /sbin/ifconfig veth0 Link encap:Ethernet HWaddr 2e:af:82:91:91:e6 inet addr:10.10.10.10 Bcast:10.255.255.255 Mask:255.0.0.0 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
この時,元の名前空間上ではインターフェースを見ると
root@plamo50:/home/karma/src/nsexec/nsexec# ifconfig | grep "Link encap" eth0 Link encap:Ethernet HWaddr 52:54:00:59:7f:7e lo Link encap:Local Loopback lxcbr0 Link encap:Ethernet HWaddr 36:da:e3:2f:6f:c8
となっており,当然ですが新しく作ったネットワーク名前空間のインターフェースは見えません.
マウント名前空間
同じようなことをマウント名前空間で試してみます.新しく作成したユーザ名前空間は,元の名前空間上では uid/gid = 1000/100 ですから,名前空間では uid/gid=0/0 の root ユーザでも /root ディレクトリ内を見ることはできません.
root@plamo50:~/src/nsexec/nsexec# id uid=0(root) gid=0(root) groups=0(root),65534(nogroup) root@plamo50:~/src/nsexec/nsexec# ls /root ls: ディレクトリ /root を開くことが出来ません: 許可がありません
ここで新たにマウント名前空間を作成して,以下のようなことをしてみると,元のユーザ (uid/gid = 1000/100) のホームディレクトリの内容が /root として見えます.
root@plamo50:~/src/nsexec/nsexec# unshare -m /bin/bash root@plamo50:~/src/nsexec/nsexec# mount --bind $HOME /root root@plamo50:~/src/nsexec/nsexec# ls /root (元のユーザの $HOME の内容が表示される)