github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/core/unshare/unshare_linux.go (about)

     1  // Copyright 2016-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Disassociate parts of the process execution context.
     6  //
     7  // Synopsis:
     8  //
     9  //	unshare [OPTIONS] [PROGRAM [ARGS]...]
    10  //
    11  // Description:
    12  //
    13  //	Go applications use multiple processes, and the Go user level scheduler
    14  //	schedules goroutines onto those processes. For this reason, it is not
    15  //	possible to use syscall.Unshare. A goroutine can call `syscall.Unshare`
    16  //	from process m and the scheduler can resume that goroutine in process n,
    17  //	which has not had the unshare operation! This is a known problem with
    18  //	any system call that modifies the name space or file system context of
    19  //	only one process as opposed to the entire Go application, i.e. all of
    20  //	its processes. Examples include chroot and unshare. There has been
    21  //	lively discussion of this problem but no resolution as of yet. In sum:
    22  //	it is not possible to use `syscall.Unshare` from Go with any reasonable
    23  //	expectation of success.
    24  //
    25  //	If PROGRAM is not specified, unshare defaults to /ubin/elvish.
    26  //
    27  // Options:
    28  //
    29  //	-ipc:           Unshare the IPC namespace
    30  //	-mount:         Unshare the mount namespace
    31  //	-pid:           Unshare the pid namespace
    32  //	-net:           Unshare the net namespace
    33  //	-uts:           Unshare the uts namespace
    34  //	-user:          Unshare the user namespace
    35  //	-map-root-user: Map current uid to root. Not working
    36  package main
    37  
    38  import (
    39  	"flag"
    40  	"log"
    41  	"os"
    42  	"os/exec"
    43  	"syscall"
    44  )
    45  
    46  var (
    47  	ipc   = flag.Bool("ipc", false, "Unshare the IPC namespace")
    48  	mount = flag.Bool("mount", false, "Unshare the mount namespace")
    49  	pid   = flag.Bool("pid", false, "Unshare the pid namespace")
    50  	net   = flag.Bool("net", false, "Unshare the net namespace")
    51  	uts   = flag.Bool("uts", false, "Unshare the uts namespace")
    52  	user  = flag.Bool("user", false, "Unshare the user namespace")
    53  )
    54  
    55  func main() {
    56  	flag.Parse()
    57  
    58  	a := flag.Args()
    59  	if len(a) == 0 {
    60  		a = []string{"/ubin/elvish", "elvish"}
    61  	}
    62  
    63  	c := exec.Command(a[0], a[1:]...)
    64  	c.SysProcAttr = &syscall.SysProcAttr{}
    65  	if *mount {
    66  		c.SysProcAttr.Cloneflags |= syscall.CLONE_NEWNS
    67  	}
    68  	if *uts {
    69  		c.SysProcAttr.Cloneflags |= syscall.CLONE_NEWUTS
    70  	}
    71  	if *ipc {
    72  		c.SysProcAttr.Cloneflags |= syscall.CLONE_NEWIPC
    73  	}
    74  	if *net {
    75  		c.SysProcAttr.Cloneflags |= syscall.CLONE_NEWNET
    76  	}
    77  	if *pid {
    78  		c.SysProcAttr.Cloneflags |= syscall.CLONE_NEWPID
    79  	}
    80  	if *user {
    81  		c.SysProcAttr.Cloneflags |= syscall.CLONE_NEWUSER
    82  	}
    83  
    84  	c.Stdin = os.Stdin
    85  	c.Stdout = os.Stdout
    86  	c.Stderr = os.Stderr
    87  
    88  	if err := c.Run(); err != nil {
    89  		log.Fatalf("%v", err)
    90  	}
    91  }