user_ns: task_structからuser_nsの取得めも

誰得なめも。task_structからuser_nsの取得の方法。

名前空間struct nsproxyで管理されているけど、user namespacestruct credが管理していて、user namespace以外の名前空間はその構造体にuser namespaceへのポインタを持っている。 このポインタがどう使われるかというと、流れとしては、do_fork()からcopy_namespace()を呼び、そこからcreate_new_namespaces()を呼ぶときに、user namespaceを引数として渡して、get_user_ns()で参照カウントを増やす。

例えば、clone_uts_ns()でuts namespaceを新規に作成した時に、新しく作ったuts名前空間のuser_nsは引数で渡されたuser namespaceを参照するようにしている。

 54         memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
 55         ns->user_ns = get_user_ns(user_ns);
 56         up_read(&uts_sem);

では、実際の処理を。 struct task_structはstruct credを2個持っていて、どちらをcopy_namespace()に渡しているのか?ってなるので、そこから見ます。

1440 /* process credentials */
1441         const struct cred __rcu *real_cred; /* objective and real subjective task
1442                                          * credentials (COW) */
1443         const struct cred __rcu *cred;  /* effective (overridable) subjective task
1444                                          * credentials (COW) */
1445         char comm[TASK_COMM_LEN]; /* executable name excluding path
1446                                      - access with [gs]et_task_comm (which lock
1447                                        it with task_lock())
1448                                      - initialized normally by setup_new_exec */
1449 /* file system info */

copy_namespaces()では、下記のようにtask_structからuser namespaceを取得している。

127         struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);

task_cred_xxx()はマクロでこのような処理。これを見ると実際にuser namespaceを返すのは328行目の__task_cred((task))->xxxというのがわかりますね。

324 #define task_cred_xxx(task, xxx)                        \
325 ({                                                      \
326         __typeof__(((struct cred *)NULL)->xxx) ___val;  \
327         rcu_read_lock();                                \
328         ___val = __task_cred((task))->xxx;              \
329         rcu_read_unlock();                              \
330         ___val;                                         \
331 })

で、 __task_cred()はというと、このようなマクロです。task_structにあった2個のstruct credのうち、real_credの方を使ってますね。

281 #define __task_cred(task)       \
282         rcu_dereference((task)->real_cred)

というわけで、user namespace以外のnamespacesはtask_structのメンバ変数real_credを参照するとわかりました。

Dockerエキスパート養成読本[活用の基礎と実践ノウハウ満載!] (Software Design plus)

Dockerエキスパート養成読本[活用の基礎と実践ノウハウ満載!] (Software Design plus)