Merge pull request #47206 from thaJeztah/24.0_backport_vendor_runc_1.1.11
[24.0 backport] vendor: github.com/opencontainers/runc v1.1.11
This commit is contained in:
commit
3205a51dc5
8 changed files with 298 additions and 13 deletions
|
@ -71,7 +71,7 @@ require (
|
|||
github.com/morikuni/aec v1.0.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3
|
||||
github.com/opencontainers/runc v1.1.10
|
||||
github.com/opencontainers/runc v1.1.11
|
||||
github.com/opencontainers/runtime-spec v1.1.0-rc.2
|
||||
github.com/opencontainers/selinux v1.11.0
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
|
|
|
@ -1147,8 +1147,8 @@ github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rm
|
|||
github.com/opencontainers/runc v1.0.0-rc92/go.mod h1:X1zlU4p7wOlX4+WRCz+hvlRv8phdL7UqbYD+vQwNMmE=
|
||||
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
|
||||
github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
|
||||
github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40=
|
||||
github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M=
|
||||
github.com/opencontainers/runc v1.1.11 h1:9LjxyVlE0BPMRP2wuQDRlHV4941Jp9rc3F0+YKimopA=
|
||||
github.com/opencontainers/runc v1.1.11/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
|
|
2
vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go
generated
vendored
|
@ -78,6 +78,8 @@ type MemoryStats struct {
|
|||
Usage MemoryData `json:"usage,omitempty"`
|
||||
// usage of memory + swap
|
||||
SwapUsage MemoryData `json:"swap_usage,omitempty"`
|
||||
// usage of swap only
|
||||
SwapOnlyUsage MemoryData `json:"swap_only_usage,omitempty"`
|
||||
// usage of kernel memory
|
||||
KernelUsage MemoryData `json:"kernel_usage,omitempty"`
|
||||
// usage of kernel TCP memory
|
||||
|
|
6
vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
generated
vendored
|
@ -21,9 +21,9 @@ type Rlimit struct {
|
|||
|
||||
// IDMap represents UID/GID Mappings for User Namespaces.
|
||||
type IDMap struct {
|
||||
ContainerID int `json:"container_id"`
|
||||
HostID int `json:"host_id"`
|
||||
Size int `json:"size"`
|
||||
ContainerID int64 `json:"container_id"`
|
||||
HostID int64 `json:"host_id"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
// Seccomp represents syscall restrictions
|
||||
|
|
30
vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go
generated
vendored
30
vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go
generated
vendored
|
@ -1,6 +1,10 @@
|
|||
package configs
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoUIDMap = errors.New("User namespaces enabled, but no uid mappings found.")
|
||||
|
@ -16,11 +20,18 @@ func (c Config) HostUID(containerId int) (int, error) {
|
|||
if c.UidMappings == nil {
|
||||
return -1, errNoUIDMap
|
||||
}
|
||||
id, found := c.hostIDFromMapping(containerId, c.UidMappings)
|
||||
id, found := c.hostIDFromMapping(int64(containerId), c.UidMappings)
|
||||
if !found {
|
||||
return -1, errNoUserMap
|
||||
}
|
||||
return id, nil
|
||||
// If we are a 32-bit binary running on a 64-bit system, it's possible
|
||||
// the mapped user is too large to store in an int, which means we
|
||||
// cannot do the mapping. We can't just return an int64, because
|
||||
// os.Setuid() takes an int.
|
||||
if id > math.MaxInt {
|
||||
return -1, fmt.Errorf("mapping for uid %d (host id %d) is larger than native integer size (%d)", containerId, id, math.MaxInt)
|
||||
}
|
||||
return int(id), nil
|
||||
}
|
||||
// Return unchanged id.
|
||||
return containerId, nil
|
||||
|
@ -39,11 +50,18 @@ func (c Config) HostGID(containerId int) (int, error) {
|
|||
if c.GidMappings == nil {
|
||||
return -1, errNoGIDMap
|
||||
}
|
||||
id, found := c.hostIDFromMapping(containerId, c.GidMappings)
|
||||
id, found := c.hostIDFromMapping(int64(containerId), c.GidMappings)
|
||||
if !found {
|
||||
return -1, errNoGroupMap
|
||||
}
|
||||
return id, nil
|
||||
// If we are a 32-bit binary running on a 64-bit system, it's possible
|
||||
// the mapped user is too large to store in an int, which means we
|
||||
// cannot do the mapping. We can't just return an int64, because
|
||||
// os.Setgid() takes an int.
|
||||
if id > math.MaxInt {
|
||||
return -1, fmt.Errorf("mapping for gid %d (host id %d) is larger than native integer size (%d)", containerId, id, math.MaxInt)
|
||||
}
|
||||
return int(id), nil
|
||||
}
|
||||
// Return unchanged id.
|
||||
return containerId, nil
|
||||
|
@ -57,7 +75,7 @@ func (c Config) HostRootGID() (int, error) {
|
|||
|
||||
// Utility function that gets a host ID for a container ID from user namespace map
|
||||
// if that ID is present in the map.
|
||||
func (c Config) hostIDFromMapping(containerID int, uMap []IDMap) (int, bool) {
|
||||
func (c Config) hostIDFromMapping(containerID int64, uMap []IDMap) (int64, bool) {
|
||||
for _, m := range uMap {
|
||||
if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) {
|
||||
hostID := m.HostID + (containerID - m.ContainerID)
|
||||
|
|
79
vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps.c
generated
vendored
Normal file
79
vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps.c
generated
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* All of the code here is run inside an aync-signal-safe context, so we need
|
||||
* to be careful to not call any functions that could cause issues. In theory,
|
||||
* since we are a Go program, there are fewer restrictions in practice, it's
|
||||
* better to be safe than sorry.
|
||||
*
|
||||
* The only exception is exit, which we need to call to make sure we don't
|
||||
* return into runc.
|
||||
*/
|
||||
|
||||
void bail(int pipefd, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vdprintf(pipefd, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int spawn_userns_cat(char *userns_path, char *path, int outfd, int errfd)
|
||||
{
|
||||
char buffer[4096] = { 0 };
|
||||
|
||||
pid_t child = fork();
|
||||
if (child != 0)
|
||||
return child;
|
||||
/* in child */
|
||||
|
||||
/* Join the target userns. */
|
||||
int nsfd = open(userns_path, O_RDONLY);
|
||||
if (nsfd < 0)
|
||||
bail(errfd, "open userns path %s failed: %m", userns_path);
|
||||
|
||||
int err = setns(nsfd, CLONE_NEWUSER);
|
||||
if (err < 0)
|
||||
bail(errfd, "setns %s failed: %m", userns_path);
|
||||
|
||||
close(nsfd);
|
||||
|
||||
/* Pipe the requested file contents. */
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
bail(errfd, "open %s in userns %s failed: %m", path, userns_path);
|
||||
|
||||
int nread, ntotal = 0;
|
||||
while ((nread = read(fd, buffer, sizeof(buffer))) != 0) {
|
||||
if (nread < 0)
|
||||
bail(errfd, "read bytes from %s failed (after %d total bytes read): %m", path, ntotal);
|
||||
ntotal += nread;
|
||||
|
||||
int nwritten = 0;
|
||||
while (nwritten < nread) {
|
||||
int n = write(outfd, buffer, nread - nwritten);
|
||||
if (n < 0)
|
||||
bail(errfd, "write %d bytes from %s failed (after %d bytes written): %m",
|
||||
nread - nwritten, path, nwritten);
|
||||
nwritten += n;
|
||||
}
|
||||
if (nread != nwritten)
|
||||
bail(errfd, "mismatch for bytes read and written: %d read != %d written", nread, nwritten);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
close(outfd);
|
||||
close(errfd);
|
||||
|
||||
/* We must exit here, otherwise we would return into a forked runc. */
|
||||
exit(0);
|
||||
}
|
186
vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps_linux.go
generated
vendored
Normal file
186
vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,186 @@
|
|||
//go:build linux
|
||||
|
||||
package userns
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
extern int spawn_userns_cat(char *userns_path, char *path, int outfd, int errfd);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func parseIdmapData(data []byte) (ms []configs.IDMap, err error) {
|
||||
scanner := bufio.NewScanner(bytes.NewReader(data))
|
||||
for scanner.Scan() {
|
||||
var m configs.IDMap
|
||||
line := scanner.Text()
|
||||
if _, err := fmt.Sscanf(line, "%d %d %d", &m.ContainerID, &m.HostID, &m.Size); err != nil {
|
||||
return nil, fmt.Errorf("parsing id map failed: invalid format in line %q: %w", line, err)
|
||||
}
|
||||
ms = append(ms, m)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("parsing id map failed: %w", err)
|
||||
}
|
||||
return ms, nil
|
||||
}
|
||||
|
||||
// Do something equivalent to nsenter --user=<nsPath> cat <path>, but more
|
||||
// efficiently. Returns the contents of the requested file from within the user
|
||||
// namespace.
|
||||
func spawnUserNamespaceCat(nsPath string, path string) ([]byte, error) {
|
||||
rdr, wtr, err := os.Pipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create pipe for userns spawn failed: %w", err)
|
||||
}
|
||||
defer rdr.Close()
|
||||
defer wtr.Close()
|
||||
|
||||
errRdr, errWtr, err := os.Pipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create error pipe for userns spawn failed: %w", err)
|
||||
}
|
||||
defer errRdr.Close()
|
||||
defer errWtr.Close()
|
||||
|
||||
cNsPath := C.CString(nsPath)
|
||||
defer C.free(unsafe.Pointer(cNsPath))
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
childPid := C.spawn_userns_cat(cNsPath, cPath, C.int(wtr.Fd()), C.int(errWtr.Fd()))
|
||||
|
||||
if childPid < 0 {
|
||||
return nil, fmt.Errorf("failed to spawn fork for userns")
|
||||
} else if childPid == 0 {
|
||||
// this should never happen
|
||||
panic("runc executing inside fork child -- unsafe state!")
|
||||
}
|
||||
|
||||
// We are in the parent -- close the write end of the pipe before reading.
|
||||
wtr.Close()
|
||||
output, err := io.ReadAll(rdr)
|
||||
rdr.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading from userns spawn failed: %w", err)
|
||||
}
|
||||
|
||||
// Ditto for the error pipe.
|
||||
errWtr.Close()
|
||||
errOutput, err := io.ReadAll(errRdr)
|
||||
errRdr.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading from userns spawn error pipe failed: %w", err)
|
||||
}
|
||||
errOutput = bytes.TrimSpace(errOutput)
|
||||
|
||||
// Clean up the child.
|
||||
child, err := os.FindProcess(int(childPid))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find userns spawn process: %w", err)
|
||||
}
|
||||
state, err := child.Wait()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to wait for userns spawn process: %w", err)
|
||||
}
|
||||
if !state.Success() {
|
||||
errStr := string(errOutput)
|
||||
if errStr == "" {
|
||||
errStr = fmt.Sprintf("unknown error (status code %d)", state.ExitCode())
|
||||
}
|
||||
return nil, fmt.Errorf("userns spawn: %s", errStr)
|
||||
} else if len(errOutput) > 0 {
|
||||
// We can just ignore weird output in the error pipe if the process
|
||||
// didn't bail(), but for completeness output for debugging.
|
||||
logrus.Debugf("userns spawn succeeded but unexpected error message found: %s", string(errOutput))
|
||||
}
|
||||
// The subprocess succeeded, return whatever it wrote to the pipe.
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func GetUserNamespaceMappings(nsPath string) (uidMap, gidMap []configs.IDMap, err error) {
|
||||
var (
|
||||
pid int
|
||||
extra rune
|
||||
tryFastPath bool
|
||||
)
|
||||
|
||||
// nsPath is usually of the form /proc/<pid>/ns/user, which means that we
|
||||
// already have a pid that is part of the user namespace and thus we can
|
||||
// just use the pid to read from /proc/<pid>/*id_map.
|
||||
//
|
||||
// Note that Sscanf doesn't consume the whole input, so we check for any
|
||||
// trailing data with %c. That way, we can be sure the pattern matched
|
||||
// /proc/$pid/ns/user _exactly_ iff n === 1.
|
||||
if n, _ := fmt.Sscanf(nsPath, "/proc/%d/ns/user%c", &pid, &extra); n == 1 {
|
||||
tryFastPath = pid > 0
|
||||
}
|
||||
|
||||
for _, mapType := range []struct {
|
||||
name string
|
||||
idMap *[]configs.IDMap
|
||||
}{
|
||||
{"uid_map", &uidMap},
|
||||
{"gid_map", &gidMap},
|
||||
} {
|
||||
var mapData []byte
|
||||
|
||||
if tryFastPath {
|
||||
path := fmt.Sprintf("/proc/%d/%s", pid, mapType.name)
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
// Do not error out here -- we need to try the slow path if the
|
||||
// fast path failed.
|
||||
logrus.Debugf("failed to use fast path to read %s from userns %s (error: %s), falling back to slow userns-join path", mapType.name, nsPath, err)
|
||||
} else {
|
||||
mapData = data
|
||||
}
|
||||
} else {
|
||||
logrus.Debugf("cannot use fast path to read %s from userns %s, falling back to slow userns-join path", mapType.name, nsPath)
|
||||
}
|
||||
|
||||
if mapData == nil {
|
||||
// We have to actually join the namespace if we cannot take the
|
||||
// fast path. The path is resolved with respect to the child
|
||||
// process, so just use /proc/self.
|
||||
data, err := spawnUserNamespaceCat(nsPath, "/proc/self/"+mapType.name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mapData = data
|
||||
}
|
||||
idMap, err := parseIdmapData(mapData)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse %s of userns %s: %w", mapType.name, nsPath, err)
|
||||
}
|
||||
*mapType.idMap = idMap
|
||||
}
|
||||
|
||||
return uidMap, gidMap, nil
|
||||
}
|
||||
|
||||
// IsSameMapping returns whether or not the two id mappings are the same. Note
|
||||
// that if the order of the mappings is different, or a mapping has been split,
|
||||
// the mappings will be considered different.
|
||||
func IsSameMapping(a, b []configs.IDMap) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for idx := range a {
|
||||
if a[idx] != b[idx] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
|
@ -837,7 +837,7 @@ github.com/opencontainers/go-digest/digestset
|
|||
github.com/opencontainers/image-spec/identity
|
||||
github.com/opencontainers/image-spec/specs-go
|
||||
github.com/opencontainers/image-spec/specs-go/v1
|
||||
# github.com/opencontainers/runc v1.1.10
|
||||
# github.com/opencontainers/runc v1.1.11
|
||||
## explicit; go 1.17
|
||||
github.com/opencontainers/runc/libcontainer/cgroups
|
||||
github.com/opencontainers/runc/libcontainer/configs
|
||||
|
|
Loading…
Add table
Reference in a new issue