mirror of
https://github.com/golang/go
synced 2024-11-18 21:05:02 -07:00
syscall: support UID/GID map files for Linux user namespaces
Fixes #8447. LGTM=iant R=golang-codereviews, bradfitz, iant CC=golang-codereviews https://golang.org/cl/126190043
This commit is contained in:
parent
ea491c5f96
commit
f9d7e13955
@ -10,19 +10,29 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux.
|
||||||
|
// See user_namespaces(7).
|
||||||
|
type SysProcIDMap struct {
|
||||||
|
ContainerID int // Container ID.
|
||||||
|
HostID int // Host ID.
|
||||||
|
Size int // Size.
|
||||||
|
}
|
||||||
|
|
||||||
type SysProcAttr struct {
|
type SysProcAttr struct {
|
||||||
Chroot string // Chroot.
|
Chroot string // Chroot.
|
||||||
Credential *Credential // Credential.
|
Credential *Credential // Credential.
|
||||||
Ptrace bool // Enable tracing.
|
Ptrace bool // Enable tracing.
|
||||||
Setsid bool // Create session.
|
Setsid bool // Create session.
|
||||||
Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
|
Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
|
||||||
Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
|
Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
|
||||||
Noctty bool // Detach fd 0 from controlling terminal
|
Noctty bool // Detach fd 0 from controlling terminal
|
||||||
Ctty int // Controlling TTY fd (Linux only)
|
Ctty int // Controlling TTY fd (Linux only)
|
||||||
Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
|
Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
|
||||||
Cloneflags uintptr // Flags for clone calls (Linux only)
|
Cloneflags uintptr // Flags for clone calls (Linux only)
|
||||||
Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY)
|
Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY)
|
||||||
Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set)
|
Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set)
|
||||||
|
UidMappings []SysProcIDMap // User ID mappings for user namespaces.
|
||||||
|
GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implemented in runtime package.
|
// Implemented in runtime package.
|
||||||
@ -44,8 +54,10 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
|
|||||||
var (
|
var (
|
||||||
r1 uintptr
|
r1 uintptr
|
||||||
err1 Errno
|
err1 Errno
|
||||||
|
err2 Errno
|
||||||
nextfd int
|
nextfd int
|
||||||
i int
|
i int
|
||||||
|
p [2]int
|
||||||
)
|
)
|
||||||
|
|
||||||
// Guard against side effects of shuffling fds below.
|
// Guard against side effects of shuffling fds below.
|
||||||
@ -61,6 +73,14 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
|
|||||||
}
|
}
|
||||||
nextfd++
|
nextfd++
|
||||||
|
|
||||||
|
// Allocate another pipe for parent to child communication for
|
||||||
|
// synchronizing writing of User ID/Group ID mappings.
|
||||||
|
if sys.UidMappings != nil || sys.GidMappings != nil {
|
||||||
|
if err := forkExecPipe(p[:]); err != nil {
|
||||||
|
return 0, err.(Errno)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// About to call fork.
|
// About to call fork.
|
||||||
// No more allocation or calls of non-assembly functions.
|
// No more allocation or calls of non-assembly functions.
|
||||||
runtime_BeforeFork()
|
runtime_BeforeFork()
|
||||||
@ -75,6 +95,16 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
|
|||||||
runtime_AfterFork()
|
runtime_AfterFork()
|
||||||
pid = int(r1)
|
pid = int(r1)
|
||||||
|
|
||||||
|
if sys.UidMappings != nil || sys.GidMappings != nil {
|
||||||
|
Close(p[0])
|
||||||
|
err := writeUidGidMappings(pid, sys)
|
||||||
|
if err != nil {
|
||||||
|
err2 = err.(Errno)
|
||||||
|
}
|
||||||
|
RawSyscall(SYS_WRITE, uintptr(p[1]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2))
|
||||||
|
Close(p[1])
|
||||||
|
}
|
||||||
|
|
||||||
if sys.Joinpgrp != 0 {
|
if sys.Joinpgrp != 0 {
|
||||||
// Place the child in the specified process group.
|
// Place the child in the specified process group.
|
||||||
RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0)
|
RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0)
|
||||||
@ -93,6 +123,25 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
|
|||||||
|
|
||||||
// Fork succeeded, now in child.
|
// Fork succeeded, now in child.
|
||||||
|
|
||||||
|
// Wait for User ID/Group ID mappings to be written.
|
||||||
|
if sys.UidMappings != nil || sys.GidMappings != nil {
|
||||||
|
if _, _, err1 = RawSyscall(SYS_CLOSE, uintptr(p[1]), 0, 0); err1 != 0 {
|
||||||
|
goto childerror
|
||||||
|
}
|
||||||
|
r1, _, err1 = RawSyscall(SYS_READ, uintptr(p[0]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2))
|
||||||
|
if err1 != 0 {
|
||||||
|
goto childerror
|
||||||
|
}
|
||||||
|
if r1 != unsafe.Sizeof(err2) {
|
||||||
|
err1 = EINVAL
|
||||||
|
goto childerror
|
||||||
|
}
|
||||||
|
if err2 != 0 {
|
||||||
|
err1 = err2
|
||||||
|
goto childerror
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parent death signal
|
// Parent death signal
|
||||||
if sys.Pdeathsig != 0 {
|
if sys.Pdeathsig != 0 {
|
||||||
_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
|
_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
|
||||||
@ -296,3 +345,53 @@ func forkExecPipe(p []int) (err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeIDMappings writes the user namespace User ID or Group ID mappings to the specified path.
|
||||||
|
func writeIDMappings(path string, idMap []SysProcIDMap) error {
|
||||||
|
fd, err := Open(path, O_RDWR, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data := ""
|
||||||
|
for _, im := range idMap {
|
||||||
|
data = data + itoa(im.ContainerID) + " " + itoa(im.HostID) + " " + itoa(im.Size) + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := ByteSliceFromString(data)
|
||||||
|
if err != nil {
|
||||||
|
Close(fd)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := Write(fd, bytes); err != nil {
|
||||||
|
Close(fd)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Close(fd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeUidGidMappings writes User ID and Group ID mappings for user namespaces
|
||||||
|
// for a process and it is called from the parent process.
|
||||||
|
func writeUidGidMappings(pid int, sys *SysProcAttr) error {
|
||||||
|
if sys.UidMappings != nil {
|
||||||
|
uidf := "/proc/" + itoa(pid) + "/uid_map"
|
||||||
|
if err := writeIDMappings(uidf, sys.UidMappings); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sys.GidMappings != nil {
|
||||||
|
gidf := "/proc/" + itoa(pid) + "/gid_map"
|
||||||
|
if err := writeIDMappings(gidf, sys.GidMappings); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user