Ian Lance Taylor posted comments on this change.
Patch set 2:
Can you confirm that `sudo go test os/exec` failed before this CL and works after it?
(1 comment)
Patch Set #1, Line 23: private namespaces on Linux.
You can dro pthe Signed-off-by line, we don't use them.
To view, visit change 38471. To unsubscribe, visit settings.
ron minnich has uploaded this change for review.
os/exec: add a mount command when Unshareflags include CLONE_NEWNS
In some newer Linux distros, the mountflags specified at boot essentially
disable the CLONE_NEWNS flag in unshare(2). This problem is most commonly seen
on systems with systemd, but it can happen anywhere.
Hence, to create a private mount namespace, it is not sufficient to just set
CLONE_NEWS; you have to call mount(2) to change the behavior of namespaces, i.e.
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)
This is tested and working and we can now correctly start child process with
private namespaces on Linux.
Fixes #19661
Change-Id: I52240b59628e3772b529d9bbef7166606b0c157d
Signed-off-by: Ronald G. Minnich <rmin...@gmail.com>
---
M src/syscall/exec_linux.go
1 file changed, 9 insertions(+), 0 deletions(-)
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 6ad20f6..aa307e2 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -66,6 +66,8 @@
nextfd int
i int
p [2]int
+ n = uintptr(unsafe.Pointer(&[]byte("none")[0]))
+ s = uintptr(unsafe.Pointer(&[]byte("/")[0]))
)
// Record parent PID so child can test if it has died.
@@ -201,6 +203,13 @@
if err1 != 0 {
goto childerror
}
+ if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
+ _, _, err1 = RawSyscall6(SYS_MOUNT, n, s, 0, MS_REC|MS_PRIVATE, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+
+ }
}
// User and groups
To view, visit change 38471. To unsubscribe, visit settings.
ron minnich uploaded patch set #2 to this change.
os/exec: correctly handle Unshareflags with CLONE_NEWNS
In some newer Linux distros, the mountflags specified
at boot essentially
disable the CLONE_NEWNS flag in unshare(2).
This problem is most commonly seen
on systems with systemd, but it can happen anywhere.
Hence, to create a private mount namespace,
it is not sufficient to just set
CLONE_NEWS; you have to call mount(2) to change
the behavior of namespaces, i.e.
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)
This is tested and working and we can now correctly
start child process with
private namespaces on Linux.
Fixes #19661
Change-Id: I52240b59628e3772b529d9bbef7166606b0c157d
Signed-off-by: Ronald G. Minnich <rmin...@gmail.com>
---
M src/syscall/exec_linux.go
1 file changed, 9 insertions(+), 0 deletions(-)
ron minnich uploaded patch set #3 to this change.
os/exec: handle Unshareflags with CLONE_NEWNS
In some newer Linux distros, the mountflags specified
at boot essentially
disable the CLONE_NEWNS flag in unshare(2).
This problem is most commonly seen
on systems with systemd, but it can happen anywhere.
Hence, to create a private mount namespace,
it is not sufficient to just set
CLONE_NEWS; you have to call mount(2) to change
the behavior of namespaces, i.e.
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)
This is tested and working and we can now correctly
start child process with
private namespaces on Linux.
Fixes #19661
Change-Id: I52240b59628e3772b529d9bbef7166606b0c157d
Signed-off-by: Ronald G. Minnich <rmin...@gmail.com>
---
M src/syscall/exec_linux.go
1 file changed, 9 insertions(+), 0 deletions(-)
ron minnich posted comments on this change.
Patch set 3:
Patch Set 2:
(1 comment)
Can you confirm that `sudo go test os/exec` failed before this CL and works after it?
Nope, it does not fail. I'm happy to try to modify it to fail, however, if that helps. It gets a tad messy as whether it fails depends, in most cases, on whether you're running systemd and whether it's set up mounts to have certain default behavior. I expect it will involve a lot of rooting around in /sys.
ron minnich uploaded patch set #4 to this change.
os/exec: handle Unshareflags with CLONE_NEWNS
In some newer Linux distros, the mountflags specified
at boot essentially
disable the CLONE_NEWNS flag in unshare(2).
This problem is most commonly seen
on systems with systemd, but it can happen anywhere.
Hence, to create a private mount namespace,
it is not sufficient to just set
CLONE_NEWS; you have to call mount(2) to change
the behavior of namespaces, i.e.
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)
This is tested and working and we can now correctly
start child process with
private namespaces on Linux.
Fixes #19661
Change-Id: I52240b59628e3772b529d9bbef7166606b0c157d
---
M src/syscall/exec_linux.go
1 file changed, 9 insertions(+), 0 deletions(-)
ron minnich posted comments on this change.
Patch set 4:
Patch Set 3:
Patch Set 2:
(1 comment)
Can you confirm that `sudo go test os/exec` failed before this CL and works after it?
Nope, it does not fail. I'm happy to try to modify it to fail, however, if that helps. It gets a tad messy as whether it fails depends, in most cases, on whether you're running systemd and whether it's set up mounts to have certain default behavior. I expect it will involve a lot of rooting around in /sys.
other context: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=739593
Ian Lance Taylor posted comments on this change.
Patch set 4:
My concern about the test is simply that we have no way of knowing whether this works or not. I understand that this is system-specific, but I gather from your comments that you have some way of knowing that this patch fixed something. Ideally I would like to capture that in exec_linux_test.go, if possible, even if the resulting test always passes on machines without systemd.
(2 comments)
File src/syscall/exec_linux.go:
Patch Set #4, Line 69: n = uintptr(unsafe.Pointer(&[]byte("none")[0]))
Let's just make this global variables.
Patch Set #4, Line 206: if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
Pretty minor, but I would write this as
if sys.Unshareflags&CLONE_NEWNS != 0 {Also this needs a comment.
To view, visit change 38471. To unsubscribe, visit settings.
ron minnich posted comments on this change.
Patch set 4:
Patch Set 4:
(2 comments)
My concern about the test is simply that we have no way of knowing whether this works or not. I understand that this is system-specific, but I gather from your comments that you have some way of knowing that this patch fixed something. Ideally I would like to capture that in exec_linux_test.go, if possible, even if the resulting test always passes on machines without systemd.
So, a false positive is probably ok here. I think this makes sense. I have a rough idea of what to do, will do. Thanks.
(2 comments)
Patch Set #4, Line 69: n = uintptr(unsafe.Pointer(&[]byte("none")[0]))
Let's just make this global variables.
Done
Patch Set #4, Line 206: if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
Pretty minor, but I would write this as
I've stopped writing that style because I've seen people get burned once or twice (in Go and other languages) when the constant in question is a multi-bit field. Yes, this is not a multi-bit field, now, but, how do we know, precisely? This test is safer. Anyway, I can change it, but I'm a bit uncomfortable doing so.
To view, visit change 38471. To unsubscribe, visit settings.
Ian Lance Taylor posted comments on this change.
Patch set 4:
So, a false positive is probably ok here. I think this makes sense. I have a rough idea of what to do, will do. Thanks.
I think I would say that a false negative is OK here. That is, it's OK if the test passes unexpectedly, as long as it fails sometimes. That is probably what you meant too.
(1 comment)
File src/syscall/exec_linux.go:
Patch Set #4, Line 206: if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
I've stopped writing that style because I've seen people get burned once or
Ack
To view, visit change 38471. To unsubscribe, visit settings.
ron minnich uploaded patch set #5 to this change.
os/exec: handle Unshareflags with CLONE_NEWNS
In some newer Linux distros, systemd forces
all mount namespaces to be shared, starting
at /. This disables the CLONE_NEWNS
flag in unshare(2) and clone(2).
While this problem is most commonly seen
on systems with systemd, it can happen anywhere,
due to how Linux namespaces now work.
Hence, to create a private mount namespace,
it is not sufficient to just set
CLONE_NEWS; you have to call mount(2) to change
the behavior of namespaces, i.e.
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)
This is tested and working and we can now correctly
start child process with private namespaces on Linux
distros that use systemd.
The new test works correctly on Ubuntu 16.04.2 LTS.
It fails if I comment out the new Mount, and
succeeds otherwise. In each case it correctly
cleans up after itself.
Fixes #19661
Change-Id: I52240b59628e3772b529d9bbef7166606b0c157d
---
M src/syscall/exec_linux.go
M src/syscall/exec_linux_test.go
2 files changed, 81 insertions(+), 0 deletions(-)
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 6ad20f6..3c16acc 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -42,6 +42,11 @@
GidMappingsEnableSetgroups bool
}
+var (
+ n = uintptr(unsafe.Pointer(&[]byte("none")[0]))
+ s = uintptr(unsafe.Pointer(&[]byte("/")[0]))
+)
+
// Implemented in runtime package.
func runtime_BeforeFork()
func runtime_AfterFork()
@@ -201,6 +206,19 @@
if err1 != 0 {
goto childerror
}
+ // The unshare system call in Linux doesn't unshare mount points
+ // mounted with --shared. Systemd mounts / with --shared. For a
+ // long discussion of the pros and cons of this see debian bug 739593.
+ // The Go model of unsharing is more like Plan 9, where you ask
+ // to unshare and the namespaces are unconditionally unshared.
+ // To make this model work we must further mark / as MS_PRIVATE.
+ // This is what the standard unshare command does.
+ if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
+ _, _, err1 = RawSyscall6(SYS_MOUNT, n, s, 0, MS_REC|MS_PRIVATE, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
}
// User and groups
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index 7a4b571..0a7cf30 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -7,6 +7,8 @@
package syscall_test
import (
+ "flag"
+ "fmt"
"io/ioutil"
"os"
"os/exec"
@@ -253,3 +255,64 @@
}
t.Errorf("id command output: %q, expected one of %q", strOut, expected)
}
+
+// TestUnshareHelperProcess isn't a real test. It's used as a helper process
+// for TestUnshareMountNameSpace.
+func TestUnshareMountNameSpaceHelper(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+
+ if err := syscall.Mount("none", flag.Args()[0], "proc", 0, ""); err != nil {
+ fmt.Fprintf(os.Stderr, "unshare: mount %v failed: %v", os.Args, err)
+ os.Exit(2)
+ }
+ os.Exit(0)
+}
+
+// Test for Issue 38471: unshare fails because systemd has forced / to be shared
+func TestUnshareMountNameSpace(t *testing.T) {
+ // Make sure we are running as root so we have permissions to use unshare
+ // and create a network namespace.
+ if os.Getuid() != 0 {
+ t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
+ }
+
+ // When running under the Go continuous build, skip tests for
+ // now when under Kubernetes. (where things are root but not quite)
+ // Both of these are our own environment variables.
+ // See Issue 12815.
+ if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
+ t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
+ }
+
+ d, err := ioutil.TempDir("", "unshare")
+ if err != nil {
+ t.Fatalf("tempdir: %v", err)
+ }
+
+ cmd := exec.Command(os.Args[0], "-test.run=TestUnshareMountNameSpaceHelper", d)
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
+
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("unshare failed: %v, %v", o, err)
+ }
+
+ // How do we tell if the namespace was really unshared? It turns out
+ // to be simple: just try to remove the directory. If it's still mounted
+ // on the rm will fail with EBUSY. Then we have some cleanup to do:
+ // we must unmount it, then try to remove it again.
+
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir failed on %v: %v", d, err)
+ if err := syscall.Unmount(d, syscall.MNT_FORCE); err != nil {
+ t.Errorf("Can't unmount %v: %v", d, err)
+ }
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir after unmount failed on %v: %v", d, err)
+ }
+ }
+}
To view, visit change 38471. To unsubscribe, visit settings.
ron minnich uploaded patch set #6 to this change.
os/exec: handle Unshareflags with CLONE_NEWNS
In some newer Linux distros, systemd forces
all mount namespaces to be shared, starting
at /. This disables the CLONE_NEWNS
flag in unshare(2) and clone(2).
While this problem is most commonly seen
on systems with systemd, it can happen anywhere,
due to how Linux namespaces now work.
Hence, to create a private mount namespace,
it is not sufficient to just set
CLONE_NEWS; you have to call mount(2) to change
the behavior of namespaces, i.e.
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)
This is tested and working and we can now correctly
start child process with private namespaces on Linux
distros that use systemd.
The new test works correctly on Ubuntu 16.04.2 LTS.
It fails if I comment out the new Mount, and
succeeds otherwise. In each case it correctly
cleans up after itself.
Fixes #19661
Change-Id: I52240b59628e3772b529d9bbef7166606b0c157d
---
M src/syscall/exec_linux.go
M src/syscall/exec_linux_test.go
2 files changed, 80 insertions(+), 0 deletions(-)
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 6ad20f6..3c16acc 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -42,6 +42,11 @@
GidMappingsEnableSetgroups bool
}
+var (
+ n = uintptr(unsafe.Pointer(&[]byte("none")[0]))
+ s = uintptr(unsafe.Pointer(&[]byte("/")[0]))
+)
+
// Implemented in runtime package.
func runtime_BeforeFork()
func runtime_AfterFork()
@@ -201,6 +206,19 @@
if err1 != 0 {
goto childerror
}
+ // The unshare system call in Linux doesn't unshare mount points
+ // mounted with --shared. Systemd mounts / with --shared. For a
+ // long discussion of the pros and cons of this see debian bug 739593.
+ // The Go model of unsharing is more like Plan 9, where you ask
+ // to unshare and the namespaces are unconditionally unshared.
+ // To make this model work we must further mark / as MS_PRIVATE.
+ // This is what the standard unshare command does.
+ if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
+ _, _, err1 = RawSyscall6(SYS_MOUNT, n, s, 0, MS_REC|MS_PRIVATE, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
}
// User and groups
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index 7a4b571..ed44ddf 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -7,6 +7,8 @@
package syscall_test
import (
+ "flag"
+ "fmt"
"io/ioutil"
"os"
"os/exec"
@@ -253,3 +255,63 @@
}
t.Errorf("id command output: %q, expected one of %q", strOut, expected)
}
+
+// TestUnshareHelperProcess isn't a real test. It's used as a helper process
+// for TestUnshareMountNameSpace.
+func TestUnshareMountNameSpaceHelper(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+
+ if err := syscall.Mount("none", flag.Args()[0], "proc", 0, ""); err != nil {
+ fmt.Fprintf(os.Stderr, "unshare: mount %v failed: %v", os.Args, err)
+ os.Exit(2)
+ }
+}
+
+// Test for Issue 38471: unshare fails because systemd has forced / to be shared
+func TestUnshareMountNameSpace(t *testing.T) {
+ // Make sure we are running as root so we have permissions to use unshare
+ // and create a network namespace.
+ if os.Getuid() != 0 {
+ t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
+ }
+
+ // When running under the Go continuous build, skip tests for
+ // now when under Kubernetes. (where things are root but not quite)
+ // Both of these are our own environment variables.
+ // See Issue 12815.
+ if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
+ t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
+ }
+
+ d, err := ioutil.TempDir("", "unshare")
+ if err != nil {
+ t.Fatalf("tempdir: %v", err)
+ }
+
+ cmd := exec.Command(os.Args[0], "-test.run=TestUnshareMountNameSpaceHelper", d)
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
+
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("unshare failed: %v, %v", o, err)
+ }
+
+ // How do we tell if the namespace was really unshared? It turns out
+ // to be simple: just try to remove the directory. If it's still mounted
+ // on the rm will fail with EBUSY. Then we have some cleanup to do:
+ // we must unmount it, then try to remove it again.
+
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir failed on %v: %v", d, err)
+ if err := syscall.Unmount(d, syscall.MNT_FORCE); err != nil {
+ t.Errorf("Can't unmount %v: %v", d, err)
+ }
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir after unmount failed on %v: %v", d, err)
+ }
+ }
+}
To view, visit change 38471. To unsubscribe, visit settings.
Ian Lance Taylor posted comments on this change.
Patch set 6:Run-TryBot +1
(1 comment)
File src/syscall/exec_linux.go:
Patch Set #6, Line 46: n = uintptr(unsafe.Pointer(&[]byte("none")[0]))
Oh, sorry, don't write it like this. You need longer names, and you just need something you can pass to the kernel, so use [...]byte to save space.
var (
none = [...]byte{'n', 'o', 'n', 'e'}
slash = [...byte{'/'}
)Then below you can use
uintptr(unsafe.Pointer(&none[0]))To view, visit change 38471. To unsubscribe, visit settings.
Gobot Gobot posted comments on this change.
Patch set 6:
TryBots beginning. Status page: http://farmer.golang.org/try?commit=77286cb5
Gobot Gobot posted comments on this change.
Patch set 6:TryBot-Result +1
TryBots are happy.
ron minnich uploaded patch set #7 to this change.
os/exec: handle Unshareflags with CLONE_NEWNS
In some newer Linux distros, systemd forces
all mount namespaces to be shared, starting
at /. This disables the CLONE_NEWNS
flag in unshare(2) and clone(2).
While this problem is most commonly seen
on systems with systemd, it can happen anywhere,
due to how Linux namespaces now work.
Hence, to create a private mount namespace,
it is not sufficient to just set
CLONE_NEWS; you have to call mount(2) to change
the behavior of namespaces, i.e.
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)
This is tested and working and we can now correctly
start child process with private namespaces on Linux
distros that use systemd.
The new test works correctly on Ubuntu 16.04.2 LTS.
It fails if I comment out the new Mount, and
succeeds otherwise. In each case it correctly
cleans up after itself.
Fixes #19661
Change-Id: I52240b59628e3772b529d9bbef7166606b0c157d
---
M src/syscall/exec_linux.go
M src/syscall/exec_linux_test.go
2 files changed, 80 insertions(+), 0 deletions(-)
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 6ad20f6..8465bbc 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -42,6 +42,11 @@
GidMappingsEnableSetgroups bool
}
+var (
+ none = []byte("none\000")
+ slash = []byte("/\000")
+)
+
// Implemented in runtime package.
func runtime_BeforeFork()
func runtime_AfterFork()
@@ -201,6 +206,19 @@
if err1 != 0 {
goto childerror
}
+ // The unshare system call in Linux doesn't unshare mount points
+ // mounted with --shared. Systemd mounts / with --shared. For a
+ // long discussion of the pros and cons of this see debian bug 739593.
+ // The Go model of unsharing is more like Plan 9, where you ask
+ // to unshare and the namespaces are unconditionally unshared.
+ // To make this model work we must further mark / as MS_PRIVATE.
+ // This is what the standard unshare command does.
+ if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
+ _, _, err1 = RawSyscall6(SYS_MOUNT, uintptr(unsafe.Pointer(&none[0])), uintptr(unsafe.Pointer(&slash[0])), 0, MS_REC|MS_PRIVATE, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
}
// User and groups
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index 7a4b571..ed44ddf 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -7,6 +7,8 @@
package syscall_test
import (
+ "flag"
+ "fmt"
"io/ioutil"
"os"
"os/exec"
@@ -253,3 +255,63 @@
}
t.Errorf("id command output: %q, expected one of %q", strOut, expected)
}
+
+// TestUnshareHelperProcess isn't a real test. It's used as a helper process
+// for TestUnshareMountNameSpace.
+func TestUnshareMountNameSpaceHelper(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+
+ if err := syscall.Mount("none", flag.Args()[0], "proc", 0, ""); err != nil {
+ fmt.Fprintf(os.Stderr, "unshare: mount %v failed: %v", os.Args, err)
+ os.Exit(2)
+ }
+}
+
+// Test for Issue 38471: unshare fails because systemd has forced / to be shared
+func TestUnshareMountNameSpace(t *testing.T) {
+ // Make sure we are running as root so we have permissions to use unshare
+ // and create a network namespace.
+ if os.Getuid() != 0 {
+ t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
+ }
+
+ // When running under the Go continuous build, skip tests for
+ // now when under Kubernetes. (where things are root but not quite)
+ // Both of these are our own environment variables.
+ // See Issue 12815.
+ if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
+ t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
+ }
+
+ d, err := ioutil.TempDir("", "unshare")
+ if err != nil {
+ t.Fatalf("tempdir: %v", err)
+ }
+
+ cmd := exec.Command(os.Args[0], "-test.run=TestUnshareMountNameSpaceHelper", d)
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
+
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("unshare failed: %v, %v", o, err)
+ }
+
+ // How do we tell if the namespace was really unshared? It turns out
+ // to be simple: just try to remove the directory. If it's still mounted
+ // on the rm will fail with EBUSY. Then we have some cleanup to do:
+ // we must unmount it, then try to remove it again.
+
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir failed on %v: %v", d, err)
+ if err := syscall.Unmount(d, syscall.MNT_FORCE); err != nil {
+ t.Errorf("Can't unmount %v: %v", d, err)
+ }
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir after unmount failed on %v: %v", d, err)
+ }
+ }
+}
To view, visit change 38471. To unsubscribe, visit settings.
ron minnich posted comments on this change.
Patch set 6:
(1 comment)
Patch Set #6, Line 46: n = uintptr(unsafe.Pointer(&[]byte("none")[0]))
Oh, sorry, don't write it like this. You need longer names, and you just n
I like your change but in practice it does not work. The string passed to the system call is not null-terminated. So to the kernel it looks like none<garbage> and /<garbage>
Now I know it should work but does not. I've no idea why and I'll get back to it when I can.
I've done an alternate form that works, though I doubt you'll like it. I actually prefer the "none" to 'n', 'o', ... anyway. the latter form I've found harder to read.
To view, visit change 38471. To unsubscribe, visit settings.
Ian Lance Taylor posted comments on this change.
Patch set 7:
Patch Set 6:
(1 comment)
(1 comment)
File src/syscall/exec_linux.go:
Patch Set #6, Line 46: none = []byte("none\000")
I like your change but in practice it does not work. The string passed to t
Hmmmm, did you try
none = [...]byte{'n', 'o', 'n', 'e', '\000'}
(has an explicit \000 at the end). I agree that the "none" is nicer but that form takes more memory in the executable because it uses a slice rather than an array. Since this is code that matters for approximately nobody, I'm trying to minimize the cost.
To view, visit change 38471. To unsubscribe, visit settings.
ron minnich uploaded patch set #8 to this change.
os/exec: handle Unshareflags with CLONE_NEWNS
In some newer Linux distros, systemd forces
all mount namespaces to be shared, starting
at /. This disables the CLONE_NEWNS
flag in unshare(2) and clone(2).
While this problem is most commonly seen
on systems with systemd, it can happen anywhere,
due to how Linux namespaces now work.
Hence, to create a private mount namespace,
it is not sufficient to just set
CLONE_NEWS; you have to call mount(2) to change
the behavior of namespaces, i.e.
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)
This is tested and working and we can now correctly
start child process with private namespaces on Linux
distros that use systemd.
The new test works correctly on Ubuntu 16.04.2 LTS.
It fails if I comment out the new Mount, and
succeeds otherwise. In each case it correctly
cleans up after itself.
Fixes #19661
Change-Id: I52240b59628e3772b529d9bbef7166606b0c157d
---
M src/syscall/exec_linux.go
M src/syscall/exec_linux_test.go
2 files changed, 80 insertions(+), 0 deletions(-)
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 6ad20f6..b36de96 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -42,6 +42,11 @@
GidMappingsEnableSetgroups bool
}
+var (
+ none = []byte{'n', 'o', 'n', 'e', 0}
+ slash = []byte{'/', 0}
+)
+
// Implemented in runtime package.
func runtime_BeforeFork()
func runtime_AfterFork()
@@ -201,6 +206,19 @@
if err1 != 0 {
goto childerror
}
+ // The unshare system call in Linux doesn't unshare mount points
+ // mounted with --shared. Systemd mounts / with --shared. For a
+ // long discussion of the pros and cons of this see debian bug 739593.
+ // The Go model of unsharing is more like Plan 9, where you ask
+ // to unshare and the namespaces are unconditionally unshared.
+ // To make this model work we must further mark / as MS_PRIVATE.
+ // This is what the standard unshare command does.
+ if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
+ _, _, err1 = RawSyscall6(SYS_MOUNT, uintptr(unsafe.Pointer(&none[0])), uintptr(unsafe.Pointer(&slash[0])), 0, MS_REC|MS_PRIVATE, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
}
// User and groups
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index 7a4b571..ed44ddf 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -7,6 +7,8 @@
package syscall_test
import (
+ "flag"
+ "fmt"
"io/ioutil"
"os"
"os/exec"
@@ -253,3 +255,63 @@
}
t.Errorf("id command output: %q, expected one of %q", strOut, expected)
}
+
+// TestUnshareHelperProcess isn't a real test. It's used as a helper process
+// for TestUnshareMountNameSpace.
+func TestUnshareMountNameSpaceHelper(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+
+ if err := syscall.Mount("none", flag.Args()[0], "proc", 0, ""); err != nil {
+ fmt.Fprintf(os.Stderr, "unshare: mount %v failed: %v", os.Args, err)
+ os.Exit(2)
+ }
+}
+
+// Test for Issue 38471: unshare fails because systemd has forced / to be shared
+func TestUnshareMountNameSpace(t *testing.T) {
+ // Make sure we are running as root so we have permissions to use unshare
+ // and create a network namespace.
+ if os.Getuid() != 0 {
+ t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
+ }
+
+ // When running under the Go continuous build, skip tests for
+ // now when under Kubernetes. (where things are root but not quite)
+ // Both of these are our own environment variables.
+ // See Issue 12815.
+ if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
+ t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
+ }
+
+ d, err := ioutil.TempDir("", "unshare")
+ if err != nil {
+ t.Fatalf("tempdir: %v", err)
+ }
+
+ cmd := exec.Command(os.Args[0], "-test.run=TestUnshareMountNameSpaceHelper", d)
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
+
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("unshare failed: %v, %v", o, err)
+ }
+
+ // How do we tell if the namespace was really unshared? It turns out
+ // to be simple: just try to remove the directory. If it's still mounted
+ // on the rm will fail with EBUSY. Then we have some cleanup to do:
+ // we must unmount it, then try to remove it again.
+
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir failed on %v: %v", d, err)
+ if err := syscall.Unmount(d, syscall.MNT_FORCE); err != nil {
+ t.Errorf("Can't unmount %v: %v", d, err)
+ }
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir after unmount failed on %v: %v", d, err)
+ }
+ }
+}
To view, visit change 38471. To unsubscribe, visit settings.
Ian Lance Taylor posted comments on this change.
Patch set 8:
(1 comment)
File src/syscall/exec_linux.go:
Patch Set #8, Line 46: none = []byte{'n', 'o', 'n', 'e', 0}
Really sorry about this, but it should be
[...]byte
not
[]byteTo view, visit change 38471. To unsubscribe, visit settings.
ron minnich posted comments on this change.
File src/syscall/exec_linux.go:
Patch Set #6, Line 46: none = []byte{'n', 'o', 'n', 'e', 0}
Hmmmm, did you try
Done
To view, visit change 38471. To unsubscribe, visit settings.
File src/syscall/exec_linux.go:
Patch Set #8, Line 46: none = []byte{'n', 'o', 'n', 'e', 0}
Really sorry about this, but it should be
yeah but ... that did not work. That's why I'm here with this :-)
To view, visit change 38471. To unsubscribe, visit settings.
Patch Set 8:
(1 comment)
Just to be sure I'm not nuts, I did test this one more time and ... no good. The none and / strings are not null terminated. Bug in go? I don't know. This *should* work.
ron minnich uploaded patch set #9 to this change.
os/exec: handle Unshareflags with CLONE_NEWNS
In some newer Linux distros, systemd forces
all mount namespaces to be shared, starting
at /. This disables the CLONE_NEWNS
flag in unshare(2) and clone(2).
While this problem is most commonly seen
on systems with systemd, it can happen anywhere,
due to how Linux namespaces now work.
Hence, to create a private mount namespace,
it is not sufficient to just set
CLONE_NEWS; you have to call mount(2) to change
the behavior of namespaces, i.e.
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)
This is tested and working and we can now correctly
start child process with private namespaces on Linux
distros that use systemd.
The new test works correctly on Ubuntu 16.04.2 LTS.
It fails if I comment out the new Mount, and
succeeds otherwise. In each case it correctly
cleans up after itself.
Fixes #19661
Change-Id: I52240b59628e3772b529d9bbef7166606b0c157d
---
M src/syscall/exec_linux.go
M src/syscall/exec_linux_test.go
2 files changed, 80 insertions(+), 0 deletions(-)
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 6ad20f6..a5e9a56 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -42,6 +42,11 @@
GidMappingsEnableSetgroups bool
}
+var (
+ none = [...]byte{'n', 'o', 'n', 'e', 0}
+ slash = [...]byte{'/', 0}
+)
+
// Implemented in runtime package.
func runtime_BeforeFork()
func runtime_AfterFork()
@@ -201,6 +206,19 @@
if err1 != 0 {
goto childerror
}
+ // The unshare system call in Linux doesn't unshare mount points
+ // mounted with --shared. Systemd mounts / with --shared. For a
+ // long discussion of the pros and cons of this see debian bug 739593.
+ // The Go model of unsharing is more like Plan 9, where you ask
+ // to unshare and the namespaces are unconditionally unshared.
+ // To make this model work we must further mark / as MS_PRIVATE.
+ // This is what the standard unshare command does.
+ if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
+ _, _, err1 = RawSyscall6(SYS_MOUNT, uintptr(unsafe.Pointer(&none[0])), uintptr(unsafe.Pointer(&slash[0])), 0, MS_REC|MS_PRIVATE, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
}
// User and groups
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index 7a4b571..ed44ddf 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -7,6 +7,8 @@
package syscall_test
import (
+ "flag"
+ "fmt"
"io/ioutil"
"os"
"os/exec"
@@ -253,3 +255,63 @@
}
t.Errorf("id command output: %q, expected one of %q", strOut, expected)
}
+
+// TestUnshareHelperProcess isn't a real test. It's used as a helper process
+// for TestUnshareMountNameSpace.
+func TestUnshareMountNameSpaceHelper(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+
+ if err := syscall.Mount("none", flag.Args()[0], "proc", 0, ""); err != nil {
+ fmt.Fprintf(os.Stderr, "unshare: mount %v failed: %v", os.Args, err)
+ os.Exit(2)
+ }
+}
+
+// Test for Issue 38471: unshare fails because systemd has forced / to be shared
+func TestUnshareMountNameSpace(t *testing.T) {
+ // Make sure we are running as root so we have permissions to use unshare
+ // and create a network namespace.
+ if os.Getuid() != 0 {
+ t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
+ }
+
+ // When running under the Go continuous build, skip tests for
+ // now when under Kubernetes. (where things are root but not quite)
+ // Both of these are our own environment variables.
+ // See Issue 12815.
+ if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
+ t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
+ }
+
+ d, err := ioutil.TempDir("", "unshare")
+ if err != nil {
+ t.Fatalf("tempdir: %v", err)
+ }
+
+ cmd := exec.Command(os.Args[0], "-test.run=TestUnshareMountNameSpaceHelper", d)
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
+
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("unshare failed: %v, %v", o, err)
+ }
+
+ // How do we tell if the namespace was really unshared? It turns out
+ // to be simple: just try to remove the directory. If it's still mounted
+ // on the rm will fail with EBUSY. Then we have some cleanup to do:
+ // we must unmount it, then try to remove it again.
+
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir failed on %v: %v", d, err)
+ if err := syscall.Unmount(d, syscall.MNT_FORCE); err != nil {
+ t.Errorf("Can't unmount %v: %v", d, err)
+ }
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir after unmount failed on %v: %v", d, err)
+ }
+ }
+}
To view, visit change 38471. To unsubscribe, visit settings.
Ian Lance Taylor posted comments on this change.
Patch set 9:
(1 comment)
File src/syscall/exec_linux.go:
Patch Set #8, Line 46: none = [...]byte{'n', 'o', 'n', 'e', 0}
yeah but ... that did not work. That's why I'm here with this :-)
Hmmm, I don't get it. I just tried recreating the problem and failed. Can you upload the code that does not work?
To view, visit change 38471. To unsubscribe, visit settings.
ron minnich posted comments on this change.
Patch set 8:
(1 comment)
File src/syscall/exec_linux.go:
Patch Set #8, Line 46: none = []byte{'n', 'o', 'n', 'e', 0}
Hmmm, I don't get it. I just tried recreating the problem and failed. Can
If you delete the , 0 it will fail. But I've changed it to ...
To view, visit change 38471. To unsubscribe, visit settings.
Ian Lance Taylor posted comments on this change.
Patch set 9:
(1 comment)
File src/syscall/exec_linux.go:
Patch Set #8, Line 46: none = [...]byte{'n', 'o', 'n', 'e', 0}
If you delete the , 0
Don't delete the ", 0". You need it.
I tried the version with
none = [...]byte{'n', 'o', 'n', 'e', 0}
slash = [...]byte{'/', 0}and it seems to work as expected for me. Using strace -f I see this:
[pid 7132] mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) = 0
To view, visit change 38471. To unsubscribe, visit settings.
ron minnich posted comments on this change.
Patch set 9:
yep, my brain was in neutral as I confused Go syntax with another language. Thanks for your patience.
Anyway, this fixes my problem.
Ian Lance Taylor posted comments on this change.
Patch set 9:Run-TryBot +1Code-Review +2
Thanks for your patience.
Gobot Gobot posted comments on this change.
Patch set 9:
TryBots beginning. Status page: http://farmer.golang.org/try?commit=c9cd277c
Gobot Gobot posted comments on this change.
Patch set 9:TryBot-Result +1
TryBots are happy.
To view, visit change 38471. To unsubscribe, visit settings.
Ian Lance Taylor merged this change.
os/exec: handle Unshareflags with CLONE_NEWNS
In some newer Linux distros, systemd forces
all mount namespaces to be shared, starting
at /. This disables the CLONE_NEWNS
flag in unshare(2) and clone(2).
While this problem is most commonly seen
on systems with systemd, it can happen anywhere,
due to how Linux namespaces now work.
Hence, to create a private mount namespace,
it is not sufficient to just set
CLONE_NEWS; you have to call mount(2) to change
the behavior of namespaces, i.e.
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)
This is tested and working and we can now correctly
start child process with private namespaces on Linux
distros that use systemd.
The new test works correctly on Ubuntu 16.04.2 LTS.
It fails if I comment out the new Mount, and
succeeds otherwise. In each case it correctly
cleans up after itself.
Fixes #19661
Change-Id: I52240b59628e3772b529d9bbef7166606b0c157d
Reviewed-on: https://go-review.googlesource.com/38471
Reviewed-by: Ian Lance Taylor <ia...@golang.org>
Run-TryBot: Ian Lance Taylor <ia...@golang.org>
TryBot-Result: Gobot Gobot <go...@golang.org>
---
M src/syscall/exec_linux.go
M src/syscall/exec_linux_test.go
2 files changed, 80 insertions(+), 0 deletions(-)
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 1ed10dd..e35ac25 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -42,6 +42,11 @@
GidMappingsEnableSetgroups bool
}
+var (
+ none = [...]byte{'n', 'o', 'n', 'e', 0}
+ slash = [...]byte{'/', 0}
+)
+
// Implemented in runtime package.
func runtime_BeforeFork()
func runtime_AfterFork()
@@ -204,6 +209,19 @@
if err1 != 0 {
goto childerror
}
+ // The unshare system call in Linux doesn't unshare mount points
+ // mounted with --shared. Systemd mounts / with --shared. For a
+ // long discussion of the pros and cons of this see debian bug 739593.
+ // The Go model of unsharing is more like Plan 9, where you ask
+ // to unshare and the namespaces are unconditionally unshared.
+ // To make this model work we must further mark / as MS_PRIVATE.
+ // This is what the standard unshare command does.
+ if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
+ _, _, err1 = RawSyscall6(SYS_MOUNT, uintptr(unsafe.Pointer(&none[0])), uintptr(unsafe.Pointer(&slash[0])), 0, MS_REC|MS_PRIVATE, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
}
// User and groups
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index 7a4b571..ed44ddf 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -7,6 +7,8 @@
package syscall_test
import (
+ "flag"
+ "fmt"
"io/ioutil"
"os"
"os/exec"
@@ -253,3 +255,63 @@
}
t.Errorf("id command output: %q, expected one of %q", strOut, expected)
}
+
+// TestUnshareHelperProcess isn't a real test. It's used as a helper process
+// for TestUnshareMountNameSpace.
+func TestUnshareMountNameSpaceHelper(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+
+ if err := syscall.Mount("none", flag.Args()[0], "proc", 0, ""); err != nil {
+ fmt.Fprintf(os.Stderr, "unshare: mount %v failed: %v", os.Args, err)
+ os.Exit(2)
+ }
+}
+
+// Test for Issue 38471: unshare fails because systemd has forced / to be shared
+func TestUnshareMountNameSpace(t *testing.T) {
+ // Make sure we are running as root so we have permissions to use unshare
+ // and create a network namespace.
+ if os.Getuid() != 0 {
+ t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
+ }
+
+ // When running under the Go continuous build, skip tests for
+ // now when under Kubernetes. (where things are root but not quite)
+ // Both of these are our own environment variables.
+ // See Issue 12815.
+ if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
+ t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
+ }
+
+ d, err := ioutil.TempDir("", "unshare")
+ if err != nil {
+ t.Fatalf("tempdir: %v", err)
+ }
+
+ cmd := exec.Command(os.Args[0], "-test.run=TestUnshareMountNameSpaceHelper", d)
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
+
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("unshare failed: %v, %v", o, err)
+ }
+
+ // How do we tell if the namespace was really unshared? It turns out
+ // to be simple: just try to remove the directory. If it's still mounted
+ // on the rm will fail with EBUSY. Then we have some cleanup to do:
+ // we must unmount it, then try to remove it again.
+
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir failed on %v: %v", d, err)
+ if err := syscall.Unmount(d, syscall.MNT_FORCE); err != nil {
+ t.Errorf("Can't unmount %v: %v", d, err)
+ }
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir after unmount failed on %v: %v", d, err)
+ }
+ }
+}
To view, visit change 38471. To unsubscribe, visit settings.
Elias Naur posted comments on this change.
Patch set 10:
This CL seems to have broken the (only) linux/arm64 builder:
https://build.golang.org/log/a2fd112da23e96e2c5ea00840544a1ddb6f45a2c
man that's weird, that's a really innocuous change. Not sure if you can but if you can get me access to an ARM system somehow I'm happy to look. My ARM system is still in the mail.Also, if there is an unshare command on that system, this change is equivalent to unshare -m /bin/date, so if you want to strace that and send me output I can take a look.thanksron
On Sat, Mar 25, 2017 at 6:49 AM Elias Naur (Gerrit) <noreply-gerritcodereview-2DDInOvE1MrCWMxYGxqB3g@google.com> wrote:Elias Naur posted comments on this change.
Patch set 10:
This CL seems to have broken the (only) linux/arm64 builder:
https://build.golang.org/log/a2fd112da23e96e2c5ea00840544a1ddb6f45a2c
To view, visit change 38471. To unsubscribe, visit settings.
--
You received this message because you are subscribed to the Google Groups "golang-codereviews" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-codereviews+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
ron minnich posted comments on this change.
Patch set 10:
if you can get me to a box to try I can take a look. My ARM is in the mail.
Do you have an unshare command on that system? can you
sudo strace unshare -m /bin/bash
and send me the output?
Brad Fitzpatrick posted comments on this change.
Patch set 10:
Ron, the tests need to pass as a regular user too.
I think you need to modify the tests to t.Skip on any permissions error, at least if the user isn't Uid 0.
ron minnich posted comments on this change.
Patch set 10:
First three lines of the test:
if os.Getuid() != 0 {
t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
}
Why isn't that sufficient? On my system it prints the message and skips the test if I run as ! root
Brad Fitzpatrick posted comments on this change.
Patch set 10:
Oh, hm. No clue.
Elias Naur posted comments on this change.
Patch set 10:
Patch Set 10:
if you can get me to a box to try I can take a look. My ARM is in the mail.
Do you have an unshare command on that system? can you
sudo strace unshare -m /bin/bash
and send me the output?
I don't have access to a linux/arm64 machine. I merely followed the string of broken builds :) Perhaps Brad or someone else is able to get you access (is that what gomote can do?).
ron minnich posted comments on this change.
Patch set 10:
Thanks very much for catching this. Can someone do a uname -a and cat /etc/issue on that machine? I'll set up a VM I guess to try to recreate what's going on. I have little experience with the builder infrastructure, sorry.