-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
main: support rootless mode in userns #1688
Changes from all commits
9c7d8bc
f103de5
cdb7f23
c938157
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,13 +3,12 @@ | |
package system | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"syscall" // only for exec | ||
"unsafe" | ||
|
||
"github.com/opencontainers/runc/libcontainer/user" | ||
"golang.org/x/sys/unix" | ||
) | ||
|
||
|
@@ -102,34 +101,43 @@ func Setctty() error { | |
} | ||
|
||
// RunningInUserNS detects whether we are currently running in a user namespace. | ||
// Copied from github.com/lxc/lxd/shared/util.go | ||
// Originally copied from github.com/lxc/lxd/shared/util.go | ||
func RunningInUserNS() bool { | ||
file, err := os.Open("/proc/self/uid_map") | ||
uidmap, err := user.CurrentProcessUIDMap() | ||
if err != nil { | ||
// This kernel-provided file only exists if user namespaces are supported | ||
return false | ||
} | ||
defer file.Close() | ||
|
||
buf := bufio.NewReader(file) | ||
l, _, err := buf.ReadLine() | ||
if err != nil { | ||
return false | ||
} | ||
return UIDMapInUserNS(uidmap) | ||
} | ||
|
||
line := string(l) | ||
var a, b, c int64 | ||
fmt.Sscanf(line, "%d %d %d", &a, &b, &c) | ||
func UIDMapInUserNS(uidmap []user.IDMap) bool { | ||
/* | ||
* We assume we are in the initial user namespace if we have a full | ||
* range - 4294967295 uids starting at uid 0. | ||
*/ | ||
if a == 0 && b == 0 && c == 4294967295 { | ||
if len(uidmap) == 1 && uidmap[0].ID == 0 && uidmap[0].ParentID == 0 && uidmap[0].Count == 4294967295 { | ||
return false | ||
} | ||
return true | ||
} | ||
|
||
// GetParentNSeuid returns the euid within the parent user namespace | ||
func GetParentNSeuid() int { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think @brauner had a patch like this for Ubuntu? This code should also check There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As commented above, I think we need to find an alternative check to support nested userns |
||
euid := os.Geteuid() | ||
uidmap, err := user.CurrentProcessUIDMap() | ||
if err != nil { | ||
// This kernel-provided file only exists if user namespaces are supported | ||
return euid | ||
} | ||
for _, um := range uidmap { | ||
if um.ID <= euid && euid <= um.ID+um.Count-1 { | ||
return um.ParentID + euid - um.ID | ||
} | ||
} | ||
return euid | ||
} | ||
|
||
// SetSubreaper sets the value i as the subreaper setting for the calling process | ||
func SetSubreaper(i int) error { | ||
return unix.Prctl(PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// +build linux | ||
|
||
package system | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
|
||
"github.com/opencontainers/runc/libcontainer/user" | ||
) | ||
|
||
func TestUIDMapInUserNS(t *testing.T) { | ||
cases := []struct { | ||
s string | ||
expected bool | ||
}{ | ||
{ | ||
s: " 0 0 4294967295\n", | ||
expected: false, | ||
}, | ||
{ | ||
s: " 0 0 1\n", | ||
expected: true, | ||
}, | ||
{ | ||
s: " 0 1001 1\n 1 231072 65536\n", | ||
expected: true, | ||
}, | ||
{ | ||
// file exist but empty (the initial state when userns is created. see man 7 user_namespaces) | ||
s: "", | ||
expected: true, | ||
}, | ||
} | ||
for _, c := range cases { | ||
uidmap, err := user.ParseIDMap(strings.NewReader(c.s)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
actual := UIDMapInUserNS(uidmap) | ||
if c.expected != actual { | ||
t.Fatalf("expected %v, got %v for %q", c.expected, actual, c.s) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this broke ARM builds in Moby;