user namespaceめも

user namespace以外のnamespaceはcreate_new_namespaces()で作るけどuser namespaceだけは別ルートになっているのでその辺のめも。 見ているのはLinux 3.16。

user namespaceの場合copy_creds()の処理中に以下のような形で呼ばれる。

339         if (clone_flags & CLONE_NEWUSER) {
340                 ret = create_user_ns(new);
341                 if (ret < 0)
342                         goto error_put;
343         }

copy_creds()が呼び出されるのは下記のような流れです。

clone()
  -> do_fork()
    -> copy_process()
      -> copy_creds()

create_user_ns()はこのような関数ですね。kuid_t、kgit_dに関しては 前に書いた「Linux: コンテナ型の仮想化サポートとkuid_t、kgid_t - φ(・・*)ゞ ウーン カーネルとか弄ったりのメモ」参照で。

 58 int create_user_ns(struct cred *new)
 59 {
 60         struct user_namespace *ns, *parent_ns = new->user_ns;
 61         kuid_t owner = new->euid;
 62         kgid_t group = new->egid;
 63         int ret;
 64 

ここのチェックですがuser namespaceは32段の階層構造までサポートするようです。 他のnamespaceだとこの辺のチェックは無いですね。

 65         if (parent_ns->level > 32)
 66                 return -EUSERS;

次はchrootされているかのチェックで、理由はコメントの通り。

 67 
 68         /*
 69          * Verify that we can not violate the policy of which files
 70          * may be accessed that is specified by the root directory,
 71          * by verifing that the root directory is at the root of the
 72          * mount namespace which allows all files to be accessed.
 73          */
 74         if (current_chrooted())
 75                 return -EPERM;
 76 

parentのuser namespaceと新規作成するuser namespaceのuid、gidマッピングに関するチェック。

 77         /* The creator needs a mapping in the parent user namespace
 78          * or else we won't be able to reasonably tell userspace who
 79          * created a user_namespace.
 80          */
 81         if (!kuid_has_mapping(parent_ns, owner) ||
 82             !kgid_has_mapping(parent_ns, group))
 83                 return -EPERM;
 84 

見たままですね。

 85         ns = kmem_cache_zalloc(user_ns_cachep, GFP_KERNEL);
 86         if (!ns)
 87                 return -ENOMEM;
 88 

procfs経由でuser namespaceを操作できるようにinode番号の確保。

 89         ret = proc_alloc_inum(&ns->proc_inum);
 90         if (ret) {
 91                 kmem_cache_free(user_ns_cachep, ns);
 92                 return ret;
 93         }
 94 

まだ自分以外にこのnamespaceを参照するプロセスはいないのでcountは1に。

 95         atomic_set(&ns->count, 1);

ここでuser namespaceを設定。親プロセスのnamespace、自分の階層位置、所有者、グループ。

 96         /* Leave the new->user_ns reference with the new user namespace. */
 97         ns->parent = parent_ns;
 98         ns->level = parent_ns->level + 1;
 99         ns->owner = owner;
100         ns->group = group;
101 

set_cred_user_ns()で新規プロセス用のcred構造体(new)に対して今作ったuser namespaceを設定。

102         set_cred_user_ns(new, ns);
103 

セマフォの初期化。

104 #ifdef CONFIG_PERSISTENT_KEYRINGS
105         init_rwsem(&ns->persistent_keyring_register_sem);
106 #endif
107         return 0;
108 }

CONFIG_PERSISTENT_KEYRINGSはKconfigのhelpによるとEnable register of persistent per-UID keyringsとのこと。
と、言われてもピンときてないですが。。 まあここは飛ばしても良いか。

ここまででuser namespaceの作成まで終わっているのですがこの機能を実際に使うためにはuid、gidマッピングが必要になります。この辺は/proc/pid/uid_map、/proc/pid/gid_mapを使います。これについてはLWNのNamespaces in operation, part 5: User namespaces [LWN.net]がサンプルコード付きで解説しているのでそちらをどうぞ。

P.S. user namespaceを使うはカーネルの.configでCONFIG_USER_NS=yになっている必要があります。自分が見たところFedoraはデフォルトのカーネルで有効、Archは無効になってました。

日経Linux(リナックス) 2014年 09月号 [雑誌]

日経Linux(リナックス) 2014年 09月号 [雑誌]