hisamounaのブログ

アウトプットを習慣化するためのブログ

Rustを使ってコンテナの実装を学ぶ (UID/GID の設定)

Rustを使ってコンテナの実装を学ぶの続きをやっていきたいと思います。

hisamouna.hatenablog.com

実行環境(再掲)

GCPVMインスタンスを1台起動させて、実行環境として利用しました。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 10 (buster)
Release:    10
Codename:   buster

$ arch
x86_64

UID/GID の設定

設定する前のUID/GIDを確認すると、nobody/nogroupとなっています。

$ id
uid=26038 gid=65534(nogroup) groups=65534(nogroup)

これは CLONE_NEWUSERフラグを付与してclone(2)を実行したことで user namespaceが分離されたからです。

/proc/[pid]/uid_map と /proc/[pid]/gid_mapへ書き込みを行うことで、namespace内外のuser間でのmappingを設定できます。 (参考)

UID/GIDを0(root)に変更してみたいと思います。

実装

/proc/[pid]/uid_map と /proc/[pid]/gid_mapに書き込みを行う関数を作成しました。

write_id_mapping でmappingフォーマットを定義しています。

フォーマット: ns内のID ns外のID length

write_fileでファイル書き込みを行います。

fn write_id_mapping(
    container_id: u32,
    host_id: u32,
    length: u8,
    map_file: &str,
) -> Result<()> {
    let mapping = format!("{} {} {}", container_id,host_id,length);
    write_file(map_file,mapping)?;
    Ok(())
}

fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
    let path = path.as_ref();
    fs::write(path,contents).with_context(|| format!("failed to write to {:?}",path))?;
    Ok(())
}

子プロセスを生成した後に、mapping処理を実装しました。

let child_pid = sched::clone(cb, stack, flags, Some(Signal::SIGCHLD as i32)).expect("failed to create child process");

let root_id = 0;

let uid_map_file : &str = &format!("/proc/{}/uid_map",child_pid);
let host_uid = unsafe { libc::getuid() };
if let Err(err) = write_id_mapping(root_id,host_uid, 1,uid_map_file) {
    eprintln!("UID mapping failed: {}",err)
}

let host_gid = unsafe { libc::getgid() };
let gid_map_file : &str = &format!("/proc/{}/gid_map",child_pid);
if let Err(err) = write_id_mapping(root_id,host_gid, 1,gid_map_file) {
    eprintln!("GID mapping failed: {}",err)
}

if let Err(err) = ... は Goでいう if err := func(); err != nil { ... } と同じようなことが出来ます。 より短くかけるので良きです。

ビルドして実行してみたところ、uid/gidが0となりました!

$ id
uid=0(root) gid=0(root) groups=0(root)