tailhook/unshare

unshare --map-root-user

shriphani opened this issue · 1 comments

Hi,

Thanks for this amazing library. I need to execute a binary using unshare. I am able to execute it in my shell using: unshare --map-root-user --net -- /path/to/binary just fine.

I have this so far but I get errors:

let mut namespaces: Vec<unshare::Namespace> = Vec::new();
namespaces.push(unshare::Namespace::Net);
namespaces.push(unshare::Namespace::User);

let mut executor = unshare::Command::new(dest);
executor
  .arg("job_id")
  .arg(job_path1)
  .arg("--verbose")
  .unshare(&namespaces)
  .uid(0)
  .gid(0);


let executor_process_handle = executor
  .spawn()
  .map_err(|e| tonic::Status::internal(format!("Unable to spawn executor {}", e)))?;

And this gives me:

Unable to spawn executor error when forking: Operation not permitted (os error 1)

I also tried this:

let mut namespaces: Vec<unshare::Namespace> = Vec::new();
namespaces.push(unshare::Namespace::Net);
namespaces.push(unshare::Namespace::User);
namespaces.push(unshare::Namespace::Pid);

let uid_map = UidMap {
     inside_uid: 0,
     outside_uid: getuid().as_raw(),
     count: 1,
 };
 let gid_map = GidMap {
     inside_gid: 0,
     outside_gid: getgid().as_raw(),
     count: 0,
 };

 let mut executor = unshare::Command::new(dest);

 executor
     .arg("job_id")
     .arg(job_path1)
     .arg("--verbose")
     .unshare(&namespaces)
     .set_id_maps(vec![uid_map], vec![gid_map]);

let executor_process_handle = executor
  .spawn()
  .map_err(|e| tonic::Status::internal(format!("Unable to spawn executor {}", e)))?;

And this gives me: Unable to spawn executor error setting uid/gid mappings: Permission denied (os error 13).

Just not sure what I am missing. Any help would be appreciated.

Best,
Shriphani

7Ji commented

Might be late but I encountered the same problem when I found this Cargo today to implement my containered network-less builder.

You need to call .set_id_map_commands() method if you are not mapping a same ID pair between the child and your current process. The default behaviour when .set_id_map_commands() is not called only applies to when you map your ID to itself.

A simple program to showcase how you should do to imitate the unshare --map-root-user behaviour:

use unshare;
use libc;

fn main() {
    let uidmap = unshare::UidMap {
        inside_uid: 0,
        outside_uid: unsafe {
            libc::getuid()
        },
        count: 1,
    };
    let gidmap = unshare::GidMap {
        inside_gid: 0,
        outside_gid: unsafe {
            libc::getgid()
        },
        count: 1,
    };
    unshare::Command::new("/bin/bash")
        .arg("-c")
        .arg("ip link set dev lo up; ping 127.0.0.1")
        .unshare(&[unshare::Namespace::User, unshare::Namespace::Net])
        .set_id_map_commands("/usr/bin/newuidmap", "/usr/bin/newgidmap")
        .set_id_maps(vec![uidmap], vec![gidmap])
        .spawn()
        .unwrap()
        .wait()
        .unwrap();
}