简体   繁体   中英

Problems with creating and using Linux namespaces

I'm making a go library wrapper on namespaces. There were no problems with the.net ns, with ips ns and with uts ns, but there are problems with the others:

UserNs:

  • When trying to create, I get "invalid argument"(syscall error).

MntNS:

  • mnt ns is being created, but doesn't work, I checked using mount proc.

ProcNS:

  • proc ns is also created, but shows host processes, mounting does not work.

TimeNS:

  • time ns is not created with the error "too many users"(syscall error).

Create Namespace code:

func NewNamespace(NSs []string) (*Namespace, error) {
    var flag int = 0
    for _, ns := range NSs {
        if val, ok := CloneFlags[ns]; ok == true {
            flag = flag | val
            continue
        }
        return nil, errors.New("unsupported ns " + ns)
    }
    if err := unix.Unshare(flag); err != nil {
        return nil, err
    }
    return GetCurrent()
}

Get Current NS Code:

func GetCurrent() (*Namespace, error) {
    return GetFromThread(os.Getpid(), unix.Gettid())
}

func GetFromThread(pid, tid int) (*Namespace, error) {
    ns := newNamespace()
    for _, n := range NSs {
        if entry, ok := ns.ns[n]; ok {
            entry.path = fmt.Sprintf("/proc/%d/task/%d/ns/%s", pid, tid, n)
            fd, err := OpenNS(entry.path)
            if err != nil {
                return nil, err
            }
            entry.fd = fd
            ns.ns[n] = entry
        }
    }
    return ns, nil
}

Set NS Code:

func SetNamespace(ns *Namespace, NSs []string) error {
    for _, n := range NSs {
        if entry, ok := ns.ns[n]; ok {
            entry.share = true

            ns.ns[n] = entry
        }
    }
    for key, val := range ns.ns {
        if !val.share {
            continue
        }
        fmt.Printf("Preparing %s...\n", key)
        err := unix.Setns(val.fd, CloneFlags[key])
        if err != nil {
            return err
        }
        fmt.Printf("Set %s\n", key)
    }
    return nil
}

Mount proc code:

func mountProc() error {
    if err := syscall.Mount("proc", "/proc", "proc", 0, ""); err != nil {
        return err
    }
    return nil
}

Flags:

const (
    CLONE_NEWUTS    = unix.CLONE_NEWUTS //Work
    CLONE_NEWNS     = unix.CLONE_NEWNS
    CLONE_NEWCGROUP = unix.CLONE_NEWCGROUP
    CLONE_NEWTIME   = unix.CLONE_NEWTIME
    CLONE_NEWIPC    = unix.CLONE_NEWIPC //Work
    CLONE_NEWUSER   = unix.CLONE_NEWUSER
    CLONE_NEWPID    = unix.CLONE_NEWPID
    CLONE_NEWNET    = unix.CLONE_NEWNET //Work
    CLONE_IO        = unix.CLONE_IO
)

I think I'm missing something but I can't figure out what, perhaps a combination of ns is needed.

UserNs:

  • When trying to create, I get "invalid argument"(syscall error).

Per man 2 unshare , " CLONE_NEWUSER requires that the calling process is not threaded", but your process is threaded, as you can tell by the clone syscall with CLONE_THREAD in your strace output.

MntNS:

  • mnt ns is being created, but doesn't work, I checked using mount proc.

I don't know exactly without knowing what you checked, but I'm guessing what you're running into is that systemd changes the default mount propagation in a way that makes mount namespaces effectively not work , so every time you make one, the first thing you need to do immediately afterwards is to change it back. See if doing something like syscall.Mount("none", "/", nil, syscall.MS_REC | syscall.MS_PRIVATE, "") right after creating the mount namespace helps.

ProcNS:

  • proc ns is also created, but shows host processes, mounting does not work.

I assume you mean PID namespace, since there's no such thing as a proc namespace. This time, I can think of two reasons things could be going wrong. First, again per man 2 unshare , "the calling process has a new PID namespace for its children" and "The calling process is not moved into the new namespace." So that won't affect your process, and for it to do anything, you need to start a child process. Second, per man 7 pid_namespaces , you need to mount a new instance of the proc filesystem from within the PID namespace to see the PIDs within it.

TimeNS:

  • time ns is not created with the error "too many users"(syscall error).

It looks like this is being created and is just failing to set. It's hard to find documentation that explicitly says this, but by reading kernel source code, it looks like as with user namespaces, you can't set time namespaces on a multithreaded process, but as with PID namespaces, if you spawn a child process, it should have it set.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM