mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-06 10:43:56 +00:00
bump runc to v1.1.11
Signed-off-by: Kay Yan <kay.yan@daocloud.io>
This commit is contained in:
parent
6cf77098aa
commit
7503440ba8
2
go.mod
2
go.mod
@ -53,7 +53,7 @@ require (
|
|||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
||||||
github.com/onsi/ginkgo/v2 v2.13.2
|
github.com/onsi/ginkgo/v2 v2.13.2
|
||||||
github.com/onsi/gomega v1.30.0
|
github.com/onsi/gomega v1.30.0
|
||||||
github.com/opencontainers/runc v1.1.10
|
github.com/opencontainers/runc v1.1.11
|
||||||
github.com/opencontainers/selinux v1.11.0
|
github.com/opencontainers/selinux v1.11.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pmezard/go-difflib v1.0.0
|
github.com/pmezard/go-difflib v1.0.0
|
||||||
|
4
go.sum
4
go.sum
@ -659,8 +659,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
|||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
|
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
|
||||||
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||||
github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40=
|
github.com/opencontainers/runc v1.1.11 h1:9LjxyVlE0BPMRP2wuQDRlHV4941Jp9rc3F0+YKimopA=
|
||||||
github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M=
|
github.com/opencontainers/runc v1.1.11/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
|
||||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
github.com/opencontainers/runtime-spec v1.0.3-0.20220909204839-494a5a6aca78 h1:R5M2qXZiK/mWPMT4VldCOiSL9HIAMuxQZWdG0CSM5+4=
|
github.com/opencontainers/runtime-spec v1.0.3-0.20220909204839-494a5a6aca78 h1:R5M2qXZiK/mWPMT4VldCOiSL9HIAMuxQZWdG0CSM5+4=
|
||||||
|
4
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go
generated
vendored
4
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go
generated
vendored
@ -170,6 +170,10 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
stats.MemoryStats.SwapUsage = swapUsage
|
stats.MemoryStats.SwapUsage = swapUsage
|
||||||
|
stats.MemoryStats.SwapOnlyUsage = cgroups.MemoryData{
|
||||||
|
Usage: swapUsage.Usage - memoryUsage.Usage,
|
||||||
|
Failcnt: swapUsage.Failcnt - memoryUsage.Failcnt,
|
||||||
|
}
|
||||||
kernelUsage, err := getMemoryData(path, "kmem")
|
kernelUsage, err := getMemoryData(path, "kmem")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
18
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go
generated
vendored
18
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go
generated
vendored
@ -100,7 +100,7 @@ func statMemory(dirPath string, stats *cgroups.Stats) error {
|
|||||||
memoryUsage, err := getMemoryDataV2(dirPath, "")
|
memoryUsage, err := getMemoryDataV2(dirPath, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, unix.ENOENT) && dirPath == UnifiedMountpoint {
|
if errors.Is(err, unix.ENOENT) && dirPath == UnifiedMountpoint {
|
||||||
// The root cgroup does not have memory.{current,max}
|
// The root cgroup does not have memory.{current,max,peak}
|
||||||
// so emulate those using data from /proc/meminfo and
|
// so emulate those using data from /proc/meminfo and
|
||||||
// /sys/fs/cgroup/memory.stat
|
// /sys/fs/cgroup/memory.stat
|
||||||
return rootStatsFromMeminfo(stats)
|
return rootStatsFromMeminfo(stats)
|
||||||
@ -108,10 +108,12 @@ func statMemory(dirPath string, stats *cgroups.Stats) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
stats.MemoryStats.Usage = memoryUsage
|
stats.MemoryStats.Usage = memoryUsage
|
||||||
swapUsage, err := getMemoryDataV2(dirPath, "swap")
|
swapOnlyUsage, err := getMemoryDataV2(dirPath, "swap")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
stats.MemoryStats.SwapOnlyUsage = swapOnlyUsage
|
||||||
|
swapUsage := swapOnlyUsage
|
||||||
// As cgroup v1 reports SwapUsage values as mem+swap combined,
|
// As cgroup v1 reports SwapUsage values as mem+swap combined,
|
||||||
// while in cgroup v2 swap values do not include memory,
|
// while in cgroup v2 swap values do not include memory,
|
||||||
// report combined mem+swap for v1 compatibility.
|
// report combined mem+swap for v1 compatibility.
|
||||||
@ -119,6 +121,9 @@ func statMemory(dirPath string, stats *cgroups.Stats) error {
|
|||||||
if swapUsage.Limit != math.MaxUint64 {
|
if swapUsage.Limit != math.MaxUint64 {
|
||||||
swapUsage.Limit += memoryUsage.Limit
|
swapUsage.Limit += memoryUsage.Limit
|
||||||
}
|
}
|
||||||
|
// The `MaxUsage` of mem+swap cannot simply combine mem with
|
||||||
|
// swap. So set it to 0 for v1 compatibility.
|
||||||
|
swapUsage.MaxUsage = 0
|
||||||
stats.MemoryStats.SwapUsage = swapUsage
|
stats.MemoryStats.SwapUsage = swapUsage
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -133,6 +138,7 @@ func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) {
|
|||||||
}
|
}
|
||||||
usage := moduleName + ".current"
|
usage := moduleName + ".current"
|
||||||
limit := moduleName + ".max"
|
limit := moduleName + ".max"
|
||||||
|
maxUsage := moduleName + ".peak"
|
||||||
|
|
||||||
value, err := fscommon.GetCgroupParamUint(path, usage)
|
value, err := fscommon.GetCgroupParamUint(path, usage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -152,6 +158,14 @@ func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) {
|
|||||||
}
|
}
|
||||||
memoryData.Limit = value
|
memoryData.Limit = value
|
||||||
|
|
||||||
|
// `memory.peak` since kernel 5.19
|
||||||
|
// `memory.swap.peak` since kernel 6.5
|
||||||
|
value, err = fscommon.GetCgroupParamUint(path, maxUsage)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return cgroups.MemoryData{}, err
|
||||||
|
}
|
||||||
|
memoryData.MaxUsage = value
|
||||||
|
|
||||||
return memoryData, nil
|
return memoryData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 MemoryData `json:"usage,omitempty"`
|
||||||
// usage of memory + swap
|
// usage of memory + swap
|
||||||
SwapUsage MemoryData `json:"swap_usage,omitempty"`
|
SwapUsage MemoryData `json:"swap_usage,omitempty"`
|
||||||
|
// usage of swap only
|
||||||
|
SwapOnlyUsage MemoryData `json:"swap_only_usage,omitempty"`
|
||||||
// usage of kernel memory
|
// usage of kernel memory
|
||||||
KernelUsage MemoryData `json:"kernel_usage,omitempty"`
|
KernelUsage MemoryData `json:"kernel_usage,omitempty"`
|
||||||
// usage of kernel TCP memory
|
// 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.
|
// IDMap represents UID/GID Mappings for User Namespaces.
|
||||||
type IDMap struct {
|
type IDMap struct {
|
||||||
ContainerID int `json:"container_id"`
|
ContainerID int64 `json:"container_id"`
|
||||||
HostID int `json:"host_id"`
|
HostID int64 `json:"host_id"`
|
||||||
Size int `json:"size"`
|
Size int64 `json:"size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seccomp represents syscall restrictions
|
// 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
|
package configs
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNoUIDMap = errors.New("User namespaces enabled, but no uid mappings found.")
|
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 {
|
if c.UidMappings == nil {
|
||||||
return -1, errNoUIDMap
|
return -1, errNoUIDMap
|
||||||
}
|
}
|
||||||
id, found := c.hostIDFromMapping(containerId, c.UidMappings)
|
id, found := c.hostIDFromMapping(int64(containerId), c.UidMappings)
|
||||||
if !found {
|
if !found {
|
||||||
return -1, errNoUserMap
|
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 unchanged id.
|
||||||
return containerId, nil
|
return containerId, nil
|
||||||
@ -39,11 +50,18 @@ func (c Config) HostGID(containerId int) (int, error) {
|
|||||||
if c.GidMappings == nil {
|
if c.GidMappings == nil {
|
||||||
return -1, errNoGIDMap
|
return -1, errNoGIDMap
|
||||||
}
|
}
|
||||||
id, found := c.hostIDFromMapping(containerId, c.GidMappings)
|
id, found := c.hostIDFromMapping(int64(containerId), c.GidMappings)
|
||||||
if !found {
|
if !found {
|
||||||
return -1, errNoGroupMap
|
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 unchanged id.
|
||||||
return containerId, nil
|
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
|
// Utility function that gets a host ID for a container ID from user namespace map
|
||||||
// if that ID is present in the 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 {
|
for _, m := range uMap {
|
||||||
if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) {
|
if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) {
|
||||||
hostID := m.HostID + (containerID - m.ContainerID)
|
hostID := m.HostID + (containerID - m.ContainerID)
|
||||||
|
31
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go
generated
vendored
31
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go
generated
vendored
@ -28,25 +28,18 @@ func (v *ConfigValidator) rootlessEUID(config *configs.Config) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasIDMapping(id int, mappings []configs.IDMap) bool {
|
|
||||||
for _, m := range mappings {
|
|
||||||
if id >= m.ContainerID && id < m.ContainerID+m.Size {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func rootlessEUIDMappings(config *configs.Config) error {
|
func rootlessEUIDMappings(config *configs.Config) error {
|
||||||
if !config.Namespaces.Contains(configs.NEWUSER) {
|
if !config.Namespaces.Contains(configs.NEWUSER) {
|
||||||
return errors.New("rootless container requires user namespaces")
|
return errors.New("rootless container requires user namespaces")
|
||||||
}
|
}
|
||||||
|
// We only require mappings if we are not joining another userns.
|
||||||
if len(config.UidMappings) == 0 {
|
if path := config.Namespaces.PathOf(configs.NEWUSER); path == "" {
|
||||||
return errors.New("rootless containers requires at least one UID mapping")
|
if len(config.UidMappings) == 0 {
|
||||||
}
|
return errors.New("rootless containers requires at least one UID mapping")
|
||||||
if len(config.GidMappings) == 0 {
|
}
|
||||||
return errors.New("rootless containers requires at least one GID mapping")
|
if len(config.GidMappings) == 0 {
|
||||||
|
return errors.New("rootless containers requires at least one GID mapping")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -70,8 +63,8 @@ func rootlessEUIDMount(config *configs.Config) error {
|
|||||||
// Ignore unknown mount options.
|
// Ignore unknown mount options.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !hasIDMapping(uid, config.UidMappings) {
|
if _, err := config.HostUID(uid); err != nil {
|
||||||
return errors.New("cannot specify uid= mount options for unmapped uid in rootless containers")
|
return fmt.Errorf("cannot specify uid=%d mount option for rootless container: %w", uid, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +75,8 @@ func rootlessEUIDMount(config *configs.Config) error {
|
|||||||
// Ignore unknown mount options.
|
// Ignore unknown mount options.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !hasIDMapping(gid, config.GidMappings) {
|
if _, err := config.HostGID(gid); err != nil {
|
||||||
return errors.New("cannot specify gid= mount options for unmapped gid in rootless containers")
|
return fmt.Errorf("cannot specify gid=%d mount option for rootless container: %w", gid, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
generated
vendored
12
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
generated
vendored
@ -109,11 +109,19 @@ func (v *ConfigValidator) security(config *configs.Config) error {
|
|||||||
func (v *ConfigValidator) usernamespace(config *configs.Config) error {
|
func (v *ConfigValidator) usernamespace(config *configs.Config) error {
|
||||||
if config.Namespaces.Contains(configs.NEWUSER) {
|
if config.Namespaces.Contains(configs.NEWUSER) {
|
||||||
if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
|
if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
|
||||||
return errors.New("USER namespaces aren't enabled in the kernel")
|
return errors.New("user namespaces aren't enabled in the kernel")
|
||||||
}
|
}
|
||||||
|
hasPath := config.Namespaces.PathOf(configs.NEWUSER) != ""
|
||||||
|
hasMappings := config.UidMappings != nil || config.GidMappings != nil
|
||||||
|
if !hasPath && !hasMappings {
|
||||||
|
return errors.New("user namespaces enabled, but no namespace path to join nor mappings to apply specified")
|
||||||
|
}
|
||||||
|
// The hasPath && hasMappings validation case is handled in specconv --
|
||||||
|
// we cache the mappings in Config during specconv in the hasPath case,
|
||||||
|
// so we cannot do that validation here.
|
||||||
} else {
|
} else {
|
||||||
if config.UidMappings != nil || config.GidMappings != nil {
|
if config.UidMappings != nil || config.GidMappings != nil {
|
||||||
return errors.New("User namespace mappings specified, but USER namespace isn't enabled in the config")
|
return errors.New("user namespace mappings specified, but user namespace isn't enabled in the config")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
2
vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
generated
vendored
@ -2268,7 +2268,7 @@ func ignoreTerminateErrors(err error) error {
|
|||||||
|
|
||||||
func requiresRootOrMappingTool(c *configs.Config) bool {
|
func requiresRootOrMappingTool(c *configs.Config) bool {
|
||||||
gidMap := []configs.IDMap{
|
gidMap := []configs.IDMap{
|
||||||
{ContainerID: 0, HostID: os.Getegid(), Size: 1},
|
{ContainerID: 0, HostID: int64(os.Getegid()), Size: 1},
|
||||||
}
|
}
|
||||||
return !reflect.DeepEqual(c.GidMappings, gidMap)
|
return !reflect.DeepEqual(c.GidMappings, gidMap)
|
||||||
}
|
}
|
||||||
|
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
@ -591,7 +591,7 @@ github.com/onsi/gomega/types
|
|||||||
# github.com/opencontainers/go-digest v1.0.0
|
# github.com/opencontainers/go-digest v1.0.0
|
||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
github.com/opencontainers/go-digest
|
github.com/opencontainers/go-digest
|
||||||
# github.com/opencontainers/runc v1.1.10
|
# github.com/opencontainers/runc v1.1.11
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
github.com/opencontainers/runc/libcontainer
|
github.com/opencontainers/runc/libcontainer
|
||||||
github.com/opencontainers/runc/libcontainer/apparmor
|
github.com/opencontainers/runc/libcontainer/apparmor
|
||||||
|
Loading…
Reference in New Issue
Block a user