⚒️

ユーザー名前空間について

2023/12/10に公開

この記事は Systemi(株式会社システムアイ) Advent Calendar 2023 の10日目の記事です。

https://qiita.com/advent-calendar/2023/systemi23

はじめに

巷でコンテナ技術について仮想化との対比で表されることが多いけど、実際どうなんだろうと思ってLinuxカーネル上での実装をみていると、ユーザー名前空間だけ異質な感じがしたので記事化をしました。

名前空間について

コンテナ技術の権限分離の機能として名前空間があります。
その名前空間として現時点(カーネル6.6.5)では以下が確認できました。

  • UTS名前空間
  • TIME名前空間
  • IPC名前空間
  • PID名前空間
  • ネットワーク名前空間
  • CGroup名前空間
  • マウント名前空間
  • ユーザー名前空間

この中のユーザー名前空間について気になったのでちょっと調べてみました。

Linuxカーネル上での実装

前述の名前空間はカーネル上ではタスク(プロセス)の1要素として定義されています。
ソース上だと以下の構造体で定義されてますね。

// nsproxy.h
struct nsproxy {
	refcount_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;
	struct time_namespace *time_ns;
	struct time_namespace *time_ns_for_children;
	struct cgroup_namespace *cgroup_ns;
};

これはプロセスの構造体task_structの一要素として定義されています。

// sched.h
struct task_struct {
	...
	/* Namespaces: */
	struct nsproxy			*nsproxy;
	...
};

nsporxyの構造体をみると先の名前空間の中でユーザー名前空間の定義がありませんでした。
実は別の仕組みで実現しているのかなとも思い、ソースを調べてみると以下のようにマウント名前空間の中で定義されていました。

// mount.h
struct mnt_namespace {
	...
	struct user_namespace	*user_ns;
	...
};

構造体のツリーを描くとこんな感じですね。

タスクのツリー構造

なぜ、ユーザー名前空間だけnsproxy構造体で並列に扱わず、マウント名前空間の中で扱っているのか調べてみると以下のような理由からマウント名前空間に含めているようでした。

ユーザー名前空間とマウント名前空間は、どちらもプロセスが対象に対してアクセスを許可するかどうかの制御を行うため、同じ構造体にすることで処理を効率化することができる

こういう理由で別々の名前空間が統合されることがあるんだなと知り、自分の疑問も解けました。

あとがき

そういえば昔カーネルを見たときはnsproxyにユーザー名前空間あったよなーと思い、それも調べてみると、カーネル2.6.19で統合されたようでした。

あと、名前空間の実装を見ると、仮想化のようなエミューレートで環境を分離しているのではなく、プロセスに貼ってあるラベルが一致するか否かで分離を実現している技術なんだなと思いました。

Discussion