diff --git a/.gitignore b/.gitignore index 7668d0d..d7c4a2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/v1.0.0-rc93.tar.gz +SOURCES/v1.0.0-rc95.tar.gz diff --git a/.runc.metadata b/.runc.metadata index 0a7c604..3f0f3fc 100644 --- a/.runc.metadata +++ b/.runc.metadata @@ -1 +1 @@ -e8693109441696536710e5751e0fee6e6fa32590 SOURCES/v1.0.0-rc93.tar.gz +23f05a9f1ae2907117385a48f1a464608fd75d30 SOURCES/v1.0.0-rc95.tar.gz diff --git a/SOURCES/rc93-0001-libct-newInitConfig-nit.patch b/SOURCES/rc93-0001-libct-newInitConfig-nit.patch deleted file mode 100644 index 2040586..0000000 --- a/SOURCES/rc93-0001-libct-newInitConfig-nit.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 28daf0653d324fad545a7031e64b6891f399969b Mon Sep 17 00:00:00 2001 -From: Kir Kolyshkin -Date: Tue, 23 Feb 2021 17:58:07 -0800 -Subject: [PATCH 1/5] libct/newInitConfig: nit - -Move the initialization of Console* fields as they are unconditional. - -Signed-off-by: Kir Kolyshkin ---- - libcontainer/container_linux.go | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go -index 3dca29e4c3f2..b6100aae9d5a 100644 ---- a/libcontainer/container_linux.go -+++ b/libcontainer/container_linux.go -@@ -594,6 +594,9 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig { - AppArmorProfile: c.config.AppArmorProfile, - ProcessLabel: c.config.ProcessLabel, - Rlimits: c.config.Rlimits, -+ CreateConsole: process.ConsoleSocket != nil, -+ ConsoleWidth: process.ConsoleWidth, -+ ConsoleHeight: process.ConsoleHeight, - } - if process.NoNewPrivileges != nil { - cfg.NoNewPrivileges = *process.NoNewPrivileges -@@ -607,9 +610,7 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig { - if len(process.Rlimits) > 0 { - cfg.Rlimits = process.Rlimits - } -- cfg.CreateConsole = process.ConsoleSocket != nil -- cfg.ConsoleWidth = process.ConsoleWidth -- cfg.ConsoleHeight = process.ConsoleHeight -+ - return cfg - } - --- -2.31.1 - diff --git a/SOURCES/rc93-0002-libct-rootfs-introduce-and-use-mountConfig.patch b/SOURCES/rc93-0002-libct-rootfs-introduce-and-use-mountConfig.patch deleted file mode 100644 index 3df9b15..0000000 --- a/SOURCES/rc93-0002-libct-rootfs-introduce-and-use-mountConfig.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 46ec7b5a94d370c4963ca361e9d96cb78d75d118 Mon Sep 17 00:00:00 2001 -From: Kir Kolyshkin -Date: Tue, 23 Feb 2021 18:14:37 -0800 -Subject: [PATCH 2/5] libct/rootfs: introduce and use mountConfig - -The code is already passing three parameters around from -mountToRootfs to mountCgroupV* to mountToRootfs again. - -I am about to add another parameter, so let's introduce and -use struct mountConfig to pass around. - -Signed-off-by: Kir Kolyshkin ---- - libcontainer/rootfs_linux.go | 42 ++++++++++++++++++++++-------------- - 1 file changed, 26 insertions(+), 16 deletions(-) - -diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go -index 411496ab7c6d..a384abb7e8a5 100644 ---- a/libcontainer/rootfs_linux.go -+++ b/libcontainer/rootfs_linux.go -@@ -29,6 +29,12 @@ import ( - - const defaultMountFlags = unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV - -+type mountConfig struct { -+ root string -+ label string -+ cgroupns bool -+} -+ - // needsSetupDev returns true if /dev needs to be set up. - func needsSetupDev(config *configs.Config) bool { - for _, m := range config.Mounts { -@@ -48,7 +54,11 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { - return newSystemErrorWithCause(err, "preparing rootfs") - } - -- hasCgroupns := config.Namespaces.Contains(configs.NEWCGROUP) -+ mountConfig := &mountConfig{ -+ root: config.Rootfs, -+ label: config.MountLabel, -+ cgroupns: config.Namespaces.Contains(configs.NEWCGROUP), -+ } - setupDev := needsSetupDev(config) - for _, m := range config.Mounts { - for _, precmd := range m.PremountCmds { -@@ -56,7 +66,7 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { - return newSystemErrorWithCause(err, "running premount command") - } - } -- if err := mountToRootfs(m, config.Rootfs, config.MountLabel, hasCgroupns); err != nil { -+ if err := mountToRootfs(m, mountConfig); err != nil { - return newSystemErrorWithCausef(err, "mounting %q to rootfs at %q", m.Source, m.Destination) - } - -@@ -222,7 +232,7 @@ func prepareBindMount(m *configs.Mount, rootfs string) error { - return nil - } - --func mountCgroupV1(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { -+func mountCgroupV1(m *configs.Mount, c *mountConfig) error { - binds, err := getCgroupMounts(m) - if err != nil { - return err -@@ -242,12 +252,12 @@ func mountCgroupV1(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b - Data: "mode=755", - PropagationFlags: m.PropagationFlags, - } -- if err := mountToRootfs(tmpfs, rootfs, mountLabel, enableCgroupns); err != nil { -+ if err := mountToRootfs(tmpfs, c); err != nil { - return err - } - for _, b := range binds { -- if enableCgroupns { -- subsystemPath := filepath.Join(rootfs, b.Destination) -+ if c.cgroupns { -+ subsystemPath := filepath.Join(c.root, b.Destination) - if err := os.MkdirAll(subsystemPath, 0755); err != nil { - return err - } -@@ -266,7 +276,7 @@ func mountCgroupV1(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b - return err - } - } else { -- if err := mountToRootfs(b, rootfs, mountLabel, enableCgroupns); err != nil { -+ if err := mountToRootfs(b, c); err != nil { - return err - } - } -@@ -276,7 +286,7 @@ func mountCgroupV1(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b - // symlink(2) is very dumb, it will just shove the path into - // the link and doesn't do any checks or relative path - // conversion. Also, don't error out if the cgroup already exists. -- if err := os.Symlink(mc, filepath.Join(rootfs, m.Destination, ss)); err != nil && !os.IsExist(err) { -+ if err := os.Symlink(mc, filepath.Join(c.root, m.Destination, ss)); err != nil && !os.IsExist(err) { - return err - } - } -@@ -284,8 +294,8 @@ func mountCgroupV1(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b - return nil - } - --func mountCgroupV2(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { -- cgroupPath, err := securejoin.SecureJoin(rootfs, m.Destination) -+func mountCgroupV2(m *configs.Mount, c *mountConfig) error { -+ cgroupPath, err := securejoin.SecureJoin(c.root, m.Destination) - if err != nil { - return err - } -@@ -302,10 +312,10 @@ func mountCgroupV2(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b - return nil - } - --func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { -- var ( -- dest = m.Destination -- ) -+func mountToRootfs(m *configs.Mount, c *mountConfig) error { -+ rootfs := c.root -+ mountLabel := c.label -+ dest := m.Destination - if !strings.HasPrefix(dest, rootfs) { - dest = filepath.Join(rootfs, dest) - } -@@ -424,9 +434,9 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b - } - case "cgroup": - if cgroups.IsCgroup2UnifiedMode() { -- return mountCgroupV2(m, rootfs, mountLabel, enableCgroupns) -+ return mountCgroupV2(m, c) - } -- return mountCgroupV1(m, rootfs, mountLabel, enableCgroupns) -+ return mountCgroupV1(m, c) - default: - // ensure that the destination of the mount is resolved of symlinks at mount time because - // any previous mounts can invalidate the next mount's destination. --- -2.31.1 - diff --git a/SOURCES/rc93-0003-libct-rootfs-mountCgroupV2-minor-refactor.patch b/SOURCES/rc93-0003-libct-rootfs-mountCgroupV2-minor-refactor.patch deleted file mode 100644 index 2ded660..0000000 --- a/SOURCES/rc93-0003-libct-rootfs-mountCgroupV2-minor-refactor.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 198a2806b0b5522cff1c53bf4671cfee85e45608 Mon Sep 17 00:00:00 2001 -From: Kir Kolyshkin -Date: Tue, 23 Feb 2021 18:25:56 -0800 -Subject: [PATCH 3/5] libct/rootfs/mountCgroupV2: minor refactor - -1. s/cgroupPath/dest/ - -2. don't hardcode /sys/fs/cgroup - -Signed-off-by: Kir Kolyshkin ---- - libcontainer/rootfs_linux.go | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go -index a384abb7e8a5..0f0495b93b3e 100644 ---- a/libcontainer/rootfs_linux.go -+++ b/libcontainer/rootfs_linux.go -@@ -17,6 +17,7 @@ import ( - "github.com/moby/sys/mountinfo" - "github.com/mrunalp/fileutils" - "github.com/opencontainers/runc/libcontainer/cgroups" -+ "github.com/opencontainers/runc/libcontainer/cgroups/fs2" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/devices" - "github.com/opencontainers/runc/libcontainer/system" -@@ -295,17 +296,18 @@ func mountCgroupV1(m *configs.Mount, c *mountConfig) error { - } - - func mountCgroupV2(m *configs.Mount, c *mountConfig) error { -- cgroupPath, err := securejoin.SecureJoin(c.root, m.Destination) -+ dest, err := securejoin.SecureJoin(c.root, m.Destination) - if err != nil { - return err - } -- if err := os.MkdirAll(cgroupPath, 0755); err != nil { -+ if err := os.MkdirAll(dest, 0755); err != nil { - return err - } -- if err := unix.Mount(m.Source, cgroupPath, "cgroup2", uintptr(m.Flags), m.Data); err != nil { -+ if err := unix.Mount(m.Source, dest, "cgroup2", uintptr(m.Flags), m.Data); err != nil { - // when we are in UserNS but CgroupNS is not unshared, we cannot mount cgroup2 (#2158) - if err == unix.EPERM || err == unix.EBUSY { -- return unix.Mount("/sys/fs/cgroup", cgroupPath, "", uintptr(m.Flags)|unix.MS_BIND, "") -+ src := fs2.UnifiedMountpoint -+ return unix.Mount(src, dest, "", uintptr(m.Flags)|unix.MS_BIND, "") - } - return err - } --- -2.31.1 - diff --git a/SOURCES/rc93-0004-Fix-cgroup2-mount-for-rootless-case.patch b/SOURCES/rc93-0004-Fix-cgroup2-mount-for-rootless-case.patch deleted file mode 100644 index 971ded9..0000000 --- a/SOURCES/rc93-0004-Fix-cgroup2-mount-for-rootless-case.patch +++ /dev/null @@ -1,180 +0,0 @@ -From ce352accdfb07a91b5527e70ec8bce658a8b68de Mon Sep 17 00:00:00 2001 -From: Kir Kolyshkin -Date: Tue, 23 Feb 2021 18:27:42 -0800 -Subject: [PATCH 4/5] Fix cgroup2 mount for rootless case - -In case of rootless, cgroup2 mount is not possible (see [1] for more -details), so since commit 9c81440fb5a7 runc bind-mounts the whole -/sys/fs/cgroup into container. - -Problem is, if cgroupns is enabled, /sys/fs/cgroup inside the container -is supposed to show the cgroup files for this cgroup, not the root one. - -The fix is to pass through and use the cgroup path in case cgroup2 -mount failed, cgroupns is enabled, and the path is non-empty. - -Surely this requires the /sys/fs/cgroup mount in the spec, so modify -runc spec --rootless to keep it. - -Before: - - $ ./runc run aaa - # find /sys/fs/cgroup/ -type d - /sys/fs/cgroup - /sys/fs/cgroup/user.slice - /sys/fs/cgroup/user.slice/user-1000.slice - /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service - ... - # ls -l /sys/fs/cgroup/cgroup.controllers - -r--r--r-- 1 nobody nogroup 0 Feb 24 02:22 /sys/fs/cgroup/cgroup.controllers - # wc -w /sys/fs/cgroup/cgroup.procs - 142 /sys/fs/cgroup/cgroup.procs - # cat /sys/fs/cgroup/memory.current - cat: can't open '/sys/fs/cgroup/memory.current': No such file or directory - -After: - - # find /sys/fs/cgroup/ -type d - /sys/fs/cgroup/ - # ls -l /sys/fs/cgroup/cgroup.controllers - -r--r--r-- 1 root root 0 Feb 24 02:43 /sys/fs/cgroup/cgroup.controllers - # wc -w /sys/fs/cgroup/cgroup.procs - 2 /sys/fs/cgroup/cgroup.procs - # cat /sys/fs/cgroup/memory.current - 577536 - -[1] https://github.com/opencontainers/runc/issues/2158 - -Signed-off-by: Kir Kolyshkin ---- - libcontainer/container_linux.go | 3 +++ - libcontainer/init_linux.go | 1 + - libcontainer/rootfs_linux.go | 28 +++++++++++++++++++++------- - libcontainer/specconv/example.go | 18 +++++++++--------- - 4 files changed, 34 insertions(+), 16 deletions(-) - -diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go -index b6100aae9d5a..1cbc734172d0 100644 ---- a/libcontainer/container_linux.go -+++ b/libcontainer/container_linux.go -@@ -610,6 +610,9 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig { - if len(process.Rlimits) > 0 { - cfg.Rlimits = process.Rlimits - } -+ if cgroups.IsCgroup2UnifiedMode() { -+ cfg.Cgroup2Path = c.cgroupManager.Path("") -+ } - - return cfg - } -diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go -index c57af0eebb8b..681797099f46 100644 ---- a/libcontainer/init_linux.go -+++ b/libcontainer/init_linux.go -@@ -70,6 +70,7 @@ type initConfig struct { - RootlessEUID bool `json:"rootless_euid,omitempty"` - RootlessCgroups bool `json:"rootless_cgroups,omitempty"` - SpecState *specs.State `json:"spec_state,omitempty"` -+ Cgroup2Path string `json:"cgroup2_path,omitempty"` - } - - type initer interface { -diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go -index 0f0495b93b3e..5d2d74cf924b 100644 ---- a/libcontainer/rootfs_linux.go -+++ b/libcontainer/rootfs_linux.go -@@ -31,9 +31,11 @@ import ( - const defaultMountFlags = unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV - - type mountConfig struct { -- root string -- label string -- cgroupns bool -+ root string -+ label string -+ cgroup2Path string -+ rootlessCgroups bool -+ cgroupns bool - } - - // needsSetupDev returns true if /dev needs to be set up. -@@ -56,9 +58,11 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { - } - - mountConfig := &mountConfig{ -- root: config.Rootfs, -- label: config.MountLabel, -- cgroupns: config.Namespaces.Contains(configs.NEWCGROUP), -+ root: config.Rootfs, -+ label: config.MountLabel, -+ cgroup2Path: iConfig.Cgroup2Path, -+ rootlessCgroups: iConfig.RootlessCgroups, -+ cgroupns: config.Namespaces.Contains(configs.NEWCGROUP), - } - setupDev := needsSetupDev(config) - for _, m := range config.Mounts { -@@ -307,7 +311,17 @@ func mountCgroupV2(m *configs.Mount, c *mountConfig) error { - // when we are in UserNS but CgroupNS is not unshared, we cannot mount cgroup2 (#2158) - if err == unix.EPERM || err == unix.EBUSY { - src := fs2.UnifiedMountpoint -- return unix.Mount(src, dest, "", uintptr(m.Flags)|unix.MS_BIND, "") -+ if c.cgroupns && c.cgroup2Path != "" { -+ // Emulate cgroupns by bind-mounting -+ // the container cgroup path rather than -+ // the whole /sys/fs/cgroup. -+ src = c.cgroup2Path -+ } -+ err = unix.Mount(src, dest, "", uintptr(m.Flags)|unix.MS_BIND, "") -+ if err == unix.ENOENT && c.rootlessCgroups { -+ err = nil -+ } -+ return err - } - return err - } -diff --git a/libcontainer/specconv/example.go b/libcontainer/specconv/example.go -index 8a201bc78dd9..56bab3bfbfa5 100644 ---- a/libcontainer/specconv/example.go -+++ b/libcontainer/specconv/example.go -@@ -2,6 +2,7 @@ package specconv - - import ( - "os" -+ "path/filepath" - "strings" - - "github.com/opencontainers/runc/libcontainer/cgroups" -@@ -200,8 +201,14 @@ func ToRootless(spec *specs.Spec) { - // Fix up mounts. - var mounts []specs.Mount - for _, mount := range spec.Mounts { -- // Ignore all mounts that are under /sys. -- if strings.HasPrefix(mount.Destination, "/sys") { -+ // Replace the /sys mount with an rbind. -+ if filepath.Clean(mount.Destination) == "/sys" { -+ mounts = append(mounts, specs.Mount{ -+ Source: "/sys", -+ Destination: "/sys", -+ Type: "none", -+ Options: []string{"rbind", "nosuid", "noexec", "nodev", "ro"}, -+ }) - continue - } - -@@ -216,13 +223,6 @@ func ToRootless(spec *specs.Spec) { - mount.Options = options - mounts = append(mounts, mount) - } -- // Add the sysfs mount as an rbind. -- mounts = append(mounts, specs.Mount{ -- Source: "/sys", -- Destination: "/sys", -- Type: "none", -- Options: []string{"rbind", "nosuid", "noexec", "nodev", "ro"}, -- }) - spec.Mounts = mounts - - // Remove cgroup settings. --- -2.31.1 - diff --git a/SOURCES/rc93-0005-rootfs-add-mount-destination-validation.patch b/SOURCES/rc93-0005-rootfs-add-mount-destination-validation.patch deleted file mode 100644 index 6236232..0000000 --- a/SOURCES/rc93-0005-rootfs-add-mount-destination-validation.patch +++ /dev/null @@ -1,562 +0,0 @@ -From 14faf1c20948688a48edb9b41367ab07ac11ca91 Mon Sep 17 00:00:00 2001 -From: Aleksa Sarai -Date: Thu, 1 Apr 2021 12:00:31 -0700 -Subject: [PATCH 5/5] rootfs: add mount destination validation - -Because the target of a mount is inside a container (which may be a -volume that is shared with another container), there exists a race -condition where the target of the mount may change to a path containing -a symlink after we have sanitised the path -- resulting in us -inadvertently mounting the path outside of the container. - -This is not immediately useful because we are in a mount namespace with -MS_SLAVE mount propagation applied to "/", so we cannot mount on top of -host paths in the host namespace. However, if any subsequent mountpoints -in the configuration use a subdirectory of that host path as a source, -those subsequent mounts will use an attacker-controlled source path -(resolved within the host rootfs) -- allowing the bind-mounting of "/" -into the container. - -While arguably configuration issues like this are not entirely within -runc's threat model, within the context of Kubernetes (and possibly -other container managers that provide semi-arbitrary container creation -privileges to untrusted users) this is a legitimate issue. Since we -cannot block mounting from the host into the container, we need to block -the first stage of this attack (mounting onto a path outside the -container). - -The long-term plan to solve this would be to migrate to libpathrs, but -as a stop-gap we implement libpathrs-like path verification through -readlink(/proc/self/fd/$n) and then do mount operations through the -procfd once it's been verified to be inside the container. The target -could move after we've checked it, but if it is inside the container -then we can assume that it is safe for the same reason that libpathrs -operations would be safe. - -A slight wrinkle is the "copyup" functionality we provide for tmpfs, -which is the only case where we want to do a mount on the host -filesystem. To facilitate this, I split out the copy-up functionality -entirely so that the logic isn't interspersed with the regular tmpfs -logic. In addition, all dependencies on m.Destination being overwritten -have been removed since that pattern was just begging to be a source of -more mount-target bugs (we do still have to modify m.Destination for -tmpfs-copyup but we only do it temporarily). - -Fixes: CVE-2021-30465 -Reported-by: Etienne Champetier -Co-authored-by: Noah Meyerhans -Reviewed-by: Samuel Karp -Reviewed-by: Kir Kolyshkin (@kolyshkin) -Reviewed-by: Akihiro Suda -Signed-off-by: Aleksa Sarai ---- - libcontainer/container_linux.go | 1 - - libcontainer/rootfs_linux.go | 251 +++++++++++++++---------------- - libcontainer/utils/utils.go | 54 +++++++ - libcontainer/utils/utils_test.go | 35 +++++ - 4 files changed, 213 insertions(+), 128 deletions(-) - -diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go -index 1cbc734172d0..70b388b1252e 100644 ---- a/libcontainer/container_linux.go -+++ b/libcontainer/container_linux.go -@@ -1202,7 +1202,6 @@ func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error { - if err := checkProcMount(c.config.Rootfs, dest, ""); err != nil { - return err - } -- m.Destination = dest - if err := os.MkdirAll(dest, 0755); err != nil { - return err - } -diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go -index 5d2d74cf924b..96be669c365e 100644 ---- a/libcontainer/rootfs_linux.go -+++ b/libcontainer/rootfs_linux.go -@@ -25,6 +25,7 @@ import ( - libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" - "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/selinux/go-selinux/label" -+ "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" - ) - -@@ -228,8 +229,6 @@ func prepareBindMount(m *configs.Mount, rootfs string) error { - if err := checkProcMount(rootfs, dest, m.Source); err != nil { - return err - } -- // update the mount with the correct dest after symlinks are resolved. -- m.Destination = dest - if err := createIfNotExists(dest, stat.IsDir()); err != nil { - return err - } -@@ -266,18 +265,21 @@ func mountCgroupV1(m *configs.Mount, c *mountConfig) error { - if err := os.MkdirAll(subsystemPath, 0755); err != nil { - return err - } -- flags := defaultMountFlags -- if m.Flags&unix.MS_RDONLY != 0 { -- flags = flags | unix.MS_RDONLY -- } -- cgroupmount := &configs.Mount{ -- Source: "cgroup", -- Device: "cgroup", // this is actually fstype -- Destination: subsystemPath, -- Flags: flags, -- Data: filepath.Base(subsystemPath), -- } -- if err := mountNewCgroup(cgroupmount); err != nil { -+ if err := utils.WithProcfd(c.root, b.Destination, func(procfd string) error { -+ flags := defaultMountFlags -+ if m.Flags&unix.MS_RDONLY != 0 { -+ flags = flags | unix.MS_RDONLY -+ } -+ var ( -+ source = "cgroup" -+ data = filepath.Base(subsystemPath) -+ ) -+ if data == "systemd" { -+ data = cgroups.CgroupNamePrefix + data -+ source = "systemd" -+ } -+ return unix.Mount(source, procfd, "cgroup", uintptr(flags), data) -+ }); err != nil { - return err - } - } else { -@@ -307,33 +309,79 @@ func mountCgroupV2(m *configs.Mount, c *mountConfig) error { - if err := os.MkdirAll(dest, 0755); err != nil { - return err - } -- if err := unix.Mount(m.Source, dest, "cgroup2", uintptr(m.Flags), m.Data); err != nil { -- // when we are in UserNS but CgroupNS is not unshared, we cannot mount cgroup2 (#2158) -- if err == unix.EPERM || err == unix.EBUSY { -- src := fs2.UnifiedMountpoint -- if c.cgroupns && c.cgroup2Path != "" { -- // Emulate cgroupns by bind-mounting -- // the container cgroup path rather than -- // the whole /sys/fs/cgroup. -- src = c.cgroup2Path -- } -- err = unix.Mount(src, dest, "", uintptr(m.Flags)|unix.MS_BIND, "") -- if err == unix.ENOENT && c.rootlessCgroups { -- err = nil -+ return utils.WithProcfd(c.root, m.Destination, func(procfd string) error { -+ if err := unix.Mount(m.Source, procfd, "cgroup2", uintptr(m.Flags), m.Data); err != nil { -+ // when we are in UserNS but CgroupNS is not unshared, we cannot mount cgroup2 (#2158) -+ if err == unix.EPERM || err == unix.EBUSY { -+ src := fs2.UnifiedMountpoint -+ if c.cgroupns && c.cgroup2Path != "" { -+ // Emulate cgroupns by bind-mounting -+ // the container cgroup path rather than -+ // the whole /sys/fs/cgroup. -+ src = c.cgroup2Path -+ } -+ err = unix.Mount(src, procfd, "", uintptr(m.Flags)|unix.MS_BIND, "") -+ if err == unix.ENOENT && c.rootlessCgroups { -+ err = nil -+ } - } - return err - } -+ return nil -+ }) -+} -+ -+func doTmpfsCopyUp(m *configs.Mount, rootfs, mountLabel string) (Err error) { -+ // Set up a scratch dir for the tmpfs on the host. -+ tmpdir, err := prepareTmp("/tmp") -+ if err != nil { -+ return newSystemErrorWithCause(err, "tmpcopyup: failed to setup tmpdir") -+ } -+ defer cleanupTmp(tmpdir) -+ tmpDir, err := ioutil.TempDir(tmpdir, "runctmpdir") -+ if err != nil { -+ return newSystemErrorWithCause(err, "tmpcopyup: failed to create tmpdir") -+ } -+ defer os.RemoveAll(tmpDir) -+ -+ // Configure the *host* tmpdir as if it's the container mount. We change -+ // m.Destination since we are going to mount *on the host*. -+ oldDest := m.Destination -+ m.Destination = tmpDir -+ err = mountPropagate(m, "/", mountLabel) -+ m.Destination = oldDest -+ if err != nil { - return err - } -- return nil -+ defer func() { -+ if Err != nil { -+ if err := unix.Unmount(tmpDir, unix.MNT_DETACH); err != nil { -+ logrus.Warnf("tmpcopyup: failed to unmount tmpdir on error: %v", err) -+ } -+ } -+ }() -+ -+ return utils.WithProcfd(rootfs, m.Destination, func(procfd string) (Err error) { -+ // Copy the container data to the host tmpdir. We append "/" to force -+ // CopyDirectory to resolve the symlink rather than trying to copy the -+ // symlink itself. -+ if err := fileutils.CopyDirectory(procfd+"/", tmpDir); err != nil { -+ return fmt.Errorf("tmpcopyup: failed to copy %s to %s (%s): %w", m.Destination, procfd, tmpDir, err) -+ } -+ // Now move the mount into the container. -+ if err := unix.Mount(tmpDir, procfd, "", unix.MS_MOVE, ""); err != nil { -+ return fmt.Errorf("tmpcopyup: failed to move mount %s to %s (%s): %w", tmpDir, procfd, m.Destination, err) -+ } -+ return nil -+ }) - } - - func mountToRootfs(m *configs.Mount, c *mountConfig) error { - rootfs := c.root - mountLabel := c.label -- dest := m.Destination -- if !strings.HasPrefix(dest, rootfs) { -- dest = filepath.Join(rootfs, dest) -+ dest, err := securejoin.SecureJoin(rootfs, m.Destination) -+ if err != nil { -+ return err - } - - switch m.Device { -@@ -364,53 +412,21 @@ func mountToRootfs(m *configs.Mount, c *mountConfig) error { - } - return label.SetFileLabel(dest, mountLabel) - case "tmpfs": -- copyUp := m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP -- tmpDir := "" -- // dest might be an absolute symlink, so it needs -- // to be resolved under rootfs. -- dest, err := securejoin.SecureJoin(rootfs, m.Destination) -- if err != nil { -- return err -- } -- m.Destination = dest - stat, err := os.Stat(dest) - if err != nil { - if err := os.MkdirAll(dest, 0755); err != nil { - return err - } - } -- if copyUp { -- tmpdir, err := prepareTmp("/tmp") -- if err != nil { -- return newSystemErrorWithCause(err, "tmpcopyup: failed to setup tmpdir") -- } -- defer cleanupTmp(tmpdir) -- tmpDir, err = ioutil.TempDir(tmpdir, "runctmpdir") -- if err != nil { -- return newSystemErrorWithCause(err, "tmpcopyup: failed to create tmpdir") -- } -- defer os.RemoveAll(tmpDir) -- m.Destination = tmpDir -+ -+ if m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP { -+ err = doTmpfsCopyUp(m, rootfs, mountLabel) -+ } else { -+ err = mountPropagate(m, rootfs, mountLabel) - } -- if err := mountPropagate(m, rootfs, mountLabel); err != nil { -+ if err != nil { - return err - } -- if copyUp { -- if err := fileutils.CopyDirectory(dest, tmpDir); err != nil { -- errMsg := fmt.Errorf("tmpcopyup: failed to copy %s to %s: %v", dest, tmpDir, err) -- if err1 := unix.Unmount(tmpDir, unix.MNT_DETACH); err1 != nil { -- return newSystemErrorWithCausef(err1, "tmpcopyup: %v: failed to unmount", errMsg) -- } -- return errMsg -- } -- if err := unix.Mount(tmpDir, dest, "", unix.MS_MOVE, ""); err != nil { -- errMsg := fmt.Errorf("tmpcopyup: failed to move mount %s to %s: %v", tmpDir, dest, err) -- if err1 := unix.Unmount(tmpDir, unix.MNT_DETACH); err1 != nil { -- return newSystemErrorWithCausef(err1, "tmpcopyup: %v: failed to unmount", errMsg) -- } -- return errMsg -- } -- } - if stat != nil { - if err = os.Chmod(dest, stat.Mode()); err != nil { - return err -@@ -454,19 +470,9 @@ func mountToRootfs(m *configs.Mount, c *mountConfig) error { - } - return mountCgroupV1(m, c) - default: -- // ensure that the destination of the mount is resolved of symlinks at mount time because -- // any previous mounts can invalidate the next mount's destination. -- // this can happen when a user specifies mounts within other mounts to cause breakouts or other -- // evil stuff to try to escape the container's rootfs. -- var err error -- if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { -- return err -- } - if err := checkProcMount(rootfs, dest, m.Source); err != nil { - return err - } -- // update the mount with the correct dest after symlinks are resolved. -- m.Destination = dest - if err := os.MkdirAll(dest, 0755); err != nil { - return err - } -@@ -649,7 +655,7 @@ func createDevices(config *configs.Config) error { - return nil - } - --func bindMountDeviceNode(dest string, node *devices.Device) error { -+func bindMountDeviceNode(rootfs, dest string, node *devices.Device) error { - f, err := os.Create(dest) - if err != nil && !os.IsExist(err) { - return err -@@ -657,7 +663,9 @@ func bindMountDeviceNode(dest string, node *devices.Device) error { - if f != nil { - f.Close() - } -- return unix.Mount(node.Path, dest, "bind", unix.MS_BIND, "") -+ return utils.WithProcfd(rootfs, dest, func(procfd string) error { -+ return unix.Mount(node.Path, procfd, "bind", unix.MS_BIND, "") -+ }) - } - - // Creates the device node in the rootfs of the container. -@@ -666,18 +674,21 @@ func createDeviceNode(rootfs string, node *devices.Device, bind bool) error { - // The node only exists for cgroup reasons, ignore it here. - return nil - } -- dest := filepath.Join(rootfs, node.Path) -+ dest, err := securejoin.SecureJoin(rootfs, node.Path) -+ if err != nil { -+ return err -+ } - if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil { - return err - } - if bind { -- return bindMountDeviceNode(dest, node) -+ return bindMountDeviceNode(rootfs, dest, node) - } - if err := mknodDevice(dest, node); err != nil { - if os.IsExist(err) { - return nil - } else if os.IsPermission(err) { -- return bindMountDeviceNode(dest, node) -+ return bindMountDeviceNode(rootfs, dest, node) - } - return err - } -@@ -1013,61 +1024,47 @@ func writeSystemProperty(key, value string) error { - } - - func remount(m *configs.Mount, rootfs string) error { -- var ( -- dest = m.Destination -- ) -- if !strings.HasPrefix(dest, rootfs) { -- dest = filepath.Join(rootfs, dest) -- } -- return unix.Mount(m.Source, dest, m.Device, uintptr(m.Flags|unix.MS_REMOUNT), "") -+ return utils.WithProcfd(rootfs, m.Destination, func(procfd string) error { -+ return unix.Mount(m.Source, procfd, m.Device, uintptr(m.Flags|unix.MS_REMOUNT), "") -+ }) - } - - // Do the mount operation followed by additional mounts required to take care --// of propagation flags. -+// of propagation flags. This will always be scoped inside the container rootfs. - func mountPropagate(m *configs.Mount, rootfs string, mountLabel string) error { - var ( -- dest = m.Destination - data = label.FormatMountLabel(m.Data, mountLabel) - flags = m.Flags - ) -- if libcontainerUtils.CleanPath(dest) == "/dev" { -- flags &= ^unix.MS_RDONLY -- } -- -- // Mount it rw to allow chmod operation. A remount will be performed -- // later to make it ro if set. -- if m.Device == "tmpfs" { -+ // Delay mounting the filesystem read-only if we need to do further -+ // operations on it. We need to set up files in "/dev" and tmpfs mounts may -+ // need to be chmod-ed after mounting. The mount will be remounted ro later -+ // in finalizeRootfs() if necessary. -+ if libcontainerUtils.CleanPath(m.Destination) == "/dev" || m.Device == "tmpfs" { - flags &= ^unix.MS_RDONLY - } - -- copyUp := m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP -- if !(copyUp || strings.HasPrefix(dest, rootfs)) { -- dest = filepath.Join(rootfs, dest) -- } -- -- if err := unix.Mount(m.Source, dest, m.Device, uintptr(flags), data); err != nil { -- return err -- } -- -- for _, pflag := range m.PropagationFlags { -- if err := unix.Mount("", dest, "", uintptr(pflag), ""); err != nil { -- return err -+ // Because the destination is inside a container path which might be -+ // mutating underneath us, we verify that we are actually going to mount -+ // inside the container with WithProcfd() -- mounting through a procfd -+ // mounts on the target. -+ if err := utils.WithProcfd(rootfs, m.Destination, func(procfd string) error { -+ return unix.Mount(m.Source, procfd, m.Device, uintptr(flags), data) -+ }); err != nil { -+ return fmt.Errorf("mount through procfd: %w", err) -+ } -+ // We have to apply mount propagation flags in a separate WithProcfd() call -+ // because the previous call invalidates the passed procfd -- the mount -+ // target needs to be re-opened. -+ if err := utils.WithProcfd(rootfs, m.Destination, func(procfd string) error { -+ for _, pflag := range m.PropagationFlags { -+ if err := unix.Mount("", procfd, "", uintptr(pflag), ""); err != nil { -+ return err -+ } - } -- } -- return nil --} -- --func mountNewCgroup(m *configs.Mount) error { -- var ( -- data = m.Data -- source = m.Source -- ) -- if data == "systemd" { -- data = cgroups.CgroupNamePrefix + data -- source = "systemd" -- } -- if err := unix.Mount(source, m.Destination, m.Device, uintptr(m.Flags), data); err != nil { -- return err -+ return nil -+ }); err != nil { -+ return fmt.Errorf("change mount propagation through procfd: %w", err) - } - return nil - } -diff --git a/libcontainer/utils/utils.go b/libcontainer/utils/utils.go -index 1b72b7a1c1ba..cd78f23e1bd0 100644 ---- a/libcontainer/utils/utils.go -+++ b/libcontainer/utils/utils.go -@@ -3,12 +3,15 @@ package utils - import ( - "encoding/binary" - "encoding/json" -+ "fmt" - "io" - "os" - "path/filepath" -+ "strconv" - "strings" - "unsafe" - -+ "github.com/cyphar/filepath-securejoin" - "golang.org/x/sys/unix" - ) - -@@ -88,6 +91,57 @@ func CleanPath(path string) string { - return filepath.Clean(path) - } - -+// stripRoot returns the passed path, stripping the root path if it was -+// (lexicially) inside it. Note that both passed paths will always be treated -+// as absolute, and the returned path will also always be absolute. In -+// addition, the paths are cleaned before stripping the root. -+func stripRoot(root, path string) string { -+ // Make the paths clean and absolute. -+ root, path = CleanPath("/"+root), CleanPath("/"+path) -+ switch { -+ case path == root: -+ path = "/" -+ case root == "/": -+ // do nothing -+ case strings.HasPrefix(path, root+"/"): -+ path = strings.TrimPrefix(path, root+"/") -+ } -+ return CleanPath("/" + path) -+} -+ -+// WithProcfd runs the passed closure with a procfd path (/proc/self/fd/...) -+// corresponding to the unsafePath resolved within the root. Before passing the -+// fd, this path is verified to have been inside the root -- so operating on it -+// through the passed fdpath should be safe. Do not access this path through -+// the original path strings, and do not attempt to use the pathname outside of -+// the passed closure (the file handle will be freed once the closure returns). -+func WithProcfd(root, unsafePath string, fn func(procfd string) error) error { -+ // Remove the root then forcefully resolve inside the root. -+ unsafePath = stripRoot(root, unsafePath) -+ path, err := securejoin.SecureJoin(root, unsafePath) -+ if err != nil { -+ return fmt.Errorf("resolving path inside rootfs failed: %v", err) -+ } -+ -+ // Open the target path. -+ fh, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC, 0) -+ if err != nil { -+ return fmt.Errorf("open o_path procfd: %w", err) -+ } -+ defer fh.Close() -+ -+ // Double-check the path is the one we expected. -+ procfd := "/proc/self/fd/" + strconv.Itoa(int(fh.Fd())) -+ if realpath, err := os.Readlink(procfd); err != nil { -+ return fmt.Errorf("procfd verification failed: %w", err) -+ } else if realpath != path { -+ return fmt.Errorf("possibly malicious path detected -- refusing to operate on %s", realpath) -+ } -+ -+ // Run the closure. -+ return fn(procfd) -+} -+ - // SearchLabels searches a list of key-value pairs for the provided key and - // returns the corresponding value. The pairs must be separated with '='. - func SearchLabels(labels []string, query string) string { -diff --git a/libcontainer/utils/utils_test.go b/libcontainer/utils/utils_test.go -index 7f38ed169a6b..d33662238d36 100644 ---- a/libcontainer/utils/utils_test.go -+++ b/libcontainer/utils/utils_test.go -@@ -143,3 +143,38 @@ func TestCleanPath(t *testing.T) { - t.Errorf("expected to receive '/foo' and received %s", path) - } - } -+ -+func TestStripRoot(t *testing.T) { -+ for _, test := range []struct { -+ root, path, out string -+ }{ -+ // Works with multiple components. -+ {"/a/b", "/a/b/c", "/c"}, -+ {"/hello/world", "/hello/world/the/quick-brown/fox", "/the/quick-brown/fox"}, -+ // '/' must be a no-op. -+ {"/", "/a/b/c", "/a/b/c"}, -+ // Must be the correct order. -+ {"/a/b", "/a/c/b", "/a/c/b"}, -+ // Must be at start. -+ {"/abc/def", "/foo/abc/def/bar", "/foo/abc/def/bar"}, -+ // Must be a lexical parent. -+ {"/foo/bar", "/foo/barSAMECOMPONENT", "/foo/barSAMECOMPONENT"}, -+ // Must only strip the root once. -+ {"/foo/bar", "/foo/bar/foo/bar/baz", "/foo/bar/baz"}, -+ // Deal with .. in a fairly sane way. -+ {"/foo/bar", "/foo/bar/../baz", "/foo/baz"}, -+ {"/foo/bar", "../../../../../../foo/bar/baz", "/baz"}, -+ {"/foo/bar", "/../../../../../../foo/bar/baz", "/baz"}, -+ {"/foo/bar/../baz", "/foo/baz/bar", "/bar"}, -+ {"/foo/bar/../baz", "/foo/baz/../bar/../baz/./foo", "/foo"}, -+ // All paths are made absolute before stripping. -+ {"foo/bar", "/foo/bar/baz/bee", "/baz/bee"}, -+ {"/foo/bar", "foo/bar/baz/beef", "/baz/beef"}, -+ {"foo/bar", "foo/bar/baz/beets", "/baz/beets"}, -+ } { -+ got := stripRoot(test.root, test.path) -+ if got != test.out { -+ t.Errorf("stripRoot(%q, %q) -- got %q, expected %q", test.root, test.path, got, test.out) -+ } -+ } -+} --- -2.31.1 - diff --git a/SOURCES/runc-1947432.patch b/SOURCES/runc-1947432.patch deleted file mode 100644 index 79ae82e..0000000 --- a/SOURCES/runc-1947432.patch +++ /dev/null @@ -1,102 +0,0 @@ -From a2050ea471b0eb3c7240282219773c0f1d7ec554 Mon Sep 17 00:00:00 2001 -From: Kir Kolyshkin -Date: Wed, 7 Apr 2021 16:45:39 -0700 -Subject: [PATCH 1/2] runc run: fix start for rootless + host pidns - -Currently, runc fails like this when used from rootless podman -with host PID namespace: - -> $ podman --runtime=runc run --pid=host --rm -it busybox sh -> WARN[0000] additional gid=10 is not present in the user namespace, skip setting it -> Error: container_linux.go:380: starting container process caused: -> process_linux.go:545: container init caused: readonly path /proc/asound: -> operation not permitted: OCI permission denied - -(Here /proc/asound is the first path from OCI spec's readonlyPaths). - -The code uses MS_BIND|MS_REMOUNT flags that have a special meaning in -the kernel ("keep the flags like nodev, nosuid, noexec as is"). -For some reason, this "special meaning" trick is not working for the -above use case (rootless podman + no PID namespace), and I don't know -how to reproduce this without podman. - -Instead of relying on the kernel feature, let's just get the current -mount flags using fstatfs(2) and add those that needs to be preserved. - -While at it, wrap errors from unix.Mount into os.PathError to make -errors a bit less cryptic. - -Signed-off-by: Kir Kolyshkin ---- - libcontainer/rootfs_linux.go | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - -diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go -index ed38e77219..3d67287926 100644 ---- a/libcontainer/rootfs_linux.go -+++ b/libcontainer/rootfs_linux.go -@@ -931,9 +931,20 @@ func readonlyPath(path string) error { - if os.IsNotExist(err) { - return nil - } -- return err -+ return &os.PathError{Op: "bind-mount", Path: path, Err: err} -+ } -+ -+ var s unix.Statfs_t -+ if err := unix.Statfs(path, &s); err != nil { -+ return &os.PathError{Op: "statfs", Path: path, Err: err} - } -- return unix.Mount(path, path, "", unix.MS_BIND|unix.MS_REMOUNT|unix.MS_RDONLY|unix.MS_REC, "") -+ flags := uintptr(s.Flags) & (unix.MS_NOSUID | unix.MS_NODEV | unix.MS_NOEXEC) -+ -+ if err := unix.Mount(path, path, "", flags|unix.MS_BIND|unix.MS_REMOUNT|unix.MS_RDONLY, ""); err != nil { -+ return &os.PathError{Op: "bind-mount-ro", Path: path, Err: err} -+ } -+ -+ return nil - } - - // remountReadonly will remount an existing mount point and ensure that it is read-only. - -From 31dd1e499b2f590cd3bcf59153491967ea2a8e1f Mon Sep 17 00:00:00 2001 -From: Kir Kolyshkin -Date: Wed, 14 Apr 2021 10:58:42 -0700 -Subject: [PATCH 2/2] tests/int: add rootless + host pidns test case - -For the fix, see previous commit. Without the fix, this test case fails: - -> container_linux.go:380: starting container process caused: -> process_linux.go:545: container init caused: readonly path /proc/bus: -> operation not permitted - -Signed-off-by: Kir Kolyshkin ---- - tests/integration/start_hello.bats | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/tests/integration/start_hello.bats b/tests/integration/start_hello.bats -index 5c2a66fdb1..858847032c 100644 ---- a/tests/integration/start_hello.bats -+++ b/tests/integration/start_hello.bats -@@ -59,3 +59,20 @@ function teardown() { - - [[ "$(cat pid.txt)" =~ [0-9]+ ]] - } -+ -+# https://github.com/opencontainers/runc/pull/2897 -+@test "runc run [rootless with host pidns]" { -+ requires rootless_no_features -+ -+ # Remove pid namespace, and replace /proc mount -+ # with a bind mount from the host. -+ update_config ' .linux.namespaces -= [{"type": "pid"}] -+ | .mounts |= map((select(.type == "proc") -+ | .type = "none" -+ | .source = "/proc" -+ | .options = ["rbind", "nosuid", "nodev", "noexec"] -+ ) // .)' -+ -+ runc run test_hello -+ [ "$status" -eq 0 ] -+} diff --git a/SPECS/runc.spec b/SPECS/runc.spec index 5f6e4f7..ba36e15 100644 --- a/SPECS/runc.spec +++ b/SPECS/runc.spec @@ -19,11 +19,11 @@ go build -buildmode pie -compiler gc -tags="rpm_crashtraceback libtrust_openssl # https://github.com/opencontainers/runc %global import_path %{provider}.%{provider_tld}/%{project}/%{repo} %global git0 https://%{import_path} -%global release_candidate rc93 +%global release_candidate rc95 Name: %{repo} Version: 1.0.0 -Release: 73.%{release_candidate}%{?dist} +Release: 74.%{release_candidate}%{?dist} Summary: CLI for running Open Containers # https://fedoraproject.org/wiki/PackagingDrafts/Go#Go_Language_Architectures #ExclusiveArch: %%{go_arches} @@ -33,14 +33,6 @@ ExcludeArch: %{ix86} License: ASL 2.0 URL: %{git0} Source0: %{git0}/archive/v1.0.0-%{release_candidate}.tar.gz -Patch1: rc93-0001-libct-newInitConfig-nit.patch -Patch2: rc93-0002-libct-rootfs-introduce-and-use-mountConfig.patch -Patch3: rc93-0003-libct-rootfs-mountCgroupV2-minor-refactor.patch -Patch4: rc93-0004-Fix-cgroup2-mount-for-rootless-case.patch -Patch5: rc93-0005-rootfs-add-mount-destination-validation.patch -# related bug: https://bugzilla.redhat.com/show_bug.cgi?id=1947432 -# patch: https://github.com/opencontainers/runc/pull/2897.patch -Patch6: runc-1947432.patch Provides: oci-runtime = 1 BuildRequires: golang >= 1.12.12-4 BuildRequires: git @@ -65,6 +57,7 @@ pushd GOPATH popd pushd GOPATH/src/%{import_path} +export GO111MODULE=off export GOPATH=%{gopath}:$(pwd)/GOPATH export CGO_CFLAGS="%{optflags} -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64" export BUILDTAGS="selinux seccomp" @@ -98,6 +91,10 @@ install -p -m 0644 contrib/completions/bash/%{name} %{buildroot}%{_datadir}/bash %{_datadir}/bash-completion/completions/%{name} %changelog +* Thu Jul 01 2021 Jindrich Novy - 1.0.0-74.rc95 +- updated to rc95 to fix CVE-2021-30465 +- Related: #1954702 + * Thu May 13 2021 Jindrich Novy - 1.0.0-73.rc93 - fix "podman run --pid=host command causes OCI permission error" - Related: #1954702