From 9e68e7d26ce5a07c6313c4c8756fd760655159fd Mon Sep 17 00:00:00 2001 From: the man Date: Thu, 26 Sep 2024 22:46:39 +0000 Subject: [PATCH 1/7] cpuns: do not call with sudo -E Using -E on sudo causes sudo to fail in odd ways, on certain systems. Stop using -E and do more to craft Cmd.Env before running the programs. Signed-off-by: the man --- cmds/cpuns/main_linux.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cmds/cpuns/main_linux.go b/cmds/cpuns/main_linux.go index 77a38ea..074ad11 100644 --- a/cmds/cpuns/main_linux.go +++ b/cmds/cpuns/main_linux.go @@ -77,7 +77,7 @@ func sudo(env string, args ...string) { // the cpu command sets LC_GLENDA_CPU_FSTAB to the fstab; // we need to transform it here. - c := exec.Command("sudo", append([]string{"-E", n, "-env=" + env}, args...)...) + c := exec.Command("sudo", append([]string{n, "-env=" + env}, args...)...) v("exec.Cmd args %q", c.Args) // Find the environment variable, and transform it. @@ -123,15 +123,18 @@ func unshare(env string, args ...string) { c := exec.Command(n, args...) v("exec.Cmd args %q", c.Args) + c.Env = os.Environ() + if s := strings.Split(env, "\n"); len(s) > 0 { + c.Env = append(c.Env, s...) + } + fstab, ok := os.LookupEnv("LC_GLENDA_CPU_FSTAB") v("fstab set? %v value %q", ok, fstab) if ok { c.Env = append(c.Env, "CPU_FSTAB="+fstab) v("extended c.Env: %v", c.Env) - if s := strings.Split(env, "\n"); len(s) > 0 { - c.Env = append(c.Env, s...) - } } + c.Stdin, c.Stdout, c.Stderr, c.Dir = os.Stdin, os.Stdout, os.Stderr, os.Getenv("PWD") v("Run %q", c) @@ -160,6 +163,7 @@ func main() { args := flag.Args() v("LC_GLENDA_CPU_FSTAB %s", os.Getenv("LC_GLENDA_CPU_FSTAB")) v("CPU_FSTAB %s", os.Getenv("CPU_FSTAB")) + v("env\n\n%q\n\n", *env) if os.Getuid() != 0 { sudo(*env, args...) } @@ -209,10 +213,10 @@ func main() { } c := s.Command() + c.Env = os.Environ() if s := strings.Split(*env, "\n"); len(s) > 0 { c.Env = append(c.Env, s...) } - verbose("cpuns: Command is %q, with args %q", c, args) pwd := os.Getenv("CPU_PWD") if _, err := os.Stat(pwd); err != nil { log.Printf("%v:setting pwd to /", err) From 9142b65400715ee5ddc569dc2fa43985ae7ebb25 Mon Sep 17 00:00:00 2001 From: the man Date: Thu, 26 Sep 2024 22:49:00 +0000 Subject: [PATCH 2/7] cpuns: remove extra printing Signed-off-by: the man --- cmds/cpuns/main_linux.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmds/cpuns/main_linux.go b/cmds/cpuns/main_linux.go index 074ad11..d041099 100644 --- a/cmds/cpuns/main_linux.go +++ b/cmds/cpuns/main_linux.go @@ -65,7 +65,6 @@ func checkprivate() error { // sudo will get us into a root process, with correct environment // set up. func sudo(env string, args ...string) { - log.Printf("sudo: os.Env %v\nenv %v\nargs %v", os.Environ(), env, args) n, err := os.Executable() if err != nil { log.Fatal(err) @@ -107,7 +106,6 @@ func sudo(env string, args ...string) { // Be very careful in modifying this; it is designed to be // simple and avoid fork bombs. func unshare(env string, args ...string) { - log.Printf("unshare: os.Env %v\nenv %v\n args %v", os.Environ(), env, args) n, err := os.Executable() if err != nil { log.Fatal(err) @@ -172,7 +170,6 @@ func main() { unshare(*env, args...) } - log.Printf("mount and run: os.Env %v\n*env %v\n args %v", os.Environ(), *env, args) shell := "/bin/sh" if len(args) == 0 { sh, ok := os.LookupEnv("SHELL") From 011dc37a6424232766c0b008f8afffeb410aa99e Mon Sep 17 00:00:00 2001 From: the man Date: Thu, 26 Sep 2024 22:49:28 +0000 Subject: [PATCH 3/7] cpuns: use syscall.Get[ug]id, not os.Get[ug]id os.Get[ug]id can do more than is wanted on some systems. cpuns needs the rawest possible result. Signed-off-by: the man --- cmds/cpuns/main_linux.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmds/cpuns/main_linux.go b/cmds/cpuns/main_linux.go index d041099..03e680c 100644 --- a/cmds/cpuns/main_linux.go +++ b/cmds/cpuns/main_linux.go @@ -192,8 +192,8 @@ func main() { } // the default value of uid, gid is 0 - uid := uint32(os.Getuid()) - gid := uint32(os.Getgid()) + uid := uint32(syscall.Getuid()) + gid := uint32(syscall.Getgid()) if u, ok := os.LookupEnv("SUDO_UID"); ok { i, err := strconv.ParseUint(u, 0, 32) if err != nil { From 317ec36634985dfbdb54ac0528f6ba731541bdc4 Mon Sep 17 00:00:00 2001 From: the man Date: Thu, 26 Sep 2024 23:26:49 +0000 Subject: [PATCH 4/7] cpu: allow user to set path of cpuns Users might not be able to install cpuns in the limited set of paths sshd looks in. Add a switch, cpuns, to allow them to indicate the proper location. This works: cpu -cpuns ~/go/bin/cpuns -nfs=true -namespace="" -sp 22 -key ~/.ssh/id_rsa a3mega-a3meganodeset-0 Don't stress about all the switches: they can be easily set in .ssh/config Signed-off-by: the man --- cmds/cpu/cpu.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmds/cpu/cpu.go b/cmds/cpu/cpu.go index abc9b43..16ff7ae 100644 --- a/cmds/cpu/cpu.go +++ b/cmds/cpu/cpu.go @@ -31,7 +31,8 @@ const defaultPort = "17010" var ( defaultKeyFile = filepath.Join(os.Getenv("HOME"), ".ssh/cpu_rsa") - // For the ssh server part + // cpuns might not be in the limited search path of sshd. Allow users to set it. + cpuns = flag.String("cpuns", "cpuns", "command to run to build cpu namespace") debug = flag.Bool("d", false, "enable debug prints") dbg9p = flag.Bool("dbg9p", false, "show 9p io") dump = flag.Bool("dump", false, "Dump copious output, including a 9p trace, to a temp file at exit") @@ -49,7 +50,7 @@ var ( srvnfs = flag.Bool("nfs", false, "start nfs") cpioRoot = flag.String("cpio", "", "cpio initrd") - ssh = flag.Bool("ssh", false, "ssh only, no internal 9p, nfs, or mounts") + ssh = flag.Bool("ssh", false, "ssh only, no internal 9p, nfs, or mounts") sshd = flag.Bool("sshd", false, "server is sshd, not cpud") // v allows debug printing. @@ -153,7 +154,7 @@ func newCPU(host string, args ...string) (retErr error) { if *sshd && *srvnfs { env := append(os.Environ(), "CPU_PWD="+os.Getenv("PWD")) envargs := "-env=" + strings.Join(env, "\n") - args = append([]string{"cpuns", envargs}, args...) + args = append([]string{*cpuns, envargs}, args...) } c := client.Command(host, args...) defer func() { From 14b6417bdac0826570642d4ad444481209949589 Mon Sep 17 00:00:00 2001 From: the man Date: Fri, 27 Sep 2024 15:52:59 +0000 Subject: [PATCH 5/7] cpu: add more information about mounts. Signed-off-by: the man --- cmds/cpu/cpu.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmds/cpu/cpu.go b/cmds/cpu/cpu.go index 16ff7ae..9c7c128 100644 --- a/cmds/cpu/cpu.go +++ b/cmds/cpu/cpu.go @@ -216,9 +216,9 @@ func newCPU(host string, args ...string) (retErr error) { log.Printf("nfs: %v", err) // wg.Done() }() - verbose("nfsmount %q fstab %q join %q", nfsmount, fstab, client.JoinFSTab(nfsmount, fstab)) - fstab = client.JoinFSTab(nfsmount, fstab) - c.Env = append(c.Env, "CPU_FSTAB="+fstab, "LC_GLENDA_CPU_FSTAB="+fstab) + jfstab := client.JoinFSTab(nfsmount, fstab) + c.Env = append(c.Env, "CPU_FSTAB="+jfstab, "LC_GLENDA_CPU_FSTAB="+jfstab) + verbose("nfsmount %q fstab %q join %q env %q", nfsmount, fstab, jfstab, c.Env) } go func() { From a8c61b39d8264bb9dcf90b4e6e7c8d62880e0228 Mon Sep 17 00:00:00 2001 From: the man Date: Fri, 27 Sep 2024 16:10:11 +0000 Subject: [PATCH 6/7] cpuns: v() -> verbose(),save CPU_FSTAB from sudo change all v to verbose, so we get the CPUNS: prefix. some sudo will not blindly accept all environment variables with -E, but will let us save a select few. CPU_FSTAB seems to be acceptable. We want to save CPU_FSTAB in the environment so it is not exposed in argv, as it would be if we added it to the environment variables preserved with -env, since it exposes the port and the mount GUID. At this point, with an extremely picky sudo, cpuns works fine. Signed-off-by: the man --- cmds/cpuns/main_linux.go | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/cmds/cpuns/main_linux.go b/cmds/cpuns/main_linux.go index 03e680c..71b4b71 100644 --- a/cmds/cpuns/main_linux.go +++ b/cmds/cpuns/main_linux.go @@ -70,28 +70,28 @@ func sudo(env string, args ...string) { log.Fatal(err) } - v("Executable: %q", n) + verbose("Executable: %q", n) // sshd filters most environment variables save LC_*. // sudo strips most LC_* variables. // the cpu command sets LC_GLENDA_CPU_FSTAB to the fstab; // we need to transform it here. - c := exec.Command("sudo", append([]string{n, "-env=" + env}, args...)...) - v("exec.Cmd args %q", c.Args) + c := exec.Command("sudo", append([]string{"--preserve-env=CPU_FSTAB", n, "-env=" + env}, args...)...) + verbose("exec.Cmd args %q", c.Args) // Find the environment variable, and transform it. // sudo seems to strip many LC_* variables. fstab, ok := os.LookupEnv("LC_GLENDA_CPU_FSTAB") - v("fstab set? %v value %q", ok, fstab) + verbose("fstab set? %v value %q", ok, fstab) if ok { c.Env = append(c.Env, "CPU_FSTAB="+fstab) - v("extended c.Env: %v", c.Env) + verbose("extended c.Env: %v", c.Env) } if s := strings.Split(env, "\n"); len(s) > 0 { c.Env = append(c.Env, s...) } c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr - v("Run %q", c) + verbose("Run %q", c) // The return is carefully done here to avoid the caller // making a mistake and fork-bomb. @@ -117,9 +117,9 @@ func unshare(env string, args ...string) { // we need to transform it here. // Since we can get here direct from sshd, not sudo, // we have to this twice. - v("Executable: %q", n) + verbose("Executable: %q", n) c := exec.Command(n, args...) - v("exec.Cmd args %q", c.Args) + verbose("exec.Cmd args %q", c.Args) c.Env = os.Environ() if s := strings.Split(env, "\n"); len(s) > 0 { @@ -127,14 +127,14 @@ func unshare(env string, args ...string) { } fstab, ok := os.LookupEnv("LC_GLENDA_CPU_FSTAB") - v("fstab set? %v value %q", ok, fstab) + verbose("fstab set? %v value %q", ok, fstab) if ok { c.Env = append(c.Env, "CPU_FSTAB="+fstab) - v("extended c.Env: %v", c.Env) + verbose("extended c.Env: %v", c.Env) } c.Stdin, c.Stdout, c.Stderr, c.Dir = os.Stdin, os.Stdout, os.Stderr, os.Getenv("PWD") - v("Run %q", c) + verbose("Run %q", c) c.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS} // The return is carefully done here to avoid the caller @@ -150,23 +150,25 @@ func unshare(env string, args ...string) { // more anyway ... func main() { flag.CommandLine = flag.NewFlagSet("cpuns", flag.ExitOnError) - debug := flag.Bool("d", false, "enable debug prints") + debug := flag.Bool("d", true, "enable debug prints") env := flag.String("env", "", "newline-separated array of environment variables") flag.Parse() if *debug { v = log.Printf - verbose("cpuns: os.Args %q", os.Args) session.SetVerbose(v) + verbose("cpuns: os.Args %q env %q", os.Args, os.Environ()) } args := flag.Args() - v("LC_GLENDA_CPU_FSTAB %s", os.Getenv("LC_GLENDA_CPU_FSTAB")) - v("CPU_FSTAB %s", os.Getenv("CPU_FSTAB")) - v("env\n\n%q\n\n", *env) + verbose("LC_GLENDA_CPU_FSTAB %s", os.Getenv("LC_GLENDA_CPU_FSTAB")) + verbose("CPU_FSTAB %s", os.Getenv("CPU_FSTAB")) + verbose("env\n\n%q\n\n", *env) if os.Getuid() != 0 { + verbose("sudo %q %q", *env, args) sudo(*env, args...) } if err := checkprivate(); err != nil { + verbose("unshare %q %q", *env, args) unshare(*env, args...) } @@ -222,6 +224,7 @@ func main() { c.Stdin, c.Stdout, c.Stderr, c.Dir = s.Stdin, s.Stdout, s.Stderr, pwd c.SysProcAttr = &syscall.SysProcAttr{} c.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)} + verbose("Run %q %q %q", c, c.Args, c.Env) if err := c.Run(); err != nil { log.Fatalf("Run %v returns %v", c, err) } From 7e5a8e4d45d52d0e9a5d6e8239a7fa0c5ab9dd0f Mon Sep 17 00:00:00 2001 From: the man Date: Fri, 27 Sep 2024 17:28:32 +0000 Subject: [PATCH 7/7] cpuns: set debug default to false Signed-off-by: the man --- cmds/cpuns/main_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmds/cpuns/main_linux.go b/cmds/cpuns/main_linux.go index 71b4b71..4662556 100644 --- a/cmds/cpuns/main_linux.go +++ b/cmds/cpuns/main_linux.go @@ -150,7 +150,7 @@ func unshare(env string, args ...string) { // more anyway ... func main() { flag.CommandLine = flag.NewFlagSet("cpuns", flag.ExitOnError) - debug := flag.Bool("d", true, "enable debug prints") + debug := flag.Bool("d", false, "enable debug prints") env := flag.String("env", "", "newline-separated array of environment variables") flag.Parse() if *debug {